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