linux/drivers/isdn/gigaset/i4l.c
<<
>>
Prefs
   1/*
   2 * Stuff used by all variants of the driver
   3 *
   4 * Copyright (c) 2001 by Stefan Eilers,
   5 *                       Hansjoerg Lipp <hjlipp@web.de>,
   6 *                       Tilman Schmidt <tilman@imap.cc>.
   7 *
   8 * =====================================================================
   9 *      This program is free software; you can redistribute it and/or
  10 *      modify it under the terms of the GNU General Public License as
  11 *      published by the Free Software Foundation; either version 2 of
  12 *      the License, or (at your option) any later version.
  13 * =====================================================================
  14 */
  15
  16#include "gigaset.h"
  17
  18/* == Handling of I4L IO =====================================================*/
  19
  20/* writebuf_from_LL
  21 * called by LL to transmit data on an open channel
  22 * inserts the buffer data into the send queue and starts the transmission
  23 * Note that this operation must not sleep!
  24 * When the buffer is processed completely, gigaset_skb_sent() should be called.
  25 * parameters:
  26 *      driverID        driver ID as assigned by LL
  27 *      channel         channel number
  28 *      ack             if != 0 LL wants to be notified on completion via
  29 *                      statcallb(ISDN_STAT_BSENT)
  30 *      skb             skb containing data to send
  31 * return value:
  32 *      number of accepted bytes
  33 *      0 if temporarily unable to accept data (out of buffer space)
  34 *      <0 on error (eg. -EINVAL)
  35 */
  36static int writebuf_from_LL(int driverID, int channel, int ack,
  37                            struct sk_buff *skb)
  38{
  39        struct cardstate *cs;
  40        struct bc_state *bcs;
  41        unsigned len;
  42        unsigned skblen;
  43
  44        if (!(cs = gigaset_get_cs_by_id(driverID))) {
  45                pr_err("%s: invalid driver ID (%d)\n", __func__, driverID);
  46                return -ENODEV;
  47        }
  48        if (channel < 0 || channel >= cs->channels) {
  49                dev_err(cs->dev, "%s: invalid channel ID (%d)\n",
  50                        __func__, channel);
  51                return -ENODEV;
  52        }
  53        bcs = &cs->bcs[channel];
  54
  55        /* can only handle linear sk_buffs */
  56        if (skb_linearize(skb) < 0) {
  57                dev_err(cs->dev, "%s: skb_linearize failed\n", __func__);
  58                return -ENOMEM;
  59        }
  60        len = skb->len;
  61
  62        gig_dbg(DEBUG_LLDATA,
  63                "Receiving data from LL (id: %d, ch: %d, ack: %d, sz: %d)",
  64                driverID, channel, ack, len);
  65
  66        if (!len) {
  67                if (ack)
  68                        dev_notice(cs->dev, "%s: not ACKing empty packet\n",
  69                                   __func__);
  70                return 0;
  71        }
  72        if (len > MAX_BUF_SIZE) {
  73                dev_err(cs->dev, "%s: packet too large (%d bytes)\n",
  74                        __func__, len);
  75                return -EINVAL;
  76        }
  77
  78        skblen = ack ? len : 0;
  79        skb->head[0] = skblen & 0xff;
  80        skb->head[1] = skblen >> 8;
  81        gig_dbg(DEBUG_MCMD, "skb: len=%u, skblen=%u: %02x %02x",
  82                len, skblen, (unsigned) skb->head[0], (unsigned) skb->head[1]);
  83
  84        /* pass to device-specific module */
  85        return cs->ops->send_skb(bcs, skb);
  86}
  87
  88/**
  89 * gigaset_skb_sent() - acknowledge sending an skb
  90 * @bcs:        B channel descriptor structure.
  91 * @skb:        sent data.
  92 *
  93 * Called by hardware module {bas,ser,usb}_gigaset when the data in a
  94 * skb has been successfully sent, for signalling completion to the LL.
  95 */
  96void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
  97{
  98        unsigned len;
  99        isdn_ctrl response;
 100
 101        ++bcs->trans_up;
 102
 103        if (skb->len)
 104                dev_warn(bcs->cs->dev, "%s: skb->len==%d\n",
 105                         __func__, skb->len);
 106
 107        len = (unsigned char) skb->head[0] |
 108              (unsigned) (unsigned char) skb->head[1] << 8;
 109        if (len) {
 110                gig_dbg(DEBUG_MCMD, "ACKing to LL (id: %d, ch: %d, sz: %u)",
 111                        bcs->cs->myid, bcs->channel, len);
 112
 113                response.driver = bcs->cs->myid;
 114                response.command = ISDN_STAT_BSENT;
 115                response.arg = bcs->channel;
 116                response.parm.length = len;
 117                bcs->cs->iif.statcallb(&response);
 118        }
 119}
 120EXPORT_SYMBOL_GPL(gigaset_skb_sent);
 121
 122/* This function will be called by LL to send commands
 123 * NOTE: LL ignores the returned value, for commands other than ISDN_CMD_IOCTL,
 124 * so don't put too much effort into it.
 125 */
 126static int command_from_LL(isdn_ctrl *cntrl)
 127{
 128        struct cardstate *cs = gigaset_get_cs_by_id(cntrl->driver);
 129        struct bc_state *bcs;
 130        int retval = 0;
 131        struct setup_parm *sp;
 132
 133        gigaset_debugdrivers();
 134
 135        if (!cs) {
 136                pr_err("%s: invalid driver ID (%d)\n", __func__, cntrl->driver);
 137                return -ENODEV;
 138        }
 139
 140        switch (cntrl->command) {
 141        case ISDN_CMD_IOCTL:
 142                gig_dbg(DEBUG_ANY, "ISDN_CMD_IOCTL (driver: %d, arg: %ld)",
 143                        cntrl->driver, cntrl->arg);
 144
 145                dev_warn(cs->dev, "ISDN_CMD_IOCTL not supported\n");
 146                return -EINVAL;
 147
 148        case ISDN_CMD_DIAL:
 149                gig_dbg(DEBUG_ANY,
 150                        "ISDN_CMD_DIAL (driver: %d, ch: %ld, "
 151                        "phone: %s, ownmsn: %s, si1: %d, si2: %d)",
 152                        cntrl->driver, cntrl->arg,
 153                        cntrl->parm.setup.phone, cntrl->parm.setup.eazmsn,
 154                        cntrl->parm.setup.si1, cntrl->parm.setup.si2);
 155
 156                if (cntrl->arg >= cs->channels) {
 157                        dev_err(cs->dev,
 158                                "ISDN_CMD_DIAL: invalid channel (%d)\n",
 159                                (int) cntrl->arg);
 160                        return -EINVAL;
 161                }
 162
 163                bcs = cs->bcs + cntrl->arg;
 164
 165                if (!gigaset_get_channel(bcs)) {
 166                        dev_err(cs->dev, "ISDN_CMD_DIAL: channel not free\n");
 167                        return -EBUSY;
 168                }
 169
 170                sp = kmalloc(sizeof *sp, GFP_ATOMIC);
 171                if (!sp) {
 172                        gigaset_free_channel(bcs);
 173                        dev_err(cs->dev, "ISDN_CMD_DIAL: out of memory\n");
 174                        return -ENOMEM;
 175                }
 176                *sp = cntrl->parm.setup;
 177
 178                if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, sp,
 179                                       bcs->at_state.seq_index, NULL)) {
 180                        //FIXME what should we do?
 181                        kfree(sp);
 182                        gigaset_free_channel(bcs);
 183                        return -ENOMEM;
 184                }
 185
 186                gig_dbg(DEBUG_CMD, "scheduling DIAL");
 187                gigaset_schedule_event(cs);
 188                break;
 189        case ISDN_CMD_ACCEPTD: //FIXME
 190                gig_dbg(DEBUG_ANY, "ISDN_CMD_ACCEPTD");
 191
 192                if (cntrl->arg >= cs->channels) {
 193                        dev_err(cs->dev,
 194                                "ISDN_CMD_ACCEPTD: invalid channel (%d)\n",
 195                                (int) cntrl->arg);
 196                        return -EINVAL;
 197                }
 198
 199                if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg].at_state,
 200                                       EV_ACCEPT, NULL, 0, NULL)) {
 201                        //FIXME what should we do?
 202                        return -ENOMEM;
 203                }
 204
 205                gig_dbg(DEBUG_CMD, "scheduling ACCEPT");
 206                gigaset_schedule_event(cs);
 207
 208                break;
 209        case ISDN_CMD_ACCEPTB:
 210                gig_dbg(DEBUG_ANY, "ISDN_CMD_ACCEPTB");
 211                break;
 212        case ISDN_CMD_HANGUP:
 213                gig_dbg(DEBUG_ANY, "ISDN_CMD_HANGUP (ch: %d)",
 214                        (int) cntrl->arg);
 215
 216                if (cntrl->arg >= cs->channels) {
 217                        dev_err(cs->dev,
 218                                "ISDN_CMD_HANGUP: invalid channel (%d)\n",
 219                                (int) cntrl->arg);
 220                        return -EINVAL;
 221                }
 222
 223                if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg].at_state,
 224                                       EV_HUP, NULL, 0, NULL)) {
 225                        //FIXME what should we do?
 226                        return -ENOMEM;
 227                }
 228
 229                gig_dbg(DEBUG_CMD, "scheduling HUP");
 230                gigaset_schedule_event(cs);
 231
 232                break;
 233        case ISDN_CMD_CLREAZ: /* Do not signal incoming signals */ //FIXME
 234                gig_dbg(DEBUG_ANY, "ISDN_CMD_CLREAZ");
 235                break;
 236        case ISDN_CMD_SETEAZ: /* Signal incoming calls for given MSN */ //FIXME
 237                gig_dbg(DEBUG_ANY,
 238                        "ISDN_CMD_SETEAZ (id: %d, ch: %ld, number: %s)",
 239                        cntrl->driver, cntrl->arg, cntrl->parm.num);
 240                break;
 241        case ISDN_CMD_SETL2: /* Set L2 to given protocol */
 242                gig_dbg(DEBUG_ANY, "ISDN_CMD_SETL2 (ch: %ld, proto: %lx)",
 243                        cntrl->arg & 0xff, (cntrl->arg >> 8));
 244
 245                if ((cntrl->arg & 0xff) >= cs->channels) {
 246                        dev_err(cs->dev,
 247                                "ISDN_CMD_SETL2: invalid channel (%d)\n",
 248                                (int) cntrl->arg & 0xff);
 249                        return -EINVAL;
 250                }
 251
 252                if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg & 0xff].at_state,
 253                                       EV_PROTO_L2, NULL, cntrl->arg >> 8,
 254                                       NULL)) {
 255                        //FIXME what should we do?
 256                        return -ENOMEM;
 257                }
 258
 259                gig_dbg(DEBUG_CMD, "scheduling PROTO_L2");
 260                gigaset_schedule_event(cs);
 261                break;
 262        case ISDN_CMD_SETL3: /* Set L3 to given protocol */
 263                gig_dbg(DEBUG_ANY, "ISDN_CMD_SETL3 (ch: %ld, proto: %lx)",
 264                        cntrl->arg & 0xff, (cntrl->arg >> 8));
 265
 266                if ((cntrl->arg & 0xff) >= cs->channels) {
 267                        dev_err(cs->dev,
 268                                "ISDN_CMD_SETL3: invalid channel (%d)\n",
 269                                (int) cntrl->arg & 0xff);
 270                        return -EINVAL;
 271                }
 272
 273                if (cntrl->arg >> 8 != ISDN_PROTO_L3_TRANS) {
 274                        dev_err(cs->dev,
 275                                "ISDN_CMD_SETL3: invalid protocol %lu\n",
 276                                cntrl->arg >> 8);
 277                        return -EINVAL;
 278                }
 279
 280                break;
 281        case ISDN_CMD_PROCEED:
 282                gig_dbg(DEBUG_ANY, "ISDN_CMD_PROCEED"); //FIXME
 283                break;
 284        case ISDN_CMD_ALERT:
 285                gig_dbg(DEBUG_ANY, "ISDN_CMD_ALERT"); //FIXME
 286                if (cntrl->arg >= cs->channels) {
 287                        dev_err(cs->dev,
 288                                "ISDN_CMD_ALERT: invalid channel (%d)\n",
 289                                (int) cntrl->arg);
 290                        return -EINVAL;
 291                }
 292                //bcs = cs->bcs + cntrl->arg;
 293                //bcs->proto2 = -1;
 294                // FIXME
 295                break;
 296        case ISDN_CMD_REDIR:
 297                gig_dbg(DEBUG_ANY, "ISDN_CMD_REDIR"); //FIXME
 298                break;
 299        case ISDN_CMD_PROT_IO:
 300                gig_dbg(DEBUG_ANY, "ISDN_CMD_PROT_IO");
 301                break;
 302        case ISDN_CMD_FAXCMD:
 303                gig_dbg(DEBUG_ANY, "ISDN_CMD_FAXCMD");
 304                break;
 305        case ISDN_CMD_GETL2:
 306                gig_dbg(DEBUG_ANY, "ISDN_CMD_GETL2");
 307                break;
 308        case ISDN_CMD_GETL3:
 309                gig_dbg(DEBUG_ANY, "ISDN_CMD_GETL3");
 310                break;
 311        case ISDN_CMD_GETEAZ:
 312                gig_dbg(DEBUG_ANY, "ISDN_CMD_GETEAZ");
 313                break;
 314        case ISDN_CMD_SETSIL:
 315                gig_dbg(DEBUG_ANY, "ISDN_CMD_SETSIL");
 316                break;
 317        case ISDN_CMD_GETSIL:
 318                gig_dbg(DEBUG_ANY, "ISDN_CMD_GETSIL");
 319                break;
 320        default:
 321                dev_err(cs->dev, "unknown command %d from LL\n",
 322                        cntrl->command);
 323                return -EINVAL;
 324        }
 325
 326        return retval;
 327}
 328
 329void gigaset_i4l_cmd(struct cardstate *cs, int cmd)
 330{
 331        isdn_ctrl command;
 332
 333        command.driver = cs->myid;
 334        command.command = cmd;
 335        command.arg = 0;
 336        cs->iif.statcallb(&command);
 337}
 338
 339void gigaset_i4l_channel_cmd(struct bc_state *bcs, int cmd)
 340{
 341        isdn_ctrl command;
 342
 343        command.driver = bcs->cs->myid;
 344        command.command = cmd;
 345        command.arg = bcs->channel;
 346        bcs->cs->iif.statcallb(&command);
 347}
 348
 349int gigaset_isdn_setup_dial(struct at_state_t *at_state, void *data)
 350{
 351        struct bc_state *bcs = at_state->bcs;
 352        unsigned proto;
 353        const char *bc;
 354        size_t length[AT_NUM];
 355        size_t l;
 356        int i;
 357        struct setup_parm *sp = data;
 358
 359        switch (bcs->proto2) {
 360        case ISDN_PROTO_L2_HDLC:
 361                proto = 1; /* 0: Bitsynchron, 1: HDLC, 2: voice */
 362                break;
 363        case ISDN_PROTO_L2_TRANS:
 364                proto = 2; /* 0: Bitsynchron, 1: HDLC, 2: voice */
 365                break;
 366        default:
 367                dev_err(bcs->cs->dev, "%s: invalid L2 protocol: %u\n",
 368                        __func__, bcs->proto2);
 369                return -EINVAL;
 370        }
 371
 372        switch (sp->si1) {
 373        case 1:         /* audio */
 374                bc = "9090A3";  /* 3.1 kHz audio, A-law */
 375                break;
 376        case 7:         /* data */
 377        default:        /* hope the app knows what it is doing */
 378                bc = "8890";    /* unrestricted digital information */
 379        }
 380        //FIXME add missing si1 values from 1TR6, inspect si2, set HLC/LLC
 381
 382        length[AT_DIAL ] = 1 + strlen(sp->phone) + 1 + 1;
 383        l = strlen(sp->eazmsn);
 384        length[AT_MSN  ] = l ? 6 + l + 1 + 1 : 0;
 385        length[AT_BC   ] = 5 + strlen(bc) + 1 + 1;
 386        length[AT_PROTO] = 6 + 1 + 1 + 1; /* proto: 1 character */
 387        length[AT_ISO  ] = 6 + 1 + 1 + 1; /* channel: 1 character */
 388        length[AT_TYPE ] = 6 + 1 + 1 + 1; /* call type: 1 character */
 389        length[AT_HLC  ] = 0;
 390
 391        for (i = 0; i < AT_NUM; ++i) {
 392                kfree(bcs->commands[i]);
 393                bcs->commands[i] = NULL;
 394                if (length[i] &&
 395                    !(bcs->commands[i] = kmalloc(length[i], GFP_ATOMIC))) {
 396                        dev_err(bcs->cs->dev, "out of memory\n");
 397                        return -ENOMEM;
 398                }
 399        }
 400
 401        /* type = 1: extern, 0: intern, 2: recall, 3: door, 4: centrex */
 402        if (sp->phone[0] == '*' && sp->phone[1] == '*') {
 403                /* internal call: translate ** prefix to CTP value */
 404                snprintf(bcs->commands[AT_DIAL], length[AT_DIAL],
 405                         "D%s\r", sp->phone+2);
 406                strncpy(bcs->commands[AT_TYPE], "^SCTP=0\r", length[AT_TYPE]);
 407        } else {
 408                snprintf(bcs->commands[AT_DIAL], length[AT_DIAL],
 409                         "D%s\r", sp->phone);
 410                strncpy(bcs->commands[AT_TYPE], "^SCTP=1\r", length[AT_TYPE]);
 411        }
 412
 413        if (bcs->commands[AT_MSN])
 414                snprintf(bcs->commands[AT_MSN], length[AT_MSN],
 415                         "^SMSN=%s\r", sp->eazmsn);
 416        snprintf(bcs->commands[AT_BC   ], length[AT_BC   ],
 417                 "^SBC=%s\r", bc);
 418        snprintf(bcs->commands[AT_PROTO], length[AT_PROTO],
 419                 "^SBPR=%u\r", proto);
 420        snprintf(bcs->commands[AT_ISO  ], length[AT_ISO  ],
 421                 "^SISO=%u\r", (unsigned)bcs->channel + 1);
 422
 423        return 0;
 424}
 425
 426int gigaset_isdn_setup_accept(struct at_state_t *at_state)
 427{
 428        unsigned proto;
 429        size_t length[AT_NUM];
 430        int i;
 431        struct bc_state *bcs = at_state->bcs;
 432
 433        switch (bcs->proto2) {
 434        case ISDN_PROTO_L2_HDLC:
 435                proto = 1; /* 0: Bitsynchron, 1: HDLC, 2: voice */
 436                break;
 437        case ISDN_PROTO_L2_TRANS:
 438                proto = 2; /* 0: Bitsynchron, 1: HDLC, 2: voice */
 439                break;
 440        default:
 441                dev_err(at_state->cs->dev, "%s: invalid protocol: %u\n",
 442                        __func__, bcs->proto2);
 443                return -EINVAL;
 444        }
 445
 446        length[AT_DIAL ] = 0;
 447        length[AT_MSN  ] = 0;
 448        length[AT_BC   ] = 0;
 449        length[AT_PROTO] = 6 + 1 + 1 + 1; /* proto: 1 character */
 450        length[AT_ISO  ] = 6 + 1 + 1 + 1; /* channel: 1 character */
 451        length[AT_TYPE ] = 0;
 452        length[AT_HLC  ] = 0;
 453
 454        for (i = 0; i < AT_NUM; ++i) {
 455                kfree(bcs->commands[i]);
 456                bcs->commands[i] = NULL;
 457                if (length[i] &&
 458                    !(bcs->commands[i] = kmalloc(length[i], GFP_ATOMIC))) {
 459                        dev_err(at_state->cs->dev, "out of memory\n");
 460                        return -ENOMEM;
 461                }
 462        }
 463
 464        snprintf(bcs->commands[AT_PROTO], length[AT_PROTO],
 465                 "^SBPR=%u\r", proto);
 466        snprintf(bcs->commands[AT_ISO  ], length[AT_ISO  ],
 467                 "^SISO=%u\r", (unsigned) bcs->channel + 1);
 468
 469        return 0;
 470}
 471
 472/**
 473 * gigaset_isdn_icall() - signal incoming call
 474 * @at_state:   connection state structure.
 475 *
 476 * Called by main module to notify the LL that an incoming call has been
 477 * received. @at_state contains the parameters of the call.
 478 *
 479 * Return value: call disposition (ICALL_*)
 480 */
 481int gigaset_isdn_icall(struct at_state_t *at_state)
 482{
 483        struct cardstate *cs = at_state->cs;
 484        struct bc_state *bcs = at_state->bcs;
 485        isdn_ctrl response;
 486        int retval;
 487
 488        /* fill ICALL structure */
 489        response.parm.setup.si1 = 0;    /* default: unknown */
 490        response.parm.setup.si2 = 0;
 491        response.parm.setup.screen = 0; //FIXME how to set these?
 492        response.parm.setup.plan = 0;
 493        if (!at_state->str_var[STR_ZBC]) {
 494                /* no BC (internal call): assume speech, A-law */
 495                response.parm.setup.si1 = 1;
 496        } else if (!strcmp(at_state->str_var[STR_ZBC], "8890")) {
 497                /* unrestricted digital information */
 498                response.parm.setup.si1 = 7;
 499        } else if (!strcmp(at_state->str_var[STR_ZBC], "8090A3")) {
 500                /* speech, A-law */
 501                response.parm.setup.si1 = 1;
 502        } else if (!strcmp(at_state->str_var[STR_ZBC], "9090A3")) {
 503                /* 3,1 kHz audio, A-law */
 504                response.parm.setup.si1 = 1;
 505                response.parm.setup.si2 = 2;
 506        } else {
 507                dev_warn(cs->dev, "RING ignored - unsupported BC %s\n",
 508                     at_state->str_var[STR_ZBC]);
 509                return ICALL_IGNORE;
 510        }
 511        if (at_state->str_var[STR_NMBR]) {
 512                strncpy(response.parm.setup.phone, at_state->str_var[STR_NMBR],
 513                        sizeof response.parm.setup.phone - 1);
 514                response.parm.setup.phone[sizeof response.parm.setup.phone - 1] = 0;
 515        } else
 516                response.parm.setup.phone[0] = 0;
 517        if (at_state->str_var[STR_ZCPN]) {
 518                strncpy(response.parm.setup.eazmsn, at_state->str_var[STR_ZCPN],
 519                        sizeof response.parm.setup.eazmsn - 1);
 520                response.parm.setup.eazmsn[sizeof response.parm.setup.eazmsn - 1] = 0;
 521        } else
 522                response.parm.setup.eazmsn[0] = 0;
 523
 524        if (!bcs) {
 525                dev_notice(cs->dev, "no channel for incoming call\n");
 526                response.command = ISDN_STAT_ICALLW;
 527                response.arg = 0; //FIXME
 528        } else {
 529                gig_dbg(DEBUG_CMD, "Sending ICALL");
 530                response.command = ISDN_STAT_ICALL;
 531                response.arg = bcs->channel; //FIXME
 532        }
 533        response.driver = cs->myid;
 534        retval = cs->iif.statcallb(&response);
 535        gig_dbg(DEBUG_CMD, "Response: %d", retval);
 536        switch (retval) {
 537        case 0: /* no takers */
 538                return ICALL_IGNORE;
 539        case 1: /* alerting */
 540                bcs->chstate |= CHS_NOTIFY_LL;
 541                return ICALL_ACCEPT;
 542        case 2: /* reject */
 543                return ICALL_REJECT;
 544        case 3: /* incomplete */
 545                dev_warn(cs->dev,
 546                       "LL requested unsupported feature: Incomplete Number\n");
 547                return ICALL_IGNORE;
 548        case 4: /* proceeding */
 549                /* Gigaset will send ALERTING anyway.
 550                 * There doesn't seem to be a way to avoid this.
 551                 */
 552                return ICALL_ACCEPT;
 553        case 5: /* deflect */
 554                dev_warn(cs->dev,
 555                         "LL requested unsupported feature: Call Deflection\n");
 556                return ICALL_IGNORE;
 557        default:
 558                dev_err(cs->dev, "LL error %d on ICALL\n", retval);
 559                return ICALL_IGNORE;
 560        }
 561}
 562
 563/* Set Callback function pointer */
 564int gigaset_register_to_LL(struct cardstate *cs, const char *isdnid)
 565{
 566        isdn_if *iif = &cs->iif;
 567
 568        gig_dbg(DEBUG_ANY, "Register driver capabilities to LL");
 569
 570        if (snprintf(iif->id, sizeof iif->id, "%s_%u", isdnid, cs->minor_index)
 571            >= sizeof iif->id) {
 572                pr_err("ID too long: %s\n", isdnid);
 573                return 0;
 574        }
 575
 576        iif->owner = THIS_MODULE;
 577        iif->channels = cs->channels;
 578        iif->maxbufsize = MAX_BUF_SIZE;
 579        iif->features = ISDN_FEATURE_L2_TRANS |
 580                ISDN_FEATURE_L2_HDLC |
 581#ifdef GIG_X75
 582                ISDN_FEATURE_L2_X75I |
 583#endif
 584                ISDN_FEATURE_L3_TRANS |
 585                ISDN_FEATURE_P_EURO;
 586        iif->hl_hdrlen = HW_HDR_LEN;            /* Area for storing ack */
 587        iif->command = command_from_LL;
 588        iif->writebuf_skb = writebuf_from_LL;
 589        iif->writecmd = NULL;                   /* Don't support isdnctrl */
 590        iif->readstat = NULL;                   /* Don't support isdnctrl */
 591        iif->rcvcallb_skb = NULL;               /* Will be set by LL */
 592        iif->statcallb = NULL;                  /* Will be set by LL */
 593
 594        if (!register_isdn(iif)) {
 595                pr_err("register_isdn failed\n");
 596                return 0;
 597        }
 598
 599        cs->myid = iif->channels;               /* Set my device id */
 600        return 1;
 601}
 602