linux/drivers/isdn/capi/capidrv.c
<<
>>
Prefs
   1/* $Id: capidrv.c,v 1.1.2.2 2004/01/12 23:17:24 keil Exp $
   2 *
   3 * ISDN4Linux Driver, using capi20 interface (kernelcapi)
   4 *
   5 * Copyright 1997 by Carsten Paeth <calle@calle.de>
   6 *
   7 * This software may be used and distributed according to the terms
   8 * of the GNU General Public License, incorporated herein by reference.
   9 *
  10 */
  11
  12#include <linux/module.h>
  13#include <linux/errno.h>
  14#include <linux/kernel.h>
  15#include <linux/major.h>
  16#include <linux/slab.h>
  17#include <linux/fcntl.h>
  18#include <linux/fs.h>
  19#include <linux/signal.h>
  20#include <linux/mm.h>
  21#include <linux/timer.h>
  22#include <linux/wait.h>
  23#include <linux/skbuff.h>
  24#include <linux/isdn.h>
  25#include <linux/isdnif.h>
  26#include <linux/proc_fs.h>
  27#include <linux/capi.h>
  28#include <linux/kernelcapi.h>
  29#include <linux/ctype.h>
  30#include <linux/init.h>
  31#include <linux/moduleparam.h>
  32
  33#include <linux/isdn/capiutil.h>
  34#include <linux/isdn/capicmd.h>
  35#include "capidrv.h"
  36
  37static char *revision = "$Revision: 1.1.2.2 $";
  38static int debugmode = 0;
  39
  40MODULE_DESCRIPTION("CAPI4Linux: Interface to ISDN4Linux");
  41MODULE_AUTHOR("Carsten Paeth");
  42MODULE_LICENSE("GPL");
  43module_param(debugmode, uint, 0);
  44
  45/* -------- type definitions ----------------------------------------- */
  46
  47
  48struct capidrv_contr {
  49
  50        struct capidrv_contr *next;
  51        struct module *owner;
  52        u32 contrnr;
  53        char name[20];
  54
  55        /*
  56         * for isdn4linux
  57         */
  58        isdn_if interface;
  59        int myid;
  60
  61        /*
  62         * LISTEN state
  63         */
  64        int state;
  65        u32 cipmask;
  66        u32 cipmask2;
  67        struct timer_list listentimer;
  68
  69        /*
  70         * ID of capi message sent
  71         */
  72        u16 msgid;
  73
  74        /*
  75         * B-Channels
  76         */
  77        int nbchan;
  78        struct capidrv_bchan {
  79                struct capidrv_contr *contr;
  80                u8 msn[ISDN_MSNLEN];
  81                int l2;
  82                int l3;
  83                u8 num[ISDN_MSNLEN];
  84                u8 mynum[ISDN_MSNLEN];
  85                int si1;
  86                int si2;
  87                int incoming;
  88                int disconnecting;
  89                struct capidrv_plci {
  90                        struct capidrv_plci *next;
  91                        u32 plci;
  92                        u32 ncci;       /* ncci for CONNECT_ACTIVE_IND */
  93                        u16 msgid;      /* to identfy CONNECT_CONF */
  94                        int chan;
  95                        int state;
  96                        int leasedline;
  97                        struct capidrv_ncci {
  98                                struct capidrv_ncci *next;
  99                                struct capidrv_plci *plcip;
 100                                u32 ncci;
 101                                u16 msgid;      /* to identfy CONNECT_B3_CONF */
 102                                int chan;
 103                                int state;
 104                                int oldstate;
 105                                /* */
 106                                u16 datahandle;
 107                                struct ncci_datahandle_queue {
 108                                    struct ncci_datahandle_queue *next;
 109                                    u16                         datahandle;
 110                                    int                           len;
 111                                } *ackqueue;
 112                        } *ncci_list;
 113                } *plcip;
 114                struct capidrv_ncci *nccip;
 115        } *bchans;
 116
 117        struct capidrv_plci *plci_list;
 118
 119        /* for q931 data */
 120        u8  q931_buf[4096];
 121        u8 *q931_read;
 122        u8 *q931_write;
 123        u8 *q931_end;
 124};
 125
 126
 127struct capidrv_data {
 128        struct capi20_appl ap;
 129        int ncontr;
 130        struct capidrv_contr *contr_list;
 131};
 132
 133typedef struct capidrv_plci capidrv_plci;
 134typedef struct capidrv_ncci capidrv_ncci;
 135typedef struct capidrv_contr capidrv_contr;
 136typedef struct capidrv_data capidrv_data;
 137typedef struct capidrv_bchan capidrv_bchan;
 138
 139/* -------- data definitions ----------------------------------------- */
 140
 141static capidrv_data global;
 142static DEFINE_SPINLOCK(global_lock);
 143
 144static void handle_dtrace_data(capidrv_contr *card,
 145        int send, int level2, u8 *data, u16 len);
 146
 147/* -------- convert functions ---------------------------------------- */
 148
 149static inline u32 b1prot(int l2, int l3)
 150{
 151        switch (l2) {
 152        case ISDN_PROTO_L2_X75I:
 153        case ISDN_PROTO_L2_X75UI:
 154        case ISDN_PROTO_L2_X75BUI:
 155                return 0;
 156        case ISDN_PROTO_L2_HDLC:
 157        default:
 158                return 0;
 159        case ISDN_PROTO_L2_TRANS:
 160                return 1;
 161        case ISDN_PROTO_L2_V11096:
 162        case ISDN_PROTO_L2_V11019:
 163        case ISDN_PROTO_L2_V11038:
 164                return 2;
 165        case ISDN_PROTO_L2_FAX:
 166                return 4;
 167        case ISDN_PROTO_L2_MODEM:
 168                return 8;
 169        }
 170}
 171
 172static inline u32 b2prot(int l2, int l3)
 173{
 174        switch (l2) {
 175        case ISDN_PROTO_L2_X75I:
 176        case ISDN_PROTO_L2_X75UI:
 177        case ISDN_PROTO_L2_X75BUI:
 178        default:
 179                return 0;
 180        case ISDN_PROTO_L2_HDLC:
 181        case ISDN_PROTO_L2_TRANS:
 182        case ISDN_PROTO_L2_V11096:
 183        case ISDN_PROTO_L2_V11019:
 184        case ISDN_PROTO_L2_V11038:
 185        case ISDN_PROTO_L2_MODEM:
 186                return 1;
 187        case ISDN_PROTO_L2_FAX:
 188                return 4;
 189        }
 190}
 191
 192static inline u32 b3prot(int l2, int l3)
 193{
 194        switch (l2) {
 195        case ISDN_PROTO_L2_X75I:
 196        case ISDN_PROTO_L2_X75UI:
 197        case ISDN_PROTO_L2_X75BUI:
 198        case ISDN_PROTO_L2_HDLC:
 199        case ISDN_PROTO_L2_TRANS:
 200        case ISDN_PROTO_L2_V11096:
 201        case ISDN_PROTO_L2_V11019:
 202        case ISDN_PROTO_L2_V11038:
 203        case ISDN_PROTO_L2_MODEM:
 204        default:
 205                return 0;
 206        case ISDN_PROTO_L2_FAX:
 207                return 4;
 208        }
 209}
 210
 211static _cstruct b1config_async_v110(u16 rate)
 212{
 213        /* CAPI-Spec "B1 Configuration" */
 214        static unsigned char buf[9];
 215        buf[0] = 8; /* len */
 216        /* maximum bitrate */
 217        buf[1] = rate & 0xff; buf[2] = (rate >> 8) & 0xff;
 218        buf[3] = 8; buf[4] = 0; /* 8 bits per character */
 219        buf[5] = 0; buf[6] = 0; /* parity none */
 220        buf[7] = 0; buf[8] = 0; /* 1 stop bit */
 221        return buf;
 222}
 223
 224static _cstruct b1config(int l2, int l3)
 225{
 226        switch (l2) {
 227        case ISDN_PROTO_L2_X75I:
 228        case ISDN_PROTO_L2_X75UI:
 229        case ISDN_PROTO_L2_X75BUI:
 230        case ISDN_PROTO_L2_HDLC:
 231        case ISDN_PROTO_L2_TRANS:
 232        default:
 233                return NULL;
 234        case ISDN_PROTO_L2_V11096:
 235            return b1config_async_v110(9600);
 236        case ISDN_PROTO_L2_V11019:
 237            return b1config_async_v110(19200);
 238        case ISDN_PROTO_L2_V11038:
 239            return b1config_async_v110(38400);
 240        }
 241}
 242
 243static inline u16 si2cip(u8 si1, u8 si2)
 244{
 245        static const u8 cip[17][5] =
 246        {
 247        /*  0  1  2  3  4  */
 248                {0, 0, 0, 0, 0},        /*0 */
 249                {16, 16, 4, 26, 16},    /*1 */
 250                {17, 17, 17, 4, 4},     /*2 */
 251                {2, 2, 2, 2, 2},        /*3 */
 252                {18, 18, 18, 18, 18},   /*4 */
 253                {2, 2, 2, 2, 2},        /*5 */
 254                {0, 0, 0, 0, 0},        /*6 */
 255                {2, 2, 2, 2, 2},        /*7 */
 256                {2, 2, 2, 2, 2},        /*8 */
 257                {21, 21, 21, 21, 21},   /*9 */
 258                {19, 19, 19, 19, 19},   /*10 */
 259                {0, 0, 0, 0, 0},        /*11 */
 260                {0, 0, 0, 0, 0},        /*12 */
 261                {0, 0, 0, 0, 0},        /*13 */
 262                {0, 0, 0, 0, 0},        /*14 */
 263                {22, 22, 22, 22, 22},   /*15 */
 264                {27, 27, 27, 28, 27}    /*16 */
 265        };
 266        if (si1 > 16)
 267                si1 = 0;
 268        if (si2 > 4)
 269                si2 = 0;
 270
 271        return (u16) cip[si1][si2];
 272}
 273
 274static inline u8 cip2si1(u16 cipval)
 275{
 276        static const u8 si[32] =
 277        {7, 1, 7, 7, 1, 1, 7, 7,        /*0-7 */
 278         7, 1, 0, 0, 0, 0, 0, 0,        /*8-15 */
 279         1, 2, 4, 10, 9, 9, 15, 7,      /*16-23 */
 280         7, 7, 1, 16, 16, 0, 0, 0};     /*24-31 */
 281
 282        if (cipval > 31)
 283                cipval = 0;     /* .... */
 284        return si[cipval];
 285}
 286
 287static inline u8 cip2si2(u16 cipval)
 288{
 289        static const u8 si[32] =
 290        {0, 0, 0, 0, 2, 3, 0, 0,        /*0-7 */
 291         0, 3, 0, 0, 0, 0, 0, 0,        /*8-15 */
 292         1, 2, 0, 0, 9, 0, 0, 0,        /*16-23 */
 293         0, 0, 3, 2, 3, 0, 0, 0};       /*24-31 */
 294
 295        if (cipval > 31)
 296                cipval = 0;     /* .... */
 297        return si[cipval];
 298}
 299
 300
 301/* -------- controller management ------------------------------------- */
 302
 303static inline capidrv_contr *findcontrbydriverid(int driverid)
 304{
 305        unsigned long flags;
 306        capidrv_contr *p;
 307
 308        spin_lock_irqsave(&global_lock, flags);
 309        for (p = global.contr_list; p; p = p->next)
 310                if (p->myid == driverid)
 311                        break;
 312        spin_unlock_irqrestore(&global_lock, flags);
 313        return p;
 314}
 315
 316static capidrv_contr *findcontrbynumber(u32 contr)
 317{
 318        unsigned long flags;
 319        capidrv_contr *p = global.contr_list;
 320
 321        spin_lock_irqsave(&global_lock, flags);
 322        for (p = global.contr_list; p; p = p->next)
 323                if (p->contrnr == contr)
 324                        break;
 325        spin_unlock_irqrestore(&global_lock, flags);
 326        return p;
 327}
 328
 329
 330/* -------- plci management ------------------------------------------ */
 331
 332static capidrv_plci *new_plci(capidrv_contr * card, int chan)
 333{
 334        capidrv_plci *plcip;
 335
 336        plcip = kzalloc(sizeof(capidrv_plci), GFP_ATOMIC);
 337
 338        if (plcip == NULL)
 339                return NULL;
 340
 341        plcip->state = ST_PLCI_NONE;
 342        plcip->plci = 0;
 343        plcip->msgid = 0;
 344        plcip->chan = chan;
 345        plcip->next = card->plci_list;
 346        card->plci_list = plcip;
 347        card->bchans[chan].plcip = plcip;
 348
 349        return plcip;
 350}
 351
 352static capidrv_plci *find_plci_by_plci(capidrv_contr * card, u32 plci)
 353{
 354        capidrv_plci *p;
 355        for (p = card->plci_list; p; p = p->next)
 356                if (p->plci == plci)
 357                        return p;
 358        return NULL;
 359}
 360
 361static capidrv_plci *find_plci_by_msgid(capidrv_contr * card, u16 msgid)
 362{
 363        capidrv_plci *p;
 364        for (p = card->plci_list; p; p = p->next)
 365                if (p->msgid == msgid)
 366                        return p;
 367        return NULL;
 368}
 369
 370static capidrv_plci *find_plci_by_ncci(capidrv_contr * card, u32 ncci)
 371{
 372        capidrv_plci *p;
 373        for (p = card->plci_list; p; p = p->next)
 374                if (p->plci == (ncci & 0xffff))
 375                        return p;
 376        return NULL;
 377}
 378
 379static void free_plci(capidrv_contr * card, capidrv_plci * plcip)
 380{
 381        capidrv_plci **pp;
 382
 383        for (pp = &card->plci_list; *pp; pp = &(*pp)->next) {
 384                if (*pp == plcip) {
 385                        *pp = (*pp)->next;
 386                        card->bchans[plcip->chan].plcip = NULL;
 387                        card->bchans[plcip->chan].disconnecting = 0;
 388                        card->bchans[plcip->chan].incoming = 0;
 389                        kfree(plcip);
 390                        return;
 391                }
 392        }
 393        printk(KERN_ERR "capidrv-%d: free_plci %p (0x%x) not found, Huh?\n",
 394               card->contrnr, plcip, plcip->plci);
 395}
 396
 397/* -------- ncci management ------------------------------------------ */
 398
 399static inline capidrv_ncci *new_ncci(capidrv_contr * card,
 400                                     capidrv_plci * plcip,
 401                                     u32 ncci)
 402{
 403        capidrv_ncci *nccip;
 404
 405        nccip = kzalloc(sizeof(capidrv_ncci), GFP_ATOMIC);
 406
 407        if (nccip == NULL)
 408                return NULL;
 409
 410        nccip->ncci = ncci;
 411        nccip->state = ST_NCCI_NONE;
 412        nccip->plcip = plcip;
 413        nccip->chan = plcip->chan;
 414        nccip->datahandle = 0;
 415
 416        nccip->next = plcip->ncci_list;
 417        plcip->ncci_list = nccip;
 418
 419        card->bchans[plcip->chan].nccip = nccip;
 420
 421        return nccip;
 422}
 423
 424static inline capidrv_ncci *find_ncci(capidrv_contr * card, u32 ncci)
 425{
 426        capidrv_plci *plcip;
 427        capidrv_ncci *p;
 428
 429        if ((plcip = find_plci_by_ncci(card, ncci)) == NULL)
 430                return NULL;
 431
 432        for (p = plcip->ncci_list; p; p = p->next)
 433                if (p->ncci == ncci)
 434                        return p;
 435        return NULL;
 436}
 437
 438static inline capidrv_ncci *find_ncci_by_msgid(capidrv_contr * card,
 439                                               u32 ncci, u16 msgid)
 440{
 441        capidrv_plci *plcip;
 442        capidrv_ncci *p;
 443
 444        if ((plcip = find_plci_by_ncci(card, ncci)) == NULL)
 445                return NULL;
 446
 447        for (p = plcip->ncci_list; p; p = p->next)
 448                if (p->msgid == msgid)
 449                        return p;
 450        return NULL;
 451}
 452
 453static void free_ncci(capidrv_contr * card, struct capidrv_ncci *nccip)
 454{
 455        struct capidrv_ncci **pp;
 456
 457        for (pp = &(nccip->plcip->ncci_list); *pp; pp = &(*pp)->next) {
 458                if (*pp == nccip) {
 459                        *pp = (*pp)->next;
 460                        break;
 461                }
 462        }
 463        card->bchans[nccip->chan].nccip = NULL;
 464        kfree(nccip);
 465}
 466
 467static int capidrv_add_ack(struct capidrv_ncci *nccip,
 468                           u16 datahandle, int len)
 469{
 470        struct ncci_datahandle_queue *n, **pp;
 471
 472        n = (struct ncci_datahandle_queue *)
 473                kmalloc(sizeof(struct ncci_datahandle_queue), GFP_ATOMIC);
 474        if (!n) {
 475           printk(KERN_ERR "capidrv: kmalloc ncci_datahandle failed\n");
 476           return -1;
 477        }
 478        n->next = NULL;
 479        n->datahandle = datahandle;
 480        n->len = len;
 481        for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) ;
 482        *pp = n;
 483        return 0;
 484}
 485
 486static int capidrv_del_ack(struct capidrv_ncci *nccip, u16 datahandle)
 487{
 488        struct ncci_datahandle_queue **pp, *p;
 489        int len;
 490
 491        for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) {
 492                if ((*pp)->datahandle == datahandle) {
 493                        p = *pp;
 494                        len = p->len;
 495                        *pp = (*pp)->next;
 496                        kfree(p);
 497                        return len;
 498                }
 499        }
 500        return -1;
 501}
 502
 503/* -------- convert and send capi message ---------------------------- */
 504
 505static void send_message(capidrv_contr * card, _cmsg * cmsg)
 506{
 507        struct sk_buff *skb;
 508        size_t len;
 509
 510        capi_cmsg2message(cmsg, cmsg->buf);
 511        len = CAPIMSG_LEN(cmsg->buf);
 512        skb = alloc_skb(len, GFP_ATOMIC);
 513        if (!skb) {
 514                printk(KERN_ERR "capidrv::send_message: can't allocate mem\n");
 515                return;
 516        }
 517        memcpy(skb_put(skb, len), cmsg->buf, len);
 518        if (capi20_put_message(&global.ap, skb) != CAPI_NOERROR)
 519                kfree_skb(skb);
 520}
 521
 522/* -------- state machine -------------------------------------------- */
 523
 524struct listenstatechange {
 525        int actstate;
 526        int nextstate;
 527        int event;
 528};
 529
 530static struct listenstatechange listentable[] =
 531{
 532  {ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ},
 533  {ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ},
 534  {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR},
 535  {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR},
 536  {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
 537  {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
 538  {ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
 539  {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
 540  {},
 541};
 542
 543static void listen_change_state(capidrv_contr * card, int event)
 544{
 545        struct listenstatechange *p = listentable;
 546        while (p->event) {
 547                if (card->state == p->actstate && p->event == event) {
 548                        if (debugmode)
 549                                printk(KERN_DEBUG "capidrv-%d: listen_change_state %d -> %d\n",
 550                                       card->contrnr, card->state, p->nextstate);
 551                        card->state = p->nextstate;
 552                        return;
 553                }
 554                p++;
 555        }
 556        printk(KERN_ERR "capidrv-%d: listen_change_state state=%d event=%d ????\n",
 557               card->contrnr, card->state, event);
 558
 559}
 560
 561/* ------------------------------------------------------------------ */
 562
 563static void p0(capidrv_contr * card, capidrv_plci * plci)
 564{
 565        isdn_ctrl cmd;
 566
 567        card->bchans[plci->chan].contr = NULL;
 568        cmd.command = ISDN_STAT_DHUP;
 569        cmd.driver = card->myid;
 570        cmd.arg = plci->chan;
 571        card->interface.statcallb(&cmd);
 572        free_plci(card, plci);
 573}
 574
 575/* ------------------------------------------------------------------ */
 576
 577struct plcistatechange {
 578        int actstate;
 579        int nextstate;
 580        int event;
 581        void (*changefunc) (capidrv_contr * card, capidrv_plci * plci);
 582};
 583
 584static struct plcistatechange plcitable[] =
 585{
 586  /* P-0 */
 587  {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, NULL},
 588  {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, NULL},
 589  {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, NULL},
 590  {ST_PLCI_NONE, ST_PLCI_RESUMEING, EV_PLCI_RESUME_REQ, NULL},
 591  /* P-0.1 */
 592  {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0},
 593  {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, NULL},
 594  /* P-1 */
 595  {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, NULL},
 596  {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
 597  {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
 598  {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
 599  /* P-ACT */
 600  {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
 601  {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
 602  {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
 603  {ST_PLCI_ACTIVE, ST_PLCI_HELD, EV_PLCI_HOLD_IND, NULL},
 604  {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_SUSPEND_IND, NULL},
 605  /* P-2 */
 606  {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, NULL},
 607  {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, NULL},
 608  {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, NULL},
 609  {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
 610  {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
 611  {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
 612  {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CD_IND, NULL},
 613  /* P-3 */
 614  {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, NULL},
 615  {ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, NULL},
 616  {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
 617  {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
 618  {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
 619  /* P-4 */
 620  {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, NULL},
 621  {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
 622  {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
 623  {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
 624  /* P-5 */
 625  {ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
 626  /* P-6 */
 627  {ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0},
 628  /* P-0.Res */
 629  {ST_PLCI_RESUMEING, ST_PLCI_NONE, EV_PLCI_RESUME_CONF_ERROR, p0},
 630  {ST_PLCI_RESUMEING, ST_PLCI_RESUME, EV_PLCI_RESUME_CONF_OK, NULL},
 631  /* P-RES */
 632  {ST_PLCI_RESUME, ST_PLCI_ACTIVE, EV_PLCI_RESUME_IND, NULL},
 633  /* P-HELD */
 634  {ST_PLCI_HELD, ST_PLCI_ACTIVE, EV_PLCI_RETRIEVE_IND, NULL},
 635  {},
 636};
 637
 638static void plci_change_state(capidrv_contr * card, capidrv_plci * plci, int event)
 639{
 640        struct plcistatechange *p = plcitable;
 641        while (p->event) {
 642                if (plci->state == p->actstate && p->event == event) {
 643                        if (debugmode)
 644                                printk(KERN_DEBUG "capidrv-%d: plci_change_state:0x%x %d -> %d\n",
 645                                  card->contrnr, plci->plci, plci->state, p->nextstate);
 646                        plci->state = p->nextstate;
 647                        if (p->changefunc)
 648                                p->changefunc(card, plci);
 649                        return;
 650                }
 651                p++;
 652        }
 653        printk(KERN_ERR "capidrv-%d: plci_change_state:0x%x state=%d event=%d ????\n",
 654               card->contrnr, plci->plci, plci->state, event);
 655}
 656
 657/* ------------------------------------------------------------------ */
 658
 659static _cmsg cmsg;
 660
 661static void n0(capidrv_contr * card, capidrv_ncci * ncci)
 662{
 663        isdn_ctrl cmd;
 664
 665        capi_fill_DISCONNECT_REQ(&cmsg,
 666                                 global.ap.applid,
 667                                 card->msgid++,
 668                                 ncci->plcip->plci,
 669                                 NULL,  /* BChannelinformation */
 670                                 NULL,  /* Keypadfacility */
 671                                 NULL,  /* Useruserdata */   /* $$$$ */
 672                                 NULL   /* Facilitydataarray */
 673        );
 674        send_message(card, &cmsg);
 675        plci_change_state(card, ncci->plcip, EV_PLCI_DISCONNECT_REQ);
 676
 677        cmd.command = ISDN_STAT_BHUP;
 678        cmd.driver = card->myid;
 679        cmd.arg = ncci->chan;
 680        card->interface.statcallb(&cmd);
 681        free_ncci(card, ncci);
 682}
 683
 684/* ------------------------------------------------------------------ */
 685
 686struct nccistatechange {
 687        int actstate;
 688        int nextstate;
 689        int event;
 690        void (*changefunc) (capidrv_contr * card, capidrv_ncci * ncci);
 691};
 692
 693static struct nccistatechange nccitable[] =
 694{
 695  /* N-0 */
 696  {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, NULL},
 697  {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, NULL},
 698  /* N-0.1 */
 699  {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, NULL},
 700  {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, n0},
 701  /* N-1 */
 702  {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, NULL},
 703  {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, NULL},
 704  {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
 705  {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
 706  /* N-2 */
 707  {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, NULL},
 708  {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
 709  {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
 710  /* N-ACT */
 711  {ST_NCCI_ACTIVE, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, NULL},
 712  {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, NULL},
 713  {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
 714  {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
 715  /* N-3 */
 716  {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, NULL},
 717  {ST_NCCI_RESETING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
 718  {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
 719  /* N-4 */
 720  {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
 721  {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR,NULL},
 722  /* N-5 */
 723  {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0},
 724  {},
 725};
 726
 727static void ncci_change_state(capidrv_contr * card, capidrv_ncci * ncci, int event)
 728{
 729        struct nccistatechange *p = nccitable;
 730        while (p->event) {
 731                if (ncci->state == p->actstate && p->event == event) {
 732                        if (debugmode)
 733                                printk(KERN_DEBUG "capidrv-%d: ncci_change_state:0x%x %d -> %d\n",
 734                                  card->contrnr, ncci->ncci, ncci->state, p->nextstate);
 735                        if (p->nextstate == ST_NCCI_PREVIOUS) {
 736                                ncci->state = ncci->oldstate;
 737                                ncci->oldstate = p->actstate;
 738                        } else {
 739                                ncci->oldstate = p->actstate;
 740                                ncci->state = p->nextstate;
 741                        }
 742                        if (p->changefunc)
 743                                p->changefunc(card, ncci);
 744                        return;
 745                }
 746                p++;
 747        }
 748        printk(KERN_ERR "capidrv-%d: ncci_change_state:0x%x state=%d event=%d ????\n",
 749               card->contrnr, ncci->ncci, ncci->state, event);
 750}
 751
 752/* ------------------------------------------------------------------- */
 753
 754static inline int new_bchan(capidrv_contr * card)
 755{
 756        int i;
 757        for (i = 0; i < card->nbchan; i++) {
 758                if (card->bchans[i].plcip == NULL) {
 759                        card->bchans[i].disconnecting = 0;
 760                        return i;
 761                }
 762        }
 763        return -1;
 764}
 765
 766/* ------------------------------------------------------------------- */
 767
 768static void handle_controller(_cmsg * cmsg)
 769{
 770        capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
 771
 772        if (!card) {
 773                printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
 774                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
 775                       cmsg->adr.adrController & 0x7f);
 776                return;
 777        }
 778        switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
 779
 780        case CAPI_LISTEN_CONF:  /* Controller */
 781                if (debugmode)
 782                        printk(KERN_DEBUG "capidrv-%d: listenconf Info=0x%4x (%s) cipmask=0x%x\n",
 783                               card->contrnr, cmsg->Info, capi_info2str(cmsg->Info), card->cipmask);
 784                if (cmsg->Info) {
 785                        listen_change_state(card, EV_LISTEN_CONF_ERROR);
 786                } else if (card->cipmask == 0) {
 787                        listen_change_state(card, EV_LISTEN_CONF_EMPTY);
 788                } else {
 789                        listen_change_state(card, EV_LISTEN_CONF_OK);
 790                }
 791                break;
 792
 793        case CAPI_MANUFACTURER_IND:     /* Controller */
 794                if (   cmsg->ManuID == 0x214D5641
 795                    && cmsg->Class == 0
 796                    && cmsg->Function == 1) {
 797                   u8  *data = cmsg->ManuData+3;
 798                   u16  len = cmsg->ManuData[0];
 799                   u16 layer;
 800                   int direction;
 801                   if (len == 255) {
 802                      len = (cmsg->ManuData[1] | (cmsg->ManuData[2] << 8));
 803                      data += 2;
 804                   }
 805                   len -= 2;
 806                   layer = ((*(data-1)) << 8) | *(data-2);
 807                   if (layer & 0x300)
 808                        direction = (layer & 0x200) ? 0 : 1;
 809                   else direction = (layer & 0x800) ? 0 : 1;
 810                   if (layer & 0x0C00) {
 811                        if ((layer & 0xff) == 0x80) {
 812                           handle_dtrace_data(card, direction, 1, data, len);
 813                           break;
 814                        }
 815                   } else if ((layer & 0xff) < 0x80) {
 816                      handle_dtrace_data(card, direction, 0, data, len);
 817                      break;
 818                   }
 819                   printk(KERN_INFO "capidrv-%d: %s from controller 0x%x layer 0x%x, ignored\n",
 820                        card->contrnr, 
 821                        capi_cmd2str(cmsg->Command, cmsg->Subcommand),
 822                        cmsg->adr.adrController, layer);
 823                   break;
 824                }
 825                goto ignored;
 826        case CAPI_MANUFACTURER_CONF:    /* Controller */
 827                if (cmsg->ManuID == 0x214D5641) {
 828                   char *s = NULL;
 829                   switch (cmsg->Class) {
 830                      case 0: break;
 831                      case 1: s = "unknown class"; break;
 832                      case 2: s = "unknown function"; break;
 833                      default: s = "unkown error"; break;
 834                   }
 835                   if (s)
 836                   printk(KERN_INFO "capidrv-%d: %s from controller 0x%x function %d: %s\n",
 837                        card->contrnr,
 838                        capi_cmd2str(cmsg->Command, cmsg->Subcommand),
 839                        cmsg->adr.adrController,
 840                        cmsg->Function, s);
 841                   break;
 842                }
 843                goto ignored;
 844        case CAPI_FACILITY_IND: /* Controller/plci/ncci */
 845                goto ignored;
 846        case CAPI_FACILITY_CONF:        /* Controller/plci/ncci */
 847                goto ignored;
 848        case CAPI_INFO_IND:     /* Controller/plci */
 849                goto ignored;
 850        case CAPI_INFO_CONF:    /* Controller/plci */
 851                goto ignored;
 852
 853        default:
 854                printk(KERN_ERR "capidrv-%d: got %s from controller 0x%x ???",
 855                       card->contrnr,
 856                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
 857                       cmsg->adr.adrController);
 858        }
 859        return;
 860
 861      ignored:
 862        printk(KERN_INFO "capidrv-%d: %s from controller 0x%x ignored\n",
 863               card->contrnr,
 864               capi_cmd2str(cmsg->Command, cmsg->Subcommand),
 865               cmsg->adr.adrController);
 866}
 867
 868static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg)
 869{
 870        capidrv_plci *plcip;
 871        capidrv_bchan *bchan;
 872        isdn_ctrl cmd;
 873        int chan;
 874
 875        if ((chan = new_bchan(card)) == -1) {
 876                printk(KERN_ERR "capidrv-%d: incoming call on not existing bchan ?\n", card->contrnr);
 877                return;
 878        }
 879        bchan = &card->bchans[chan];
 880        if ((plcip = new_plci(card, chan)) == NULL) {
 881                printk(KERN_ERR "capidrv-%d: incoming call: no memory, sorry.\n", card->contrnr);
 882                return;
 883        }
 884        bchan->incoming = 1;
 885        plcip->plci = cmsg->adr.adrPLCI;
 886        plci_change_state(card, plcip, EV_PLCI_CONNECT_IND);
 887
 888        cmd.command = ISDN_STAT_ICALL;
 889        cmd.driver = card->myid;
 890        cmd.arg = chan;
 891        memset(&cmd.parm.setup, 0, sizeof(cmd.parm.setup));
 892        strncpy(cmd.parm.setup.phone,
 893                cmsg->CallingPartyNumber + 3,
 894                cmsg->CallingPartyNumber[0] - 2);
 895        strncpy(cmd.parm.setup.eazmsn,
 896                cmsg->CalledPartyNumber + 2,
 897                cmsg->CalledPartyNumber[0] - 1);
 898        cmd.parm.setup.si1 = cip2si1(cmsg->CIPValue);
 899        cmd.parm.setup.si2 = cip2si2(cmsg->CIPValue);
 900        cmd.parm.setup.plan = cmsg->CallingPartyNumber[1];
 901        cmd.parm.setup.screen = cmsg->CallingPartyNumber[2];
 902
 903        printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s\n", 
 904                        card->contrnr,
 905                        cmd.parm.setup.phone,
 906                        cmd.parm.setup.si1,
 907                        cmd.parm.setup.si2,
 908                        cmd.parm.setup.eazmsn);
 909
 910        if (cmd.parm.setup.si1 == 1 && cmd.parm.setup.si2 != 0) {
 911                printk(KERN_INFO "capidrv-%d: patching si2=%d to 0 for VBOX\n", 
 912                        card->contrnr,
 913                        cmd.parm.setup.si2);
 914                cmd.parm.setup.si2 = 0;
 915        }
 916
 917        switch (card->interface.statcallb(&cmd)) {
 918        case 0:
 919        case 3:
 920                /* No device matching this call.
 921                 * and isdn_common.c has send a HANGUP command
 922                 * which is ignored in state ST_PLCI_INCOMING,
 923                 * so we send RESP to ignore the call
 924                 */
 925                capi_cmsg_answer(cmsg);
 926                cmsg->Reject = 1;       /* ignore */
 927                send_message(card, cmsg);
 928                plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
 929                printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s ignored\n",
 930                        card->contrnr,
 931                        cmd.parm.setup.phone,
 932                        cmd.parm.setup.si1,
 933                        cmd.parm.setup.si2,
 934                        cmd.parm.setup.eazmsn);
 935                break;
 936        case 1:
 937                /* At least one device matching this call (RING on ttyI)
 938                 * HL-driver may send ALERTING on the D-channel in this
 939                 * case.
 940                 * really means: RING on ttyI or a net interface
 941                 * accepted this call already.
 942                 *
 943                 * If the call was accepted, state has already changed,
 944                 * and CONNECT_RESP already sent.
 945                 */
 946                if (plcip->state == ST_PLCI_INCOMING) {
 947                        printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s tty alerting\n",
 948                                card->contrnr,
 949                                cmd.parm.setup.phone,
 950                                cmd.parm.setup.si1,
 951                                cmd.parm.setup.si2,
 952                                cmd.parm.setup.eazmsn);
 953                        capi_fill_ALERT_REQ(cmsg,
 954                                            global.ap.applid,
 955                                            card->msgid++,
 956                                            plcip->plci,        /* adr */
 957                                            NULL,/* BChannelinformation */
 958                                            NULL,/* Keypadfacility */
 959                                            NULL,/* Useruserdata */
 960                                            NULL /* Facilitydataarray */
 961                        );
 962                        plcip->msgid = cmsg->Messagenumber;
 963                        send_message(card, cmsg);
 964                } else {
 965                        printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s on netdev\n",
 966                                card->contrnr,
 967                                cmd.parm.setup.phone,
 968                                cmd.parm.setup.si1,
 969                                cmd.parm.setup.si2,
 970                                cmd.parm.setup.eazmsn);
 971                }
 972                break;
 973
 974        case 2:         /* Call will be rejected. */
 975                capi_cmsg_answer(cmsg);
 976                cmsg->Reject = 2;       /* reject call, normal call clearing */
 977                send_message(card, cmsg);
 978                plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
 979                break;
 980
 981        default:
 982                /* An error happened. (Invalid parameters for example.) */
 983                capi_cmsg_answer(cmsg);
 984                cmsg->Reject = 8;       /* reject call,
 985                                           destination out of order */
 986                send_message(card, cmsg);
 987                plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
 988                break;
 989        }
 990        return;
 991}
 992
 993static void handle_plci(_cmsg * cmsg)
 994{
 995        capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
 996        capidrv_plci *plcip;
 997        isdn_ctrl cmd;
 998        _cdebbuf *cdb;
 999
1000        if (!card) {
1001                printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
1002                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1003                       cmsg->adr.adrController & 0x7f);
1004                return;
1005        }
1006        switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
1007
1008        case CAPI_DISCONNECT_IND:       /* plci */
1009                if (cmsg->Reason) {
1010                        printk(KERN_INFO "capidrv-%d: %s reason 0x%x (%s) for plci 0x%x\n",
1011                           card->contrnr,
1012                           capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1013                               cmsg->Reason, capi_info2str(cmsg->Reason), cmsg->adr.adrPLCI);
1014                }
1015                if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) {
1016                        capi_cmsg_answer(cmsg);
1017                        send_message(card, cmsg);
1018                        goto notfound;
1019                }
1020                card->bchans[plcip->chan].disconnecting = 1;
1021                plci_change_state(card, plcip, EV_PLCI_DISCONNECT_IND);
1022                capi_cmsg_answer(cmsg);
1023                send_message(card, cmsg);
1024                plci_change_state(card, plcip, EV_PLCI_DISCONNECT_RESP);
1025                break;
1026
1027        case CAPI_DISCONNECT_CONF:      /* plci */
1028                if (cmsg->Info) {
1029                        printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
1030                           card->contrnr,
1031                           capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1032                               cmsg->Info, capi_info2str(cmsg->Info), 
1033                               cmsg->adr.adrPLCI);
1034                }
1035                if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
1036                        goto notfound;
1037
1038                card->bchans[plcip->chan].disconnecting = 1;
1039                break;
1040
1041        case CAPI_ALERT_CONF:   /* plci */
1042                if (cmsg->Info) {
1043                        printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
1044                           card->contrnr,
1045                           capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1046                               cmsg->Info, capi_info2str(cmsg->Info), 
1047                               cmsg->adr.adrPLCI);
1048                }
1049                break;
1050
1051        case CAPI_CONNECT_IND:  /* plci */
1052                handle_incoming_call(card, cmsg);
1053                break;
1054
1055        case CAPI_CONNECT_CONF: /* plci */
1056                if (cmsg->Info) {
1057                        printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
1058                           card->contrnr,
1059                           capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1060                               cmsg->Info, capi_info2str(cmsg->Info), 
1061                               cmsg->adr.adrPLCI);
1062                }
1063                if (!(plcip = find_plci_by_msgid(card, cmsg->Messagenumber)))
1064                        goto notfound;
1065
1066                plcip->plci = cmsg->adr.adrPLCI;
1067                if (cmsg->Info) {
1068                        plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_ERROR);
1069                } else {
1070                        plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_OK);
1071                }
1072                break;
1073
1074        case CAPI_CONNECT_ACTIVE_IND:   /* plci */
1075
1076                if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
1077                        goto notfound;
1078
1079                if (card->bchans[plcip->chan].incoming) {
1080                        capi_cmsg_answer(cmsg);
1081                        send_message(card, cmsg);
1082                        plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND);
1083                } else {
1084                        capidrv_ncci *nccip;
1085                        capi_cmsg_answer(cmsg);
1086                        send_message(card, cmsg);
1087
1088                        nccip = new_ncci(card, plcip, cmsg->adr.adrPLCI);
1089
1090                        if (!nccip) {
1091                                printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr);
1092                                break;  /* $$$$ */
1093                        }
1094                        capi_fill_CONNECT_B3_REQ(cmsg,
1095                                                 global.ap.applid,
1096                                                 card->msgid++,
1097                                                 plcip->plci,   /* adr */
1098                                                 NULL   /* NCPI */
1099                        );
1100                        nccip->msgid = cmsg->Messagenumber;
1101                        send_message(card, cmsg);
1102                        cmd.command = ISDN_STAT_DCONN;
1103                        cmd.driver = card->myid;
1104                        cmd.arg = plcip->chan;
1105                        card->interface.statcallb(&cmd);
1106                        plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND);
1107                        ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_REQ);
1108                }
1109                break;
1110
1111        case CAPI_INFO_IND:     /* Controller/plci */
1112
1113                if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
1114                        goto notfound;
1115
1116                if (cmsg->InfoNumber == 0x4000) {
1117                        if (cmsg->InfoElement[0] == 4) {
1118                                cmd.command = ISDN_STAT_CINF;
1119                                cmd.driver = card->myid;
1120                                cmd.arg = plcip->chan;
1121                                sprintf(cmd.parm.num, "%lu",
1122                                        (unsigned long)
1123                                        ((u32) cmsg->InfoElement[1]
1124                                  | ((u32) (cmsg->InfoElement[2]) << 8)
1125                                 | ((u32) (cmsg->InfoElement[3]) << 16)
1126                                         | ((u32) (cmsg->InfoElement[4]) << 24)));
1127                                card->interface.statcallb(&cmd);
1128                                break;
1129                        }
1130                }
1131                cdb = capi_cmsg2str(cmsg);
1132                if (cdb) {
1133                        printk(KERN_WARNING "capidrv-%d: %s\n",
1134                                card->contrnr, cdb->buf);
1135                        cdebbuf_free(cdb);
1136                } else
1137                        printk(KERN_WARNING "capidrv-%d: CAPI_INFO_IND InfoNumber %x not handled\n",
1138                                card->contrnr, cmsg->InfoNumber);
1139
1140                break;
1141
1142        case CAPI_CONNECT_ACTIVE_CONF:          /* plci */
1143                goto ignored;
1144        case CAPI_SELECT_B_PROTOCOL_CONF:       /* plci */
1145                goto ignored;
1146        case CAPI_FACILITY_IND: /* Controller/plci/ncci */
1147                goto ignored;
1148        case CAPI_FACILITY_CONF:        /* Controller/plci/ncci */
1149                goto ignored;
1150
1151        case CAPI_INFO_CONF:    /* Controller/plci */
1152                goto ignored;
1153
1154        default:
1155                printk(KERN_ERR "capidrv-%d: got %s for plci 0x%x ???",
1156                       card->contrnr,
1157                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1158                       cmsg->adr.adrPLCI);
1159        }
1160        return;
1161      ignored:
1162        printk(KERN_INFO "capidrv-%d: %s for plci 0x%x ignored\n",
1163               card->contrnr,
1164               capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1165               cmsg->adr.adrPLCI);
1166        return;
1167      notfound:
1168        printk(KERN_ERR "capidrv-%d: %s: plci 0x%x not found\n",
1169               card->contrnr,
1170               capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1171               cmsg->adr.adrPLCI);
1172        return;
1173}
1174
1175static void handle_ncci(_cmsg * cmsg)
1176{
1177        capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
1178        capidrv_plci *plcip;
1179        capidrv_ncci *nccip;
1180        isdn_ctrl cmd;
1181        int len;
1182
1183        if (!card) {
1184                printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
1185                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1186                       cmsg->adr.adrController & 0x7f);
1187                return;
1188        }
1189        switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
1190
1191        case CAPI_CONNECT_B3_ACTIVE_IND:        /* ncci */
1192                if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1193                        goto notfound;
1194
1195                capi_cmsg_answer(cmsg);
1196                send_message(card, cmsg);
1197                ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_ACTIVE_IND);
1198
1199                cmd.command = ISDN_STAT_BCONN;
1200                cmd.driver = card->myid;
1201                cmd.arg = nccip->chan;
1202                card->interface.statcallb(&cmd);
1203
1204                printk(KERN_INFO "capidrv-%d: chan %d up with ncci 0x%x\n",
1205                       card->contrnr, nccip->chan, nccip->ncci);
1206                break;
1207
1208        case CAPI_CONNECT_B3_ACTIVE_CONF:       /* ncci */
1209                goto ignored;
1210
1211        case CAPI_CONNECT_B3_IND:       /* ncci */
1212
1213                plcip = find_plci_by_ncci(card, cmsg->adr.adrNCCI);
1214                if (plcip) {
1215                        nccip = new_ncci(card, plcip, cmsg->adr.adrNCCI);
1216                        if (nccip) {
1217                                ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_IND);
1218                                capi_fill_CONNECT_B3_RESP(cmsg,
1219                                                          global.ap.applid,
1220                                                          card->msgid++,
1221                                                          nccip->ncci,  /* adr */
1222                                                          0,    /* Reject */
1223                                                          NULL  /* NCPI */
1224                                );
1225                                send_message(card, cmsg);
1226                                ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_RESP);
1227                                break;
1228                        }
1229                        printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n",                                                 card->contrnr);
1230                } else {
1231                        printk(KERN_ERR "capidrv-%d: %s: plci for ncci 0x%x not found\n",
1232                           card->contrnr,
1233                           capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1234                               cmsg->adr.adrNCCI);
1235                }
1236                capi_fill_CONNECT_B3_RESP(cmsg,
1237                                          global.ap.applid,
1238                                          card->msgid++,
1239                                          cmsg->adr.adrNCCI,
1240                                          2,    /* Reject */
1241                                          NULL  /* NCPI */
1242                );
1243                send_message(card, cmsg);
1244                break;
1245
1246        case CAPI_CONNECT_B3_CONF:      /* ncci */
1247
1248                if (!(nccip = find_ncci_by_msgid(card,
1249                                                 cmsg->adr.adrNCCI,
1250                                                 cmsg->Messagenumber)))
1251                        goto notfound;
1252
1253                nccip->ncci = cmsg->adr.adrNCCI;
1254                if (cmsg->Info) {
1255                        printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n",
1256                           card->contrnr,
1257                           capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1258                               cmsg->Info, capi_info2str(cmsg->Info), 
1259                               cmsg->adr.adrNCCI);
1260                }
1261
1262                if (cmsg->Info)
1263                        ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_ERROR);
1264                else
1265                        ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_OK);
1266                break;
1267
1268        case CAPI_CONNECT_B3_T90_ACTIVE_IND:    /* ncci */
1269                capi_cmsg_answer(cmsg);
1270                send_message(card, cmsg);
1271                break;
1272
1273        case CAPI_DATA_B3_IND:  /* ncci */
1274                /* handled in handle_data() */
1275                goto ignored;
1276
1277        case CAPI_DATA_B3_CONF: /* ncci */
1278                if (cmsg->Info) {
1279                        printk(KERN_WARNING "CAPI_DATA_B3_CONF: Info %x - %s\n",
1280                                cmsg->Info, capi_info2str(cmsg->Info));
1281                }
1282                if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1283                        goto notfound;
1284
1285                len = capidrv_del_ack(nccip, cmsg->DataHandle);
1286                if (len < 0)
1287                        break;
1288                cmd.command = ISDN_STAT_BSENT;
1289                cmd.driver = card->myid;
1290                cmd.arg = nccip->chan;
1291                cmd.parm.length = len;
1292                card->interface.statcallb(&cmd);
1293                break;
1294
1295        case CAPI_DISCONNECT_B3_IND:    /* ncci */
1296                if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1297                        goto notfound;
1298
1299                card->bchans[nccip->chan].disconnecting = 1;
1300                ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_IND);
1301                capi_cmsg_answer(cmsg);
1302                send_message(card, cmsg);
1303                ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_RESP);
1304                break;
1305
1306        case CAPI_DISCONNECT_B3_CONF:   /* ncci */
1307                if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1308                        goto notfound;
1309                if (cmsg->Info) {
1310                        printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n",
1311                           card->contrnr,
1312                           capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1313                               cmsg->Info, capi_info2str(cmsg->Info), 
1314                               cmsg->adr.adrNCCI);
1315                        ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_CONF_ERROR);
1316                }
1317                break;
1318
1319        case CAPI_RESET_B3_IND: /* ncci */
1320                if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI)))
1321                        goto notfound;
1322                ncci_change_state(card, nccip, EV_NCCI_RESET_B3_IND);
1323                capi_cmsg_answer(cmsg);
1324                send_message(card, cmsg);
1325                break;
1326
1327        case CAPI_RESET_B3_CONF:        /* ncci */
1328                goto ignored;   /* $$$$ */
1329
1330        case CAPI_FACILITY_IND: /* Controller/plci/ncci */
1331                goto ignored;
1332        case CAPI_FACILITY_CONF:        /* Controller/plci/ncci */
1333                goto ignored;
1334
1335        default:
1336                printk(KERN_ERR "capidrv-%d: got %s for ncci 0x%x ???",
1337                       card->contrnr,
1338                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1339                       cmsg->adr.adrNCCI);
1340        }
1341        return;
1342      ignored:
1343        printk(KERN_INFO "capidrv-%d: %s for ncci 0x%x ignored\n",
1344               card->contrnr,
1345               capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1346               cmsg->adr.adrNCCI);
1347        return;
1348      notfound:
1349        printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n",
1350               card->contrnr,
1351               capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1352               cmsg->adr.adrNCCI);
1353}
1354
1355
1356static void handle_data(_cmsg * cmsg, struct sk_buff *skb)
1357{
1358        capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
1359        capidrv_ncci *nccip;
1360
1361        if (!card) {
1362                printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
1363                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1364                       cmsg->adr.adrController & 0x7f);
1365                kfree_skb(skb);
1366                return;
1367        }
1368        if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) {
1369                printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n",
1370                       card->contrnr,
1371                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1372                       cmsg->adr.adrNCCI);
1373                kfree_skb(skb);
1374                return;
1375        }
1376        (void) skb_pull(skb, CAPIMSG_LEN(skb->data));
1377        card->interface.rcvcallb_skb(card->myid, nccip->chan, skb);
1378        capi_cmsg_answer(cmsg);
1379        send_message(card, cmsg);
1380}
1381
1382static _cmsg s_cmsg;
1383
1384static void capidrv_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
1385{
1386        capi_message2cmsg(&s_cmsg, skb->data);
1387        if (debugmode > 3) {
1388                _cdebbuf *cdb = capi_cmsg2str(&s_cmsg);
1389
1390                if (cdb) {
1391                        printk(KERN_DEBUG "%s: applid=%d %s\n", __func__,
1392                                ap->applid, cdb->buf);
1393                        cdebbuf_free(cdb);
1394                } else
1395                        printk(KERN_DEBUG "%s: applid=%d %s not traced\n",
1396                                __func__, ap->applid,
1397                                capi_cmd2str(s_cmsg.Command, s_cmsg.Subcommand));
1398        }
1399        if (s_cmsg.Command == CAPI_DATA_B3
1400            && s_cmsg.Subcommand == CAPI_IND) {
1401                handle_data(&s_cmsg, skb);
1402                return;
1403        }
1404        if ((s_cmsg.adr.adrController & 0xffffff00) == 0)
1405                handle_controller(&s_cmsg);
1406        else if ((s_cmsg.adr.adrPLCI & 0xffff0000) == 0)
1407                handle_plci(&s_cmsg);
1408        else
1409                handle_ncci(&s_cmsg);
1410        /*
1411         * data of skb used in s_cmsg,
1412         * free data when s_cmsg is not used again
1413         * thanks to Lars Heete <hel@admin.de>
1414         */
1415        kfree_skb(skb);
1416}
1417
1418/* ------------------------------------------------------------------- */
1419
1420#define PUTBYTE_TO_STATUS(card, byte) \
1421        do { \
1422                *(card)->q931_write++ = (byte); \
1423                if ((card)->q931_write > (card)->q931_end) \
1424                        (card)->q931_write = (card)->q931_buf; \
1425        } while (0)
1426
1427static void handle_dtrace_data(capidrv_contr *card,
1428                             int send, int level2, u8 *data, u16 len)
1429{
1430        u8 *p, *end;
1431        isdn_ctrl cmd;
1432
1433        if (!len) {
1434                printk(KERN_DEBUG "capidrv-%d: avmb1_q931_data: len == %d\n",
1435                                card->contrnr, len);
1436                return;
1437        }
1438
1439        if (level2) {
1440                PUTBYTE_TO_STATUS(card, 'D');
1441                PUTBYTE_TO_STATUS(card, '2');
1442                PUTBYTE_TO_STATUS(card, send ? '>' : '<');
1443                PUTBYTE_TO_STATUS(card, ':');
1444        } else {
1445                PUTBYTE_TO_STATUS(card, 'D');
1446                PUTBYTE_TO_STATUS(card, '3');
1447                PUTBYTE_TO_STATUS(card, send ? '>' : '<');
1448                PUTBYTE_TO_STATUS(card, ':');
1449        }
1450
1451        for (p = data, end = data+len; p < end; p++) {
1452                u8 w;
1453                PUTBYTE_TO_STATUS(card, ' ');
1454                w = (*p >> 4) & 0xf;
1455                PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
1456                w = *p & 0xf;
1457                PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
1458        }
1459        PUTBYTE_TO_STATUS(card, '\n');
1460
1461        cmd.command = ISDN_STAT_STAVAIL;
1462        cmd.driver = card->myid;
1463        cmd.arg = len*3+5;
1464        card->interface.statcallb(&cmd);
1465}
1466
1467/* ------------------------------------------------------------------- */
1468
1469static _cmsg cmdcmsg;
1470
1471static int capidrv_ioctl(isdn_ctrl * c, capidrv_contr * card)
1472{
1473        switch (c->arg) {
1474        case 1:
1475                debugmode = (int)(*((unsigned int *)c->parm.num));
1476                printk(KERN_DEBUG "capidrv-%d: debugmode=%d\n",
1477                                card->contrnr, debugmode);
1478                return 0;
1479        default:
1480                printk(KERN_DEBUG "capidrv-%d: capidrv_ioctl(%ld) called ??\n",
1481                                card->contrnr, c->arg);
1482                return -EINVAL;
1483        }
1484        return -EINVAL;
1485}
1486
1487/*
1488 * Handle leased lines (CAPI-Bundling)
1489 */
1490
1491struct internal_bchannelinfo {
1492   unsigned short channelalloc;
1493   unsigned short operation;
1494   unsigned char  cmask[31];
1495};
1496
1497static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep)
1498{
1499        unsigned long bmask = 0;
1500        int active = !0;
1501        char *s;
1502        int i;
1503
1504        if (strncmp(teln, "FV:", 3) != 0)
1505                return 1;
1506        s = teln + 3;
1507        while (*s && *s == ' ') s++;
1508        if (!*s) return -2;
1509        if (*s == 'p' || *s == 'P') {
1510                active = 0;
1511                s++;
1512        }
1513        if (*s == 'a' || *s == 'A') {
1514                active = !0;
1515                s++;
1516        }
1517        while (*s) {
1518                int digit1 = 0;
1519                int digit2 = 0;
1520                if (!isdigit(*s)) return -3;
1521                while (isdigit(*s)) { digit1 = digit1*10 + (*s - '0'); s++; }
1522                if (digit1 <= 0 && digit1 > 30) return -4;
1523                if (*s == 0 || *s == ',' || *s == ' ') {
1524                        bmask |= (1 << digit1);
1525                        digit1 = 0;
1526                        if (*s) s++;
1527                        continue;
1528                }
1529                if (*s != '-') return -5;
1530                s++;
1531                if (!isdigit(*s)) return -3;
1532                while (isdigit(*s)) { digit2 = digit2*10 + (*s - '0'); s++; }
1533                if (digit2 <= 0 && digit2 > 30) return -4;
1534                if (*s == 0 || *s == ',' || *s == ' ') {
1535                        if (digit1 > digit2)
1536                                for (i = digit2; i <= digit1 ; i++)
1537                                        bmask |= (1 << i);
1538                        else 
1539                                for (i = digit1; i <= digit2 ; i++)
1540                                        bmask |= (1 << i);
1541                        digit1 = digit2 = 0;
1542                        if (*s) s++;
1543                        continue;
1544                }
1545                return -6;
1546        }
1547        if (activep) *activep = active;
1548        if (bmaskp) *bmaskp = bmask;
1549        return 0;
1550}
1551
1552static int FVteln2capi20(char *teln, u8 AdditionalInfo[1+2+2+31])
1553{
1554        unsigned long bmask;
1555        int active;
1556        int rc, i;
1557   
1558        rc = decodeFVteln(teln, &bmask, &active);
1559        if (rc) return rc;
1560        /* Length */
1561        AdditionalInfo[0] = 2+2+31;
1562        /* Channel: 3 => use channel allocation */
1563        AdditionalInfo[1] = 3; AdditionalInfo[2] = 0;
1564        /* Operation: 0 => DTE mode, 1 => DCE mode */
1565        if (active) {
1566                AdditionalInfo[3] = 0; AdditionalInfo[4] = 0;
1567        } else {
1568                AdditionalInfo[3] = 1; AdditionalInfo[4] = 0;
1569        }
1570        /* Channel mask array */
1571        AdditionalInfo[5] = 0; /* no D-Channel */
1572        for (i=1; i <= 30; i++)
1573                AdditionalInfo[5+i] = (bmask & (1 << i)) ? 0xff : 0;
1574        return 0;
1575}
1576
1577static int capidrv_command(isdn_ctrl * c, capidrv_contr * card)
1578{
1579        isdn_ctrl cmd;
1580        struct capidrv_bchan *bchan;
1581        struct capidrv_plci *plcip;
1582        u8 AdditionalInfo[1+2+2+31];
1583        int rc, isleasedline = 0;
1584
1585        if (c->command == ISDN_CMD_IOCTL)
1586                return capidrv_ioctl(c, card);
1587
1588        switch (c->command) {
1589        case ISDN_CMD_DIAL:{
1590                        u8 calling[ISDN_MSNLEN + 3];
1591                        u8 called[ISDN_MSNLEN + 2];
1592
1593                        if (debugmode)
1594                                printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n",
1595                                        card->contrnr,
1596                                        c->arg,
1597                                        c->parm.setup.phone,
1598                                        c->parm.setup.si1,
1599                                        c->parm.setup.si2,
1600                                        c->parm.setup.eazmsn);
1601
1602                        bchan = &card->bchans[c->arg % card->nbchan];
1603
1604                        if (bchan->plcip) {
1605                                printk(KERN_ERR "capidrv-%d: dail ch=%ld,\"%s,%d,%d,%s\" in use (plci=0x%x)\n",
1606                                        card->contrnr,
1607                                        c->arg, 
1608                                        c->parm.setup.phone,
1609                                        c->parm.setup.si1,
1610                                        c->parm.setup.si2,
1611                                        c->parm.setup.eazmsn,
1612                                        bchan->plcip->plci);
1613                                return 0;
1614                        }
1615                        bchan->si1 = c->parm.setup.si1;
1616                        bchan->si2 = c->parm.setup.si2;
1617
1618                        strncpy(bchan->num, c->parm.setup.phone, sizeof(bchan->num));
1619                        strncpy(bchan->mynum, c->parm.setup.eazmsn, sizeof(bchan->mynum));
1620                        rc = FVteln2capi20(bchan->num, AdditionalInfo);
1621                        isleasedline = (rc == 0);
1622                        if (rc < 0)
1623                                printk(KERN_ERR "capidrv-%d: WARNING: invalid leased linedefinition \"%s\"\n", card->contrnr, bchan->num);
1624
1625                        if (isleasedline) {
1626                                calling[0] = 0;
1627                                called[0] = 0;
1628                                if (debugmode)
1629                                        printk(KERN_DEBUG "capidrv-%d: connecting leased line\n", card->contrnr);
1630                        } else {
1631                                calling[0] = strlen(bchan->mynum) + 2;
1632                                calling[1] = 0;
1633                                calling[2] = 0x80;
1634                                strncpy(calling + 3, bchan->mynum, ISDN_MSNLEN);
1635                                called[0] = strlen(bchan->num) + 1;
1636                                called[1] = 0x80;
1637                                strncpy(called + 2, bchan->num, ISDN_MSNLEN);
1638                        }
1639
1640                        capi_fill_CONNECT_REQ(&cmdcmsg,
1641                                              global.ap.applid,
1642                                              card->msgid++,
1643                                              card->contrnr,    /* adr */
1644                                          si2cip(bchan->si1, bchan->si2),       /* cipvalue */
1645                                              called,   /* CalledPartyNumber */
1646                                              calling,  /* CallingPartyNumber */
1647                                              NULL,     /* CalledPartySubaddress */
1648                                              NULL,     /* CallingPartySubaddress */
1649                                            b1prot(bchan->l2, bchan->l3),       /* B1protocol */
1650                                            b2prot(bchan->l2, bchan->l3),       /* B2protocol */
1651                                            b3prot(bchan->l2, bchan->l3),       /* B3protocol */
1652                                            b1config(bchan->l2, bchan->l3),     /* B1configuration */
1653                                              NULL,     /* B2configuration */
1654                                              NULL,     /* B3configuration */
1655                                              NULL,     /* BC */
1656                                              NULL,     /* LLC */
1657                                              NULL,     /* HLC */
1658                                              /* BChannelinformation */
1659                                              isleasedline ? AdditionalInfo : NULL,
1660                                              NULL,     /* Keypadfacility */
1661                                              NULL,     /* Useruserdata */
1662                                              NULL      /* Facilitydataarray */
1663                            );
1664                        if ((plcip = new_plci(card, (c->arg % card->nbchan))) == NULL) {
1665                                cmd.command = ISDN_STAT_DHUP;
1666                                cmd.driver = card->myid;
1667                                cmd.arg = (c->arg % card->nbchan);
1668                                card->interface.statcallb(&cmd);
1669                                return -1;
1670                        }
1671                        plcip->msgid = cmdcmsg.Messagenumber;
1672                        plcip->leasedline = isleasedline;
1673                        plci_change_state(card, plcip, EV_PLCI_CONNECT_REQ);
1674                        send_message(card, &cmdcmsg);
1675                        return 0;
1676                }
1677
1678        case ISDN_CMD_ACCEPTD:
1679
1680                bchan = &card->bchans[c->arg % card->nbchan];
1681                if (debugmode)
1682                        printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTD(ch=%ld) l2=%d l3=%d\n",
1683                               card->contrnr,
1684                               c->arg, bchan->l2, bchan->l3);
1685
1686                capi_fill_CONNECT_RESP(&cmdcmsg,
1687                                       global.ap.applid,
1688                                       card->msgid++,
1689                                       bchan->plcip->plci,      /* adr */
1690                                       0,       /* Reject */
1691                                       b1prot(bchan->l2, bchan->l3),    /* B1protocol */
1692                                       b2prot(bchan->l2, bchan->l3),    /* B2protocol */
1693                                       b3prot(bchan->l2, bchan->l3),    /* B3protocol */
1694                                       b1config(bchan->l2, bchan->l3),  /* B1configuration */
1695                                       NULL,    /* B2configuration */
1696                                       NULL,    /* B3configuration */
1697                                       NULL,    /* ConnectedNumber */
1698                                       NULL,    /* ConnectedSubaddress */
1699                                       NULL,    /* LLC */
1700                                       NULL,    /* BChannelinformation */
1701                                       NULL,    /* Keypadfacility */
1702                                       NULL,    /* Useruserdata */
1703                                       NULL     /* Facilitydataarray */
1704                );
1705                capi_cmsg2message(&cmdcmsg, cmdcmsg.buf);
1706                plci_change_state(card, bchan->plcip, EV_PLCI_CONNECT_RESP);
1707                send_message(card, &cmdcmsg);
1708                return 0;
1709
1710        case ISDN_CMD_ACCEPTB:
1711                if (debugmode)
1712                        printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTB(ch=%ld)\n",
1713                               card->contrnr,
1714                               c->arg);
1715                return -ENOSYS;
1716
1717        case ISDN_CMD_HANGUP:
1718                if (debugmode)
1719                        printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_HANGUP(ch=%ld)\n",
1720                               card->contrnr,
1721                               c->arg);
1722                bchan = &card->bchans[c->arg % card->nbchan];
1723
1724                if (bchan->disconnecting) {
1725                        if (debugmode)
1726                                printk(KERN_DEBUG "capidrv-%d: chan %ld already disconnecting ...\n",
1727                                       card->contrnr,
1728                                       c->arg);
1729                        return 0;
1730                }
1731                if (bchan->nccip) {
1732                        bchan->disconnecting = 1;
1733                        capi_fill_DISCONNECT_B3_REQ(&cmdcmsg,
1734                                                    global.ap.applid,
1735                                                    card->msgid++,
1736                                                    bchan->nccip->ncci,
1737                                                    NULL        /* NCPI */
1738                        );
1739                        ncci_change_state(card, bchan->nccip, EV_NCCI_DISCONNECT_B3_REQ);
1740                        send_message(card, &cmdcmsg);
1741                        return 0;
1742                } else if (bchan->plcip) {
1743                        if (bchan->plcip->state == ST_PLCI_INCOMING) {
1744                                /*
1745                                 * just ignore, we a called from
1746                                 * isdn_status_callback(),
1747                                 * which will return 0 or 2, this is handled
1748                                 * by the CONNECT_IND handler
1749                                 */
1750                                bchan->disconnecting = 1;
1751                                return 0;
1752                        } else if (bchan->plcip->plci) {
1753                                bchan->disconnecting = 1;
1754                                capi_fill_DISCONNECT_REQ(&cmdcmsg,
1755                                                         global.ap.applid,
1756                                                         card->msgid++,
1757                                                      bchan->plcip->plci,
1758                                                         NULL,  /* BChannelinformation */
1759                                                         NULL,  /* Keypadfacility */
1760                                                         NULL,  /* Useruserdata */
1761                                                         NULL   /* Facilitydataarray */
1762                                );
1763                                plci_change_state(card, bchan->plcip, EV_PLCI_DISCONNECT_REQ);
1764                                send_message(card, &cmdcmsg);
1765                                return 0;
1766                        } else {
1767                                printk(KERN_ERR "capidrv-%d: chan %ld disconnect request while waiting for CONNECT_CONF\n",
1768                                       card->contrnr,
1769                                       c->arg);
1770                                return -EINVAL;
1771                        }
1772                }
1773                printk(KERN_ERR "capidrv-%d: chan %ld disconnect request on free channel\n",
1774                                       card->contrnr,
1775                                       c->arg);
1776                return -EINVAL;
1777/* ready */
1778
1779        case ISDN_CMD_SETL2:
1780                if (debugmode)
1781                        printk(KERN_DEBUG "capidrv-%d: set L2 on chan %ld to %ld\n",
1782                               card->contrnr,
1783                               (c->arg & 0xff), (c->arg >> 8));
1784                bchan = &card->bchans[(c->arg & 0xff) % card->nbchan];
1785                bchan->l2 = (c->arg >> 8);
1786                return 0;
1787
1788        case ISDN_CMD_SETL3:
1789                if (debugmode)
1790                        printk(KERN_DEBUG "capidrv-%d: set L3 on chan %ld to %ld\n",
1791                               card->contrnr,
1792                               (c->arg & 0xff), (c->arg >> 8));
1793                bchan = &card->bchans[(c->arg & 0xff) % card->nbchan];
1794                bchan->l3 = (c->arg >> 8);
1795                return 0;
1796
1797        case ISDN_CMD_SETEAZ:
1798                if (debugmode)
1799                        printk(KERN_DEBUG "capidrv-%d: set EAZ \"%s\" on chan %ld\n",
1800                               card->contrnr,
1801                               c->parm.num, c->arg);
1802                bchan = &card->bchans[c->arg % card->nbchan];
1803                strncpy(bchan->msn, c->parm.num, ISDN_MSNLEN);
1804                return 0;
1805
1806        case ISDN_CMD_CLREAZ:
1807                if (debugmode)
1808                        printk(KERN_DEBUG "capidrv-%d: clearing EAZ on chan %ld\n",
1809                                        card->contrnr, c->arg);
1810                bchan = &card->bchans[c->arg % card->nbchan];
1811                bchan->msn[0] = 0;
1812                return 0;
1813
1814        default:
1815                printk(KERN_ERR "capidrv-%d: ISDN_CMD_%d, Huh?\n",
1816                                        card->contrnr, c->command);
1817                return -EINVAL;
1818        }
1819        return 0;
1820}
1821
1822static int if_command(isdn_ctrl * c)
1823{
1824        capidrv_contr *card = findcontrbydriverid(c->driver);
1825
1826        if (card)
1827                return capidrv_command(c, card);
1828
1829        printk(KERN_ERR
1830             "capidrv: if_command %d called with invalid driverId %d!\n",
1831                                                c->command, c->driver);
1832        return -ENODEV;
1833}
1834
1835static _cmsg sendcmsg;
1836
1837static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb)
1838{
1839        capidrv_contr *card = findcontrbydriverid(id);
1840        capidrv_bchan *bchan;
1841        capidrv_ncci *nccip;
1842        int len = skb->len;
1843        int msglen;
1844        u16 errcode;
1845        u16 datahandle;
1846        u32 data;
1847
1848        if (!card) {
1849                printk(KERN_ERR "capidrv: if_sendbuf called with invalid driverId %d!\n",
1850                       id);
1851                return 0;
1852        }
1853        if (debugmode > 4)
1854                printk(KERN_DEBUG "capidrv-%d: sendbuf len=%d skb=%p doack=%d\n",
1855                                        card->contrnr, len, skb, doack);
1856        bchan = &card->bchans[channel % card->nbchan];
1857        nccip = bchan->nccip;
1858        if (!nccip || nccip->state != ST_NCCI_ACTIVE) {
1859                printk(KERN_ERR "capidrv-%d: if_sendbuf: %s:%d: chan not up!\n",
1860                       card->contrnr, card->name, channel);
1861                return 0;
1862        }
1863        datahandle = nccip->datahandle;
1864
1865        /*
1866         * Here we copy pointer skb->data into the 32-bit 'Data' field.
1867         * The 'Data' field is not used in practice in linux kernel
1868         * (neither in 32 or 64 bit), but should have some value,
1869         * since a CAPI message trace will display it.
1870         *
1871         * The correct value in the 32 bit case is the address of the
1872         * data, in 64 bit it makes no sense, we use 0 there.
1873         */
1874
1875#ifdef CONFIG_64BIT
1876        data = 0;
1877#else
1878        data = (unsigned long) skb->data;
1879#endif
1880
1881        capi_fill_DATA_B3_REQ(&sendcmsg, global.ap.applid, card->msgid++,
1882                              nccip->ncci,      /* adr */
1883                              data,             /* Data */
1884                              skb->len,         /* DataLength */
1885                              datahandle,       /* DataHandle */
1886                              0 /* Flags */
1887            );
1888
1889        if (capidrv_add_ack(nccip, datahandle, doack ? (int)skb->len : -1) < 0)
1890           return 0;
1891
1892        capi_cmsg2message(&sendcmsg, sendcmsg.buf);
1893        msglen = CAPIMSG_LEN(sendcmsg.buf);
1894        if (skb_headroom(skb) < msglen) {
1895                struct sk_buff *nskb = skb_realloc_headroom(skb, msglen);
1896                if (!nskb) {
1897                        printk(KERN_ERR "capidrv-%d: if_sendbuf: no memory\n",
1898                                card->contrnr);
1899                        (void)capidrv_del_ack(nccip, datahandle);
1900                        return 0;
1901                }
1902                printk(KERN_DEBUG "capidrv-%d: only %d bytes headroom, need %d\n",
1903                       card->contrnr, skb_headroom(skb), msglen);
1904                memcpy(skb_push(nskb, msglen), sendcmsg.buf, msglen);
1905                errcode = capi20_put_message(&global.ap, nskb);
1906                if (errcode == CAPI_NOERROR) {
1907                        dev_kfree_skb(skb);
1908                        nccip->datahandle++;
1909                        return len;
1910                }
1911                if (debugmode > 3)
1912                        printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n",
1913                                card->contrnr, errcode, capi_info2str(errcode));
1914                (void)capidrv_del_ack(nccip, datahandle);
1915                dev_kfree_skb(nskb);
1916                return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
1917        } else {
1918                memcpy(skb_push(skb, msglen), sendcmsg.buf, msglen);
1919                errcode = capi20_put_message(&global.ap, skb);
1920                if (errcode == CAPI_NOERROR) {
1921                        nccip->datahandle++;
1922                        return len;
1923                }
1924                if (debugmode > 3)
1925                        printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n",
1926                                card->contrnr, errcode, capi_info2str(errcode));
1927                skb_pull(skb, msglen);
1928                (void)capidrv_del_ack(nccip, datahandle);
1929                return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
1930        }
1931}
1932
1933static int if_readstat(u8 __user *buf, int len, int id, int channel)
1934{
1935        capidrv_contr *card = findcontrbydriverid(id);
1936        int count;
1937        u8 __user *p;
1938
1939        if (!card) {
1940                printk(KERN_ERR "capidrv: if_readstat called with invalid driverId %d!\n",
1941                       id);
1942                return -ENODEV;
1943        }
1944
1945        for (p=buf, count=0; count < len; p++, count++) {
1946                if (put_user(*card->q931_read++, p))
1947                        return -EFAULT;
1948                if (card->q931_read > card->q931_end)
1949                        card->q931_read = card->q931_buf;
1950        }
1951        return count;
1952
1953}
1954
1955static void enable_dchannel_trace(capidrv_contr *card)
1956{
1957        u8 manufacturer[CAPI_MANUFACTURER_LEN];
1958        capi_version version;
1959        u16 contr = card->contrnr;
1960        u16 errcode;
1961        u16 avmversion[3];
1962
1963        errcode = capi20_get_manufacturer(contr, manufacturer);
1964        if (errcode != CAPI_NOERROR) {
1965           printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n",
1966                        card->name, errcode);
1967           return;
1968        }
1969        if (strstr(manufacturer, "AVM") == NULL) {
1970           printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n",
1971                        card->name, manufacturer);
1972           return;
1973        }
1974        errcode = capi20_get_version(contr, &version);
1975        if (errcode != CAPI_NOERROR) {
1976           printk(KERN_ERR "%s: can't get version (0x%x)\n",
1977                        card->name, errcode);
1978           return;
1979        }
1980        avmversion[0] = (version.majormanuversion >> 4) & 0x0f;
1981        avmversion[1] = (version.majormanuversion << 4) & 0xf0;
1982        avmversion[1] |= (version.minormanuversion >> 4) & 0x0f;
1983        avmversion[2] |= version.minormanuversion & 0x0f;
1984
1985        if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) {
1986                printk(KERN_INFO "%s: D2 trace enabled\n", card->name);
1987                capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.ap.applid,
1988                                           card->msgid++,
1989                                           contr,
1990                                           0x214D5641,  /* ManuID */
1991                                           0,           /* Class */
1992                                           1,           /* Function */
1993                                           (_cstruct)"\004\200\014\000\000");
1994        } else {
1995                printk(KERN_INFO "%s: D3 trace enabled\n", card->name);
1996                capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.ap.applid,
1997                                           card->msgid++,
1998                                           contr,
1999                                           0x214D5641,  /* ManuID */
2000                                           0,           /* Class */
2001                                           1,           /* Function */
2002                                           (_cstruct)"\004\002\003\000\000");
2003        }
2004        send_message(card, &cmdcmsg);
2005}
2006
2007
2008static void send_listen(capidrv_contr *card)
2009{
2010        capi_fill_LISTEN_REQ(&cmdcmsg, global.ap.applid,
2011                             card->msgid++,
2012                             card->contrnr, /* controller */
2013                             1 << 6,    /* Infomask */
2014                             card->cipmask,
2015                             card->cipmask2,
2016                             NULL, NULL);
2017        send_message(card, &cmdcmsg);
2018        listen_change_state(card, EV_LISTEN_REQ);
2019}
2020
2021static void listentimerfunc(unsigned long x)
2022{
2023        capidrv_contr *card = (capidrv_contr *)x;
2024        if (card->state != ST_LISTEN_NONE && card->state != ST_LISTEN_ACTIVE)
2025                printk(KERN_ERR "%s: controller dead ??\n", card->name);
2026        send_listen(card);
2027        mod_timer(&card->listentimer, jiffies + 60*HZ);
2028}
2029
2030
2031static int capidrv_addcontr(u16 contr, struct capi_profile *profp)
2032{
2033        capidrv_contr *card;
2034        unsigned long flags;
2035        isdn_ctrl cmd;
2036        char id[20];
2037        int i;
2038
2039        sprintf(id, "capidrv-%d", contr);
2040        if (!try_module_get(THIS_MODULE)) {
2041                printk(KERN_WARNING "capidrv: (%s) Could not reserve module\n", id);
2042                return -1;
2043        }
2044        if (!(card = kzalloc(sizeof(capidrv_contr), GFP_ATOMIC))) {
2045                printk(KERN_WARNING
2046                 "capidrv: (%s) Could not allocate contr-struct.\n", id);
2047                return -1;
2048        }
2049        card->owner = THIS_MODULE;
2050        init_timer(&card->listentimer);
2051        strcpy(card->name, id);
2052        card->contrnr = contr;
2053        card->nbchan = profp->nbchannel;
2054        card->bchans = kmalloc(sizeof(capidrv_bchan) * card->nbchan, GFP_ATOMIC);
2055        if (!card->bchans) {
2056                printk(KERN_WARNING
2057                "capidrv: (%s) Could not allocate bchan-structs.\n", id);
2058                module_put(card->owner);
2059                kfree(card);
2060                return -1;
2061        }
2062        card->interface.channels = profp->nbchannel;
2063        card->interface.maxbufsize = 2048;
2064        card->interface.command = if_command;
2065        card->interface.writebuf_skb = if_sendbuf;
2066        card->interface.writecmd = NULL;
2067        card->interface.readstat = if_readstat;
2068        card->interface.features = ISDN_FEATURE_L2_HDLC |
2069                                   ISDN_FEATURE_L2_TRANS |
2070                                   ISDN_FEATURE_L3_TRANS |
2071                                   ISDN_FEATURE_P_UNKNOWN |
2072                                   ISDN_FEATURE_L2_X75I |
2073                                   ISDN_FEATURE_L2_X75UI |
2074                                   ISDN_FEATURE_L2_X75BUI;
2075        if (profp->support1 & (1<<2))
2076                card->interface.features |= ISDN_FEATURE_L2_V11096 |
2077                                            ISDN_FEATURE_L2_V11019 |
2078                                            ISDN_FEATURE_L2_V11038;
2079        if (profp->support1 & (1<<8))
2080                card->interface.features |= ISDN_FEATURE_L2_MODEM;
2081        card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */
2082        strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
2083
2084
2085        card->q931_read = card->q931_buf;
2086        card->q931_write = card->q931_buf;
2087        card->q931_end = card->q931_buf + sizeof(card->q931_buf) - 1;
2088
2089        if (!register_isdn(&card->interface)) {
2090                printk(KERN_ERR "capidrv: Unable to register contr %s\n", id);
2091                kfree(card->bchans);
2092                module_put(card->owner);
2093                kfree(card);
2094                return -1;
2095        }
2096        card->myid = card->interface.channels;
2097        memset(card->bchans, 0, sizeof(capidrv_bchan) * card->nbchan);
2098        for (i = 0; i < card->nbchan; i++) {
2099                card->bchans[i].contr = card;
2100        }
2101
2102        spin_lock_irqsave(&global_lock, flags);
2103        card->next = global.contr_list;
2104        global.contr_list = card;
2105        global.ncontr++;
2106        spin_unlock_irqrestore(&global_lock, flags);
2107
2108        cmd.command = ISDN_STAT_RUN;
2109        cmd.driver = card->myid;
2110        card->interface.statcallb(&cmd);
2111
2112        card->cipmask = 0x1FFF03FF;     /* any */
2113        card->cipmask2 = 0;
2114
2115        card->listentimer.data = (unsigned long)card;
2116        card->listentimer.function = listentimerfunc;
2117        send_listen(card);
2118        mod_timer(&card->listentimer, jiffies + 60*HZ);
2119
2120        printk(KERN_INFO "%s: now up (%d B channels)\n",
2121                card->name, card->nbchan);
2122
2123        enable_dchannel_trace(card);
2124
2125        return 0;
2126}
2127
2128static int capidrv_delcontr(u16 contr)
2129{
2130        capidrv_contr **pp, *card;
2131        unsigned long flags;
2132        isdn_ctrl cmd;
2133
2134        spin_lock_irqsave(&global_lock, flags);
2135        for (card = global.contr_list; card; card = card->next) {
2136                if (card->contrnr == contr)
2137                        break;
2138        }
2139        if (!card) {
2140                spin_unlock_irqrestore(&global_lock, flags);
2141                printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr);
2142                return -1;
2143        }
2144
2145        /* FIXME: maybe a race condition the card should be removed
2146         * here from global list /kkeil
2147         */
2148        spin_unlock_irqrestore(&global_lock, flags);
2149
2150        del_timer(&card->listentimer);
2151
2152        if (debugmode)
2153                printk(KERN_DEBUG "capidrv-%d: id=%d unloading\n",
2154                                        card->contrnr, card->myid);
2155
2156        cmd.command = ISDN_STAT_STOP;
2157        cmd.driver = card->myid;
2158        card->interface.statcallb(&cmd);
2159
2160        while (card->nbchan) {
2161
2162                cmd.command = ISDN_STAT_DISCH;
2163                cmd.driver = card->myid;
2164                cmd.arg = card->nbchan-1;
2165                cmd.parm.num[0] = 0;
2166                if (debugmode)
2167                        printk(KERN_DEBUG "capidrv-%d: id=%d disable chan=%ld\n",
2168                                        card->contrnr, card->myid, cmd.arg);
2169                card->interface.statcallb(&cmd);
2170
2171                if (card->bchans[card->nbchan-1].nccip)
2172                        free_ncci(card, card->bchans[card->nbchan-1].nccip);
2173                if (card->bchans[card->nbchan-1].plcip)
2174                        free_plci(card, card->bchans[card->nbchan-1].plcip);
2175                if (card->plci_list)
2176                        printk(KERN_ERR "capidrv: bug in free_plci()\n");
2177                card->nbchan--;
2178        }
2179        kfree(card->bchans);
2180        card->bchans = NULL;
2181
2182        if (debugmode)
2183                printk(KERN_DEBUG "capidrv-%d: id=%d isdn unload\n",
2184                                        card->contrnr, card->myid);
2185
2186        cmd.command = ISDN_STAT_UNLOAD;
2187        cmd.driver = card->myid;
2188        card->interface.statcallb(&cmd);
2189
2190        if (debugmode)
2191                printk(KERN_DEBUG "capidrv-%d: id=%d remove contr from list\n",
2192                                        card->contrnr, card->myid);
2193
2194        spin_lock_irqsave(&global_lock, flags);
2195        for (pp = &global.contr_list; *pp; pp = &(*pp)->next) {
2196                if (*pp == card) {
2197                        *pp = (*pp)->next;
2198                        card->next = NULL;
2199                        global.ncontr--;
2200                        break;
2201                }
2202        }
2203        spin_unlock_irqrestore(&global_lock, flags);
2204
2205        module_put(card->owner);
2206        printk(KERN_INFO "%s: now down.\n", card->name);
2207        kfree(card);
2208        return 0;
2209}
2210
2211
2212static void lower_callback(unsigned int cmd, u32 contr, void *data)
2213{
2214
2215        switch (cmd) {
2216        case KCI_CONTRUP:
2217                printk(KERN_INFO "capidrv: controller %hu up\n", contr);
2218                (void) capidrv_addcontr(contr, (capi_profile *) data);
2219                break;
2220        case KCI_CONTRDOWN:
2221                printk(KERN_INFO "capidrv: controller %hu down\n", contr);
2222                (void) capidrv_delcontr(contr);
2223                break;
2224        }
2225}
2226
2227/*
2228 * /proc/capi/capidrv:
2229 * nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
2230 */
2231static int proc_capidrv_read_proc(char *page, char **start, off_t off,
2232                                       int count, int *eof, void *data)
2233{
2234        int len = 0;
2235
2236        len += sprintf(page+len, "%lu %lu %lu %lu\n",
2237                        global.ap.nrecvctlpkt,
2238                        global.ap.nrecvdatapkt,
2239                        global.ap.nsentctlpkt,
2240                        global.ap.nsentdatapkt);
2241        if (off+count >= len)
2242           *eof = 1;
2243        if (len < off)
2244           return 0;
2245        *start = page + off;
2246        return ((count < len-off) ? count : len-off);
2247}
2248
2249static struct procfsentries {
2250  char *name;
2251  mode_t mode;
2252  int (*read_proc)(char *page, char **start, off_t off,
2253                                       int count, int *eof, void *data);
2254  struct proc_dir_entry *procent;
2255} procfsentries[] = {
2256   /* { "capi",           S_IFDIR, 0 }, */
2257   { "capi/capidrv",      0      , proc_capidrv_read_proc },
2258};
2259
2260static void __init proc_init(void)
2261{
2262    int nelem = ARRAY_SIZE(procfsentries);
2263    int i;
2264
2265    for (i=0; i < nelem; i++) {
2266        struct procfsentries *p = procfsentries + i;
2267        p->procent = create_proc_entry(p->name, p->mode, NULL);
2268        if (p->procent) p->procent->read_proc = p->read_proc;
2269    }
2270}
2271
2272static void __exit proc_exit(void)
2273{
2274    int nelem = ARRAY_SIZE(procfsentries);
2275    int i;
2276
2277    for (i=nelem-1; i >= 0; i--) {
2278        struct procfsentries *p = procfsentries + i;
2279        if (p->procent) {
2280           remove_proc_entry(p->name, NULL);
2281           p->procent = NULL;
2282        }
2283    }
2284}
2285
2286static int __init capidrv_init(void)
2287{
2288        capi_profile profile;
2289        char rev[32];
2290        char *p;
2291        u32 ncontr, contr;
2292        u16 errcode;
2293
2294        if ((p = strchr(revision, ':')) != NULL && p[1]) {
2295                strncpy(rev, p + 2, sizeof(rev));
2296                rev[sizeof(rev)-1] = 0;
2297                if ((p = strchr(rev, '$')) != NULL && p > rev)
2298                   *(p-1) = 0;
2299        } else
2300                strcpy(rev, "1.0");
2301
2302        global.ap.rparam.level3cnt = -2;  /* number of bchannels twice */
2303        global.ap.rparam.datablkcnt = 16;
2304        global.ap.rparam.datablklen = 2048;
2305
2306        global.ap.recv_message = capidrv_recv_message;
2307        errcode = capi20_register(&global.ap);
2308        if (errcode) {
2309                return -EIO;
2310        }
2311
2312        capi20_set_callback(&global.ap, lower_callback);
2313
2314        errcode = capi20_get_profile(0, &profile);
2315        if (errcode != CAPI_NOERROR) {
2316                capi20_release(&global.ap);
2317                return -EIO;
2318        }
2319
2320        ncontr = profile.ncontroller;
2321        for (contr = 1; contr <= ncontr; contr++) {
2322                errcode = capi20_get_profile(contr, &profile);
2323                if (errcode != CAPI_NOERROR)
2324                        continue;
2325                (void) capidrv_addcontr(contr, &profile);
2326        }
2327        proc_init();
2328
2329        printk(KERN_NOTICE "capidrv: Rev %s: loaded\n", rev);
2330        return 0;
2331}
2332
2333static void __exit capidrv_exit(void)
2334{
2335        char rev[32];
2336        char *p;
2337
2338        if ((p = strchr(revision, ':')) != NULL) {
2339                strncpy(rev, p + 1, sizeof(rev));
2340                rev[sizeof(rev)-1] = 0;
2341                if ((p = strchr(rev, '$')) != NULL)
2342                        *p = 0;
2343        } else {
2344                strcpy(rev, " ??? ");
2345        }
2346
2347        capi20_release(&global.ap);
2348
2349        proc_exit();
2350
2351        printk(KERN_NOTICE "capidrv: Rev%s: unloaded\n", rev);
2352}
2353
2354module_init(capidrv_init);
2355module_exit(capidrv_exit);
2356