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