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/seq_file.h>
  28#include <linux/capi.h>
  29#include <linux/kernelcapi.h>
  30#include <linux/ctype.h>
  31#include <linux/init.h>
  32#include <linux/moduleparam.h>
  33
  34#include <linux/isdn/capiutil.h>
  35#include <linux/isdn/capicmd.h>
  36#include "capidrv.h"
  37
  38static int debugmode = 0;
  39
  40MODULE_DESCRIPTION("CAPI4Linux: Interface to ISDN4Linux");
  41MODULE_AUTHOR("Carsten Paeth");
  42MODULE_LICENSE("GPL");
  43module_param(debugmode, uint, S_IRUGO | S_IWUSR);
  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 = kmalloc(sizeof(struct ncci_datahandle_queue), GFP_ATOMIC);
 473        if (!n) {
 474                printk(KERN_ERR "capidrv: kmalloc ncci_datahandle failed\n");
 475                return -1;
 476        }
 477        n->next = NULL;
 478        n->datahandle = datahandle;
 479        n->len = len;
 480        for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next);
 481        *pp = n;
 482        return 0;
 483}
 484
 485static int capidrv_del_ack(struct capidrv_ncci *nccip, u16 datahandle)
 486{
 487        struct ncci_datahandle_queue **pp, *p;
 488        int len;
 489
 490        for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) {
 491                if ((*pp)->datahandle == datahandle) {
 492                        p = *pp;
 493                        len = p->len;
 494                        *pp = (*pp)->next;
 495                        kfree(p);
 496                        return len;
 497                }
 498        }
 499        return -1;
 500}
 501
 502/* -------- convert and send capi message ---------------------------- */
 503
 504static void send_message(capidrv_contr *card, _cmsg *cmsg)
 505{
 506        struct sk_buff *skb;
 507        size_t len;
 508
 509        capi_cmsg2message(cmsg, cmsg->buf);
 510        len = CAPIMSG_LEN(cmsg->buf);
 511        skb = alloc_skb(len, GFP_ATOMIC);
 512        if (!skb) {
 513                printk(KERN_ERR "capidrv::send_message: can't allocate mem\n");
 514                return;
 515        }
 516        memcpy(skb_put(skb, len), cmsg->buf, len);
 517        if (capi20_put_message(&global.ap, skb) != CAPI_NOERROR)
 518                kfree_skb(skb);
 519}
 520
 521/* -------- state machine -------------------------------------------- */
 522
 523struct listenstatechange {
 524        int actstate;
 525        int nextstate;
 526        int event;
 527};
 528
 529static struct listenstatechange listentable[] =
 530{
 531        {ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ},
 532        {ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ},
 533        {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR},
 534        {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR},
 535        {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
 536        {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY},
 537        {ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
 538        {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK},
 539        {},
 540};
 541
 542static void listen_change_state(capidrv_contr *card, int event)
 543{
 544        struct listenstatechange *p = listentable;
 545        while (p->event) {
 546                if (card->state == p->actstate && p->event == event) {
 547                        if (debugmode)
 548                                printk(KERN_DEBUG "capidrv-%d: listen_change_state %d -> %d\n",
 549                                       card->contrnr, card->state, p->nextstate);
 550                        card->state = p->nextstate;
 551                        return;
 552                }
 553                p++;
 554        }
 555        printk(KERN_ERR "capidrv-%d: listen_change_state state=%d event=%d ????\n",
 556               card->contrnr, card->state, event);
 557
 558}
 559
 560/* ------------------------------------------------------------------ */
 561
 562static void p0(capidrv_contr *card, capidrv_plci *plci)
 563{
 564        isdn_ctrl cmd;
 565
 566        card->bchans[plci->chan].contr = NULL;
 567        cmd.command = ISDN_STAT_DHUP;
 568        cmd.driver = card->myid;
 569        cmd.arg = plci->chan;
 570        card->interface.statcallb(&cmd);
 571        free_plci(card, plci);
 572}
 573
 574/* ------------------------------------------------------------------ */
 575
 576struct plcistatechange {
 577        int actstate;
 578        int nextstate;
 579        int event;
 580        void (*changefunc)(capidrv_contr *card, capidrv_plci *plci);
 581};
 582
 583static struct plcistatechange plcitable[] =
 584{
 585        /* P-0 */
 586        {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, NULL},
 587        {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, NULL},
 588        {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, NULL},
 589        {ST_PLCI_NONE, ST_PLCI_RESUMEING, EV_PLCI_RESUME_REQ, NULL},
 590        /* P-0.1 */
 591        {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0},
 592        {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, NULL},
 593        /* P-1 */
 594        {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, NULL},
 595        {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
 596        {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
 597        {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
 598        /* P-ACT */
 599        {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
 600        {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
 601        {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
 602        {ST_PLCI_ACTIVE, ST_PLCI_HELD, EV_PLCI_HOLD_IND, NULL},
 603        {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_SUSPEND_IND, NULL},
 604        /* P-2 */
 605        {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, NULL},
 606        {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, NULL},
 607        {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, NULL},
 608        {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
 609        {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
 610        {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
 611        {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CD_IND, NULL},
 612        /* P-3 */
 613        {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, NULL},
 614        {ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, NULL},
 615        {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
 616        {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
 617        {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
 618        /* P-4 */
 619        {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, NULL},
 620        {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL},
 621        {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL},
 622        {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
 623        /* P-5 */
 624        {ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL},
 625        /* P-6 */
 626        {ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0},
 627        /* P-0.Res */
 628        {ST_PLCI_RESUMEING, ST_PLCI_NONE, EV_PLCI_RESUME_CONF_ERROR, p0},
 629        {ST_PLCI_RESUMEING, ST_PLCI_RESUME, EV_PLCI_RESUME_CONF_OK, NULL},
 630        /* P-RES */
 631        {ST_PLCI_RESUME, ST_PLCI_ACTIVE, EV_PLCI_RESUME_IND, NULL},
 632        /* P-HELD */
 633        {ST_PLCI_HELD, ST_PLCI_ACTIVE, EV_PLCI_RETRIEVE_IND, NULL},
 634        {},
 635};
 636
 637static void plci_change_state(capidrv_contr *card, capidrv_plci *plci, int event)
 638{
 639        struct plcistatechange *p = plcitable;
 640        while (p->event) {
 641                if (plci->state == p->actstate && p->event == event) {
 642                        if (debugmode)
 643                                printk(KERN_DEBUG "capidrv-%d: plci_change_state:0x%x %d -> %d\n",
 644                                       card->contrnr, plci->plci, plci->state, p->nextstate);
 645                        plci->state = p->nextstate;
 646                        if (p->changefunc)
 647                                p->changefunc(card, plci);
 648                        return;
 649                }
 650                p++;
 651        }
 652        printk(KERN_ERR "capidrv-%d: plci_change_state:0x%x state=%d event=%d ????\n",
 653               card->contrnr, plci->plci, plci->state, event);
 654}
 655
 656/* ------------------------------------------------------------------ */
 657
 658static _cmsg cmsg;
 659
 660static void n0(capidrv_contr *card, capidrv_ncci *ncci)
 661{
 662        isdn_ctrl cmd;
 663
 664        capi_fill_DISCONNECT_REQ(&cmsg,
 665                                 global.ap.applid,
 666                                 card->msgid++,
 667                                 ncci->plcip->plci,
 668                                 NULL,  /* BChannelinformation */
 669                                 NULL,  /* Keypadfacility */
 670                                 NULL,  /* Useruserdata */   /* $$$$ */
 671                                 NULL   /* Facilitydataarray */
 672                );
 673        plci_change_state(card, ncci->plcip, EV_PLCI_DISCONNECT_REQ);
 674        send_message(card, &cmsg);
 675
 676        cmd.command = ISDN_STAT_BHUP;
 677        cmd.driver = card->myid;
 678        cmd.arg = ncci->chan;
 679        card->interface.statcallb(&cmd);
 680        free_ncci(card, ncci);
 681}
 682
 683/* ------------------------------------------------------------------ */
 684
 685struct nccistatechange {
 686        int actstate;
 687        int nextstate;
 688        int event;
 689        void (*changefunc)(capidrv_contr *card, capidrv_ncci *ncci);
 690};
 691
 692static struct nccistatechange nccitable[] =
 693{
 694        /* N-0 */
 695        {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, NULL},
 696        {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, NULL},
 697        /* N-0.1 */
 698        {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, NULL},
 699        {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, n0},
 700        /* N-1 */
 701        {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, NULL},
 702        {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, NULL},
 703        {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
 704        {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
 705        /* N-2 */
 706        {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, NULL},
 707        {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
 708        {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
 709        /* N-ACT */
 710        {ST_NCCI_ACTIVE, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, NULL},
 711        {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, NULL},
 712        {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
 713        {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
 714        /* N-3 */
 715        {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, NULL},
 716        {ST_NCCI_RESETING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
 717        {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL},
 718        /* N-4 */
 719        {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL},
 720        {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR, NULL},
 721        /* N-5 */
 722        {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0},
 723        {},
 724};
 725
 726static void ncci_change_state(capidrv_contr *card, capidrv_ncci *ncci, int event)
 727{
 728        struct nccistatechange *p = nccitable;
 729        while (p->event) {
 730                if (ncci->state == p->actstate && p->event == event) {
 731                        if (debugmode)
 732                                printk(KERN_DEBUG "capidrv-%d: ncci_change_state:0x%x %d -> %d\n",
 733                                       card->contrnr, ncci->ncci, ncci->state, p->nextstate);
 734                        if (p->nextstate == ST_NCCI_PREVIOUS) {
 735                                ncci->state = ncci->oldstate;
 736                                ncci->oldstate = p->actstate;
 737                        } else {
 738                                ncci->oldstate = p->actstate;
 739                                ncci->state = p->nextstate;
 740                        }
 741                        if (p->changefunc)
 742                                p->changefunc(card, ncci);
 743                        return;
 744                }
 745                p++;
 746        }
 747        printk(KERN_ERR "capidrv-%d: ncci_change_state:0x%x state=%d event=%d ????\n",
 748               card->contrnr, ncci->ncci, ncci->state, event);
 749}
 750
 751/* ------------------------------------------------------------------- */
 752
 753static inline int new_bchan(capidrv_contr *card)
 754{
 755        int i;
 756        for (i = 0; i < card->nbchan; i++) {
 757                if (card->bchans[i].plcip == NULL) {
 758                        card->bchans[i].disconnecting = 0;
 759                        return i;
 760                }
 761        }
 762        return -1;
 763}
 764
 765/* ------------------------------------------------------------------- */
 766
 767static void handle_controller(_cmsg *cmsg)
 768{
 769        capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
 770
 771        if (!card) {
 772                printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
 773                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
 774                       cmsg->adr.adrController & 0x7f);
 775                return;
 776        }
 777        switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
 778
 779        case CAPI_LISTEN_CONF:  /* Controller */
 780                if (debugmode)
 781                        printk(KERN_DEBUG "capidrv-%d: listenconf Info=0x%4x (%s) cipmask=0x%x\n",
 782                               card->contrnr, cmsg->Info, capi_info2str(cmsg->Info), card->cipmask);
 783                if (cmsg->Info) {
 784                        listen_change_state(card, EV_LISTEN_CONF_ERROR);
 785                } else if (card->cipmask == 0) {
 786                        listen_change_state(card, EV_LISTEN_CONF_EMPTY);
 787                } else {
 788                        listen_change_state(card, EV_LISTEN_CONF_OK);
 789                }
 790                break;
 791
 792        case CAPI_MANUFACTURER_IND:     /* Controller */
 793                if (cmsg->ManuID == 0x214D5641
 794                    && cmsg->Class == 0
 795                    && cmsg->Function == 1) {
 796                        u8  *data = cmsg->ManuData + 3;
 797                        u16  len = cmsg->ManuData[0];
 798                        u16 layer;
 799                        int direction;
 800                        if (len == 255) {
 801                                len = (cmsg->ManuData[1] | (cmsg->ManuData[2] << 8));
 802                                data += 2;
 803                        }
 804                        len -= 2;
 805                        layer = ((*(data - 1)) << 8) | *(data - 2);
 806                        if (layer & 0x300)
 807                                direction = (layer & 0x200) ? 0 : 1;
 808                        else direction = (layer & 0x800) ? 0 : 1;
 809                        if (layer & 0x0C00) {
 810                                if ((layer & 0xff) == 0x80) {
 811                                        handle_dtrace_data(card, direction, 1, data, len);
 812                                        break;
 813                                }
 814                        } else if ((layer & 0xff) < 0x80) {
 815                                handle_dtrace_data(card, direction, 0, data, len);
 816                                break;
 817                        }
 818                        printk(KERN_INFO "capidrv-%d: %s from controller 0x%x layer 0x%x, ignored\n",
 819                               card->contrnr,
 820                               capi_cmd2str(cmsg->Command, cmsg->Subcommand),
 821                               cmsg->adr.adrController, layer);
 822                        break;
 823                }
 824                goto ignored;
 825        case CAPI_MANUFACTURER_CONF:    /* Controller */
 826                if (cmsg->ManuID == 0x214D5641) {
 827                        char *s = NULL;
 828                        switch (cmsg->Class) {
 829                        case 0: break;
 830                        case 1: s = "unknown class"; break;
 831                        case 2: s = "unknown function"; break;
 832                        default: s = "unknown error"; break;
 833                        }
 834                        if (s)
 835                                printk(KERN_INFO "capidrv-%d: %s from controller 0x%x function %d: %s\n",
 836                                       card->contrnr,
 837                                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
 838                                       cmsg->adr.adrController,
 839                                       cmsg->Function, s);
 840                        break;
 841                }
 842                goto ignored;
 843        case CAPI_FACILITY_IND: /* Controller/plci/ncci */
 844                goto ignored;
 845        case CAPI_FACILITY_CONF:        /* Controller/plci/ncci */
 846                goto ignored;
 847        case CAPI_INFO_IND:     /* Controller/plci */
 848                goto ignored;
 849        case CAPI_INFO_CONF:    /* Controller/plci */
 850                goto ignored;
 851
 852        default:
 853                printk(KERN_ERR "capidrv-%d: got %s from controller 0x%x ???",
 854                       card->contrnr,
 855                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
 856                       cmsg->adr.adrController);
 857        }
 858        return;
 859
 860ignored:
 861        printk(KERN_INFO "capidrv-%d: %s from controller 0x%x ignored\n",
 862               card->contrnr,
 863               capi_cmd2str(cmsg->Command, cmsg->Subcommand),
 864               cmsg->adr.adrController);
 865}
 866
 867static void handle_incoming_call(capidrv_contr *card, _cmsg *cmsg)
 868{
 869        capidrv_plci *plcip;
 870        capidrv_bchan *bchan;
 871        isdn_ctrl cmd;
 872        int chan;
 873
 874        if ((chan = new_bchan(card)) == -1) {
 875                printk(KERN_ERR "capidrv-%d: incoming call on not existing bchan ?\n", card->contrnr);
 876                return;
 877        }
 878        bchan = &card->bchans[chan];
 879        if ((plcip = new_plci(card, chan)) == NULL) {
 880                printk(KERN_ERR "capidrv-%d: incoming call: no memory, sorry.\n", card->contrnr);
 881                return;
 882        }
 883        bchan->incoming = 1;
 884        plcip->plci = cmsg->adr.adrPLCI;
 885        plci_change_state(card, plcip, EV_PLCI_CONNECT_IND);
 886
 887        cmd.command = ISDN_STAT_ICALL;
 888        cmd.driver = card->myid;
 889        cmd.arg = chan;
 890        memset(&cmd.parm.setup, 0, sizeof(cmd.parm.setup));
 891        strncpy(cmd.parm.setup.phone,
 892                cmsg->CallingPartyNumber + 3,
 893                cmsg->CallingPartyNumber[0] - 2);
 894        strncpy(cmd.parm.setup.eazmsn,
 895                cmsg->CalledPartyNumber + 2,
 896                cmsg->CalledPartyNumber[0] - 1);
 897        cmd.parm.setup.si1 = cip2si1(cmsg->CIPValue);
 898        cmd.parm.setup.si2 = cip2si2(cmsg->CIPValue);
 899        cmd.parm.setup.plan = cmsg->CallingPartyNumber[1];
 900        cmd.parm.setup.screen = cmsg->CallingPartyNumber[2];
 901
 902        printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s\n",
 903               card->contrnr,
 904               cmd.parm.setup.phone,
 905               cmd.parm.setup.si1,
 906               cmd.parm.setup.si2,
 907               cmd.parm.setup.eazmsn);
 908
 909        if (cmd.parm.setup.si1 == 1 && cmd.parm.setup.si2 != 0) {
 910                printk(KERN_INFO "capidrv-%d: patching si2=%d to 0 for VBOX\n",
 911                       card->contrnr,
 912                       cmd.parm.setup.si2);
 913                cmd.parm.setup.si2 = 0;
 914        }
 915
 916        switch (card->interface.statcallb(&cmd)) {
 917        case 0:
 918        case 3:
 919                /* No device matching this call.
 920                 * and isdn_common.c has send a HANGUP command
 921                 * which is ignored in state ST_PLCI_INCOMING,
 922                 * so we send RESP to ignore the call
 923                 */
 924                capi_cmsg_answer(cmsg);
 925                cmsg->Reject = 1;       /* ignore */
 926                plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
 927                send_message(card, cmsg);
 928                printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s ignored\n",
 929                       card->contrnr,
 930                       cmd.parm.setup.phone,
 931                       cmd.parm.setup.si1,
 932                       cmd.parm.setup.si2,
 933                       cmd.parm.setup.eazmsn);
 934                break;
 935        case 1:
 936                /* At least one device matching this call (RING on ttyI)
 937                 * HL-driver may send ALERTING on the D-channel in this
 938                 * case.
 939                 * really means: RING on ttyI or a net interface
 940                 * accepted this call already.
 941                 *
 942                 * If the call was accepted, state has already changed,
 943                 * and CONNECT_RESP already sent.
 944                 */
 945                if (plcip->state == ST_PLCI_INCOMING) {
 946                        printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s tty alerting\n",
 947                               card->contrnr,
 948                               cmd.parm.setup.phone,
 949                               cmd.parm.setup.si1,
 950                               cmd.parm.setup.si2,
 951                               cmd.parm.setup.eazmsn);
 952                        capi_fill_ALERT_REQ(cmsg,
 953                                            global.ap.applid,
 954                                            card->msgid++,
 955                                            plcip->plci,        /* adr */
 956                                            NULL,/* BChannelinformation */
 957                                            NULL,/* Keypadfacility */
 958                                            NULL,/* Useruserdata */
 959                                            NULL /* Facilitydataarray */
 960                                );
 961                        plcip->msgid = cmsg->Messagenumber;
 962                        send_message(card, cmsg);
 963                } else {
 964                        printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s on netdev\n",
 965                               card->contrnr,
 966                               cmd.parm.setup.phone,
 967                               cmd.parm.setup.si1,
 968                               cmd.parm.setup.si2,
 969                               cmd.parm.setup.eazmsn);
 970                }
 971                break;
 972
 973        case 2:         /* Call will be rejected. */
 974                capi_cmsg_answer(cmsg);
 975                cmsg->Reject = 2;       /* reject call, normal call clearing */
 976                plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
 977                send_message(card, cmsg);
 978                break;
 979
 980        default:
 981                /* An error happened. (Invalid parameters for example.) */
 982                capi_cmsg_answer(cmsg);
 983                cmsg->Reject = 8;       /* reject call,
 984                                           destination out of order */
 985                plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
 986                send_message(card, cmsg);
 987                break;
 988        }
 989        return;
 990}
 991
 992static void handle_plci(_cmsg *cmsg)
 993{
 994        capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f);
 995        capidrv_plci *plcip;
 996        isdn_ctrl cmd;
 997        _cdebbuf *cdb;
 998
 999        if (!card) {
1000                printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n",
1001                       capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1002                       cmsg->adr.adrController & 0x7f);
1003                return;
1004        }
1005        switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) {
1006
1007        case CAPI_DISCONNECT_IND:       /* plci */
1008                if (cmsg->Reason) {
1009                        printk(KERN_INFO "capidrv-%d: %s reason 0x%x (%s) for plci 0x%x\n",
1010                               card->contrnr,
1011                               capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1012                               cmsg->Reason, capi_info2str(cmsg->Reason), cmsg->adr.adrPLCI);
1013                }
1014                if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) {
1015                        capi_cmsg_answer(cmsg);
1016                        send_message(card, cmsg);
1017                        goto notfound;
1018                }
1019                card->bchans[plcip->chan].disconnecting = 1;
1020                plci_change_state(card, plcip, EV_PLCI_DISCONNECT_IND);
1021                capi_cmsg_answer(cmsg);
1022                plci_change_state(card, plcip, EV_PLCI_DISCONNECT_RESP);
1023                send_message(card, cmsg);
1024                break;
1025
1026        case CAPI_DISCONNECT_CONF:      /* plci */
1027                if (cmsg->Info) {
1028                        printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
1029                               card->contrnr,
1030                               capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1031                               cmsg->Info, capi_info2str(cmsg->Info),
1032                               cmsg->adr.adrPLCI);
1033                }
1034                if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
1035                        goto notfound;
1036
1037                card->bchans[plcip->chan].disconnecting = 1;
1038                break;
1039
1040        case CAPI_ALERT_CONF:   /* plci */
1041                if (cmsg->Info) {
1042                        printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
1043                               card->contrnr,
1044                               capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1045                               cmsg->Info, capi_info2str(cmsg->Info),
1046                               cmsg->adr.adrPLCI);
1047                }
1048                break;
1049
1050        case CAPI_CONNECT_IND:  /* plci */
1051                handle_incoming_call(card, cmsg);
1052                break;
1053
1054        case CAPI_CONNECT_CONF: /* plci */
1055                if (cmsg->Info) {
1056                        printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n",
1057                               card->contrnr,
1058                               capi_cmd2str(cmsg->Command, cmsg->Subcommand),
1059                               cmsg->Info, capi_info2str(cmsg->Info),
1060                               cmsg->adr.adrPLCI);
1061                }
1062                if (!(plcip = find_plci_by_msgid(card, cmsg->Messagenumber)))
1063                        goto notfound;
1064
1065                plcip->plci = cmsg->adr.adrPLCI;
1066                if (cmsg->Info) {
1067                        plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_ERROR);
1068                } else {
1069                        plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_OK);
1070                }
1071                break;
1072
1073        case CAPI_CONNECT_ACTIVE_IND:   /* plci */
1074
1075                if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI)))
1076                        goto notfound;
1077
1078                if (card->bchans[plcip->chan].incoming) {
1079                        capi_cmsg_answer(cmsg);
1080                        plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND);
1081                        send_message(card, cmsg);
1082                } else {
1083                        capidrv_ncci *nccip;
1084                        capi_cmsg_answer(cmsg);
1085                        send_message(card, cmsg);
1086
1087                        nccip = new_ncci(card, plcip, cmsg->adr.adrPLCI);
1088
1089                        if (!nccip) {
1090                                printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr);
1091                                break;  /* $$$$ */
1092                        }
1093                        capi_fill_CONNECT_B3_REQ(cmsg,
1094                                                 global.ap.applid,
1095                                                 card->msgid++,
1096                                                 plcip->plci,   /* adr */
1097                                                 NULL   /* NCPI */
1098                                );
1099                        nccip->msgid = cmsg->Messagenumber;
1100                        plci_change_state(card, plcip,
1101                                          EV_PLCI_CONNECT_ACTIVE_IND);
1102                        ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_REQ);
1103                        send_message(card, cmsg);
1104                        cmd.command = ISDN_STAT_DCONN;
1105                        cmd.driver = card->myid;
1106                        cmd.arg = plcip->chan;
1107                        card->interface.statcallb(&cmd);
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;
1161ignored:
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;
1167notfound:
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                ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_ACTIVE_IND);
1197                send_message(card, cmsg);
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                                ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_RESP);
1226                                send_message(card, cmsg);
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                ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_RESP);
1303                send_message(card, cmsg);
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;
1342ignored:
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;
1348notfound:
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                PUTBYTE_TO_STATUS(card, ' ');
1453                PUTBYTE_TO_STATUS(card, hex_asc_hi(*p));
1454                PUTBYTE_TO_STATUS(card, hex_asc_lo(*p));
1455        }
1456        PUTBYTE_TO_STATUS(card, '\n');
1457
1458        cmd.command = ISDN_STAT_STAVAIL;
1459        cmd.driver = card->myid;
1460        cmd.arg = len * 3 + 5;
1461        card->interface.statcallb(&cmd);
1462}
1463
1464/* ------------------------------------------------------------------- */
1465
1466static _cmsg cmdcmsg;
1467
1468static int capidrv_ioctl(isdn_ctrl *c, capidrv_contr *card)
1469{
1470        switch (c->arg) {
1471        case 1:
1472                debugmode = (int)(*((unsigned int *)c->parm.num));
1473                printk(KERN_DEBUG "capidrv-%d: debugmode=%d\n",
1474                       card->contrnr, debugmode);
1475                return 0;
1476        default:
1477                printk(KERN_DEBUG "capidrv-%d: capidrv_ioctl(%ld) called ??\n",
1478                       card->contrnr, c->arg);
1479                return -EINVAL;
1480        }
1481        return -EINVAL;
1482}
1483
1484/*
1485 * Handle leased lines (CAPI-Bundling)
1486 */
1487
1488struct internal_bchannelinfo {
1489        unsigned short channelalloc;
1490        unsigned short operation;
1491        unsigned char  cmask[31];
1492};
1493
1494static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep)
1495{
1496        unsigned long bmask = 0;
1497        int active = !0;
1498        char *s;
1499        int i;
1500
1501        if (strncmp(teln, "FV:", 3) != 0)
1502                return 1;
1503        s = teln + 3;
1504        while (*s && *s == ' ') s++;
1505        if (!*s) return -2;
1506        if (*s == 'p' || *s == 'P') {
1507                active = 0;
1508                s++;
1509        }
1510        if (*s == 'a' || *s == 'A') {
1511                active = !0;
1512                s++;
1513        }
1514        while (*s) {
1515                int digit1 = 0;
1516                int digit2 = 0;
1517                char *endp;
1518
1519                digit1 = simple_strtoul(s, &endp, 10);
1520                if (s == endp)
1521                        return -3;
1522                s = endp;
1523
1524                if (digit1 <= 0 || digit1 > 30) return -4;
1525                if (*s == 0 || *s == ',' || *s == ' ') {
1526                        bmask |= (1 << digit1);
1527                        digit1 = 0;
1528                        if (*s) s++;
1529                        continue;
1530                }
1531                if (*s != '-') return -5;
1532                s++;
1533
1534                digit2 = simple_strtoul(s, &endp, 10);
1535                if (s == endp)
1536                        return -3;
1537                s = endp;
1538
1539                if (digit2 <= 0 || digit2 > 30) return -4;
1540                if (*s == 0 || *s == ',' || *s == ' ') {
1541                        if (digit1 > digit2)
1542                                for (i = digit2; i <= digit1; i++)
1543                                        bmask |= (1 << i);
1544                        else
1545                                for (i = digit1; i <= digit2; i++)
1546                                        bmask |= (1 << i);
1547                        digit1 = digit2 = 0;
1548                        if (*s) s++;
1549                        continue;
1550                }
1551                return -6;
1552        }
1553        if (activep) *activep = active;
1554        if (bmaskp) *bmaskp = bmask;
1555        return 0;
1556}
1557
1558static int FVteln2capi20(char *teln, u8 AdditionalInfo[1 + 2 + 2 + 31])
1559{
1560        unsigned long bmask;
1561        int active;
1562        int rc, i;
1563
1564        rc = decodeFVteln(teln, &bmask, &active);
1565        if (rc) return rc;
1566        /* Length */
1567        AdditionalInfo[0] = 2 + 2 + 31;
1568        /* Channel: 3 => use channel allocation */
1569        AdditionalInfo[1] = 3; AdditionalInfo[2] = 0;
1570        /* Operation: 0 => DTE mode, 1 => DCE mode */
1571        if (active) {
1572                AdditionalInfo[3] = 0; AdditionalInfo[4] = 0;
1573        } else {
1574                AdditionalInfo[3] = 1; AdditionalInfo[4] = 0;
1575        }
1576        /* Channel mask array */
1577        AdditionalInfo[5] = 0; /* no D-Channel */
1578        for (i = 1; i <= 30; i++)
1579                AdditionalInfo[5 + i] = (bmask & (1 << i)) ? 0xff : 0;
1580        return 0;
1581}
1582
1583static int capidrv_command(isdn_ctrl *c, capidrv_contr *card)
1584{
1585        isdn_ctrl cmd;
1586        struct capidrv_bchan *bchan;
1587        struct capidrv_plci *plcip;
1588        u8 AdditionalInfo[1 + 2 + 2 + 31];
1589        int rc, isleasedline = 0;
1590
1591        if (c->command == ISDN_CMD_IOCTL)
1592                return capidrv_ioctl(c, card);
1593
1594        switch (c->command) {
1595        case ISDN_CMD_DIAL: {
1596                u8 calling[ISDN_MSNLEN + 3];
1597                u8 called[ISDN_MSNLEN + 2];
1598
1599                if (debugmode)
1600                        printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n",
1601                               card->contrnr,
1602                               c->arg,
1603                               c->parm.setup.phone,
1604                               c->parm.setup.si1,
1605                               c->parm.setup.si2,
1606                               c->parm.setup.eazmsn);
1607
1608                bchan = &card->bchans[c->arg % card->nbchan];
1609
1610                if (bchan->plcip) {
1611                        printk(KERN_ERR "capidrv-%d: dail ch=%ld,\"%s,%d,%d,%s\" in use (plci=0x%x)\n",
1612                               card->contrnr,
1613                               c->arg,
1614                               c->parm.setup.phone,
1615                               c->parm.setup.si1,
1616                               c->parm.setup.si2,
1617                               c->parm.setup.eazmsn,
1618                               bchan->plcip->plci);
1619                        return 0;
1620                }
1621                bchan->si1 = c->parm.setup.si1;
1622                bchan->si2 = c->parm.setup.si2;
1623
1624                strncpy(bchan->num, c->parm.setup.phone, sizeof(bchan->num));
1625                strncpy(bchan->mynum, c->parm.setup.eazmsn, sizeof(bchan->mynum));
1626                rc = FVteln2capi20(bchan->num, AdditionalInfo);
1627                isleasedline = (rc == 0);
1628                if (rc < 0)
1629                        printk(KERN_ERR "capidrv-%d: WARNING: invalid leased linedefinition \"%s\"\n", card->contrnr, bchan->num);
1630
1631                if (isleasedline) {
1632                        calling[0] = 0;
1633                        called[0] = 0;
1634                        if (debugmode)
1635                                printk(KERN_DEBUG "capidrv-%d: connecting leased line\n", card->contrnr);
1636                } else {
1637                        calling[0] = strlen(bchan->mynum) + 2;
1638                        calling[1] = 0;
1639                        calling[2] = 0x80;
1640                        strncpy(calling + 3, bchan->mynum, ISDN_MSNLEN);
1641                        called[0] = strlen(bchan->num) + 1;
1642                        called[1] = 0x80;
1643                        strncpy(called + 2, bchan->num, ISDN_MSNLEN);
1644                }
1645
1646                capi_fill_CONNECT_REQ(&cmdcmsg,
1647                                      global.ap.applid,
1648                                      card->msgid++,
1649                                      card->contrnr,    /* adr */
1650                                      si2cip(bchan->si1, bchan->si2),   /* cipvalue */
1651                                      called,   /* CalledPartyNumber */
1652                                      calling,  /* CallingPartyNumber */
1653                                      NULL,     /* CalledPartySubaddress */
1654                                      NULL,     /* CallingPartySubaddress */
1655                                      b1prot(bchan->l2, bchan->l3),     /* B1protocol */
1656                                      b2prot(bchan->l2, bchan->l3),     /* B2protocol */
1657                                      b3prot(bchan->l2, bchan->l3),     /* B3protocol */
1658                                      b1config(bchan->l2, bchan->l3),   /* B1configuration */
1659                                      NULL,     /* B2configuration */
1660                                      NULL,     /* B3configuration */
1661                                      NULL,     /* BC */
1662                                      NULL,     /* LLC */
1663                                      NULL,     /* HLC */
1664                                      /* BChannelinformation */
1665                                      isleasedline ? AdditionalInfo : NULL,
1666                                      NULL,     /* Keypadfacility */
1667                                      NULL,     /* Useruserdata */
1668                                      NULL      /* Facilitydataarray */
1669                        );
1670                if ((plcip = new_plci(card, (c->arg % card->nbchan))) == NULL) {
1671                        cmd.command = ISDN_STAT_DHUP;
1672                        cmd.driver = card->myid;
1673                        cmd.arg = (c->arg % card->nbchan);
1674                        card->interface.statcallb(&cmd);
1675                        return -1;
1676                }
1677                plcip->msgid = cmdcmsg.Messagenumber;
1678                plcip->leasedline = isleasedline;
1679                plci_change_state(card, plcip, EV_PLCI_CONNECT_REQ);
1680                send_message(card, &cmdcmsg);
1681                return 0;
1682        }
1683
1684        case ISDN_CMD_ACCEPTD:
1685
1686                bchan = &card->bchans[c->arg % card->nbchan];
1687                if (debugmode)
1688                        printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTD(ch=%ld) l2=%d l3=%d\n",
1689                               card->contrnr,
1690                               c->arg, bchan->l2, bchan->l3);
1691
1692                capi_fill_CONNECT_RESP(&cmdcmsg,
1693                                       global.ap.applid,
1694                                       card->msgid++,
1695                                       bchan->plcip->plci,      /* adr */
1696                                       0,       /* Reject */
1697                                       b1prot(bchan->l2, bchan->l3),    /* B1protocol */
1698                                       b2prot(bchan->l2, bchan->l3),    /* B2protocol */
1699                                       b3prot(bchan->l2, bchan->l3),    /* B3protocol */
1700                                       b1config(bchan->l2, bchan->l3),  /* B1configuration */
1701                                       NULL,    /* B2configuration */
1702                                       NULL,    /* B3configuration */
1703                                       NULL,    /* ConnectedNumber */
1704                                       NULL,    /* ConnectedSubaddress */
1705                                       NULL,    /* LLC */
1706                                       NULL,    /* BChannelinformation */
1707                                       NULL,    /* Keypadfacility */
1708                                       NULL,    /* Useruserdata */
1709                                       NULL     /* Facilitydataarray */
1710                        );
1711                capi_cmsg2message(&cmdcmsg, cmdcmsg.buf);
1712                plci_change_state(card, bchan->plcip, EV_PLCI_CONNECT_RESP);
1713                send_message(card, &cmdcmsg);
1714                return 0;
1715
1716        case ISDN_CMD_ACCEPTB:
1717                if (debugmode)
1718                        printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTB(ch=%ld)\n",
1719                               card->contrnr,
1720                               c->arg);
1721                return -ENOSYS;
1722
1723        case ISDN_CMD_HANGUP:
1724                if (debugmode)
1725                        printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_HANGUP(ch=%ld)\n",
1726                               card->contrnr,
1727                               c->arg);
1728                bchan = &card->bchans[c->arg % card->nbchan];
1729
1730                if (bchan->disconnecting) {
1731                        if (debugmode)
1732                                printk(KERN_DEBUG "capidrv-%d: chan %ld already disconnecting ...\n",
1733                                       card->contrnr,
1734                                       c->arg);
1735                        return 0;
1736                }
1737                if (bchan->nccip) {
1738                        bchan->disconnecting = 1;
1739                        capi_fill_DISCONNECT_B3_REQ(&cmdcmsg,
1740                                                    global.ap.applid,
1741                                                    card->msgid++,
1742                                                    bchan->nccip->ncci,
1743                                                    NULL        /* NCPI */
1744                                );
1745                        ncci_change_state(card, bchan->nccip, EV_NCCI_DISCONNECT_B3_REQ);
1746                        send_message(card, &cmdcmsg);
1747                        return 0;
1748                } else if (bchan->plcip) {
1749                        if (bchan->plcip->state == ST_PLCI_INCOMING) {
1750                                /*
1751                                 * just ignore, we a called from
1752                                 * isdn_status_callback(),
1753                                 * which will return 0 or 2, this is handled
1754                                 * by the CONNECT_IND handler
1755                                 */
1756                                bchan->disconnecting = 1;
1757                                return 0;
1758                        } else if (bchan->plcip->plci) {
1759                                bchan->disconnecting = 1;
1760                                capi_fill_DISCONNECT_REQ(&cmdcmsg,
1761                                                         global.ap.applid,
1762                                                         card->msgid++,
1763                                                         bchan->plcip->plci,
1764                                                         NULL,  /* BChannelinformation */
1765                                                         NULL,  /* Keypadfacility */
1766                                                         NULL,  /* Useruserdata */
1767                                                         NULL   /* Facilitydataarray */
1768                                        );
1769                                plci_change_state(card, bchan->plcip, EV_PLCI_DISCONNECT_REQ);
1770                                send_message(card, &cmdcmsg);
1771                                return 0;
1772                        } else {
1773                                printk(KERN_ERR "capidrv-%d: chan %ld disconnect request while waiting for CONNECT_CONF\n",
1774                                       card->contrnr,
1775                                       c->arg);
1776                                return -EINVAL;
1777                        }
1778                }
1779                printk(KERN_ERR "capidrv-%d: chan %ld disconnect request on free channel\n",
1780                       card->contrnr,
1781                       c->arg);
1782                return -EINVAL;
1783/* ready */
1784
1785        case ISDN_CMD_SETL2:
1786                if (debugmode)
1787                        printk(KERN_DEBUG "capidrv-%d: set L2 on chan %ld to %ld\n",
1788                               card->contrnr,
1789                               (c->arg & 0xff), (c->arg >> 8));
1790                bchan = &card->bchans[(c->arg & 0xff) % card->nbchan];
1791                bchan->l2 = (c->arg >> 8);
1792                return 0;
1793
1794        case ISDN_CMD_SETL3:
1795                if (debugmode)
1796                        printk(KERN_DEBUG "capidrv-%d: set L3 on chan %ld to %ld\n",
1797                               card->contrnr,
1798                               (c->arg & 0xff), (c->arg >> 8));
1799                bchan = &card->bchans[(c->arg & 0xff) % card->nbchan];
1800                bchan->l3 = (c->arg >> 8);
1801                return 0;
1802
1803        case ISDN_CMD_SETEAZ:
1804                if (debugmode)
1805                        printk(KERN_DEBUG "capidrv-%d: set EAZ \"%s\" on chan %ld\n",
1806                               card->contrnr,
1807                               c->parm.num, c->arg);
1808                bchan = &card->bchans[c->arg % card->nbchan];
1809                strncpy(bchan->msn, c->parm.num, ISDN_MSNLEN);
1810                return 0;
1811
1812        case ISDN_CMD_CLREAZ:
1813                if (debugmode)
1814                        printk(KERN_DEBUG "capidrv-%d: clearing EAZ on chan %ld\n",
1815                               card->contrnr, c->arg);
1816                bchan = &card->bchans[c->arg % card->nbchan];
1817                bchan->msn[0] = 0;
1818                return 0;
1819
1820        default:
1821                printk(KERN_ERR "capidrv-%d: ISDN_CMD_%d, Huh?\n",
1822                       card->contrnr, c->command);
1823                return -EINVAL;
1824        }
1825        return 0;
1826}
1827
1828static int if_command(isdn_ctrl *c)
1829{
1830        capidrv_contr *card = findcontrbydriverid(c->driver);
1831
1832        if (card)
1833                return capidrv_command(c, card);
1834
1835        printk(KERN_ERR
1836               "capidrv: if_command %d called with invalid driverId %d!\n",
1837               c->command, c->driver);
1838        return -ENODEV;
1839}
1840
1841static _cmsg sendcmsg;
1842
1843static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb)
1844{
1845        capidrv_contr *card = findcontrbydriverid(id);
1846        capidrv_bchan *bchan;
1847        capidrv_ncci *nccip;
1848        int len = skb->len;
1849        int msglen;
1850        u16 errcode;
1851        u16 datahandle;
1852        u32 data;
1853
1854        if (!card) {
1855                printk(KERN_ERR "capidrv: if_sendbuf called with invalid driverId %d!\n",
1856                       id);
1857                return 0;
1858        }
1859        if (debugmode > 4)
1860                printk(KERN_DEBUG "capidrv-%d: sendbuf len=%d skb=%p doack=%d\n",
1861                       card->contrnr, len, skb, doack);
1862        bchan = &card->bchans[channel % card->nbchan];
1863        nccip = bchan->nccip;
1864        if (!nccip || nccip->state != ST_NCCI_ACTIVE) {
1865                printk(KERN_ERR "capidrv-%d: if_sendbuf: %s:%d: chan not up!\n",
1866                       card->contrnr, card->name, channel);
1867                return 0;
1868        }
1869        datahandle = nccip->datahandle;
1870
1871        /*
1872         * Here we copy pointer skb->data into the 32-bit 'Data' field.
1873         * The 'Data' field is not used in practice in linux kernel
1874         * (neither in 32 or 64 bit), but should have some value,
1875         * since a CAPI message trace will display it.
1876         *
1877         * The correct value in the 32 bit case is the address of the
1878         * data, in 64 bit it makes no sense, we use 0 there.
1879         */
1880
1881#ifdef CONFIG_64BIT
1882        data = 0;
1883#else
1884        data = (unsigned long) skb->data;
1885#endif
1886
1887        capi_fill_DATA_B3_REQ(&sendcmsg, global.ap.applid, card->msgid++,
1888                              nccip->ncci,      /* adr */
1889                              data,             /* Data */
1890                              skb->len,         /* DataLength */
1891                              datahandle,       /* DataHandle */
1892                              0 /* Flags */
1893                );
1894
1895        if (capidrv_add_ack(nccip, datahandle, doack ? (int)skb->len : -1) < 0)
1896                return 0;
1897
1898        capi_cmsg2message(&sendcmsg, sendcmsg.buf);
1899        msglen = CAPIMSG_LEN(sendcmsg.buf);
1900        if (skb_headroom(skb) < msglen) {
1901                struct sk_buff *nskb = skb_realloc_headroom(skb, msglen);
1902                if (!nskb) {
1903                        printk(KERN_ERR "capidrv-%d: if_sendbuf: no memory\n",
1904                               card->contrnr);
1905                        (void)capidrv_del_ack(nccip, datahandle);
1906                        return 0;
1907                }
1908                printk(KERN_DEBUG "capidrv-%d: only %d bytes headroom, need %d\n",
1909                       card->contrnr, skb_headroom(skb), msglen);
1910                memcpy(skb_push(nskb, msglen), sendcmsg.buf, msglen);
1911                errcode = capi20_put_message(&global.ap, nskb);
1912                if (errcode == CAPI_NOERROR) {
1913                        dev_kfree_skb(skb);
1914                        nccip->datahandle++;
1915                        return len;
1916                }
1917                if (debugmode > 3)
1918                        printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n",
1919                               card->contrnr, errcode, capi_info2str(errcode));
1920                (void)capidrv_del_ack(nccip, datahandle);
1921                dev_kfree_skb(nskb);
1922                return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
1923        } else {
1924                memcpy(skb_push(skb, msglen), sendcmsg.buf, msglen);
1925                errcode = capi20_put_message(&global.ap, skb);
1926                if (errcode == CAPI_NOERROR) {
1927                        nccip->datahandle++;
1928                        return len;
1929                }
1930                if (debugmode > 3)
1931                        printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n",
1932                               card->contrnr, errcode, capi_info2str(errcode));
1933                skb_pull(skb, msglen);
1934                (void)capidrv_del_ack(nccip, datahandle);
1935                return errcode == CAPI_SENDQUEUEFULL ? 0 : -1;
1936        }
1937}
1938
1939static int if_readstat(u8 __user *buf, int len, int id, int channel)
1940{
1941        capidrv_contr *card = findcontrbydriverid(id);
1942        int count;
1943        u8 __user *p;
1944
1945        if (!card) {
1946                printk(KERN_ERR "capidrv: if_readstat called with invalid driverId %d!\n",
1947                       id);
1948                return -ENODEV;
1949        }
1950
1951        for (p = buf, count = 0; count < len; p++, count++) {
1952                if (put_user(*card->q931_read++, p))
1953                        return -EFAULT;
1954                if (card->q931_read > card->q931_end)
1955                        card->q931_read = card->q931_buf;
1956        }
1957        return count;
1958
1959}
1960
1961static void enable_dchannel_trace(capidrv_contr *card)
1962{
1963        u8 manufacturer[CAPI_MANUFACTURER_LEN];
1964        capi_version version;
1965        u16 contr = card->contrnr;
1966        u16 errcode;
1967        u16 avmversion[3];
1968
1969        errcode = capi20_get_manufacturer(contr, manufacturer);
1970        if (errcode != CAPI_NOERROR) {
1971                printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n",
1972                       card->name, errcode);
1973                return;
1974        }
1975        if (strstr(manufacturer, "AVM") == NULL) {
1976                printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n",
1977                       card->name, manufacturer);
1978                return;
1979        }
1980        errcode = capi20_get_version(contr, &version);
1981        if (errcode != CAPI_NOERROR) {
1982                printk(KERN_ERR "%s: can't get version (0x%x)\n",
1983                       card->name, errcode);
1984                return;
1985        }
1986        avmversion[0] = (version.majormanuversion >> 4) & 0x0f;
1987        avmversion[1] = (version.majormanuversion << 4) & 0xf0;
1988        avmversion[1] |= (version.minormanuversion >> 4) & 0x0f;
1989        avmversion[2] |= version.minormanuversion & 0x0f;
1990
1991        if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) {
1992                printk(KERN_INFO "%s: D2 trace enabled\n", card->name);
1993                capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.ap.applid,
1994                                           card->msgid++,
1995                                           contr,
1996                                           0x214D5641,  /* ManuID */
1997                                           0,           /* Class */
1998                                           1,           /* Function */
1999                                           (_cstruct)"\004\200\014\000\000");
2000        } else {
2001                printk(KERN_INFO "%s: D3 trace enabled\n", card->name);
2002                capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.ap.applid,
2003                                           card->msgid++,
2004                                           contr,
2005                                           0x214D5641,  /* ManuID */
2006                                           0,           /* Class */
2007                                           1,           /* Function */
2008                                           (_cstruct)"\004\002\003\000\000");
2009        }
2010        send_message(card, &cmdcmsg);
2011}
2012
2013
2014static void send_listen(capidrv_contr *card)
2015{
2016        capi_fill_LISTEN_REQ(&cmdcmsg, global.ap.applid,
2017                             card->msgid++,
2018                             card->contrnr, /* controller */
2019                             1 << 6,    /* Infomask */
2020                             card->cipmask,
2021                             card->cipmask2,
2022                             NULL, NULL);
2023        listen_change_state(card, EV_LISTEN_REQ);
2024        send_message(card, &cmdcmsg);
2025}
2026
2027static void listentimerfunc(unsigned long x)
2028{
2029        capidrv_contr *card = (capidrv_contr *)x;
2030        if (card->state != ST_LISTEN_NONE && card->state != ST_LISTEN_ACTIVE)
2031                printk(KERN_ERR "%s: controller dead ??\n", card->name);
2032        send_listen(card);
2033        mod_timer(&card->listentimer, jiffies + 60 * HZ);
2034}
2035
2036
2037static int capidrv_addcontr(u16 contr, struct capi_profile *profp)
2038{
2039        capidrv_contr *card;
2040        unsigned long flags;
2041        isdn_ctrl cmd;
2042        char id[20];
2043        int i;
2044
2045        sprintf(id, "capidrv-%d", contr);
2046        if (!try_module_get(THIS_MODULE)) {
2047                printk(KERN_WARNING "capidrv: (%s) Could not reserve module\n", id);
2048                return -1;
2049        }
2050        if (!(card = kzalloc(sizeof(capidrv_contr), GFP_ATOMIC))) {
2051                printk(KERN_WARNING
2052                       "capidrv: (%s) Could not allocate contr-struct.\n", id);
2053                return -1;
2054        }
2055        card->owner = THIS_MODULE;
2056        init_timer(&card->listentimer);
2057        strcpy(card->name, id);
2058        card->contrnr = contr;
2059        card->nbchan = profp->nbchannel;
2060        card->bchans = kmalloc(sizeof(capidrv_bchan) * card->nbchan, GFP_ATOMIC);
2061        if (!card->bchans) {
2062                printk(KERN_WARNING
2063                       "capidrv: (%s) Could not allocate bchan-structs.\n", id);
2064                module_put(card->owner);
2065                kfree(card);
2066                return -1;
2067        }
2068        card->interface.channels = profp->nbchannel;
2069        card->interface.maxbufsize = 2048;
2070        card->interface.command = if_command;
2071        card->interface.writebuf_skb = if_sendbuf;
2072        card->interface.writecmd = NULL;
2073        card->interface.readstat = if_readstat;
2074        card->interface.features =
2075                ISDN_FEATURE_L2_HDLC |
2076                ISDN_FEATURE_L2_TRANS |
2077                ISDN_FEATURE_L3_TRANS |
2078                ISDN_FEATURE_P_UNKNOWN |
2079                ISDN_FEATURE_L2_X75I |
2080                ISDN_FEATURE_L2_X75UI |
2081                ISDN_FEATURE_L2_X75BUI;
2082        if (profp->support1 & (1 << 2))
2083                card->interface.features |=
2084                        ISDN_FEATURE_L2_V11096 |
2085                        ISDN_FEATURE_L2_V11019 |
2086                        ISDN_FEATURE_L2_V11038;
2087        if (profp->support1 & (1 << 8))
2088                card->interface.features |= ISDN_FEATURE_L2_MODEM;
2089        card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */
2090        strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
2091
2092
2093        card->q931_read = card->q931_buf;
2094        card->q931_write = card->q931_buf;
2095        card->q931_end = card->q931_buf + sizeof(card->q931_buf) - 1;
2096
2097        if (!register_isdn(&card->interface)) {
2098                printk(KERN_ERR "capidrv: Unable to register contr %s\n", id);
2099                kfree(card->bchans);
2100                module_put(card->owner);
2101                kfree(card);
2102                return -1;
2103        }
2104        card->myid = card->interface.channels;
2105        memset(card->bchans, 0, sizeof(capidrv_bchan) * card->nbchan);
2106        for (i = 0; i < card->nbchan; i++) {
2107                card->bchans[i].contr = card;
2108        }
2109
2110        spin_lock_irqsave(&global_lock, flags);
2111        card->next = global.contr_list;
2112        global.contr_list = card;
2113        global.ncontr++;
2114        spin_unlock_irqrestore(&global_lock, flags);
2115
2116        cmd.command = ISDN_STAT_RUN;
2117        cmd.driver = card->myid;
2118        card->interface.statcallb(&cmd);
2119
2120        card->cipmask = 0x1FFF03FF;     /* any */
2121        card->cipmask2 = 0;
2122
2123        card->listentimer.data = (unsigned long)card;
2124        card->listentimer.function = listentimerfunc;
2125        send_listen(card);
2126        mod_timer(&card->listentimer, jiffies + 60 * HZ);
2127
2128        printk(KERN_INFO "%s: now up (%d B channels)\n",
2129               card->name, card->nbchan);
2130
2131        enable_dchannel_trace(card);
2132
2133        return 0;
2134}
2135
2136static int capidrv_delcontr(u16 contr)
2137{
2138        capidrv_contr **pp, *card;
2139        unsigned long flags;
2140        isdn_ctrl cmd;
2141
2142        spin_lock_irqsave(&global_lock, flags);
2143        for (card = global.contr_list; card; card = card->next) {
2144                if (card->contrnr == contr)
2145                        break;
2146        }
2147        if (!card) {
2148                spin_unlock_irqrestore(&global_lock, flags);
2149                printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr);
2150                return -1;
2151        }
2152
2153        /* FIXME: maybe a race condition the card should be removed
2154         * here from global list /kkeil
2155         */
2156        spin_unlock_irqrestore(&global_lock, flags);
2157
2158        del_timer(&card->listentimer);
2159
2160        if (debugmode)
2161                printk(KERN_DEBUG "capidrv-%d: id=%d unloading\n",
2162                       card->contrnr, card->myid);
2163
2164        cmd.command = ISDN_STAT_STOP;
2165        cmd.driver = card->myid;
2166        card->interface.statcallb(&cmd);
2167
2168        while (card->nbchan) {
2169
2170                cmd.command = ISDN_STAT_DISCH;
2171                cmd.driver = card->myid;
2172                cmd.arg = card->nbchan - 1;
2173                cmd.parm.num[0] = 0;
2174                if (debugmode)
2175                        printk(KERN_DEBUG "capidrv-%d: id=%d disable chan=%ld\n",
2176                               card->contrnr, card->myid, cmd.arg);
2177                card->interface.statcallb(&cmd);
2178
2179                if (card->bchans[card->nbchan - 1].nccip)
2180                        free_ncci(card, card->bchans[card->nbchan - 1].nccip);
2181                if (card->bchans[card->nbchan - 1].plcip)
2182                        free_plci(card, card->bchans[card->nbchan - 1].plcip);
2183                if (card->plci_list)
2184                        printk(KERN_ERR "capidrv: bug in free_plci()\n");
2185                card->nbchan--;
2186        }
2187        kfree(card->bchans);
2188        card->bchans = NULL;
2189
2190        if (debugmode)
2191                printk(KERN_DEBUG "capidrv-%d: id=%d isdn unload\n",
2192                       card->contrnr, card->myid);
2193
2194        cmd.command = ISDN_STAT_UNLOAD;
2195        cmd.driver = card->myid;
2196        card->interface.statcallb(&cmd);
2197
2198        if (debugmode)
2199                printk(KERN_DEBUG "capidrv-%d: id=%d remove contr from list\n",
2200                       card->contrnr, card->myid);
2201
2202        spin_lock_irqsave(&global_lock, flags);
2203        for (pp = &global.contr_list; *pp; pp = &(*pp)->next) {
2204                if (*pp == card) {
2205                        *pp = (*pp)->next;
2206                        card->next = NULL;
2207                        global.ncontr--;
2208                        break;
2209                }
2210        }
2211        spin_unlock_irqrestore(&global_lock, flags);
2212
2213        module_put(card->owner);
2214        printk(KERN_INFO "%s: now down.\n", card->name);
2215        kfree(card);
2216        return 0;
2217}
2218
2219
2220static int
2221lower_callback(struct notifier_block *nb, unsigned long val, void *v)
2222{
2223        capi_profile profile;
2224        u32 contr = (long)v;
2225
2226        switch (val) {
2227        case CAPICTR_UP:
2228                printk(KERN_INFO "capidrv: controller %hu up\n", contr);
2229                if (capi20_get_profile(contr, &profile) == CAPI_NOERROR)
2230                        (void) capidrv_addcontr(contr, &profile);
2231                break;
2232        case CAPICTR_DOWN:
2233                printk(KERN_INFO "capidrv: controller %hu down\n", contr);
2234                (void) capidrv_delcontr(contr);
2235                break;
2236        }
2237        return NOTIFY_OK;
2238}
2239
2240/*
2241 * /proc/capi/capidrv:
2242 * nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
2243 */
2244static int capidrv_proc_show(struct seq_file *m, void *v)
2245{
2246        seq_printf(m, "%lu %lu %lu %lu\n",
2247                   global.ap.nrecvctlpkt,
2248                   global.ap.nrecvdatapkt,
2249                   global.ap.nsentctlpkt,
2250                   global.ap.nsentdatapkt);
2251        return 0;
2252}
2253
2254static int capidrv_proc_open(struct inode *inode, struct file *file)
2255{
2256        return single_open(file, capidrv_proc_show, NULL);
2257}
2258
2259static const struct file_operations capidrv_proc_fops = {
2260        .owner          = THIS_MODULE,
2261        .open           = capidrv_proc_open,
2262        .read           = seq_read,
2263        .llseek         = seq_lseek,
2264        .release        = single_release,
2265};
2266
2267static void __init proc_init(void)
2268{
2269        proc_create("capi/capidrv", 0, NULL, &capidrv_proc_fops);
2270}
2271
2272static void __exit proc_exit(void)
2273{
2274        remove_proc_entry("capi/capidrv", NULL);
2275}
2276
2277static struct notifier_block capictr_nb = {
2278        .notifier_call = lower_callback,
2279};
2280
2281static int __init capidrv_init(void)
2282{
2283        capi_profile profile;
2284        u32 ncontr, contr;
2285        u16 errcode;
2286
2287        global.ap.rparam.level3cnt = -2;  /* number of bchannels twice */
2288        global.ap.rparam.datablkcnt = 16;
2289        global.ap.rparam.datablklen = 2048;
2290
2291        global.ap.recv_message = capidrv_recv_message;
2292        errcode = capi20_register(&global.ap);
2293        if (errcode) {
2294                return -EIO;
2295        }
2296
2297        register_capictr_notifier(&capictr_nb);
2298
2299        errcode = capi20_get_profile(0, &profile);
2300        if (errcode != CAPI_NOERROR) {
2301                unregister_capictr_notifier(&capictr_nb);
2302                capi20_release(&global.ap);
2303                return -EIO;
2304        }
2305
2306        ncontr = profile.ncontroller;
2307        for (contr = 1; contr <= ncontr; contr++) {
2308                errcode = capi20_get_profile(contr, &profile);
2309                if (errcode != CAPI_NOERROR)
2310                        continue;
2311                (void) capidrv_addcontr(contr, &profile);
2312        }
2313        proc_init();
2314
2315        return 0;
2316}
2317
2318static void __exit capidrv_exit(void)
2319{
2320        unregister_capictr_notifier(&capictr_nb);
2321        capi20_release(&global.ap);
2322
2323        proc_exit();
2324}
2325
2326module_init(capidrv_init);
2327module_exit(capidrv_exit);
2328