linux/drivers/isdn/i4l/isdn_tty.c
<<
>>
Prefs
   1/* $Id: isdn_tty.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $
   2 *
   3 * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
   4 *
   5 * Copyright 1994-1999  by Fritz Elfert (fritz@isdn4linux.de)
   6 * Copyright 1995,96    by Thinking Objects Software GmbH Wuerzburg
   7 *
   8 * This software may be used and distributed according to the terms
   9 * of the GNU General Public License, incorporated herein by reference.
  10 *
  11 */
  12#undef ISDN_TTY_STAT_DEBUG
  13
  14#include <linux/isdn.h>
  15#include <linux/delay.h>
  16#include <linux/smp_lock.h>
  17#include "isdn_common.h"
  18#include "isdn_tty.h"
  19#ifdef CONFIG_ISDN_AUDIO
  20#include "isdn_audio.h"
  21#define VBUF 0x3e0
  22#define VBUFX (VBUF/16)
  23#endif
  24
  25#define FIX_FILE_TRANSFER
  26#define DUMMY_HAYES_AT
  27
  28/* Prototypes */
  29
  30static int isdn_tty_edit_at(const char *, int, modem_info *);
  31static void isdn_tty_check_esc(const u_char *, u_char, int, int *, u_long *);
  32static void isdn_tty_modem_reset_regs(modem_info *, int);
  33static void isdn_tty_cmd_ATA(modem_info *);
  34static void isdn_tty_flush_buffer(struct tty_struct *);
  35static void isdn_tty_modem_result(int, modem_info *);
  36#ifdef CONFIG_ISDN_AUDIO
  37static int isdn_tty_countDLE(unsigned char *, int);
  38#endif
  39
  40/* Leave this unchanged unless you know what you do! */
  41#define MODEM_PARANOIA_CHECK
  42#define MODEM_DO_RESTART
  43
  44static int bit2si[8] =
  45{1, 5, 7, 7, 7, 7, 7, 7};
  46static int si2bit[8] =
  47{4, 1, 4, 4, 4, 4, 4, 4};
  48
  49char *isdn_tty_revision = "$Revision: 1.1.2.3 $";
  50
  51
  52/* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
  53 * to stuff incoming data directly into a tty's flip-buffer. This
  54 * is done to speed up tty-receiving if the receive-queue is empty.
  55 * This routine MUST be called with interrupts off.
  56 * Return:
  57 *  1 = Success
  58 *  0 = Failure, data has to be buffered and later processed by
  59 *      isdn_tty_readmodem().
  60 */
  61static int
  62isdn_tty_try_read(modem_info * info, struct sk_buff *skb)
  63{
  64        int c;
  65        int len;
  66        struct tty_struct *tty;
  67        char last;
  68
  69        if (info->online) {
  70                if ((tty = info->tty)) {
  71                        if (info->mcr & UART_MCR_RTS) {
  72                                len = skb->len
  73#ifdef CONFIG_ISDN_AUDIO
  74                                        + ISDN_AUDIO_SKB_DLECOUNT(skb)
  75#endif
  76                                        ;
  77
  78                                c = tty_buffer_request_room(tty, len);
  79                                if (c >= len) {
  80#ifdef CONFIG_ISDN_AUDIO
  81                                        if (ISDN_AUDIO_SKB_DLECOUNT(skb)) {
  82                                                int l = skb->len;
  83                                                unsigned char *dp = skb->data;
  84                                                while (--l) {
  85                                                        if (*dp == DLE)
  86                                                                tty_insert_flip_char(tty, DLE, 0);
  87                                                        tty_insert_flip_char(tty, *dp++, 0);
  88                                                }
  89                                                if (*dp == DLE)
  90                                                        tty_insert_flip_char(tty, DLE, 0);
  91                                                last = *dp;
  92                                        } else {
  93#endif
  94                                                if(len > 1)
  95                                                        tty_insert_flip_string(tty, skb->data, len - 1);
  96                                                last = skb->data[len - 1];
  97#ifdef CONFIG_ISDN_AUDIO
  98                                        }
  99#endif
 100                                        if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP)
 101                                                tty_insert_flip_char(tty, last, 0xFF);
 102                                        else
 103                                                tty_insert_flip_char(tty, last, TTY_NORMAL);
 104                                        tty_flip_buffer_push(tty);
 105                                        kfree_skb(skb);
 106                                        return 1;
 107                                }
 108                        }
 109                }
 110        }
 111        return 0;
 112}
 113
 114/* isdn_tty_readmodem() is called periodically from within timer-interrupt.
 115 * It tries getting received data from the receive queue an stuff it into
 116 * the tty's flip-buffer.
 117 */
 118void
 119isdn_tty_readmodem(void)
 120{
 121        int resched = 0;
 122        int midx;
 123        int i;
 124        int r;
 125        struct tty_struct *tty;
 126        modem_info *info;
 127
 128        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 129                if ((midx = dev->m_idx[i]) >= 0) {
 130                        info = &dev->mdm.info[midx];
 131                        if (info->online) {
 132                                r = 0;
 133#ifdef CONFIG_ISDN_AUDIO
 134                                isdn_audio_eval_dtmf(info);
 135                                if ((info->vonline & 1) && (info->emu.vpar[1]))
 136                                        isdn_audio_eval_silence(info);
 137#endif
 138                                if ((tty = info->tty)) {
 139                                        if (info->mcr & UART_MCR_RTS) {
 140                                                /* CISCO AsyncPPP Hack */
 141                                                if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
 142                                                        r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 0);
 143                                                else
 144                                                        r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 1);
 145                                                if (r)
 146                                                        tty_flip_buffer_push(tty);
 147                                        } else
 148                                                r = 1;
 149                                } else
 150                                        r = 1;
 151                                if (r) {
 152                                        info->rcvsched = 0;
 153                                        resched = 1;
 154                                } else
 155                                        info->rcvsched = 1;
 156                        }
 157                }
 158        }
 159        if (!resched)
 160                isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0);
 161}
 162
 163int
 164isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
 165{
 166        ulong flags;
 167        int midx;
 168#ifdef CONFIG_ISDN_AUDIO
 169        int ifmt;
 170#endif
 171        modem_info *info;
 172
 173        if ((midx = dev->m_idx[i]) < 0) {
 174                /* if midx is invalid, packet is not for tty */
 175                return 0;
 176        }
 177        info = &dev->mdm.info[midx];
 178#ifdef CONFIG_ISDN_AUDIO
 179        ifmt = 1;
 180        
 181        if ((info->vonline) && (!info->emu.vpar[4]))
 182                isdn_audio_calc_dtmf(info, skb->data, skb->len, ifmt);
 183        if ((info->vonline & 1) && (info->emu.vpar[1]))
 184                isdn_audio_calc_silence(info, skb->data, skb->len, ifmt);
 185#endif
 186        if ((info->online < 2)
 187#ifdef CONFIG_ISDN_AUDIO
 188            && (!(info->vonline & 1))
 189#endif
 190                ) {
 191                /* If Modem not listening, drop data */
 192                kfree_skb(skb);
 193                return 1;
 194        }
 195        if (info->emu.mdmreg[REG_T70] & BIT_T70) {
 196                if (info->emu.mdmreg[REG_T70] & BIT_T70_EXT) {
 197                        /* T.70 decoding: throw away the T.70 header (2 or 4 bytes)   */
 198                        if (skb->data[0] == 3) /* pure data packet -> 4 byte headers  */
 199                                skb_pull(skb, 4);
 200                        else
 201                                if (skb->data[0] == 1) /* keepalive packet -> 2 byte hdr  */
 202                                        skb_pull(skb, 2);
 203                } else
 204                        /* T.70 decoding: Simply throw away the T.70 header (4 bytes) */
 205                        if ((skb->data[0] == 1) && ((skb->data[1] == 0) || (skb->data[1] == 1)))
 206                                skb_pull(skb, 4);
 207        }
 208#ifdef CONFIG_ISDN_AUDIO
 209        ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
 210        ISDN_AUDIO_SKB_LOCK(skb) = 0;
 211        if (info->vonline & 1) {
 212                /* voice conversion/compression */
 213                switch (info->emu.vpar[3]) {
 214                        case 2:
 215                        case 3:
 216                        case 4:
 217                                /* adpcm
 218                                 * Since compressed data takes less
 219                                 * space, we can overwrite the buffer.
 220                                 */
 221                                skb_trim(skb, isdn_audio_xlaw2adpcm(info->adpcmr,
 222                                                                    ifmt,
 223                                                                    skb->data,
 224                                                                    skb->data,
 225                                                                    skb->len));
 226                                break;
 227                        case 5:
 228                                /* a-law */
 229                                if (!ifmt)
 230                                        isdn_audio_ulaw2alaw(skb->data, skb->len);
 231                                break;
 232                        case 6:
 233                                /* u-law */
 234                                if (ifmt)
 235                                        isdn_audio_alaw2ulaw(skb->data, skb->len);
 236                                break;
 237                }
 238                ISDN_AUDIO_SKB_DLECOUNT(skb) =
 239                        isdn_tty_countDLE(skb->data, skb->len);
 240        }
 241#ifdef CONFIG_ISDN_TTY_FAX
 242        else {
 243                if (info->faxonline & 2) {
 244                        isdn_tty_fax_bitorder(info, skb);
 245                        ISDN_AUDIO_SKB_DLECOUNT(skb) =
 246                                isdn_tty_countDLE(skb->data, skb->len);
 247                }
 248        }
 249#endif
 250#endif
 251        /* Try to deliver directly via tty-buf if queue is empty */
 252        spin_lock_irqsave(&info->readlock, flags);
 253        if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
 254                if (isdn_tty_try_read(info, skb)) {
 255                        spin_unlock_irqrestore(&info->readlock, flags);
 256                        return 1;
 257                }
 258        /* Direct deliver failed or queue wasn't empty.
 259         * Queue up for later dequeueing via timer-irq.
 260         */
 261        __skb_queue_tail(&dev->drv[di]->rpqueue[channel], skb);
 262        dev->drv[di]->rcvcount[channel] +=
 263                (skb->len
 264#ifdef CONFIG_ISDN_AUDIO
 265                 + ISDN_AUDIO_SKB_DLECOUNT(skb)
 266#endif
 267                        );
 268        spin_unlock_irqrestore(&info->readlock, flags);
 269        /* Schedule dequeuing */
 270        if ((dev->modempoll) && (info->rcvsched))
 271                isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
 272        return 1;
 273}
 274
 275static void
 276isdn_tty_cleanup_xmit(modem_info * info)
 277{
 278        skb_queue_purge(&info->xmit_queue);
 279#ifdef CONFIG_ISDN_AUDIO
 280        skb_queue_purge(&info->dtmf_queue);
 281#endif
 282}
 283
 284static void
 285isdn_tty_tint(modem_info * info)
 286{
 287        struct sk_buff *skb = skb_dequeue(&info->xmit_queue);
 288        int len, slen;
 289
 290        if (!skb)
 291                return;
 292        len = skb->len;
 293        if ((slen = isdn_writebuf_skb_stub(info->isdn_driver,
 294                                           info->isdn_channel, 1, skb)) == len) {
 295                struct tty_struct *tty = info->tty;
 296                info->send_outstanding++;
 297                info->msr &= ~UART_MSR_CTS;
 298                info->lsr &= ~UART_LSR_TEMT;
 299                tty_wakeup(tty);
 300                return;
 301        }
 302        if (slen < 0) {
 303                /* Error: no channel, already shutdown, or wrong parameter */
 304                dev_kfree_skb(skb);
 305                return;
 306        }
 307        skb_queue_head(&info->xmit_queue, skb);
 308}
 309
 310#ifdef CONFIG_ISDN_AUDIO
 311static int
 312isdn_tty_countDLE(unsigned char *buf, int len)
 313{
 314        int count = 0;
 315
 316        while (len--)
 317                if (*buf++ == DLE)
 318                        count++;
 319        return count;
 320}
 321
 322/* This routine is called from within isdn_tty_write() to perform
 323 * DLE-decoding when sending audio-data.
 324 */
 325static int
 326isdn_tty_handleDLEdown(modem_info * info, atemu * m, int len)
 327{
 328        unsigned char *p = &info->xmit_buf[info->xmit_count];
 329        int count = 0;
 330
 331        while (len > 0) {
 332                if (m->lastDLE) {
 333                        m->lastDLE = 0;
 334                        switch (*p) {
 335                                case DLE:
 336                                        /* Escape code */
 337                                        if (len > 1)
 338                                                memmove(p, p + 1, len - 1);
 339                                        p--;
 340                                        count++;
 341                                        break;
 342                                case ETX:
 343                                        /* End of data */
 344                                        info->vonline |= 4;
 345                                        return count;
 346                                case DC4:
 347                                        /* Abort RX */
 348                                        info->vonline &= ~1;
 349#ifdef ISDN_DEBUG_MODEM_VOICE
 350                                        printk(KERN_DEBUG
 351                                               "DLEdown: got DLE-DC4, send DLE-ETX on ttyI%d\n",
 352                                               info->line);
 353#endif
 354                                        isdn_tty_at_cout("\020\003", info);
 355                                        if (!info->vonline) {
 356#ifdef ISDN_DEBUG_MODEM_VOICE
 357                                                printk(KERN_DEBUG
 358                                                       "DLEdown: send VCON on ttyI%d\n",
 359                                                       info->line);
 360#endif
 361                                                isdn_tty_at_cout("\r\nVCON\r\n", info);
 362                                        }
 363                                        /* Fall through */
 364                                case 'q':
 365                                case 's':
 366                                        /* Silence */
 367                                        if (len > 1)
 368                                                memmove(p, p + 1, len - 1);
 369                                        p--;
 370                                        break;
 371                        }
 372                } else {
 373                        if (*p == DLE)
 374                                m->lastDLE = 1;
 375                        else
 376                                count++;
 377                }
 378                p++;
 379                len--;
 380        }
 381        if (len < 0) {
 382                printk(KERN_WARNING "isdn_tty: len<0 in DLEdown\n");
 383                return 0;
 384        }
 385        return count;
 386}
 387
 388/* This routine is called from within isdn_tty_write() when receiving
 389 * audio-data. It interrupts receiving, if an character other than
 390 * ^S or ^Q is sent.
 391 */
 392static int
 393isdn_tty_end_vrx(const char *buf, int c)
 394{
 395        char ch;
 396
 397        while (c--) {
 398                ch = *buf;
 399                if ((ch != 0x11) && (ch != 0x13))
 400                        return 1;
 401                buf++;
 402        }
 403        return 0;
 404}
 405
 406static int voice_cf[7] =
 407{0, 0, 4, 3, 2, 0, 0};
 408
 409#endif                          /* CONFIG_ISDN_AUDIO */
 410
 411/* isdn_tty_senddown() is called either directly from within isdn_tty_write()
 412 * or via timer-interrupt from within isdn_tty_modem_xmit(). It pulls
 413 * outgoing data from the tty's xmit-buffer, handles voice-decompression or
 414 * T.70 if necessary, and finally queues it up for sending via isdn_tty_tint.
 415 */
 416static void
 417isdn_tty_senddown(modem_info * info)
 418{
 419        int buflen;
 420        int skb_res;
 421#ifdef CONFIG_ISDN_AUDIO
 422        int audio_len;
 423#endif
 424        struct sk_buff *skb;
 425
 426#ifdef CONFIG_ISDN_AUDIO
 427        if (info->vonline & 4) {
 428                info->vonline &= ~6;
 429                if (!info->vonline) {
 430#ifdef ISDN_DEBUG_MODEM_VOICE
 431                        printk(KERN_DEBUG
 432                               "senddown: send VCON on ttyI%d\n",
 433                               info->line);
 434#endif
 435                        isdn_tty_at_cout("\r\nVCON\r\n", info);
 436                }
 437        }
 438#endif
 439        if (!(buflen = info->xmit_count))
 440                return;
 441        if ((info->emu.mdmreg[REG_CTS] & BIT_CTS) != 0)
 442                info->msr &= ~UART_MSR_CTS;
 443        info->lsr &= ~UART_LSR_TEMT;    
 444        /* info->xmit_count is modified here and in isdn_tty_write().
 445         * So we return here if isdn_tty_write() is in the
 446         * critical section.
 447         */
 448        atomic_inc(&info->xmit_lock);
 449        if (!(atomic_dec_and_test(&info->xmit_lock)))
 450                return;
 451        if (info->isdn_driver < 0) {
 452                info->xmit_count = 0;
 453                return;
 454        }
 455        skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4;
 456#ifdef CONFIG_ISDN_AUDIO
 457        if (info->vonline & 2)
 458                audio_len = buflen * voice_cf[info->emu.vpar[3]];
 459        else
 460                audio_len = 0;
 461        skb = dev_alloc_skb(skb_res + buflen + audio_len);
 462#else
 463        skb = dev_alloc_skb(skb_res + buflen);
 464#endif
 465        if (!skb) {
 466                printk(KERN_WARNING
 467                       "isdn_tty: Out of memory in ttyI%d senddown\n",
 468                       info->line);
 469                return;
 470        }
 471        skb_reserve(skb, skb_res);
 472        memcpy(skb_put(skb, buflen), info->xmit_buf, buflen);
 473        info->xmit_count = 0;
 474#ifdef CONFIG_ISDN_AUDIO
 475        if (info->vonline & 2) {
 476                /* For now, ifmt is fixed to 1 (alaw), since this
 477                 * is used with ISDN everywhere in the world, except
 478                 * US, Canada and Japan.
 479                 * Later, when US-ISDN protocols are implemented,
 480                 * this setting will depend on the D-channel protocol.
 481                 */
 482                int ifmt = 1;
 483
 484                /* voice conversion/decompression */
 485                switch (info->emu.vpar[3]) {
 486                        case 2:
 487                        case 3:
 488                        case 4:
 489                                /* adpcm, compatible to ZyXel 1496 modem
 490                                 * with ROM revision 6.01
 491                                 */
 492                                audio_len = isdn_audio_adpcm2xlaw(info->adpcms,
 493                                                                  ifmt,
 494                                                                  skb->data,
 495                                                    skb_put(skb, audio_len),
 496                                                                  buflen);
 497                                skb_pull(skb, buflen);
 498                                skb_trim(skb, audio_len);
 499                                break;
 500                        case 5:
 501                                /* a-law */
 502                                if (!ifmt)
 503                                        isdn_audio_alaw2ulaw(skb->data,
 504                                                             buflen);
 505                                break;
 506                        case 6:
 507                                /* u-law */
 508                                if (ifmt)
 509                                        isdn_audio_ulaw2alaw(skb->data,
 510                                                             buflen);
 511                                break;
 512                }
 513        }
 514#endif                          /* CONFIG_ISDN_AUDIO */
 515        if (info->emu.mdmreg[REG_T70] & BIT_T70) {
 516                /* Add T.70 simplified header */
 517                if (info->emu.mdmreg[REG_T70] & BIT_T70_EXT)
 518                        memcpy(skb_push(skb, 2), "\1\0", 2);
 519                else
 520                        memcpy(skb_push(skb, 4), "\1\0\1\0", 4);
 521        }
 522        skb_queue_tail(&info->xmit_queue, skb);
 523}
 524
 525/************************************************************
 526 *
 527 * Modem-functions
 528 *
 529 * mostly "stolen" from original Linux-serial.c and friends.
 530 *
 531 ************************************************************/
 532
 533/* The next routine is called once from within timer-interrupt
 534 * triggered within isdn_tty_modem_ncarrier(). It calls
 535 * isdn_tty_modem_result() to stuff a "NO CARRIER" Message
 536 * into the tty's buffer.
 537 */
 538static void
 539isdn_tty_modem_do_ncarrier(unsigned long data)
 540{
 541        modem_info *info = (modem_info *) data;
 542        isdn_tty_modem_result(RESULT_NO_CARRIER, info);
 543}
 544
 545/* Next routine is called, whenever the DTR-signal is raised.
 546 * It checks the ncarrier-flag, and triggers the above routine
 547 * when necessary. The ncarrier-flag is set, whenever DTR goes
 548 * low.
 549 */
 550static void
 551isdn_tty_modem_ncarrier(modem_info * info)
 552{
 553        if (info->ncarrier) {
 554                info->nc_timer.expires = jiffies + HZ;
 555                add_timer(&info->nc_timer);
 556        }
 557}
 558
 559/*
 560 * return the usage calculated by si and layer 2 protocol
 561 */
 562static int
 563isdn_calc_usage(int si, int l2)
 564{
 565        int usg = ISDN_USAGE_MODEM;
 566
 567#ifdef CONFIG_ISDN_AUDIO
 568        if (si == 1) {
 569                switch(l2) {
 570                        case ISDN_PROTO_L2_MODEM: 
 571                                usg = ISDN_USAGE_MODEM;
 572                                break;
 573#ifdef CONFIG_ISDN_TTY_FAX
 574                        case ISDN_PROTO_L2_FAX: 
 575                                usg = ISDN_USAGE_FAX;
 576                                break;
 577#endif
 578                        case ISDN_PROTO_L2_TRANS: 
 579                        default:
 580                                usg = ISDN_USAGE_VOICE;
 581                                break;
 582                }
 583        }
 584#endif
 585        return(usg);
 586}
 587
 588/* isdn_tty_dial() performs dialing of a tty an the necessary
 589 * setup of the lower levels before that.
 590 */
 591static void
 592isdn_tty_dial(char *n, modem_info * info, atemu * m)
 593{
 594        int usg = ISDN_USAGE_MODEM;
 595        int si = 7;
 596        int l2 = m->mdmreg[REG_L2PROT];
 597        u_long flags;
 598        isdn_ctrl cmd;
 599        int i;
 600        int j;
 601
 602        for (j = 7; j >= 0; j--)
 603                if (m->mdmreg[REG_SI1] & (1 << j)) {
 604                        si = bit2si[j];
 605                        break;
 606                }
 607        usg = isdn_calc_usage(si, l2);
 608#ifdef CONFIG_ISDN_AUDIO
 609        if ((si == 1) && 
 610                (l2 != ISDN_PROTO_L2_MODEM)
 611#ifdef CONFIG_ISDN_TTY_FAX
 612                && (l2 != ISDN_PROTO_L2_FAX)
 613#endif
 614                ) {
 615                l2 = ISDN_PROTO_L2_TRANS;
 616                usg = ISDN_USAGE_VOICE;
 617        }
 618#endif
 619        m->mdmreg[REG_SI1I] = si2bit[si];
 620        spin_lock_irqsave(&dev->lock, flags);
 621        i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
 622        if (i < 0) {
 623                spin_unlock_irqrestore(&dev->lock, flags);
 624                isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
 625        } else {
 626                info->isdn_driver = dev->drvmap[i];
 627                info->isdn_channel = dev->chanmap[i];
 628                info->drv_index = i;
 629                dev->m_idx[i] = info->line;
 630                dev->usage[i] |= ISDN_USAGE_OUTGOING;
 631                info->last_dir = 1;
 632                strcpy(info->last_num, n);
 633                isdn_info_update();
 634                spin_unlock_irqrestore(&dev->lock, flags);
 635                cmd.driver = info->isdn_driver;
 636                cmd.arg = info->isdn_channel;
 637                cmd.command = ISDN_CMD_CLREAZ;
 638                isdn_command(&cmd);
 639                strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
 640                cmd.driver = info->isdn_driver;
 641                cmd.command = ISDN_CMD_SETEAZ;
 642                isdn_command(&cmd);
 643                cmd.driver = info->isdn_driver;
 644                cmd.command = ISDN_CMD_SETL2;
 645                info->last_l2 = l2;
 646                cmd.arg = info->isdn_channel + (l2 << 8);
 647                isdn_command(&cmd);
 648                cmd.driver = info->isdn_driver;
 649                cmd.command = ISDN_CMD_SETL3;
 650                cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
 651#ifdef CONFIG_ISDN_TTY_FAX
 652                if (l2 == ISDN_PROTO_L2_FAX) {
 653                        cmd.parm.fax = info->fax;
 654                        info->fax->direction = ISDN_TTY_FAX_CONN_OUT;
 655                }
 656#endif
 657                isdn_command(&cmd);
 658                cmd.driver = info->isdn_driver;
 659                cmd.arg = info->isdn_channel;
 660                sprintf(cmd.parm.setup.phone, "%s", n);
 661                sprintf(cmd.parm.setup.eazmsn, "%s",
 662                        isdn_map_eaz2msn(m->msn, info->isdn_driver));
 663                cmd.parm.setup.si1 = si;
 664                cmd.parm.setup.si2 = m->mdmreg[REG_SI2];
 665                cmd.command = ISDN_CMD_DIAL;
 666                info->dialing = 1;
 667                info->emu.carrierwait = 0;
 668                strcpy(dev->num[i], n);
 669                isdn_info_update();
 670                isdn_command(&cmd);
 671                isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
 672        }
 673}
 674
 675/* isdn_tty_hangup() disassociates a tty from the real
 676 * ISDN-line (hangup). The usage-status is cleared
 677 * and some cleanup is done also.
 678 */
 679void
 680isdn_tty_modem_hup(modem_info * info, int local)
 681{
 682        isdn_ctrl cmd;
 683        int di, ch;
 684
 685        if (!info)
 686                return;
 687
 688        di = info->isdn_driver;
 689        ch = info->isdn_channel;
 690        if (di < 0 || ch < 0)
 691                return;
 692
 693        info->isdn_driver = -1;
 694        info->isdn_channel = -1;
 695
 696#ifdef ISDN_DEBUG_MODEM_HUP
 697        printk(KERN_DEBUG "Mhup ttyI%d\n", info->line);
 698#endif
 699        info->rcvsched = 0;
 700        isdn_tty_flush_buffer(info->tty);
 701        if (info->online) {
 702                info->last_lhup = local;
 703                info->online = 0;
 704                isdn_tty_modem_result(RESULT_NO_CARRIER, info);
 705        }
 706#ifdef CONFIG_ISDN_AUDIO
 707        info->vonline = 0;
 708#ifdef CONFIG_ISDN_TTY_FAX
 709        info->faxonline = 0;
 710        info->fax->phase = ISDN_FAX_PHASE_IDLE;
 711#endif
 712        info->emu.vpar[4] = 0;
 713        info->emu.vpar[5] = 8;
 714        kfree(info->dtmf_state);
 715        info->dtmf_state = NULL;
 716        kfree(info->silence_state);
 717        info->silence_state = NULL;
 718        kfree(info->adpcms);
 719        info->adpcms = NULL;
 720        kfree(info->adpcmr);
 721        info->adpcmr = NULL;
 722#endif
 723        if ((info->msr & UART_MSR_RI) &&
 724                (info->emu.mdmreg[REG_RUNG] & BIT_RUNG))
 725                isdn_tty_modem_result(RESULT_RUNG, info);
 726        info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
 727        info->lsr |= UART_LSR_TEMT;
 728
 729        if (local) {
 730                cmd.driver = di;
 731                cmd.command = ISDN_CMD_HANGUP;
 732                cmd.arg = ch;
 733                isdn_command(&cmd);
 734        }
 735
 736        isdn_all_eaz(di, ch);
 737        info->emu.mdmreg[REG_RINGCNT] = 0;
 738        isdn_free_channel(di, ch, 0);
 739
 740        if (info->drv_index >= 0) {
 741                dev->m_idx[info->drv_index] = -1;
 742                info->drv_index = -1;
 743        }
 744}
 745
 746/*
 747 * Begin of a CAPI like interface, currently used only for 
 748 * supplementary service (CAPI 2.0 part III)
 749 */
 750#include <linux/isdn/capicmd.h>
 751
 752int
 753isdn_tty_capi_facility(capi_msg *cm) {
 754        return(-1); /* dummy */
 755}
 756
 757/* isdn_tty_suspend() tries to suspend the current tty connection
 758 */
 759static void
 760isdn_tty_suspend(char *id, modem_info * info, atemu * m)
 761{
 762        isdn_ctrl cmd;
 763        
 764        int l;
 765
 766        if (!info)
 767                return;
 768
 769#ifdef ISDN_DEBUG_MODEM_SERVICES
 770        printk(KERN_DEBUG "Msusp ttyI%d\n", info->line);
 771#endif
 772        l = strlen(id);
 773        if ((info->isdn_driver >= 0)) {
 774                cmd.parm.cmsg.Length = l+18;
 775                cmd.parm.cmsg.Command = CAPI_FACILITY;
 776                cmd.parm.cmsg.Subcommand = CAPI_REQ;
 777                cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
 778                cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */
 779                cmd.parm.cmsg.para[1] = 0;
 780                cmd.parm.cmsg.para[2] = l + 3;
 781                cmd.parm.cmsg.para[3] = 4; /* 16 bit 0x0004 Suspend */
 782                cmd.parm.cmsg.para[4] = 0;
 783                cmd.parm.cmsg.para[5] = l;
 784                strncpy(&cmd.parm.cmsg.para[6], id, l);
 785                cmd.command = CAPI_PUT_MESSAGE;
 786                cmd.driver = info->isdn_driver;
 787                cmd.arg = info->isdn_channel;
 788                isdn_command(&cmd);
 789        }
 790}
 791
 792/* isdn_tty_resume() tries to resume a suspended call
 793 * setup of the lower levels before that. unfortunatly here is no
 794 * checking for compatibility of used protocols implemented by Q931
 795 * It does the same things like isdn_tty_dial, the last command
 796 * is different, may be we can merge it.
 797 */
 798
 799static void
 800isdn_tty_resume(char *id, modem_info * info, atemu * m)
 801{
 802        int usg = ISDN_USAGE_MODEM;
 803        int si = 7;
 804        int l2 = m->mdmreg[REG_L2PROT];
 805        isdn_ctrl cmd;
 806        ulong flags;
 807        int i;
 808        int j;
 809        int l;
 810
 811        l = strlen(id);
 812        for (j = 7; j >= 0; j--)
 813                if (m->mdmreg[REG_SI1] & (1 << j)) {
 814                        si = bit2si[j];
 815                        break;
 816                }
 817        usg = isdn_calc_usage(si, l2);
 818#ifdef CONFIG_ISDN_AUDIO
 819        if ((si == 1) && 
 820                (l2 != ISDN_PROTO_L2_MODEM)
 821#ifdef CONFIG_ISDN_TTY_FAX
 822                && (l2 != ISDN_PROTO_L2_FAX)
 823#endif
 824                ) {
 825                l2 = ISDN_PROTO_L2_TRANS;
 826                usg = ISDN_USAGE_VOICE;
 827        }
 828#endif
 829        m->mdmreg[REG_SI1I] = si2bit[si];
 830        spin_lock_irqsave(&dev->lock, flags);
 831        i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
 832        if (i < 0) {
 833                spin_unlock_irqrestore(&dev->lock, flags);
 834                isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
 835        } else {
 836                info->isdn_driver = dev->drvmap[i];
 837                info->isdn_channel = dev->chanmap[i];
 838                info->drv_index = i;
 839                dev->m_idx[i] = info->line;
 840                dev->usage[i] |= ISDN_USAGE_OUTGOING;
 841                info->last_dir = 1;
 842//              strcpy(info->last_num, n);
 843                isdn_info_update();
 844                spin_unlock_irqrestore(&dev->lock, flags);
 845                cmd.driver = info->isdn_driver;
 846                cmd.arg = info->isdn_channel;
 847                cmd.command = ISDN_CMD_CLREAZ;
 848                isdn_command(&cmd);
 849                strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
 850                cmd.driver = info->isdn_driver;
 851                cmd.command = ISDN_CMD_SETEAZ;
 852                isdn_command(&cmd);
 853                cmd.driver = info->isdn_driver;
 854                cmd.command = ISDN_CMD_SETL2;
 855                info->last_l2 = l2;
 856                cmd.arg = info->isdn_channel + (l2 << 8);
 857                isdn_command(&cmd);
 858                cmd.driver = info->isdn_driver;
 859                cmd.command = ISDN_CMD_SETL3;
 860                cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
 861                isdn_command(&cmd);
 862                cmd.driver = info->isdn_driver;
 863                cmd.arg = info->isdn_channel;
 864                cmd.parm.cmsg.Length = l+18;
 865                cmd.parm.cmsg.Command = CAPI_FACILITY;
 866                cmd.parm.cmsg.Subcommand = CAPI_REQ;
 867                cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
 868                cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */
 869                cmd.parm.cmsg.para[1] = 0;
 870                cmd.parm.cmsg.para[2] = l+3;
 871                cmd.parm.cmsg.para[3] = 5; /* 16 bit 0x0005 Resume */
 872                cmd.parm.cmsg.para[4] = 0;
 873                cmd.parm.cmsg.para[5] = l;
 874                strncpy(&cmd.parm.cmsg.para[6], id, l);
 875                cmd.command =CAPI_PUT_MESSAGE;
 876                info->dialing = 1;
 877//              strcpy(dev->num[i], n);
 878                isdn_info_update();
 879                isdn_command(&cmd);
 880                isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
 881        }
 882}
 883
 884/* isdn_tty_send_msg() sends a message to a HL driver
 885 * This is used for hybrid modem cards to send AT commands to it
 886 */
 887
 888static void
 889isdn_tty_send_msg(modem_info * info, atemu * m, char *msg)
 890{
 891        int usg = ISDN_USAGE_MODEM;
 892        int si = 7;
 893        int l2 = m->mdmreg[REG_L2PROT];
 894        isdn_ctrl cmd;
 895        ulong flags;
 896        int i;
 897        int j;
 898        int l;
 899
 900        l = strlen(msg);
 901        if (!l) {
 902                isdn_tty_modem_result(RESULT_ERROR, info);
 903                return;
 904        }
 905        for (j = 7; j >= 0; j--)
 906                if (m->mdmreg[REG_SI1] & (1 << j)) {
 907                        si = bit2si[j];
 908                        break;
 909                }
 910        usg = isdn_calc_usage(si, l2);
 911#ifdef CONFIG_ISDN_AUDIO
 912        if ((si == 1) && 
 913                (l2 != ISDN_PROTO_L2_MODEM)
 914#ifdef CONFIG_ISDN_TTY_FAX
 915                && (l2 != ISDN_PROTO_L2_FAX)
 916#endif
 917                ) {
 918                l2 = ISDN_PROTO_L2_TRANS;
 919                usg = ISDN_USAGE_VOICE;
 920        }
 921#endif
 922        m->mdmreg[REG_SI1I] = si2bit[si];
 923        spin_lock_irqsave(&dev->lock, flags);
 924        i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
 925        if (i < 0) {
 926                spin_unlock_irqrestore(&dev->lock, flags);
 927                isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
 928        } else {
 929                info->isdn_driver = dev->drvmap[i];
 930                info->isdn_channel = dev->chanmap[i];
 931                info->drv_index = i;
 932                dev->m_idx[i] = info->line;
 933                dev->usage[i] |= ISDN_USAGE_OUTGOING;
 934                info->last_dir = 1;
 935                isdn_info_update();
 936                spin_unlock_irqrestore(&dev->lock, flags);
 937                cmd.driver = info->isdn_driver;
 938                cmd.arg = info->isdn_channel;
 939                cmd.command = ISDN_CMD_CLREAZ;
 940                isdn_command(&cmd);
 941                strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
 942                cmd.driver = info->isdn_driver;
 943                cmd.command = ISDN_CMD_SETEAZ;
 944                isdn_command(&cmd);
 945                cmd.driver = info->isdn_driver;
 946                cmd.command = ISDN_CMD_SETL2;
 947                info->last_l2 = l2;
 948                cmd.arg = info->isdn_channel + (l2 << 8);
 949                isdn_command(&cmd);
 950                cmd.driver = info->isdn_driver;
 951                cmd.command = ISDN_CMD_SETL3;
 952                cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
 953                isdn_command(&cmd);
 954                cmd.driver = info->isdn_driver;
 955                cmd.arg = info->isdn_channel;
 956                cmd.parm.cmsg.Length = l+14;
 957                cmd.parm.cmsg.Command = CAPI_MANUFACTURER;
 958                cmd.parm.cmsg.Subcommand = CAPI_REQ;
 959                cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
 960                cmd.parm.cmsg.para[0] = l+1;
 961                strncpy(&cmd.parm.cmsg.para[1], msg, l);
 962                cmd.parm.cmsg.para[l+1] = 0xd;
 963                cmd.command =CAPI_PUT_MESSAGE;
 964/*              info->dialing = 1;
 965                strcpy(dev->num[i], n);
 966                isdn_info_update();
 967*/
 968                isdn_command(&cmd);
 969        }
 970}
 971
 972static inline int
 973isdn_tty_paranoia_check(modem_info *info, char *name, const char *routine)
 974{
 975#ifdef MODEM_PARANOIA_CHECK
 976        if (!info) {
 977                printk(KERN_WARNING "isdn_tty: null info_struct for %s in %s\n",
 978                        name, routine);
 979                return 1;
 980        }
 981        if (info->magic != ISDN_ASYNC_MAGIC) {
 982                printk(KERN_WARNING "isdn_tty: bad magic for modem struct %s in %s\n",
 983                       name, routine);
 984                return 1;
 985        }
 986#endif
 987        return 0;
 988}
 989
 990/*
 991 * This routine is called to set the UART divisor registers to match
 992 * the specified baud rate for a serial port.
 993 */
 994static void
 995isdn_tty_change_speed(modem_info * info)
 996{
 997        uint cflag,
 998         cval,
 999         fcr,
1000         quot;
1001        int i;
1002
1003        if (!info->tty || !info->tty->termios)
1004                return;
1005        cflag = info->tty->termios->c_cflag;
1006
1007        quot = i = cflag & CBAUD;
1008        if (i & CBAUDEX) {
1009                i &= ~CBAUDEX;
1010                if (i < 1 || i > 2)
1011                        info->tty->termios->c_cflag &= ~CBAUDEX;
1012                else
1013                        i += 15;
1014        }
1015        if (quot) {
1016                info->mcr |= UART_MCR_DTR;
1017                isdn_tty_modem_ncarrier(info);
1018        } else {
1019                info->mcr &= ~UART_MCR_DTR;
1020                if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
1021#ifdef ISDN_DEBUG_MODEM_HUP
1022                        printk(KERN_DEBUG "Mhup in changespeed\n");
1023#endif
1024                        if (info->online)
1025                                info->ncarrier = 1;
1026                        isdn_tty_modem_reset_regs(info, 0);
1027                        isdn_tty_modem_hup(info, 1);
1028                }
1029                return;
1030        }
1031        /* byte size and parity */
1032        cval = cflag & (CSIZE | CSTOPB);
1033        cval >>= 4;
1034        if (cflag & PARENB)
1035                cval |= UART_LCR_PARITY;
1036        if (!(cflag & PARODD))
1037                cval |= UART_LCR_EPAR;
1038        fcr = 0;
1039
1040        /* CTS flow control flag and modem status interrupts */
1041        if (cflag & CRTSCTS) {
1042                info->flags |= ISDN_ASYNC_CTS_FLOW;
1043        } else
1044                info->flags &= ~ISDN_ASYNC_CTS_FLOW;
1045        if (cflag & CLOCAL)
1046                info->flags &= ~ISDN_ASYNC_CHECK_CD;
1047        else {
1048                info->flags |= ISDN_ASYNC_CHECK_CD;
1049        }
1050}
1051
1052static int
1053isdn_tty_startup(modem_info * info)
1054{
1055        if (info->flags & ISDN_ASYNC_INITIALIZED)
1056                return 0;
1057        isdn_lock_drivers();
1058#ifdef ISDN_DEBUG_MODEM_OPEN
1059        printk(KERN_DEBUG "starting up ttyi%d ...\n", info->line);
1060#endif
1061        /*
1062         * Now, initialize the UART
1063         */
1064        info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
1065        if (info->tty)
1066                clear_bit(TTY_IO_ERROR, &info->tty->flags);
1067        /*
1068         * and set the speed of the serial port
1069         */
1070        isdn_tty_change_speed(info);
1071
1072        info->flags |= ISDN_ASYNC_INITIALIZED;
1073        info->msr |= (UART_MSR_DSR | UART_MSR_CTS);
1074        info->send_outstanding = 0;
1075        return 0;
1076}
1077
1078/*
1079 * This routine will shutdown a serial port; interrupts are disabled, and
1080 * DTR is dropped if the hangup on close termio flag is on.
1081 */
1082static void
1083isdn_tty_shutdown(modem_info * info)
1084{
1085        if (!(info->flags & ISDN_ASYNC_INITIALIZED))
1086                return;
1087#ifdef ISDN_DEBUG_MODEM_OPEN
1088        printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line);
1089#endif
1090        isdn_unlock_drivers();
1091        info->msr &= ~UART_MSR_RI;
1092        if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
1093                info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
1094                if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
1095                        isdn_tty_modem_reset_regs(info, 0);
1096#ifdef ISDN_DEBUG_MODEM_HUP
1097                        printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n");
1098#endif
1099                        isdn_tty_modem_hup(info, 1);
1100                }
1101        }
1102        if (info->tty)
1103                set_bit(TTY_IO_ERROR, &info->tty->flags);
1104
1105        info->flags &= ~ISDN_ASYNC_INITIALIZED;
1106}
1107
1108/* isdn_tty_write() is the main send-routine. It is called from the upper
1109 * levels within the kernel to perform sending data. Depending on the
1110 * online-flag it either directs output to the at-command-interpreter or
1111 * to the lower level. Additional tasks done here:
1112 *  - If online, check for escape-sequence (+++)
1113 *  - If sending audio-data, call isdn_tty_DLEdown() to parse DLE-codes.
1114 *  - If receiving audio-data, call isdn_tty_end_vrx() to abort if needed.
1115 *  - If dialing, abort dial.
1116 */
1117static int
1118isdn_tty_write(struct tty_struct *tty, const u_char * buf, int count)
1119{
1120        int c;
1121        int total = 0;
1122        modem_info *info = (modem_info *) tty->driver_data;
1123        atemu *m = &info->emu;
1124
1125        if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_write"))
1126                return 0;
1127        /* See isdn_tty_senddown() */
1128        atomic_inc(&info->xmit_lock);
1129        while (1) {
1130                c = count;
1131                if (c > info->xmit_size - info->xmit_count)
1132                        c = info->xmit_size - info->xmit_count;
1133                if (info->isdn_driver >= 0 && c > dev->drv[info->isdn_driver]->maxbufsize)
1134                        c = dev->drv[info->isdn_driver]->maxbufsize;
1135                if (c <= 0)
1136                        break;
1137                if ((info->online > 1)
1138#ifdef CONFIG_ISDN_AUDIO
1139                    || (info->vonline & 3)
1140#endif
1141                        ) {
1142#ifdef CONFIG_ISDN_AUDIO
1143                        if (!info->vonline)
1144#endif
1145                                isdn_tty_check_esc(buf, m->mdmreg[REG_ESC], c,
1146                                                   &(m->pluscount),
1147                                                   &(m->lastplus));
1148                        memcpy(&(info->xmit_buf[info->xmit_count]), buf, c);
1149#ifdef CONFIG_ISDN_AUDIO
1150                        if (info->vonline) {
1151                                int cc = isdn_tty_handleDLEdown(info, m, c);
1152                                if (info->vonline & 2) {
1153                                        if (!cc) {
1154                                                /* If DLE decoding results in zero-transmit, but
1155                                                 * c originally was non-zero, do a wakeup.
1156                                                 */
1157                                                tty_wakeup(tty);
1158                                                info->msr |= UART_MSR_CTS;
1159                                                info->lsr |= UART_LSR_TEMT;
1160                                        }
1161                                        info->xmit_count += cc;
1162                                }
1163                                if ((info->vonline & 3) == 1) {
1164                                        /* Do NOT handle Ctrl-Q or Ctrl-S
1165                                         * when in full-duplex audio mode.
1166                                         */
1167                                        if (isdn_tty_end_vrx(buf, c)) {
1168                                                info->vonline &= ~1;
1169#ifdef ISDN_DEBUG_MODEM_VOICE
1170                                                printk(KERN_DEBUG
1171                                                       "got !^Q/^S, send DLE-ETX,VCON on ttyI%d\n",
1172                                                       info->line);
1173#endif
1174                                                isdn_tty_at_cout("\020\003\r\nVCON\r\n", info);
1175                                        }
1176                                }
1177                        } else
1178                        if (TTY_IS_FCLASS1(info)) {
1179                                int cc = isdn_tty_handleDLEdown(info, m, c);
1180                                
1181                                if (info->vonline & 4) { /* ETX seen */
1182                                        isdn_ctrl c;
1183
1184                                        c.command = ISDN_CMD_FAXCMD;
1185                                        c.driver = info->isdn_driver;
1186                                        c.arg = info->isdn_channel;
1187                                        c.parm.aux.cmd = ISDN_FAX_CLASS1_CTRL;
1188                                        c.parm.aux.subcmd = ETX;
1189                                        isdn_command(&c);
1190                                }
1191                                info->vonline = 0;
1192#ifdef ISDN_DEBUG_MODEM_VOICE
1193                                printk(KERN_DEBUG "fax dle cc/c %d/%d\n", cc, c);
1194#endif
1195                                info->xmit_count += cc;
1196                        } else
1197#endif
1198                                info->xmit_count += c;
1199                } else {
1200                        info->msr |= UART_MSR_CTS;
1201                        info->lsr |= UART_LSR_TEMT;
1202                        if (info->dialing) {
1203                                info->dialing = 0;
1204#ifdef ISDN_DEBUG_MODEM_HUP
1205                                printk(KERN_DEBUG "Mhup in isdn_tty_write\n");
1206#endif
1207                                isdn_tty_modem_result(RESULT_NO_CARRIER, info);
1208                                isdn_tty_modem_hup(info, 1);
1209                        } else
1210                                c = isdn_tty_edit_at(buf, c, info);
1211                }
1212                buf += c;
1213                count -= c;
1214                total += c;
1215        }
1216        atomic_dec(&info->xmit_lock);
1217        if ((info->xmit_count) || !skb_queue_empty(&info->xmit_queue)) {
1218                if (m->mdmreg[REG_DXMT] & BIT_DXMT) {
1219                        isdn_tty_senddown(info);
1220                        isdn_tty_tint(info);
1221                }
1222                isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
1223        }
1224        return total;
1225}
1226
1227static int
1228isdn_tty_write_room(struct tty_struct *tty)
1229{
1230        modem_info *info = (modem_info *) tty->driver_data;
1231        int ret;
1232
1233        if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_write_room"))
1234                return 0;
1235        if (!info->online)
1236                return info->xmit_size;
1237        ret = info->xmit_size - info->xmit_count;
1238        return (ret < 0) ? 0 : ret;
1239}
1240
1241static int
1242isdn_tty_chars_in_buffer(struct tty_struct *tty)
1243{
1244        modem_info *info = (modem_info *) tty->driver_data;
1245
1246        if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_chars_in_buffer"))
1247                return 0;
1248        if (!info->online)
1249                return 0;
1250        return (info->xmit_count);
1251}
1252
1253static void
1254isdn_tty_flush_buffer(struct tty_struct *tty)
1255{
1256        modem_info *info;
1257
1258        if (!tty) {
1259                return;
1260        }
1261        info = (modem_info *) tty->driver_data;
1262        if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_buffer")) {
1263                return;
1264        }
1265        isdn_tty_cleanup_xmit(info);
1266        info->xmit_count = 0;
1267        tty_wakeup(tty);
1268}
1269
1270static void
1271isdn_tty_flush_chars(struct tty_struct *tty)
1272{
1273        modem_info *info = (modem_info *) tty->driver_data;
1274
1275        if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_chars"))
1276                return;
1277        if ((info->xmit_count) || !skb_queue_empty(&info->xmit_queue))
1278                isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
1279}
1280
1281/*
1282 * ------------------------------------------------------------
1283 * isdn_tty_throttle()
1284 *
1285 * This routine is called by the upper-layer tty layer to signal that
1286 * incoming characters should be throttled.
1287 * ------------------------------------------------------------
1288 */
1289static void
1290isdn_tty_throttle(struct tty_struct *tty)
1291{
1292        modem_info *info = (modem_info *) tty->driver_data;
1293
1294        if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_throttle"))
1295                return;
1296        if (I_IXOFF(tty))
1297                info->x_char = STOP_CHAR(tty);
1298        info->mcr &= ~UART_MCR_RTS;
1299}
1300
1301static void
1302isdn_tty_unthrottle(struct tty_struct *tty)
1303{
1304        modem_info *info = (modem_info *) tty->driver_data;
1305
1306        if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_unthrottle"))
1307                return;
1308        if (I_IXOFF(tty)) {
1309                if (info->x_char)
1310                        info->x_char = 0;
1311                else
1312                        info->x_char = START_CHAR(tty);
1313        }
1314        info->mcr |= UART_MCR_RTS;
1315}
1316
1317/*
1318 * ------------------------------------------------------------
1319 * isdn_tty_ioctl() and friends
1320 * ------------------------------------------------------------
1321 */
1322
1323/*
1324 * isdn_tty_get_lsr_info - get line status register info
1325 *
1326 * Purpose: Let user call ioctl() to get info when the UART physically
1327 *          is emptied.  On bus types like RS485, the transmitter must
1328 *          release the bus after transmitting. This must be done when
1329 *          the transmit shift register is empty, not be done when the
1330 *          transmit holding register is empty.  This functionality
1331 *          allows RS485 driver to be written in user space.
1332 */
1333static int
1334isdn_tty_get_lsr_info(modem_info * info, uint __user * value)
1335{
1336        u_char status;
1337        uint result;
1338
1339        status = info->lsr;
1340        result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
1341        return put_user(result, value);
1342}
1343
1344
1345static int
1346isdn_tty_tiocmget(struct tty_struct *tty, struct file *file)
1347{
1348        modem_info *info = (modem_info *) tty->driver_data;
1349        u_char control, status;
1350
1351        if (isdn_tty_paranoia_check(info, tty->name, __func__))
1352                return -ENODEV;
1353        if (tty->flags & (1 << TTY_IO_ERROR))
1354                return -EIO;
1355
1356        lock_kernel();
1357#ifdef ISDN_DEBUG_MODEM_IOCTL
1358        printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line);
1359#endif
1360
1361        control = info->mcr;
1362        status = info->msr;
1363        unlock_kernel();
1364        return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
1365            | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
1366            | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0)
1367            | ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
1368            | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
1369            | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
1370}
1371
1372static int
1373isdn_tty_tiocmset(struct tty_struct *tty, struct file *file,
1374                unsigned int set, unsigned int clear)
1375{
1376        modem_info *info = (modem_info *) tty->driver_data;
1377
1378        if (isdn_tty_paranoia_check(info, tty->name, __func__))
1379                return -ENODEV;
1380        if (tty->flags & (1 << TTY_IO_ERROR))
1381                return -EIO;
1382
1383#ifdef ISDN_DEBUG_MODEM_IOCTL
1384        printk(KERN_DEBUG "ttyI%d ioctl TIOCMxxx: %x %x\n", info->line, set, clear);
1385#endif
1386
1387        lock_kernel();
1388        if (set & TIOCM_RTS)
1389                info->mcr |= UART_MCR_RTS;
1390        if (set & TIOCM_DTR) {
1391                info->mcr |= UART_MCR_DTR;
1392                isdn_tty_modem_ncarrier(info);
1393        }
1394
1395        if (clear & TIOCM_RTS)
1396                info->mcr &= ~UART_MCR_RTS;
1397        if (clear & TIOCM_DTR) {
1398                info->mcr &= ~UART_MCR_DTR;
1399                if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
1400                        isdn_tty_modem_reset_regs(info, 0);
1401#ifdef ISDN_DEBUG_MODEM_HUP
1402                        printk(KERN_DEBUG "Mhup in TIOCMSET\n");
1403#endif
1404                        if (info->online)
1405                                info->ncarrier = 1;
1406                        isdn_tty_modem_hup(info, 1);
1407                }
1408        }
1409        unlock_kernel();
1410        return 0;
1411}
1412
1413static int
1414isdn_tty_ioctl(struct tty_struct *tty, struct file *file,
1415               uint cmd, ulong arg)
1416{
1417        modem_info *info = (modem_info *) tty->driver_data;
1418        int retval;
1419
1420        if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_ioctl"))
1421                return -ENODEV;
1422        if (tty->flags & (1 << TTY_IO_ERROR))
1423                return -EIO;
1424        switch (cmd) {
1425                case TCSBRK:   /* SVID version: non-zero arg --> no break */
1426#ifdef ISDN_DEBUG_MODEM_IOCTL
1427                        printk(KERN_DEBUG "ttyI%d ioctl TCSBRK\n", info->line);
1428#endif
1429                        retval = tty_check_change(tty);
1430                        if (retval)
1431                                return retval;
1432                        tty_wait_until_sent(tty, 0);
1433                        return 0;
1434                case TCSBRKP:  /* support for POSIX tcsendbreak() */
1435#ifdef ISDN_DEBUG_MODEM_IOCTL
1436                        printk(KERN_DEBUG "ttyI%d ioctl TCSBRKP\n", info->line);
1437#endif
1438                        retval = tty_check_change(tty);
1439                        if (retval)
1440                                return retval;
1441                        tty_wait_until_sent(tty, 0);
1442                        return 0;
1443                case TIOCSERGETLSR:     /* Get line status register */
1444#ifdef ISDN_DEBUG_MODEM_IOCTL
1445                        printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line);
1446#endif
1447                        return isdn_tty_get_lsr_info(info, (uint __user *) arg);
1448                default:
1449#ifdef ISDN_DEBUG_MODEM_IOCTL
1450                        printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on ttyi%d\n", cmd, info->line);
1451#endif
1452                        return -ENOIOCTLCMD;
1453        }
1454        return 0;
1455}
1456
1457static void
1458isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
1459{
1460        modem_info *info = (modem_info *) tty->driver_data;
1461
1462        if (!old_termios)
1463                isdn_tty_change_speed(info);
1464        else {
1465                if (tty->termios->c_cflag == old_termios->c_cflag &&
1466                    tty->termios->c_ispeed == old_termios->c_ispeed &&
1467                    tty->termios->c_ospeed == old_termios->c_ospeed)
1468                        return;
1469                isdn_tty_change_speed(info);
1470                if ((old_termios->c_cflag & CRTSCTS) &&
1471                    !(tty->termios->c_cflag & CRTSCTS))
1472                        tty->hw_stopped = 0;
1473        }
1474}
1475
1476/*
1477 * ------------------------------------------------------------
1478 * isdn_tty_open() and friends
1479 * ------------------------------------------------------------
1480 */
1481static int
1482isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info * info)
1483{
1484        DECLARE_WAITQUEUE(wait, NULL);
1485        int do_clocal = 0;
1486        int retval;
1487
1488        /*
1489         * If the device is in the middle of being closed, then block
1490         * until it's done, and then try again.
1491         */
1492        if (tty_hung_up_p(filp) ||
1493            (info->flags & ISDN_ASYNC_CLOSING)) {
1494                if (info->flags & ISDN_ASYNC_CLOSING)
1495                        interruptible_sleep_on(&info->close_wait);
1496#ifdef MODEM_DO_RESTART
1497                if (info->flags & ISDN_ASYNC_HUP_NOTIFY)
1498                        return -EAGAIN;
1499                else
1500                        return -ERESTARTSYS;
1501#else
1502                return -EAGAIN;
1503#endif
1504        }
1505        /*
1506         * If non-blocking mode is set, then make the check up front
1507         * and then exit.
1508         */
1509        if ((filp->f_flags & O_NONBLOCK) ||
1510            (tty->flags & (1 << TTY_IO_ERROR))) {
1511                if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
1512                        return -EBUSY;
1513                info->flags |= ISDN_ASYNC_NORMAL_ACTIVE;
1514                return 0;
1515        }
1516        if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) {
1517                if (info->normal_termios.c_cflag & CLOCAL)
1518                        do_clocal = 1;
1519        } else {
1520                if (tty->termios->c_cflag & CLOCAL)
1521                        do_clocal = 1;
1522        }
1523        /*
1524         * Block waiting for the carrier detect and the line to become
1525         * free (i.e., not in use by the callout).  While we are in
1526         * this loop, info->count is dropped by one, so that
1527         * isdn_tty_close() knows when to free things.  We restore it upon
1528         * exit, either normal or abnormal.
1529         */
1530        retval = 0;
1531        add_wait_queue(&info->open_wait, &wait);
1532#ifdef ISDN_DEBUG_MODEM_OPEN
1533        printk(KERN_DEBUG "isdn_tty_block_til_ready before block: ttyi%d, count = %d\n",
1534               info->line, info->count);
1535#endif
1536        if (!(tty_hung_up_p(filp)))
1537                info->count--;
1538        info->blocked_open++;
1539        while (1) {
1540                set_current_state(TASK_INTERRUPTIBLE);
1541                if (tty_hung_up_p(filp) ||
1542                    !(info->flags & ISDN_ASYNC_INITIALIZED)) {
1543#ifdef MODEM_DO_RESTART
1544                        if (info->flags & ISDN_ASYNC_HUP_NOTIFY)
1545                                retval = -EAGAIN;
1546                        else
1547                                retval = -ERESTARTSYS;
1548#else
1549                        retval = -EAGAIN;
1550#endif
1551                        break;
1552                }
1553                if (!(info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
1554                    !(info->flags & ISDN_ASYNC_CLOSING) &&
1555                    (do_clocal || (info->msr & UART_MSR_DCD))) {
1556                        break;
1557                }
1558                if (signal_pending(current)) {
1559                        retval = -ERESTARTSYS;
1560                        break;
1561                }
1562#ifdef ISDN_DEBUG_MODEM_OPEN
1563                printk(KERN_DEBUG "isdn_tty_block_til_ready blocking: ttyi%d, count = %d\n",
1564                       info->line, info->count);
1565#endif
1566                schedule();
1567        }
1568        current->state = TASK_RUNNING;
1569        remove_wait_queue(&info->open_wait, &wait);
1570        if (!tty_hung_up_p(filp))
1571                info->count++;
1572        info->blocked_open--;
1573#ifdef ISDN_DEBUG_MODEM_OPEN
1574        printk(KERN_DEBUG "isdn_tty_block_til_ready after blocking: ttyi%d, count = %d\n",
1575               info->line, info->count);
1576#endif
1577        if (retval)
1578                return retval;
1579        info->flags |= ISDN_ASYNC_NORMAL_ACTIVE;
1580        return 0;
1581}
1582
1583/*
1584 * This routine is called whenever a serial port is opened.  It
1585 * enables interrupts for a serial port, linking in its async structure into
1586 * the IRQ chain.   It also performs the serial-specific
1587 * initialization for the tty structure.
1588 */
1589static int
1590isdn_tty_open(struct tty_struct *tty, struct file *filp)
1591{
1592        modem_info *info;
1593        int retval, line;
1594
1595        line = tty->index;
1596        if (line < 0 || line >= ISDN_MAX_CHANNELS)
1597                return -ENODEV;
1598        info = &dev->mdm.info[line];
1599        if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open"))
1600                return -ENODEV;
1601        if (!try_module_get(info->owner)) {
1602                printk(KERN_WARNING "%s: cannot reserve module\n", __func__);
1603                return -ENODEV;
1604        }
1605#ifdef ISDN_DEBUG_MODEM_OPEN
1606        printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name, 
1607               info->count);
1608#endif
1609        info->count++;
1610        tty->driver_data = info;
1611        info->tty = tty;
1612        /*
1613         * Start up serial port
1614         */
1615        retval = isdn_tty_startup(info);
1616        if (retval) {
1617#ifdef ISDN_DEBUG_MODEM_OPEN
1618                printk(KERN_DEBUG "isdn_tty_open return after startup\n");
1619#endif
1620                module_put(info->owner);
1621                return retval;
1622        }
1623        retval = isdn_tty_block_til_ready(tty, filp, info);
1624        if (retval) {
1625#ifdef ISDN_DEBUG_MODEM_OPEN
1626                printk(KERN_DEBUG "isdn_tty_open return after isdn_tty_block_til_ready \n");
1627#endif
1628                module_put(info->owner);
1629                return retval;
1630        }
1631#ifdef ISDN_DEBUG_MODEM_OPEN
1632        printk(KERN_DEBUG "isdn_tty_open ttyi%d successful...\n", info->line);
1633#endif
1634        dev->modempoll++;
1635#ifdef ISDN_DEBUG_MODEM_OPEN
1636        printk(KERN_DEBUG "isdn_tty_open normal exit\n");
1637#endif
1638        return 0;
1639}
1640
1641static void
1642isdn_tty_close(struct tty_struct *tty, struct file *filp)
1643{
1644        modem_info *info = (modem_info *) tty->driver_data;
1645        ulong timeout;
1646
1647        if (!info || isdn_tty_paranoia_check(info, tty->name, "isdn_tty_close"))
1648                return;
1649        if (tty_hung_up_p(filp)) {
1650#ifdef ISDN_DEBUG_MODEM_OPEN
1651                printk(KERN_DEBUG "isdn_tty_close return after tty_hung_up_p\n");
1652#endif
1653                return;
1654        }
1655        if ((tty->count == 1) && (info->count != 1)) {
1656                /*
1657                 * Uh, oh.  tty->count is 1, which means that the tty
1658                 * structure will be freed.  Info->count should always
1659                 * be one in these conditions.  If it's greater than
1660                 * one, we've got real problems, since it means the
1661                 * serial port won't be shutdown.
1662                 */
1663                printk(KERN_ERR "isdn_tty_close: bad port count; tty->count is 1, "
1664                       "info->count is %d\n", info->count);
1665                info->count = 1;
1666        }
1667        if (--info->count < 0) {
1668                printk(KERN_ERR "isdn_tty_close: bad port count for ttyi%d: %d\n",
1669                       info->line, info->count);
1670                info->count = 0;
1671        }
1672        if (info->count) {
1673#ifdef ISDN_DEBUG_MODEM_OPEN
1674                printk(KERN_DEBUG "isdn_tty_close after info->count != 0\n");
1675#endif
1676                module_put(info->owner);
1677                return;
1678        }
1679        info->flags |= ISDN_ASYNC_CLOSING;
1680        /*
1681         * Save the termios structure, since this port may have
1682         * separate termios for callout and dialin.
1683         */
1684        if (info->flags & ISDN_ASYNC_NORMAL_ACTIVE)
1685                info->normal_termios = *tty->termios;
1686        if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
1687                info->callout_termios = *tty->termios;
1688
1689        tty->closing = 1;
1690        /*
1691         * At this point we stop accepting input.  To do this, we
1692         * disable the receive line status interrupts, and tell the
1693         * interrupt driver to stop checking the data ready bit in the
1694         * line status register.
1695         */
1696        if (info->flags & ISDN_ASYNC_INITIALIZED) {
1697                tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
1698                /*
1699                 * Before we drop DTR, make sure the UART transmitter
1700                 * has completely drained; this is especially
1701                 * important if there is a transmit FIFO!
1702                 */
1703                timeout = jiffies + HZ;
1704                while (!(info->lsr & UART_LSR_TEMT)) {
1705                        schedule_timeout_interruptible(20);
1706                        if (time_after(jiffies,timeout))
1707                                break;
1708                }
1709        }
1710        dev->modempoll--;
1711        isdn_tty_shutdown(info);
1712        isdn_tty_flush_buffer(tty);
1713        tty_ldisc_flush(tty);
1714        info->tty = NULL;
1715        info->ncarrier = 0;
1716        tty->closing = 0;
1717        module_put(info->owner);
1718        if (info->blocked_open) {
1719                msleep_interruptible(500);
1720                wake_up_interruptible(&info->open_wait);
1721        }
1722        info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CLOSING);
1723        wake_up_interruptible(&info->close_wait);
1724#ifdef ISDN_DEBUG_MODEM_OPEN
1725        printk(KERN_DEBUG "isdn_tty_close normal exit\n");
1726#endif
1727}
1728
1729/*
1730 * isdn_tty_hangup() --- called by tty_hangup() when a hangup is signaled.
1731 */
1732static void
1733isdn_tty_hangup(struct tty_struct *tty)
1734{
1735        modem_info *info = (modem_info *) tty->driver_data;
1736
1737        if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_hangup"))
1738                return;
1739        isdn_tty_shutdown(info);
1740        info->count = 0;
1741        info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE);
1742        info->tty = NULL;
1743        wake_up_interruptible(&info->open_wait);
1744}
1745
1746/* This routine initializes all emulator-data.
1747 */
1748static void
1749isdn_tty_reset_profile(atemu * m)
1750{
1751        m->profile[0] = 0;
1752        m->profile[1] = 0;
1753        m->profile[2] = 43;
1754        m->profile[3] = 13;
1755        m->profile[4] = 10;
1756        m->profile[5] = 8;
1757        m->profile[6] = 3;
1758        m->profile[7] = 60;
1759        m->profile[8] = 2;
1760        m->profile[9] = 6;
1761        m->profile[10] = 7;
1762        m->profile[11] = 70;
1763        m->profile[12] = 0x45;
1764        m->profile[13] = 4;
1765        m->profile[14] = ISDN_PROTO_L2_X75I;
1766        m->profile[15] = ISDN_PROTO_L3_TRANS;
1767        m->profile[16] = ISDN_SERIAL_XMIT_SIZE / 16;
1768        m->profile[17] = ISDN_MODEM_WINSIZE;
1769        m->profile[18] = 4;
1770        m->profile[19] = 0;
1771        m->profile[20] = 0;
1772        m->profile[23] = 0;
1773        m->pmsn[0] = '\0';
1774        m->plmsn[0] = '\0';
1775}
1776
1777#ifdef CONFIG_ISDN_AUDIO
1778static void
1779isdn_tty_modem_reset_vpar(atemu * m)
1780{
1781        m->vpar[0] = 2;         /* Voice-device            (2 = phone line) */
1782        m->vpar[1] = 0;         /* Silence detection level (0 = none      ) */
1783        m->vpar[2] = 70;        /* Silence interval        (7 sec.        ) */
1784        m->vpar[3] = 2;         /* Compression type        (1 = ADPCM-2   ) */
1785        m->vpar[4] = 0;         /* DTMF detection level    (0 = softcode  ) */
1786        m->vpar[5] = 8;         /* DTMF interval           (8 * 5 ms.     ) */
1787}
1788#endif
1789
1790#ifdef CONFIG_ISDN_TTY_FAX
1791static void
1792isdn_tty_modem_reset_faxpar(modem_info * info)
1793{
1794        T30_s *f = info->fax;
1795
1796        f->code = 0;
1797        f->phase = ISDN_FAX_PHASE_IDLE;
1798        f->direction = 0;
1799        f->resolution = 1;      /* fine */
1800        f->rate = 5;            /* 14400 bit/s */
1801        f->width = 0;
1802        f->length = 0;
1803        f->compression = 0;
1804        f->ecm = 0;
1805        f->binary = 0;
1806        f->scantime = 0;
1807        memset(&f->id[0], 32, FAXIDLEN - 1);
1808        f->id[FAXIDLEN - 1] = 0;
1809        f->badlin = 0;
1810        f->badmul = 0;
1811        f->bor = 0;
1812        f->nbc = 0;
1813        f->cq = 0;
1814        f->cr = 0;
1815        f->ctcrty = 0;
1816        f->minsp = 0;
1817        f->phcto = 30;
1818        f->rel = 0;
1819        memset(&f->pollid[0], 32, FAXIDLEN - 1);
1820        f->pollid[FAXIDLEN - 1] = 0;
1821}
1822#endif
1823
1824static void
1825isdn_tty_modem_reset_regs(modem_info * info, int force)
1826{
1827        atemu *m = &info->emu;
1828        if ((m->mdmreg[REG_DTRR] & BIT_DTRR) || force) {
1829                memcpy(m->mdmreg, m->profile, ISDN_MODEM_NUMREG);
1830                memcpy(m->msn, m->pmsn, ISDN_MSNLEN);
1831                memcpy(m->lmsn, m->plmsn, ISDN_LMSNLEN);
1832                info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
1833        }
1834#ifdef CONFIG_ISDN_AUDIO
1835        isdn_tty_modem_reset_vpar(m);
1836#endif
1837#ifdef CONFIG_ISDN_TTY_FAX
1838        isdn_tty_modem_reset_faxpar(info);
1839#endif
1840        m->mdmcmdl = 0;
1841}
1842
1843static void
1844modem_write_profile(atemu * m)
1845{
1846        memcpy(m->profile, m->mdmreg, ISDN_MODEM_NUMREG);
1847        memcpy(m->pmsn, m->msn, ISDN_MSNLEN);
1848        memcpy(m->plmsn, m->lmsn, ISDN_LMSNLEN);
1849        if (dev->profd)
1850                send_sig(SIGIO, dev->profd, 1);
1851}
1852
1853static const struct tty_operations modem_ops = {
1854        .open = isdn_tty_open,
1855        .close = isdn_tty_close,
1856        .write = isdn_tty_write,
1857        .flush_chars = isdn_tty_flush_chars,
1858        .write_room = isdn_tty_write_room,
1859        .chars_in_buffer = isdn_tty_chars_in_buffer,
1860        .flush_buffer = isdn_tty_flush_buffer,
1861        .ioctl = isdn_tty_ioctl,
1862        .throttle = isdn_tty_throttle,
1863        .unthrottle = isdn_tty_unthrottle,
1864        .set_termios = isdn_tty_set_termios,
1865        .hangup = isdn_tty_hangup,
1866        .tiocmget = isdn_tty_tiocmget,
1867        .tiocmset = isdn_tty_tiocmset,
1868};
1869
1870int
1871isdn_tty_modem_init(void)
1872{
1873        isdn_modem_t    *m;
1874        int             i, retval;
1875        modem_info      *info;
1876
1877        m = &dev->mdm;
1878        m->tty_modem = alloc_tty_driver(ISDN_MAX_CHANNELS);
1879        if (!m->tty_modem)
1880                return -ENOMEM;
1881        m->tty_modem->name = "ttyI";
1882        m->tty_modem->major = ISDN_TTY_MAJOR;
1883        m->tty_modem->minor_start = 0;
1884        m->tty_modem->type = TTY_DRIVER_TYPE_SERIAL;
1885        m->tty_modem->subtype = SERIAL_TYPE_NORMAL;
1886        m->tty_modem->init_termios = tty_std_termios;
1887        m->tty_modem->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
1888        m->tty_modem->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
1889        m->tty_modem->driver_name = "isdn_tty";
1890        tty_set_operations(m->tty_modem, &modem_ops);
1891        retval = tty_register_driver(m->tty_modem);
1892        if (retval) {
1893                printk(KERN_WARNING "isdn_tty: Couldn't register modem-device\n");
1894                goto err;
1895        }
1896        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
1897                info = &m->info[i];
1898#ifdef CONFIG_ISDN_TTY_FAX
1899                if (!(info->fax = kmalloc(sizeof(T30_s), GFP_KERNEL))) {
1900                        printk(KERN_ERR "Could not allocate fax t30-buffer\n");
1901                        retval = -ENOMEM;
1902                        goto err_unregister;
1903                }
1904#endif
1905#ifdef MODULE
1906                info->owner = THIS_MODULE;
1907#endif
1908                spin_lock_init(&info->readlock);
1909                sprintf(info->last_cause, "0000");
1910                sprintf(info->last_num, "none");
1911                info->last_dir = 0;
1912                info->last_lhup = 1;
1913                info->last_l2 = -1;
1914                info->last_si = 0;
1915                isdn_tty_reset_profile(&info->emu);
1916                isdn_tty_modem_reset_regs(info, 1);
1917                info->magic = ISDN_ASYNC_MAGIC;
1918                info->line = i;
1919                info->tty = NULL;
1920                info->x_char = 0;
1921                info->count = 0;
1922                info->blocked_open = 0;
1923                init_waitqueue_head(&info->open_wait);
1924                init_waitqueue_head(&info->close_wait);
1925                info->isdn_driver = -1;
1926                info->isdn_channel = -1;
1927                info->drv_index = -1;
1928                info->xmit_size = ISDN_SERIAL_XMIT_SIZE;
1929                init_timer(&info->nc_timer);
1930                info->nc_timer.function = isdn_tty_modem_do_ncarrier;
1931                info->nc_timer.data = (unsigned long) info;
1932                skb_queue_head_init(&info->xmit_queue);
1933#ifdef CONFIG_ISDN_AUDIO
1934                skb_queue_head_init(&info->dtmf_queue);
1935#endif
1936                if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5, GFP_KERNEL))) {
1937                        printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
1938                        retval = -ENOMEM;
1939                        goto err_unregister;
1940                }
1941                /* Make room for T.70 header */
1942                info->xmit_buf += 4;
1943        }
1944        return 0;
1945err_unregister:
1946        for (i--; i >= 0; i--) {
1947                info = &m->info[i];
1948#ifdef CONFIG_ISDN_TTY_FAX
1949                kfree(info->fax);
1950#endif
1951                kfree(info->xmit_buf - 4);
1952        }
1953        tty_unregister_driver(m->tty_modem);
1954 err:
1955        put_tty_driver(m->tty_modem);
1956        m->tty_modem = NULL;
1957        return retval;
1958}
1959
1960void
1961isdn_tty_exit(void)
1962{
1963        modem_info *info;
1964        int i;
1965
1966        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
1967                info = &dev->mdm.info[i];
1968                isdn_tty_cleanup_xmit(info);
1969#ifdef CONFIG_ISDN_TTY_FAX
1970                kfree(info->fax);
1971#endif
1972                kfree(info->xmit_buf - 4);
1973        }
1974        tty_unregister_driver(dev->mdm.tty_modem);
1975        put_tty_driver(dev->mdm.tty_modem);
1976        dev->mdm.tty_modem = NULL;
1977}
1978
1979
1980/*
1981 * isdn_tty_match_icall(char *MSN, atemu *tty_emulator, int dev_idx)
1982 *      match the MSN against the MSNs (glob patterns) defined for tty_emulator,
1983 *      and return 0 for match, 1 for no match, 2 if MSN could match if longer.
1984 */
1985
1986static int
1987isdn_tty_match_icall(char *cid, atemu *emu, int di)
1988{
1989#ifdef ISDN_DEBUG_MODEM_ICALL
1990        printk(KERN_DEBUG "m_fi: msn=%s lmsn=%s mmsn=%s mreg[SI1]=%d mreg[SI2]=%d\n",
1991               emu->msn, emu->lmsn, isdn_map_eaz2msn(emu->msn, di),
1992               emu->mdmreg[REG_SI1], emu->mdmreg[REG_SI2]);
1993#endif
1994        if (strlen(emu->lmsn)) {
1995                char *p = emu->lmsn;
1996                char *q;
1997                int  tmp;
1998                int  ret = 0;
1999
2000                while (1) {
2001                        if ((q = strchr(p, ';')))
2002                                *q = '\0';
2003                        if ((tmp = isdn_msncmp(cid, isdn_map_eaz2msn(p, di))) > ret)
2004                                ret = tmp;
2005#ifdef ISDN_DEBUG_MODEM_ICALL
2006                        printk(KERN_DEBUG "m_fi: lmsnX=%s mmsn=%s -> tmp=%d\n",
2007                               p, isdn_map_eaz2msn(emu->msn, di), tmp);
2008#endif
2009                        if (q) {
2010                                *q = ';';
2011                                p = q;
2012                                p++;
2013                        }
2014                        if (!tmp)
2015                                return 0;
2016                        if (!q)
2017                                break;
2018                }
2019                return ret;
2020        } else {
2021                int tmp;
2022                tmp = isdn_msncmp(cid, isdn_map_eaz2msn(emu->msn, di));
2023#ifdef ISDN_DEBUG_MODEM_ICALL
2024                        printk(KERN_DEBUG "m_fi: mmsn=%s -> tmp=%d\n",
2025                               isdn_map_eaz2msn(emu->msn, di), tmp);
2026#endif
2027                return tmp;
2028        }
2029}
2030
2031/*
2032 * An incoming call-request has arrived.
2033 * Search the tty-devices for an appropriate device and bind
2034 * it to the ISDN-Channel.
2035 * Return:
2036 *
2037 *  0 = No matching device found.
2038 *  1 = A matching device found.
2039 *  3 = No match found, but eventually would match, if
2040 *      CID is longer.
2041 */
2042int
2043isdn_tty_find_icall(int di, int ch, setup_parm *setup)
2044{
2045        char *eaz;
2046        int i;
2047        int wret;
2048        int idx;
2049        int si1;
2050        int si2;
2051        char *nr;
2052        ulong flags;
2053
2054        if (!setup->phone[0]) {
2055                nr = "0";
2056                printk(KERN_INFO "isdn_tty: Incoming call without OAD, assuming '0'\n");
2057        } else
2058                nr = setup->phone;
2059        si1 = (int) setup->si1;
2060        si2 = (int) setup->si2;
2061        if (!setup->eazmsn[0]) {
2062                printk(KERN_WARNING "isdn_tty: Incoming call without CPN, assuming '0'\n");
2063                eaz = "0";
2064        } else
2065                eaz = setup->eazmsn;
2066#ifdef ISDN_DEBUG_MODEM_ICALL
2067        printk(KERN_DEBUG "m_fi: eaz=%s si1=%d si2=%d\n", eaz, si1, si2);
2068#endif
2069        wret = 0;
2070        spin_lock_irqsave(&dev->lock, flags);
2071        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
2072                modem_info *info = &dev->mdm.info[i];
2073
2074                if (info->count == 0)
2075                    continue;
2076                if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) &&  /* SI1 is matching */
2077                    (info->emu.mdmreg[REG_SI2] == si2)) {         /* SI2 is matching */
2078                        idx = isdn_dc2minor(di, ch);
2079#ifdef ISDN_DEBUG_MODEM_ICALL
2080                        printk(KERN_DEBUG "m_fi: match1 wret=%d\n", wret);
2081                        printk(KERN_DEBUG "m_fi: idx=%d flags=%08lx drv=%d ch=%d usg=%d\n", idx,
2082                               info->flags, info->isdn_driver, info->isdn_channel,
2083                               dev->usage[idx]);
2084#endif
2085                        if (
2086#ifndef FIX_FILE_TRANSFER
2087                                (info->flags & ISDN_ASYNC_NORMAL_ACTIVE) &&
2088#endif
2089                                (info->isdn_driver == -1) &&
2090                                (info->isdn_channel == -1) &&
2091                                (USG_NONE(dev->usage[idx]))) {
2092                                int matchret;
2093
2094                                if ((matchret = isdn_tty_match_icall(eaz, &info->emu, di)) > wret)
2095                                        wret = matchret;
2096                                if (!matchret) {                  /* EAZ is matching */
2097                                        info->isdn_driver = di;
2098                                        info->isdn_channel = ch;
2099                                        info->drv_index = idx;
2100                                        dev->m_idx[idx] = info->line;
2101                                        dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
2102                                        dev->usage[idx] |= isdn_calc_usage(si1, info->emu.mdmreg[REG_L2PROT]); 
2103                                        strcpy(dev->num[idx], nr);
2104                                        strcpy(info->emu.cpn, eaz);
2105                                        info->emu.mdmreg[REG_SI1I] = si2bit[si1];
2106                                        info->emu.mdmreg[REG_PLAN] = setup->plan;
2107                                        info->emu.mdmreg[REG_SCREEN] = setup->screen;
2108                                        isdn_info_update();
2109                                        spin_unlock_irqrestore(&dev->lock, flags);
2110                                        printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr,
2111                                               info->line);
2112                                        info->msr |= UART_MSR_RI;
2113                                        isdn_tty_modem_result(RESULT_RING, info);
2114                                        isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1);
2115                                        return 1;
2116                                }
2117                        }
2118                }
2119        }
2120        spin_unlock_irqrestore(&dev->lock, flags);
2121        printk(KERN_INFO "isdn_tty: call from %s -> %s %s\n", nr, eaz,
2122               ((dev->drv[di]->flags & DRV_FLAG_REJBUS) && (wret != 2))? "rejected" : "ignored");
2123        return (wret == 2)?3:0;
2124}
2125
2126#define TTY_IS_ACTIVE(info) \
2127        (info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE))
2128
2129int
2130isdn_tty_stat_callback(int i, isdn_ctrl *c)
2131{
2132        int mi;
2133        modem_info *info;
2134        char *e;
2135
2136        if (i < 0)
2137                return 0;
2138        if ((mi = dev->m_idx[i]) >= 0) {
2139                info = &dev->mdm.info[mi];
2140                switch (c->command) {
2141                        case ISDN_STAT_CINF:
2142                                printk(KERN_DEBUG "CHARGEINFO on ttyI%d: %ld %s\n", info->line, c->arg, c->parm.num);
2143                                info->emu.charge = (unsigned) simple_strtoul(c->parm.num, &e, 10);
2144                                if (e == (char *)c->parm.num)
2145                                        info->emu.charge = 0;
2146                                
2147                                break;                  
2148                        case ISDN_STAT_BSENT:
2149#ifdef ISDN_TTY_STAT_DEBUG
2150                                printk(KERN_DEBUG "tty_STAT_BSENT ttyI%d\n", info->line);
2151#endif
2152                                if ((info->isdn_driver == c->driver) &&
2153                                    (info->isdn_channel == c->arg)) {
2154                                        info->msr |= UART_MSR_CTS;
2155                                        if (info->send_outstanding)
2156                                                if (!(--info->send_outstanding))
2157                                                        info->lsr |= UART_LSR_TEMT;
2158                                        isdn_tty_tint(info);
2159                                        return 1;
2160                                }
2161                                break;
2162                        case ISDN_STAT_CAUSE:
2163#ifdef ISDN_TTY_STAT_DEBUG
2164                                printk(KERN_DEBUG "tty_STAT_CAUSE ttyI%d\n", info->line);
2165#endif
2166                                /* Signal cause to tty-device */
2167                                strncpy(info->last_cause, c->parm.num, 5);
2168                                return 1;
2169                        case ISDN_STAT_DISPLAY:
2170#ifdef ISDN_TTY_STAT_DEBUG
2171                                printk(KERN_DEBUG "tty_STAT_DISPLAY ttyI%d\n", info->line);
2172#endif
2173                                /* Signal display to tty-device */
2174                                if ((info->emu.mdmreg[REG_DISPLAY] & BIT_DISPLAY) && 
2175                                        !(info->emu.mdmreg[REG_RESPNUM] & BIT_RESPNUM)) {
2176                                  isdn_tty_at_cout("\r\n", info);
2177                                  isdn_tty_at_cout("DISPLAY: ", info);
2178                                  isdn_tty_at_cout(c->parm.display, info);
2179                                  isdn_tty_at_cout("\r\n", info);
2180                                }
2181                                return 1;
2182                        case ISDN_STAT_DCONN:
2183#ifdef ISDN_TTY_STAT_DEBUG
2184                                printk(KERN_DEBUG "tty_STAT_DCONN ttyI%d\n", info->line);
2185#endif
2186                                if (TTY_IS_ACTIVE(info)) {
2187                                        if (info->dialing == 1) {
2188                                                info->dialing = 2;
2189                                                return 1;
2190                                        }
2191                                }
2192                                break;
2193                        case ISDN_STAT_DHUP:
2194#ifdef ISDN_TTY_STAT_DEBUG
2195                                printk(KERN_DEBUG "tty_STAT_DHUP ttyI%d\n", info->line);
2196#endif
2197                                if (TTY_IS_ACTIVE(info)) {
2198                                        if (info->dialing == 1) 
2199                                                isdn_tty_modem_result(RESULT_BUSY, info);
2200                                        if (info->dialing > 1) 
2201                                                isdn_tty_modem_result(RESULT_NO_CARRIER, info);
2202                                        info->dialing = 0;
2203#ifdef ISDN_DEBUG_MODEM_HUP
2204                                        printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n");
2205#endif
2206                                        isdn_tty_modem_hup(info, 0);
2207                                        return 1;
2208                                }
2209                                break;
2210                        case ISDN_STAT_BCONN:
2211#ifdef ISDN_TTY_STAT_DEBUG
2212                                printk(KERN_DEBUG "tty_STAT_BCONN ttyI%d\n", info->line);
2213#endif
2214                                /* Wake up any processes waiting
2215                                 * for incoming call of this device when
2216                                 * DCD follow the state of incoming carrier
2217                                 */
2218                                if (info->blocked_open &&
2219                                   (info->emu.mdmreg[REG_DCD] & BIT_DCD)) {
2220                                        wake_up_interruptible(&info->open_wait);
2221                                }
2222
2223                                /* Schedule CONNECT-Message to any tty
2224                                 * waiting for it and
2225                                 * set DCD-bit of its modem-status.
2226                                 */
2227                                if (TTY_IS_ACTIVE(info) ||
2228                                    (info->blocked_open && (info->emu.mdmreg[REG_DCD] & BIT_DCD))) {
2229                                        info->msr |= UART_MSR_DCD;
2230                                        info->emu.charge = 0;
2231                                        if (info->dialing & 0xf)
2232                                                info->last_dir = 1;
2233                                        else
2234                                                info->last_dir = 0;
2235                                        info->dialing = 0;
2236                                        info->rcvsched = 1;
2237                                        if (USG_MODEM(dev->usage[i])) {
2238                                                if (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) {
2239                                                        strcpy(info->emu.connmsg, c->parm.num);
2240                                                        isdn_tty_modem_result(RESULT_CONNECT, info);
2241                                                } else
2242                                                        isdn_tty_modem_result(RESULT_CONNECT64000, info);
2243                                        }
2244                                        if (USG_VOICE(dev->usage[i]))
2245                                                isdn_tty_modem_result(RESULT_VCON, info);
2246                                        return 1;
2247                                }
2248                                break;
2249                        case ISDN_STAT_BHUP:
2250#ifdef ISDN_TTY_STAT_DEBUG
2251                                printk(KERN_DEBUG "tty_STAT_BHUP ttyI%d\n", info->line);
2252#endif
2253                                if (TTY_IS_ACTIVE(info)) {
2254#ifdef ISDN_DEBUG_MODEM_HUP
2255                                        printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n");
2256#endif
2257                                        isdn_tty_modem_hup(info, 0);
2258                                        return 1;
2259                                }
2260                                break;
2261                        case ISDN_STAT_NODCH:
2262#ifdef ISDN_TTY_STAT_DEBUG
2263                                printk(KERN_DEBUG "tty_STAT_NODCH ttyI%d\n", info->line);
2264#endif
2265                                if (TTY_IS_ACTIVE(info)) {
2266                                        if (info->dialing) {
2267                                                info->dialing = 0;
2268                                                info->last_l2 = -1;
2269                                                info->last_si = 0;
2270                                                sprintf(info->last_cause, "0000");
2271                                                isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
2272                                        }
2273                                        isdn_tty_modem_hup(info, 0);
2274                                        return 1;
2275                                }
2276                                break;
2277                        case ISDN_STAT_UNLOAD:
2278#ifdef ISDN_TTY_STAT_DEBUG
2279                                printk(KERN_DEBUG "tty_STAT_UNLOAD ttyI%d\n", info->line);
2280#endif
2281                                for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
2282                                        info = &dev->mdm.info[i];
2283                                        if (info->isdn_driver == c->driver) {
2284                                                if (info->online)
2285                                                        isdn_tty_modem_hup(info, 1);
2286                                        }
2287                                }
2288                                return 1;
2289#ifdef CONFIG_ISDN_TTY_FAX
2290                        case ISDN_STAT_FAXIND:
2291                                if (TTY_IS_ACTIVE(info)) {
2292                                        isdn_tty_fax_command(info, c); 
2293                                }
2294                                break;
2295#endif
2296#ifdef CONFIG_ISDN_AUDIO
2297                        case ISDN_STAT_AUDIO:
2298                                if (TTY_IS_ACTIVE(info)) {
2299                                        switch(c->parm.num[0]) {
2300                                                case ISDN_AUDIO_DTMF:
2301                                                        if (info->vonline) {
2302                                                                isdn_audio_put_dle_code(info,
2303                                                                        c->parm.num[1]);
2304                                                        }
2305                                                        break;
2306                                        }
2307                                }
2308                                break;
2309#endif
2310                }
2311        }
2312        return 0;
2313}
2314
2315/*********************************************************************
2316 Modem-Emulator-Routines
2317 *********************************************************************/
2318
2319#define cmdchar(c) ((c>=' ')&&(c<=0x7f))
2320
2321/*
2322 * Put a message from the AT-emulator into receive-buffer of tty,
2323 * convert CR, LF, and BS to values in modem-registers 3, 4 and 5.
2324 */
2325void
2326isdn_tty_at_cout(char *msg, modem_info * info)
2327{
2328        struct tty_struct *tty;
2329        atemu *m = &info->emu;
2330        char *p;
2331        char c;
2332        u_long flags;
2333        struct sk_buff *skb = NULL;
2334        char *sp = NULL;
2335        int l;
2336
2337        if (!msg) {
2338                printk(KERN_WARNING "isdn_tty: Null-Message in isdn_tty_at_cout\n");
2339                return;
2340        }
2341
2342        l = strlen(msg);
2343
2344        spin_lock_irqsave(&info->readlock, flags);
2345        tty = info->tty;
2346        if ((info->flags & ISDN_ASYNC_CLOSING) || (!tty)) {
2347                spin_unlock_irqrestore(&info->readlock, flags);
2348                return;
2349        }
2350
2351        /* use queue instead of direct, if online and */
2352        /* data is in queue or buffer is full */
2353        if (info->online && ((tty_buffer_request_room(tty, l) < l) ||
2354            !skb_queue_empty(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel]))) {
2355                skb = alloc_skb(l, GFP_ATOMIC);
2356                if (!skb) {
2357                        spin_unlock_irqrestore(&info->readlock, flags);
2358                        return;
2359                }
2360                sp = skb_put(skb, l);
2361#ifdef CONFIG_ISDN_AUDIO
2362                ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
2363                ISDN_AUDIO_SKB_LOCK(skb) = 0;
2364#endif
2365        }
2366
2367        for (p = msg; *p; p++) {
2368                switch (*p) {
2369                        case '\r':
2370                                c = m->mdmreg[REG_CR];
2371                                break;
2372                        case '\n':
2373                                c = m->mdmreg[REG_LF];
2374                                break;
2375                        case '\b':
2376                                c = m->mdmreg[REG_BS];
2377                                break;
2378                        default:
2379                                c = *p;
2380                }
2381                if (skb) {
2382                        *sp++ = c;
2383                } else {
2384                        if(tty_insert_flip_char(tty, c, TTY_NORMAL) == 0)
2385                                break;
2386                }
2387        }
2388        if (skb) {
2389                __skb_queue_tail(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel], skb);
2390                dev->drv[info->isdn_driver]->rcvcount[info->isdn_channel] += skb->len;
2391                spin_unlock_irqrestore(&info->readlock, flags);
2392                /* Schedule dequeuing */
2393                if (dev->modempoll && info->rcvsched)
2394                        isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
2395
2396        } else {
2397                spin_unlock_irqrestore(&info->readlock, flags);
2398                tty_flip_buffer_push(tty);
2399        }
2400}
2401
2402/*
2403 * Perform ATH Hangup
2404 */
2405static void
2406isdn_tty_on_hook(modem_info * info)
2407{
2408        if (info->isdn_channel >= 0) {
2409#ifdef ISDN_DEBUG_MODEM_HUP
2410                printk(KERN_DEBUG "Mhup in isdn_tty_on_hook\n");
2411#endif
2412                isdn_tty_modem_hup(info, 1);
2413        }
2414}
2415
2416static void
2417isdn_tty_off_hook(void)
2418{
2419        printk(KERN_DEBUG "isdn_tty_off_hook\n");
2420}
2421
2422#define PLUSWAIT1 (HZ/2)        /* 0.5 sec. */
2423#define PLUSWAIT2 (HZ*3/2)      /* 1.5 sec */
2424
2425/*
2426 * Check Buffer for Modem-escape-sequence, activate timer-callback to
2427 * isdn_tty_modem_escape() if sequence found.
2428 *
2429 * Parameters:
2430 *   p          pointer to databuffer
2431 *   plus       escape-character
2432 *   count      length of buffer
2433 *   pluscount  count of valid escape-characters so far
2434 *   lastplus   timestamp of last character
2435 */
2436static void
2437isdn_tty_check_esc(const u_char * p, u_char plus, int count, int *pluscount,
2438                   u_long *lastplus)
2439{
2440        if (plus > 127)
2441                return;
2442        if (count > 3) {
2443                p += count - 3;
2444                count = 3;
2445                *pluscount = 0;
2446        }
2447        while (count > 0) {
2448                if (*(p++) == plus) {
2449                        if ((*pluscount)++) {
2450                                /* Time since last '+' > 0.5 sec. ? */
2451                                if (time_after(jiffies, *lastplus + PLUSWAIT1))
2452                                        *pluscount = 1;
2453                        } else {
2454                                /* Time since last non-'+' < 1.5 sec. ? */
2455                                if (time_before(jiffies, *lastplus + PLUSWAIT2))
2456                                        *pluscount = 0;
2457                        }
2458                        if ((*pluscount == 3) && (count == 1))
2459                                isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, 1);
2460                        if (*pluscount > 3)
2461                                *pluscount = 1;
2462                } else
2463                        *pluscount = 0;
2464                *lastplus = jiffies;
2465                count--;
2466        }
2467}
2468
2469/*
2470 * Return result of AT-emulator to tty-receive-buffer, depending on
2471 * modem-register 12, bit 0 and 1.
2472 * For CONNECT-messages also switch to online-mode.
2473 * For RING-message handle auto-ATA if register 0 != 0
2474 */
2475
2476static void
2477isdn_tty_modem_result(int code, modem_info * info)
2478{
2479        atemu *m = &info->emu;
2480        static char *msg[] =
2481        {"OK", "CONNECT", "RING", "NO CARRIER", "ERROR",
2482         "CONNECT 64000", "NO DIALTONE", "BUSY", "NO ANSWER",
2483         "RINGING", "NO MSN/EAZ", "VCON", "RUNG"};
2484        char s[ISDN_MSNLEN+10];
2485
2486        switch (code) {
2487                case RESULT_RING:
2488                        m->mdmreg[REG_RINGCNT]++;
2489                        if (m->mdmreg[REG_RINGCNT] == m->mdmreg[REG_RINGATA])
2490                                /* Automatically accept incoming call */
2491                                isdn_tty_cmd_ATA(info);
2492                        break;
2493                case RESULT_NO_CARRIER:
2494#ifdef ISDN_DEBUG_MODEM_HUP
2495                        printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n",
2496                               (info->flags & ISDN_ASYNC_CLOSING),
2497                               (!info->tty));
2498#endif
2499                        m->mdmreg[REG_RINGCNT] = 0;
2500                        del_timer(&info->nc_timer);
2501                        info->ncarrier = 0;
2502                        if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
2503                                return;
2504                        }
2505#ifdef CONFIG_ISDN_AUDIO
2506                        if (info->vonline & 1) {
2507#ifdef ISDN_DEBUG_MODEM_VOICE
2508                                printk(KERN_DEBUG "res3: send DLE-ETX on ttyI%d\n",
2509                                       info->line);
2510#endif
2511                                /* voice-recording, add DLE-ETX */
2512                                isdn_tty_at_cout("\020\003", info);
2513                        }
2514                        if (info->vonline & 2) {
2515#ifdef ISDN_DEBUG_MODEM_VOICE
2516                                printk(KERN_DEBUG "res3: send DLE-DC4 on ttyI%d\n",
2517                                       info->line);
2518#endif
2519                                /* voice-playing, add DLE-DC4 */
2520                                isdn_tty_at_cout("\020\024", info);
2521                        }
2522#endif
2523                        break;
2524                case RESULT_CONNECT:
2525                case RESULT_CONNECT64000:
2526                        sprintf(info->last_cause, "0000");
2527                        if (!info->online)
2528                                info->online = 2;
2529                        break;
2530                case RESULT_VCON:
2531#ifdef ISDN_DEBUG_MODEM_VOICE
2532                        printk(KERN_DEBUG "res3: send VCON on ttyI%d\n",
2533                               info->line);
2534#endif
2535                        sprintf(info->last_cause, "0000");
2536                        if (!info->online)
2537                                info->online = 1;
2538                        break;
2539        } /* switch(code) */
2540
2541        if (m->mdmreg[REG_RESP] & BIT_RESP) {
2542                /* Show results */
2543                if (m->mdmreg[REG_RESPNUM] & BIT_RESPNUM) {
2544                        /* Show numeric results only */
2545                        sprintf(s, "\r\n%d\r\n", code);
2546                        isdn_tty_at_cout(s, info);
2547                } else {
2548                        if (code == RESULT_RING) {
2549                            /* return if "show RUNG" and ringcounter>1 */
2550                            if ((m->mdmreg[REG_RUNG] & BIT_RUNG) &&
2551                                    (m->mdmreg[REG_RINGCNT] > 1))
2552                                                return;
2553                            /* print CID, _before_ _every_ ring */
2554                            if (!(m->mdmreg[REG_CIDONCE] & BIT_CIDONCE)) {
2555                                    isdn_tty_at_cout("\r\nCALLER NUMBER: ", info);
2556                                    isdn_tty_at_cout(dev->num[info->drv_index], info);
2557                                    if (m->mdmreg[REG_CDN] & BIT_CDN) {
2558                                            isdn_tty_at_cout("\r\nCALLED NUMBER: ", info);
2559                                            isdn_tty_at_cout(info->emu.cpn, info);
2560                                    }
2561                            }
2562                        }
2563                        isdn_tty_at_cout("\r\n", info);
2564                        isdn_tty_at_cout(msg[code], info);
2565                        switch (code) {
2566                                case RESULT_CONNECT:
2567                                        switch (m->mdmreg[REG_L2PROT]) {
2568                                                case ISDN_PROTO_L2_MODEM:
2569                                                        isdn_tty_at_cout(" ", info);
2570                                                        isdn_tty_at_cout(m->connmsg, info);
2571                                                        break;
2572                                        }
2573                                        break;
2574                                case RESULT_RING:
2575                                        /* Append CPN, if enabled */
2576                                        if ((m->mdmreg[REG_CPN] & BIT_CPN)) {
2577                                                sprintf(s, "/%s", m->cpn);
2578                                                isdn_tty_at_cout(s, info);
2579                                        }
2580                                        /* Print CID only once, _after_ 1st RING */
2581                                        if ((m->mdmreg[REG_CIDONCE] & BIT_CIDONCE) &&
2582                                            (m->mdmreg[REG_RINGCNT] == 1)) {
2583                                                isdn_tty_at_cout("\r\n", info);
2584                                                isdn_tty_at_cout("CALLER NUMBER: ", info);
2585                                                isdn_tty_at_cout(dev->num[info->drv_index], info);
2586                                                if (m->mdmreg[REG_CDN] & BIT_CDN) {
2587                                                        isdn_tty_at_cout("\r\nCALLED NUMBER: ", info);
2588                                                        isdn_tty_at_cout(info->emu.cpn, info);
2589                                                }
2590                                        }
2591                                        break;
2592                                case RESULT_NO_CARRIER:
2593                                case RESULT_NO_DIALTONE:
2594                                case RESULT_BUSY:
2595                                case RESULT_NO_ANSWER:
2596                                        m->mdmreg[REG_RINGCNT] = 0;
2597                                        /* Append Cause-Message if enabled */
2598                                        if (m->mdmreg[REG_RESPXT] & BIT_RESPXT) {
2599                                                sprintf(s, "/%s", info->last_cause);
2600                                                isdn_tty_at_cout(s, info);
2601                                        }
2602                                        break;
2603                                case RESULT_CONNECT64000:
2604                                        /* Append Protocol to CONNECT message */
2605                                        switch (m->mdmreg[REG_L2PROT]) {
2606                                                case ISDN_PROTO_L2_X75I:
2607                                                case ISDN_PROTO_L2_X75UI:
2608                                                case ISDN_PROTO_L2_X75BUI:
2609                                                        isdn_tty_at_cout("/X.75", info);
2610                                                        break;
2611                                                case ISDN_PROTO_L2_HDLC:
2612                                                        isdn_tty_at_cout("/HDLC", info);
2613                                                        break;
2614                                                case ISDN_PROTO_L2_V11096:
2615                                                        isdn_tty_at_cout("/V110/9600", info);
2616                                                        break;
2617                                                case ISDN_PROTO_L2_V11019:
2618                                                        isdn_tty_at_cout("/V110/19200", info);
2619                                                        break;
2620                                                case ISDN_PROTO_L2_V11038:
2621                                                        isdn_tty_at_cout("/V110/38400", info);
2622                                                        break;
2623                                        }
2624                                        if (m->mdmreg[REG_T70] & BIT_T70) {
2625                                                isdn_tty_at_cout("/T.70", info);
2626                                                if (m->mdmreg[REG_T70] & BIT_T70_EXT)
2627                                                        isdn_tty_at_cout("+", info);
2628                                        }
2629                                        break;
2630                        }
2631                        isdn_tty_at_cout("\r\n", info);
2632                }
2633        }
2634        if (code == RESULT_NO_CARRIER) {
2635                if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
2636                        return;
2637                }
2638#ifdef CONFIG_ISDN_AUDIO
2639                if ( !info->vonline )
2640                        tty_ldisc_flush(info->tty);
2641#else
2642                tty_ldisc_flush(info->tty);
2643#endif
2644                if ((info->flags & ISDN_ASYNC_CHECK_CD) &&
2645                    (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
2646                       (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) {
2647                        tty_hangup(info->tty);
2648                }
2649        }
2650}
2651
2652
2653/*
2654 * Display a modem-register-value.
2655 */
2656static void
2657isdn_tty_show_profile(int ridx, modem_info * info)
2658{
2659        char v[6];
2660
2661        sprintf(v, "\r\n%d", info->emu.mdmreg[ridx]);
2662        isdn_tty_at_cout(v, info);
2663}
2664
2665/*
2666 * Get MSN-string from char-pointer, set pointer to end of number
2667 */
2668static void
2669isdn_tty_get_msnstr(char *n, char **p)
2670{
2671        int limit = ISDN_MSNLEN - 1;
2672
2673        while (((*p[0] >= '0' && *p[0] <= '9') ||
2674                /* Why a comma ??? */
2675                (*p[0] == ',') || (*p[0] == ':')) &&
2676                (limit--))
2677                *n++ = *p[0]++;
2678        *n = '\0';
2679}
2680
2681/*
2682 * Get phone-number from modem-commandbuffer
2683 */
2684static void
2685isdn_tty_getdial(char *p, char *q,int cnt)
2686{
2687        int first = 1;
2688        int limit = ISDN_MSNLEN - 1;    /* MUST match the size of interface var to avoid
2689                                        buffer overflow */
2690
2691        while (strchr(" 0123456789,#.*WPTSR-", *p) && *p && --cnt>0) {
2692                if ((*p >= '0' && *p <= '9') || ((*p == 'S') && first) ||
2693                    ((*p == 'R') && first) ||
2694                    (*p == '*') || (*p == '#')) {
2695                        *q++ = *p;
2696                        limit--;
2697                }
2698                if(!limit)
2699                        break;
2700                p++;
2701                first = 0;
2702        }
2703        *q = 0;
2704}
2705
2706#define PARSE_ERROR { isdn_tty_modem_result(RESULT_ERROR, info); return; }
2707#define PARSE_ERROR1 { isdn_tty_modem_result(RESULT_ERROR, info); return 1; }
2708
2709static void
2710isdn_tty_report(modem_info * info)
2711{
2712        atemu *m = &info->emu;
2713        char s[80];
2714
2715        isdn_tty_at_cout("\r\nStatistics of last connection:\r\n\r\n", info);
2716        sprintf(s, "    Remote Number:    %s\r\n", info->last_num);
2717        isdn_tty_at_cout(s, info);
2718        sprintf(s, "    Direction:        %s\r\n", info->last_dir ? "outgoing" : "incoming");
2719        isdn_tty_at_cout(s, info);
2720        isdn_tty_at_cout("    Layer-2 Protocol: ", info);
2721        switch (info->last_l2) {
2722                case ISDN_PROTO_L2_X75I:
2723                        isdn_tty_at_cout("X.75i", info);
2724                        break;
2725                case ISDN_PROTO_L2_X75UI:
2726                        isdn_tty_at_cout("X.75ui", info);
2727                        break;
2728                case ISDN_PROTO_L2_X75BUI:
2729                        isdn_tty_at_cout("X.75bui", info);
2730                        break;
2731                case ISDN_PROTO_L2_HDLC:
2732                        isdn_tty_at_cout("HDLC", info);
2733                        break;
2734                case ISDN_PROTO_L2_V11096:
2735                        isdn_tty_at_cout("V.110 9600 Baud", info);
2736                        break;
2737                case ISDN_PROTO_L2_V11019:
2738                        isdn_tty_at_cout("V.110 19200 Baud", info);
2739                        break;
2740                case ISDN_PROTO_L2_V11038:
2741                        isdn_tty_at_cout("V.110 38400 Baud", info);
2742                        break;
2743                case ISDN_PROTO_L2_TRANS:
2744                        isdn_tty_at_cout("transparent", info);
2745                        break;
2746                case ISDN_PROTO_L2_MODEM:
2747                        isdn_tty_at_cout("modem", info);
2748                        break;
2749                case ISDN_PROTO_L2_FAX:
2750                        isdn_tty_at_cout("fax", info);
2751                        break;
2752                default:
2753                        isdn_tty_at_cout("unknown", info);
2754                        break;
2755        }
2756        if (m->mdmreg[REG_T70] & BIT_T70) {
2757                isdn_tty_at_cout("/T.70", info);
2758                if (m->mdmreg[REG_T70] & BIT_T70_EXT)
2759                        isdn_tty_at_cout("+", info);
2760        }
2761        isdn_tty_at_cout("\r\n", info);
2762        isdn_tty_at_cout("    Service:          ", info);
2763        switch (info->last_si) {
2764                case 1:
2765                        isdn_tty_at_cout("audio\r\n", info);
2766                        break;
2767                case 5:
2768                        isdn_tty_at_cout("btx\r\n", info);
2769                        break;
2770                case 7:
2771                        isdn_tty_at_cout("data\r\n", info);
2772                        break;
2773                default:
2774                        sprintf(s, "%d\r\n", info->last_si);
2775                        isdn_tty_at_cout(s, info);
2776                        break;
2777        }
2778        sprintf(s, "    Hangup location:  %s\r\n", info->last_lhup ? "local" : "remote");
2779        isdn_tty_at_cout(s, info);
2780        sprintf(s, "    Last cause:       %s\r\n", info->last_cause);
2781        isdn_tty_at_cout(s, info);
2782}
2783
2784/*
2785 * Parse AT&.. commands.
2786 */
2787static int
2788isdn_tty_cmd_ATand(char **p, modem_info * info)
2789{
2790        atemu *m = &info->emu;
2791        int i;
2792        char rb[100];
2793
2794#define MAXRB (sizeof(rb) - 1)
2795
2796        switch (*p[0]) {
2797                case 'B':
2798                        /* &B - Set Buffersize */
2799                        p[0]++;
2800                        i = isdn_getnum(p);
2801                        if ((i < 0) || (i > ISDN_SERIAL_XMIT_MAX))
2802                                PARSE_ERROR1;
2803#ifdef CONFIG_ISDN_AUDIO
2804                        if ((m->mdmreg[REG_SI1] & 1) && (i > VBUF))
2805                                PARSE_ERROR1;
2806#endif
2807                        m->mdmreg[REG_PSIZE] = i / 16;
2808                        info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
2809                        switch (m->mdmreg[REG_L2PROT]) {
2810                                case ISDN_PROTO_L2_V11096:
2811                                case ISDN_PROTO_L2_V11019:
2812                                case ISDN_PROTO_L2_V11038:
2813                                        info->xmit_size /= 10;          
2814                        }
2815                        break;
2816                case 'C':
2817                        /* &C - DCD Status */
2818                        p[0]++;
2819                        switch (isdn_getnum(p)) {
2820                                case 0:
2821                                        m->mdmreg[REG_DCD] &= ~BIT_DCD;
2822                                        break;
2823                                case 1:
2824                                        m->mdmreg[REG_DCD] |= BIT_DCD;
2825                                        break;
2826                                default:
2827                                        PARSE_ERROR1
2828                        }
2829                        break;
2830                case 'D':
2831                        /* &D - Set DTR-Low-behavior */
2832                        p[0]++;
2833                        switch (isdn_getnum(p)) {
2834                                case 0:
2835                                        m->mdmreg[REG_DTRHUP] &= ~BIT_DTRHUP;
2836                                        m->mdmreg[REG_DTRR] &= ~BIT_DTRR;
2837                                        break;
2838                                case 2:
2839                                        m->mdmreg[REG_DTRHUP] |= BIT_DTRHUP;
2840                                        m->mdmreg[REG_DTRR] &= ~BIT_DTRR;
2841                                        break;
2842                                case 3:
2843                                        m->mdmreg[REG_DTRHUP] |= BIT_DTRHUP;
2844                                        m->mdmreg[REG_DTRR] |= BIT_DTRR;
2845                                        break;
2846                                default:
2847                                        PARSE_ERROR1
2848                        }
2849                        break;
2850                case 'E':
2851                        /* &E -Set EAZ/MSN */
2852                        p[0]++;
2853                        isdn_tty_get_msnstr(m->msn, p);
2854                        break;
2855                case 'F':
2856                        /* &F -Set Factory-Defaults */
2857                        p[0]++;
2858                        if (info->msr & UART_MSR_DCD)
2859                                PARSE_ERROR1;
2860                        isdn_tty_reset_profile(m);
2861                        isdn_tty_modem_reset_regs(info, 1);
2862                        break;
2863#ifdef DUMMY_HAYES_AT
2864                case 'K':
2865                        /* only for be compilant with common scripts */
2866                        /* &K Flowcontrol - no function */
2867                        p[0]++;
2868                        isdn_getnum(p);
2869                        break;
2870#endif
2871                case 'L':
2872                        /* &L -Set Numbers to listen on */
2873                        p[0]++;
2874                        i = 0;
2875                        while (*p[0] && (strchr("0123456789,-*[]?;", *p[0])) &&
2876                               (i < ISDN_LMSNLEN - 1))
2877                                m->lmsn[i++] = *p[0]++;
2878                        m->lmsn[i] = '\0';
2879                        break;
2880                case 'R':
2881                        /* &R - Set V.110 bitrate adaption */
2882                        p[0]++;
2883                        i = isdn_getnum(p);
2884                        switch (i) {
2885                                case 0:
2886                                        /* Switch off V.110, back to X.75 */
2887                                        m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
2888                                        m->mdmreg[REG_SI2] = 0;
2889                                        info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
2890                                        break;
2891                                case 9600:
2892                                        m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11096;
2893                                        m->mdmreg[REG_SI2] = 197;
2894                                        info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
2895                                        break;
2896                                case 19200:
2897                                        m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11019;
2898                                        m->mdmreg[REG_SI2] = 199;
2899                                        info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
2900                                        break;
2901                                case 38400:
2902                                        m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11038;
2903                                        m->mdmreg[REG_SI2] = 198; /* no existing standard for this */
2904                                        info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
2905                                        break;
2906                                default:
2907                                        PARSE_ERROR1;
2908                        }
2909                        /* Switch off T.70 */
2910                        m->mdmreg[REG_T70] &= ~(BIT_T70 | BIT_T70_EXT);
2911                        /* Set Service 7 */
2912                        m->mdmreg[REG_SI1] |= 4;
2913                        break;
2914                case 'S':
2915                        /* &S - Set Windowsize */
2916                        p[0]++;
2917                        i = isdn_getnum(p);
2918                        if ((i > 0) && (i < 9))
2919                                m->mdmreg[REG_WSIZE] = i;
2920                        else
2921                                PARSE_ERROR1;
2922                        break;
2923                case 'V':
2924                        /* &V - Show registers */
2925                        p[0]++;
2926                        isdn_tty_at_cout("\r\n", info);
2927                        for (i = 0; i < ISDN_MODEM_NUMREG; i++) {
2928                                sprintf(rb, "S%02d=%03d%s", i,
2929                                        m->mdmreg[i], ((i + 1) % 10) ? " " : "\r\n");
2930                                isdn_tty_at_cout(rb, info);
2931                        }
2932                        sprintf(rb, "\r\nEAZ/MSN: %.50s\r\n",
2933                                strlen(m->msn) ? m->msn : "None");
2934                        isdn_tty_at_cout(rb, info);
2935                        if (strlen(m->lmsn)) {
2936                                isdn_tty_at_cout("\r\nListen: ", info);
2937                                isdn_tty_at_cout(m->lmsn, info);
2938                                isdn_tty_at_cout("\r\n", info);
2939                        }
2940                        break;
2941                case 'W':
2942                        /* &W - Write Profile */
2943                        p[0]++;
2944                        switch (*p[0]) {
2945                                case '0':
2946                                        p[0]++;
2947                                        modem_write_profile(m);
2948                                        break;
2949                                default:
2950                                        PARSE_ERROR1;
2951                        }
2952                        break;
2953                case 'X':
2954                        /* &X - Switch to BTX-Mode and T.70 */
2955                        p[0]++;
2956                        switch (isdn_getnum(p)) {
2957                                case 0:
2958                                        m->mdmreg[REG_T70] &= ~(BIT_T70 | BIT_T70_EXT);
2959                                        info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
2960                                        break;
2961                                case 1:
2962                                        m->mdmreg[REG_T70] |= BIT_T70;
2963                                        m->mdmreg[REG_T70] &= ~BIT_T70_EXT;
2964                                        m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
2965                                        info->xmit_size = 112;
2966                                        m->mdmreg[REG_SI1] = 4;
2967                                        m->mdmreg[REG_SI2] = 0;
2968                                        break;
2969                                case 2:
2970                                        m->mdmreg[REG_T70] |= (BIT_T70 | BIT_T70_EXT);
2971                                        m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
2972                                        info->xmit_size = 112;
2973                                        m->mdmreg[REG_SI1] = 4;
2974                                        m->mdmreg[REG_SI2] = 0;
2975                                        break;
2976                                default:
2977                                        PARSE_ERROR1;
2978                        }
2979                        break;
2980                default:
2981                        PARSE_ERROR1;
2982        }
2983        return 0;
2984}
2985
2986static int
2987isdn_tty_check_ats(int mreg, int mval, modem_info * info, atemu * m)
2988{
2989        /* Some plausibility checks */
2990        switch (mreg) {
2991                case REG_L2PROT:
2992                        if (mval > ISDN_PROTO_L2_MAX)
2993                                return 1;
2994                        break;
2995                case REG_PSIZE:
2996                        if ((mval * 16) > ISDN_SERIAL_XMIT_MAX)
2997                                return 1;
2998#ifdef CONFIG_ISDN_AUDIO
2999                        if ((m->mdmreg[REG_SI1] & 1) && (mval > VBUFX))
3000                                return 1;
3001#endif
3002                        info->xmit_size = mval * 16;
3003                        switch (m->mdmreg[REG_L2PROT]) {
3004                                case ISDN_PROTO_L2_V11096:
3005                                case ISDN_PROTO_L2_V11019:
3006                                case ISDN_PROTO_L2_V11038:
3007                                        info->xmit_size /= 10;          
3008                        }
3009                        break;
3010                case REG_SI1I:
3011                case REG_PLAN:
3012                case REG_SCREEN:
3013                        /* readonly registers */
3014                        return 1;
3015        }
3016        return 0;
3017}
3018
3019/*
3020 * Perform ATS command
3021 */
3022static int
3023isdn_tty_cmd_ATS(char **p, modem_info * info)
3024{
3025        atemu *m = &info->emu;
3026        int bitpos;
3027        int mreg;
3028        int mval;
3029        int bval;
3030
3031        mreg = isdn_getnum(p);
3032        if (mreg < 0 || mreg >= ISDN_MODEM_NUMREG)
3033                PARSE_ERROR1;
3034        switch (*p[0]) {
3035                case '=':
3036                        p[0]++;
3037                        mval = isdn_getnum(p);
3038                        if (mval < 0 || mval > 255)
3039                                PARSE_ERROR1;
3040                        if (isdn_tty_check_ats(mreg, mval, info, m))
3041                                PARSE_ERROR1;
3042                        m->mdmreg[mreg] = mval;
3043                        break;
3044                case '.':
3045                        /* Set/Clear a single bit */
3046                        p[0]++;
3047                        bitpos = isdn_getnum(p);
3048                        if ((bitpos < 0) || (bitpos > 7))
3049                                PARSE_ERROR1;
3050                        switch (*p[0]) {
3051                                case '=':
3052                                        p[0]++;
3053                                        bval = isdn_getnum(p);
3054                                        if (bval < 0 || bval > 1)
3055                                                PARSE_ERROR1;
3056                                        if (bval)
3057                                                mval = m->mdmreg[mreg] | (1 << bitpos);
3058                                        else
3059                                                mval = m->mdmreg[mreg] & ~(1 << bitpos);
3060                                        if (isdn_tty_check_ats(mreg, mval, info, m))
3061                                                PARSE_ERROR1;
3062                                        m->mdmreg[mreg] = mval;
3063                                        break;
3064                                case '?':
3065                                        p[0]++;
3066                                        isdn_tty_at_cout("\r\n", info);
3067                                        isdn_tty_at_cout((m->mdmreg[mreg] & (1 << bitpos)) ? "1" : "0",
3068                                                         info);
3069                                        break;
3070                                default:
3071                                        PARSE_ERROR1;
3072                        }
3073                        break;
3074                case '?':
3075                        p[0]++;
3076                        isdn_tty_show_profile(mreg, info);
3077                        break;
3078                default:
3079                        PARSE_ERROR1;
3080                        break;
3081        }
3082        return 0;
3083}
3084
3085/*
3086 * Perform ATA command
3087 */
3088static void
3089isdn_tty_cmd_ATA(modem_info * info)
3090{
3091        atemu *m = &info->emu;
3092        isdn_ctrl cmd;
3093        int l2;
3094
3095        if (info->msr & UART_MSR_RI) {
3096                /* Accept incoming call */
3097                info->last_dir = 0;
3098                strcpy(info->last_num, dev->num[info->drv_index]);
3099                m->mdmreg[REG_RINGCNT] = 0;
3100                info->msr &= ~UART_MSR_RI;
3101                l2 = m->mdmreg[REG_L2PROT];
3102#ifdef CONFIG_ISDN_AUDIO
3103                /* If more than one bit set in reg18, autoselect Layer2 */
3104                if ((m->mdmreg[REG_SI1] & m->mdmreg[REG_SI1I]) != m->mdmreg[REG_SI1]) {
3105                        if (m->mdmreg[REG_SI1I] == 1) {
3106                                if ((l2 != ISDN_PROTO_L2_MODEM) && (l2 != ISDN_PROTO_L2_FAX))
3107                                        l2 = ISDN_PROTO_L2_TRANS;
3108                        } else
3109                                l2 = ISDN_PROTO_L2_X75I;
3110                }
3111#endif
3112                cmd.driver = info->isdn_driver;
3113                cmd.command = ISDN_CMD_SETL2;
3114                cmd.arg = info->isdn_channel + (l2 << 8);
3115                info->last_l2 = l2;
3116                isdn_command(&cmd);
3117                cmd.driver = info->isdn_driver;
3118                cmd.command = ISDN_CMD_SETL3;
3119                cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
3120#ifdef CONFIG_ISDN_TTY_FAX
3121                if (l2 == ISDN_PROTO_L2_FAX) {
3122                        cmd.parm.fax = info->fax;
3123                        info->fax->direction = ISDN_TTY_FAX_CONN_IN;
3124                }
3125#endif
3126                isdn_command(&cmd);
3127                cmd.driver = info->isdn_driver;
3128                cmd.arg = info->isdn_channel;
3129                cmd.command = ISDN_CMD_ACCEPTD;
3130                info->dialing = 16;
3131                info->emu.carrierwait = 0;
3132                isdn_command(&cmd);
3133                isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
3134        } else
3135                isdn_tty_modem_result(RESULT_NO_ANSWER, info);
3136}
3137
3138#ifdef CONFIG_ISDN_AUDIO
3139/*
3140 * Parse AT+F.. commands
3141 */
3142static int
3143isdn_tty_cmd_PLUSF(char **p, modem_info * info)
3144{
3145        atemu *m = &info->emu;
3146        char rs[20];
3147
3148        if (!strncmp(p[0], "CLASS", 5)) {
3149                p[0] += 5;
3150                switch (*p[0]) {
3151                        case '?':
3152                                p[0]++;
3153                                sprintf(rs, "\r\n%d",
3154                                        (m->mdmreg[REG_SI1] & 1) ? 8 : 0);
3155#ifdef CONFIG_ISDN_TTY_FAX
3156                                if (TTY_IS_FCLASS2(info))
3157                                                sprintf(rs, "\r\n2");
3158                                else if (TTY_IS_FCLASS1(info))
3159                                                sprintf(rs, "\r\n1");
3160#endif
3161                                isdn_tty_at_cout(rs, info);
3162                                break;
3163                        case '=':
3164                                p[0]++;
3165                                switch (*p[0]) {
3166                                        case '0':
3167                                                p[0]++;
3168                                                m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
3169                                                m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_TRANS;
3170                                                m->mdmreg[REG_SI1] = 4;
3171                                                info->xmit_size =
3172                                                    m->mdmreg[REG_PSIZE] * 16;
3173                                                break;
3174#ifdef CONFIG_ISDN_TTY_FAX
3175                                        case '1':
3176                                                p[0]++;
3177                                                if (!(dev->global_features &
3178                                                        ISDN_FEATURE_L3_FCLASS1))
3179                                                        PARSE_ERROR1;
3180                                                m->mdmreg[REG_SI1] = 1;
3181                                                m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_FAX;
3182                                                m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FCLASS1;
3183                                                info->xmit_size =
3184                                                    m->mdmreg[REG_PSIZE] * 16;
3185                                                break;
3186                                        case '2':
3187                                                p[0]++;
3188                                                if (!(dev->global_features &
3189                                                        ISDN_FEATURE_L3_FCLASS2))
3190                                                        PARSE_ERROR1;
3191                                                m->mdmreg[REG_SI1] = 1;
3192                                                m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_FAX;
3193                                                m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FCLASS2;
3194                                                info->xmit_size =
3195                                                    m->mdmreg[REG_PSIZE] * 16;
3196                                                break;
3197#endif
3198                                        case '8':
3199                                                p[0]++;
3200                                                /* L2 will change on dialout with si=1 */
3201                                                m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
3202                                                m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_TRANS;
3203                                                m->mdmreg[REG_SI1] = 5;
3204                                                info->xmit_size = VBUF;
3205                                                break;
3206                                        case '?':
3207                                                p[0]++;
3208                                                strcpy(rs, "\r\n0,");
3209#ifdef CONFIG_ISDN_TTY_FAX
3210                                                if (dev->global_features &
3211                                                        ISDN_FEATURE_L3_FCLASS1)
3212                                                        strcat(rs, "1,");
3213                                                if (dev->global_features &
3214                                                        ISDN_FEATURE_L3_FCLASS2)
3215                                                        strcat(rs, "2,");
3216#endif
3217                                                strcat(rs, "8");
3218                                                isdn_tty_at_cout(rs, info);
3219                                                break;
3220                                        default:
3221                                                PARSE_ERROR1;
3222                                }
3223                                break;
3224                        default:
3225                                PARSE_ERROR1;
3226                }
3227                return 0;
3228        }
3229#ifdef CONFIG_ISDN_TTY_FAX
3230        return (isdn_tty_cmd_PLUSF_FAX(p, info));
3231#else
3232        PARSE_ERROR1;
3233#endif
3234}
3235
3236/*
3237 * Parse AT+V.. commands
3238 */
3239static int
3240isdn_tty_cmd_PLUSV(char **p, modem_info * info)
3241{
3242        atemu *m = &info->emu;
3243        isdn_ctrl cmd;
3244        static char *vcmd[] =
3245        {"NH", "IP", "LS", "RX", "SD", "SM", "TX", "DD", NULL};
3246        int i;
3247        int par1;
3248        int par2;
3249        char rs[20];
3250
3251        i = 0;
3252        while (vcmd[i]) {
3253                if (!strncmp(vcmd[i], p[0], 2)) {
3254                        p[0] += 2;
3255                        break;
3256                }
3257                i++;
3258        }
3259        switch (i) {
3260                case 0:
3261                        /* AT+VNH - Auto hangup feature */
3262                        switch (*p[0]) {
3263                                case '?':
3264                                        p[0]++;
3265                                        isdn_tty_at_cout("\r\n1", info);
3266                                        break;
3267                                case '=':
3268                                        p[0]++;
3269                                        switch (*p[0]) {
3270                                                case '1':
3271                                                        p[0]++;
3272                                                        break;
3273                                                case '?':
3274                                                        p[0]++;
3275                                                        isdn_tty_at_cout("\r\n1", info);
3276                                                        break;
3277                                                default:
3278                                                        PARSE_ERROR1;
3279                                        }
3280                                        break;
3281                                default:
3282                                        PARSE_ERROR1;
3283                        }
3284                        break;
3285                case 1:
3286                        /* AT+VIP - Reset all voice parameters */
3287                        isdn_tty_modem_reset_vpar(m);
3288                        break;
3289                case 2:
3290                        /* AT+VLS - Select device, accept incoming call */
3291                        switch (*p[0]) {
3292                                case '?':
3293                                        p[0]++;
3294                                        sprintf(rs, "\r\n%d", m->vpar[0]);
3295                                        isdn_tty_at_cout(rs, info);
3296                                        break;
3297                                case '=':
3298                                        p[0]++;
3299                                        switch (*p[0]) {
3300                                                case '0':
3301                                                        p[0]++;
3302                                                        m->vpar[0] = 0;
3303                                                        break;
3304                                                case '2':
3305                                                        p[0]++;
3306                                                        m->vpar[0] = 2;
3307                                                        break;
3308                                                case '?':
3309                                                        p[0]++;
3310                                                        isdn_tty_at_cout("\r\n0,2", info);
3311                                                        break;
3312                                                default:
3313                                                        PARSE_ERROR1;
3314                                        }
3315                                        break;
3316                                default:
3317                                        PARSE_ERROR1;
3318                        }
3319                        break;
3320                case 3:
3321                        /* AT+VRX - Start recording */
3322                        if (!m->vpar[0])
3323                                PARSE_ERROR1;
3324                        if (info->online != 1) {
3325                                isdn_tty_modem_result(RESULT_NO_ANSWER, info);
3326                                return 1;
3327                        }
3328                        info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state);
3329                        if (!info->dtmf_state) {
3330                                printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n");
3331                                PARSE_ERROR1;
3332                        }
3333                        info->silence_state = isdn_audio_silence_init(info->silence_state);
3334                        if (!info->silence_state) {
3335                                printk(KERN_WARNING "isdn_tty: Couldn't malloc silence state\n");
3336                                PARSE_ERROR1;
3337                        }
3338                        if (m->vpar[3] < 5) {
3339                                info->adpcmr = isdn_audio_adpcm_init(info->adpcmr, m->vpar[3]);
3340                                if (!info->adpcmr) {
3341                                        printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n");
3342                                        PARSE_ERROR1;
3343                                }
3344                        }
3345#ifdef ISDN_DEBUG_AT
3346                        printk(KERN_DEBUG "AT: +VRX\n");
3347#endif
3348                        info->vonline |= 1;
3349                        isdn_tty_modem_result(RESULT_CONNECT, info);
3350                        return 0;
3351                        break;
3352                case 4:
3353                        /* AT+VSD - Silence detection */
3354                        switch (*p[0]) {
3355                                case '?':
3356                                        p[0]++;
3357                                        sprintf(rs, "\r\n<%d>,<%d>",
3358                                                m->vpar[1],
3359                                                m->vpar[2]);
3360                                        isdn_tty_at_cout(rs, info);
3361                                        break;
3362                                case '=':
3363                                        p[0]++;
3364                                        if ((*p[0]>='0') && (*p[0]<='9')) {
3365                                                par1 = isdn_getnum(p);
3366                                                if ((par1 < 0) || (par1 > 31))
3367                                                        PARSE_ERROR1;
3368                                                if (*p[0] != ',')
3369                                                        PARSE_ERROR1;
3370                                                p[0]++;
3371                                                par2 = isdn_getnum(p);
3372                                                if ((par2 < 0) || (par2 > 255))
3373                                                        PARSE_ERROR1;
3374                                                m->vpar[1] = par1;
3375                                                m->vpar[2] = par2;
3376                                                break;
3377                                        } else 
3378                                        if (*p[0] == '?') {
3379                                                p[0]++;
3380                                                isdn_tty_at_cout("\r\n<0-31>,<0-255>",
3381                                                           info);
3382                                                break;
3383                                        } else
3384                                        PARSE_ERROR1;
3385                                        break;
3386                                default:
3387                                        PARSE_ERROR1;
3388                        }
3389                        break;
3390                case 5:
3391                        /* AT+VSM - Select compression */
3392                        switch (*p[0]) {
3393                                case '?':
3394                                        p[0]++;
3395                                        sprintf(rs, "\r\n<%d>,<%d><8000>",
3396                                                m->vpar[3],
3397                                                m->vpar[1]);
3398                                        isdn_tty_at_cout(rs, info);
3399                                        break;
3400                                case '=':
3401                                        p[0]++;
3402                                        switch (*p[0]) {
3403                                                case '2':
3404                                                case '3':
3405                                                case '4':
3406                                                case '5':
3407                                                case '6':
3408                                                        par1 = isdn_getnum(p);
3409                                                        if ((par1 < 2) || (par1 > 6))
3410                                                                PARSE_ERROR1;
3411                                                        m->vpar[3] = par1;
3412                                                        break;
3413                                                case '?':
3414                                                        p[0]++;
3415                                                        isdn_tty_at_cout("\r\n2;ADPCM;2;0;(8000)\r\n",
3416                                                                   info);
3417                                                        isdn_tty_at_cout("3;ADPCM;3;0;(8000)\r\n",
3418                                                                   info);
3419                                                        isdn_tty_at_cout("4;ADPCM;4;0;(8000)\r\n",
3420                                                                   info);
3421                                                        isdn_tty_at_cout("5;ALAW;8;0;(8000)\r\n",
3422                                                                   info);
3423                                                        isdn_tty_at_cout("6;ULAW;8;0;(8000)\r\n",
3424                                                                   info);
3425                                                        break;
3426                                                default:
3427                                                        PARSE_ERROR1;
3428                                        }
3429                                        break;
3430                                default:
3431                                        PARSE_ERROR1;
3432                        }
3433                        break;
3434                case 6:
3435                        /* AT+VTX - Start sending */
3436                        if (!m->vpar[0])
3437                                PARSE_ERROR1;
3438                        if (info->online != 1) {
3439                                isdn_tty_modem_result(RESULT_NO_ANSWER, info);
3440                                return 1;
3441                        }
3442                        info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state);
3443                        if (!info->dtmf_state) {
3444                                printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n");
3445                                PARSE_ERROR1;
3446                        }
3447                        if (m->vpar[3] < 5) {
3448                                info->adpcms = isdn_audio_adpcm_init(info->adpcms, m->vpar[3]);
3449                                if (!info->adpcms) {
3450                                        printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n");
3451                                        PARSE_ERROR1;
3452                                }
3453                        }
3454#ifdef ISDN_DEBUG_AT
3455                        printk(KERN_DEBUG "AT: +VTX\n");
3456#endif
3457                        m->lastDLE = 0;
3458                        info->vonline |= 2;
3459                        isdn_tty_modem_result(RESULT_CONNECT, info);
3460                        return 0;
3461                        break;
3462                case 7:
3463                        /* AT+VDD - DTMF detection */
3464                        switch (*p[0]) {
3465                                case '?':
3466                                        p[0]++;
3467                                        sprintf(rs, "\r\n<%d>,<%d>",
3468                                                m->vpar[4],
3469                                                m->vpar[5]);
3470                                        isdn_tty_at_cout(rs, info);
3471                                        break;
3472                                case '=':
3473                                        p[0]++;
3474                                        if ((*p[0]>='0') && (*p[0]<='9')) {
3475                                                if (info->online != 1)
3476                                                        PARSE_ERROR1;
3477                                                par1 = isdn_getnum(p);
3478                                                if ((par1 < 0) || (par1 > 15))
3479                                                        PARSE_ERROR1;
3480                                                if (*p[0] != ',')
3481                                                        PARSE_ERROR1;
3482                                                p[0]++;
3483                                                par2 = isdn_getnum(p);
3484                                                if ((par2 < 0) || (par2 > 255))
3485                                                        PARSE_ERROR1;
3486                                                m->vpar[4] = par1;
3487                                                m->vpar[5] = par2;
3488                                                cmd.driver = info->isdn_driver;
3489                                                cmd.command = ISDN_CMD_AUDIO;
3490                                                cmd.arg = info->isdn_channel + (ISDN_AUDIO_SETDD << 8);
3491                                                cmd.parm.num[0] = par1;
3492                                                cmd.parm.num[1] = par2;
3493                                                isdn_command(&cmd);
3494                                                break;
3495                                        } else
3496                                        if (*p[0] == '?') {
3497                                                p[0]++;
3498                                                isdn_tty_at_cout("\r\n<0-15>,<0-255>",
3499                                                        info);
3500                                                break;
3501                                        } else
3502                                        PARSE_ERROR1;
3503                                        break;
3504                                default:
3505                                        PARSE_ERROR1;
3506                        }
3507                        break;
3508                default:
3509                        PARSE_ERROR1;
3510        }
3511        return 0;
3512}
3513#endif                          /* CONFIG_ISDN_AUDIO */
3514
3515/*
3516 * Parse and perform an AT-command-line.
3517 */
3518static void
3519isdn_tty_parse_at(modem_info * info)
3520{
3521        atemu *m = &info->emu;
3522        char *p;
3523        char ds[40];
3524
3525#ifdef ISDN_DEBUG_AT
3526        printk(KERN_DEBUG "AT: '%s'\n", m->mdmcmd);
3527#endif
3528        for (p = &m->mdmcmd[2]; *p;) {
3529                switch (*p) {
3530                        case ' ':
3531                                p++;
3532                                break;
3533                        case 'A':
3534                                /* A - Accept incoming call */
3535                                p++;
3536                                isdn_tty_cmd_ATA(info);
3537                                return;
3538                                break;
3539                        case 'D':
3540                                /* D - Dial */
3541                                if (info->msr & UART_MSR_DCD)
3542                                        PARSE_ERROR;
3543                                if (info->msr & UART_MSR_RI) {
3544                                        isdn_tty_modem_result(RESULT_NO_CARRIER, info);
3545                                        return;
3546                                }
3547                                isdn_tty_getdial(++p, ds, sizeof ds);
3548                                p += strlen(p);
3549                                if (!strlen(m->msn))
3550                                        isdn_tty_modem_result(RESULT_NO_MSN_EAZ, info);
3551                                else if (strlen(ds))
3552                                        isdn_tty_dial(ds, info, m);
3553                                else
3554                                        PARSE_ERROR;
3555                                return;
3556                        case 'E':
3557                                /* E - Turn Echo on/off */
3558                                p++;
3559                                switch (isdn_getnum(&p)) {
3560                                        case 0:
3561                                                m->mdmreg[REG_ECHO] &= ~BIT_ECHO;
3562                                                break;
3563                                        case 1:
3564                                                m->mdmreg[REG_ECHO] |= BIT_ECHO;
3565                                                break;
3566                                        default:
3567                                                PARSE_ERROR;
3568                                }
3569                                break;
3570                        case 'H':
3571                                /* H - On/Off-hook */
3572                                p++;
3573                                switch (*p) {
3574                                        case '0':
3575                                                p++;
3576                                                isdn_tty_on_hook(info);
3577                                                break;
3578                                        case '1':
3579                                                p++;
3580                                                isdn_tty_off_hook();
3581                                                break;
3582                                        default:
3583                                                isdn_tty_on_hook(info);
3584                                                break;
3585                                }
3586                                break;
3587                        case 'I':
3588                                /* I - Information */
3589                                p++;
3590                                isdn_tty_at_cout("\r\nLinux ISDN", info);
3591                                switch (*p) {
3592                                        case '0':
3593                                        case '1':
3594                                                p++;
3595                                                break;
3596                                        case '2':
3597                                                p++;
3598                                                isdn_tty_report(info);
3599                                                break;
3600                                        case '3':
3601                                                p++;
3602                                                sprintf(ds, "\r\n%d", info->emu.charge);
3603                                                isdn_tty_at_cout(ds, info);
3604                                                break;
3605                                        default:;
3606                                }
3607                                break;
3608#ifdef DUMMY_HAYES_AT
3609                        case 'L':
3610                        case 'M':
3611                                /* only for be compilant with common scripts */
3612                                /* no function */
3613                                p++;
3614                                isdn_getnum(&p);
3615                                break;
3616#endif
3617                        case 'O':
3618                                /* O - Go online */
3619                                p++;
3620                                if (info->msr & UART_MSR_DCD)
3621                                        /* if B-Channel is up */
3622                                        isdn_tty_modem_result((m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) ? RESULT_CONNECT:RESULT_CONNECT64000, info);
3623                                else
3624                                        isdn_tty_modem_result(RESULT_NO_CARRIER, info);
3625                                return;
3626                        case 'Q':
3627                                /* Q - Turn Emulator messages on/off */
3628                                p++;
3629                                switch (isdn_getnum(&p)) {
3630                                        case 0:
3631                                                m->mdmreg[REG_RESP] |= BIT_RESP;
3632                                                break;
3633                                        case 1:
3634                                                m->mdmreg[REG_RESP] &= ~BIT_RESP;
3635                                                break;
3636                                        default:
3637                                                PARSE_ERROR;
3638                                }
3639                                break;
3640                        case 'S':
3641                                /* S - Set/Get Register */
3642                                p++;
3643                                if (isdn_tty_cmd_ATS(&p, info))
3644                                        return;
3645                                break;
3646                        case 'V':
3647                                /* V - Numeric or ASCII Emulator-messages */
3648                                p++;
3649                                switch (isdn_getnum(&p)) {
3650                                        case 0:
3651                                                m->mdmreg[REG_RESP] |= BIT_RESPNUM;
3652                                                break;
3653                                        case 1:
3654                                                m->mdmreg[REG_RESP] &= ~BIT_RESPNUM;
3655                                                break;
3656                                        default:
3657                                                PARSE_ERROR;
3658                                }
3659                                break;
3660                        case 'Z':
3661                                /* Z - Load Registers from Profile */
3662                                p++;
3663                                if (info->msr & UART_MSR_DCD) {
3664                                        info->online = 0;
3665                                        isdn_tty_on_hook(info);
3666                                }
3667                                isdn_tty_modem_reset_regs(info, 1);
3668                                break;
3669                        case '+':
3670                                p++;
3671                                switch (*p) {
3672#ifdef CONFIG_ISDN_AUDIO
3673                                        case 'F':
3674                                                p++;
3675                                                if (isdn_tty_cmd_PLUSF(&p, info))
3676                                                        return;
3677                                                break;
3678                                        case 'V':
3679                                                if ((!(m->mdmreg[REG_SI1] & 1)) ||
3680                                                        (m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM))
3681                                                        PARSE_ERROR;
3682                                                p++;
3683                                                if (isdn_tty_cmd_PLUSV(&p, info))
3684                                                        return;
3685                                                break;
3686#endif                          /* CONFIG_ISDN_AUDIO */
3687                                        case 'S':       /* SUSPEND */
3688                                                p++;
3689                                                isdn_tty_get_msnstr(ds, &p);
3690                                                isdn_tty_suspend(ds, info, m);
3691                                                break;
3692                                        case 'R':       /* RESUME */
3693                                                p++;
3694                                                isdn_tty_get_msnstr(ds, &p);
3695                                                isdn_tty_resume(ds, info, m);
3696                                                break;
3697                                        case 'M':       /* MESSAGE */
3698                                                p++;
3699                                                isdn_tty_send_msg(info, m, p);
3700                                                break;
3701                                        default:
3702                                                PARSE_ERROR;
3703                                }
3704                                break;
3705                        case '&':
3706                                p++;
3707                                if (isdn_tty_cmd_ATand(&p, info))
3708                                        return;
3709                                break;
3710                        default:
3711                                PARSE_ERROR;
3712                }
3713        }
3714#ifdef CONFIG_ISDN_AUDIO
3715        if (!info->vonline)
3716#endif
3717                isdn_tty_modem_result(RESULT_OK, info);
3718}
3719
3720/* Need own toupper() because standard-toupper is not available
3721 * within modules.
3722 */
3723#define my_toupper(c) (((c>='a')&&(c<='z'))?(c&0xdf):c)
3724
3725/*
3726 * Perform line-editing of AT-commands
3727 *
3728 * Parameters:
3729 *   p        inputbuffer
3730 *   count    length of buffer
3731 *   channel  index to line (minor-device)
3732 */
3733static int
3734isdn_tty_edit_at(const char *p, int count, modem_info * info)
3735{
3736        atemu *m = &info->emu;
3737        int total = 0;
3738        u_char c;
3739        char eb[2];
3740        int cnt;
3741
3742        for (cnt = count; cnt > 0; p++, cnt--) {
3743                c = *p;
3744                total++;
3745                if (c == m->mdmreg[REG_CR] || c == m->mdmreg[REG_LF]) {
3746                        /* Separator (CR or LF) */
3747                        m->mdmcmd[m->mdmcmdl] = 0;
3748                        if (m->mdmreg[REG_ECHO] & BIT_ECHO) {
3749                                eb[0] = c;
3750                                eb[1] = 0;
3751                                isdn_tty_at_cout(eb, info);
3752                        }
3753                        if ((m->mdmcmdl >= 2) && (!(strncmp(m->mdmcmd, "AT", 2))))
3754                                isdn_tty_parse_at(info);
3755                        m->mdmcmdl = 0;
3756                        continue;
3757                }
3758                if (c == m->mdmreg[REG_BS] && m->mdmreg[REG_BS] < 128) {
3759                        /* Backspace-Function */
3760                        if ((m->mdmcmdl > 2) || (!m->mdmcmdl)) {
3761                                if (m->mdmcmdl)
3762                                        m->mdmcmdl--;
3763                                if (m->mdmreg[REG_ECHO] & BIT_ECHO)
3764                                        isdn_tty_at_cout("\b", info);
3765                        }
3766                        continue;
3767                }
3768                if (cmdchar(c)) {
3769                        if (m->mdmreg[REG_ECHO] & BIT_ECHO) {
3770                                eb[0] = c;
3771                                eb[1] = 0;
3772                                isdn_tty_at_cout(eb, info);
3773                        }
3774                        if (m->mdmcmdl < 255) {
3775                                c = my_toupper(c);
3776                                switch (m->mdmcmdl) {
3777                                        case 1:
3778                                                if (c == 'T') {
3779                                                        m->mdmcmd[m->mdmcmdl] = c;
3780                                                        m->mdmcmd[++m->mdmcmdl] = 0;
3781                                                        break;
3782                                                } else
3783                                                        m->mdmcmdl = 0;
3784                                                /* Fall through, check for 'A' */
3785                                        case 0:
3786                                                if (c == 'A') {
3787                                                        m->mdmcmd[m->mdmcmdl] = c;
3788                                                        m->mdmcmd[++m->mdmcmdl] = 0;
3789                                                }
3790                                                break;
3791                                        default:
3792                                                m->mdmcmd[m->mdmcmdl] = c;
3793                                                m->mdmcmd[++m->mdmcmdl] = 0;
3794                                }
3795                        }
3796                }
3797        }
3798        return total;
3799}
3800
3801/*
3802 * Switch all modem-channels who are online and got a valid
3803 * escape-sequence 1.5 seconds ago, to command-mode.
3804 * This function is called every second via timer-interrupt from within
3805 * timer-dispatcher isdn_timer_function()
3806 */
3807void
3808isdn_tty_modem_escape(void)
3809{
3810        int ton = 0;
3811        int i;
3812        int midx;
3813
3814        for (i = 0; i < ISDN_MAX_CHANNELS; i++)
3815                if (USG_MODEM(dev->usage[i]))
3816                        if ((midx = dev->m_idx[i]) >= 0) {
3817                                modem_info *info = &dev->mdm.info[midx];
3818                                if (info->online) {
3819                                        ton = 1;
3820                                        if ((info->emu.pluscount == 3) &&
3821                                            time_after(jiffies , info->emu.lastplus + PLUSWAIT2)) {
3822                                                info->emu.pluscount = 0;
3823                                                info->online = 0;
3824                                                isdn_tty_modem_result(RESULT_OK, info);
3825                                        }
3826                                }
3827                        }
3828        isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, ton);
3829}
3830
3831/*
3832 * Put a RING-message to all modem-channels who have the RI-bit set.
3833 * This function is called every second via timer-interrupt from within
3834 * timer-dispatcher isdn_timer_function()
3835 */
3836void
3837isdn_tty_modem_ring(void)
3838{
3839        int ton = 0;
3840        int i;
3841
3842        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
3843                modem_info *info = &dev->mdm.info[i];
3844                if (info->msr & UART_MSR_RI) {
3845                        ton = 1;
3846                        isdn_tty_modem_result(RESULT_RING, info);
3847                }
3848        }
3849        isdn_timer_ctrl(ISDN_TIMER_MODEMRING, ton);
3850}
3851
3852/*
3853 * For all online tty's, try sending data to
3854 * the lower levels.
3855 */
3856void
3857isdn_tty_modem_xmit(void)
3858{
3859        int ton = 1;
3860        int i;
3861
3862        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
3863                modem_info *info = &dev->mdm.info[i];
3864                if (info->online) {
3865                        ton = 1;
3866                        isdn_tty_senddown(info);
3867                        isdn_tty_tint(info);
3868                }
3869        }
3870        isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, ton);
3871}
3872
3873/*
3874 * Check all channels if we have a 'no carrier' timeout.
3875 * Timeout value is set by Register S7.
3876 */
3877void
3878isdn_tty_carrier_timeout(void)
3879{
3880        int ton = 0;
3881        int i;
3882
3883        for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
3884                modem_info *info = &dev->mdm.info[i];
3885                if (info->dialing) {
3886                        if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) {
3887                                info->dialing = 0;
3888                                isdn_tty_modem_result(RESULT_NO_CARRIER, info);
3889                                isdn_tty_modem_hup(info, 1);
3890                        }
3891                        else
3892                                ton = 1;
3893                }
3894        }
3895        isdn_timer_ctrl(ISDN_TIMER_CARRIER, ton);
3896}
3897
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.