root/drivers/isdn/isdn_tty.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. isdn_tty_try_read
  2. isdn_tty_readmodem
  3. isdn_tty_dial
  4. isdn_tty_modem_hup
  5. isdn_tty_paranoia_check
  6. isdn_tty_change_speed
  7. isdn_tty_startup
  8. isdn_tty_shutdown
  9. isdn_tty_write
  10. isdn_tty_write_room
  11. isdn_tty_chars_in_buffer
  12. isdn_tty_flush_buffer
  13. isdn_tty_flush_chars
  14. isdn_tty_throttle
  15. isdn_tty_unthrottle
  16. isdn_tty_get_lsr_info
  17. isdn_tty_get_modem_info
  18. isdn_tty_set_modem_info
  19. isdn_tty_ioctl
  20. isdn_tty_set_termios
  21. isdn_tty_block_til_ready
  22. isdn_tty_open
  23. isdn_tty_close
  24. isdn_tty_hangup
  25. isdn_tty_reset_profile
  26. isdn_tty_modem_reset_regs
  27. modem_write_profile
  28. isdn_tty_modem_init
  29. isdn_tty_find_icall
  30. isdn_tty_at_cout
  31. isdn_tty_on_hook
  32. isdn_tty_off_hook
  33. isdn_tty_check_esc
  34. isdn_tty_modem_result
  35. isdn_tty_show_profile
  36. isdn_tty_get_msnstr
  37. isdn_tty_getdial
  38. isdn_tty_parse_at
  39. isdn_tty_edit_at
  40. isdn_tty_modem_escape
  41. isdn_tty_modem_ring
  42. isdn_tty_modem_xmit
  43. isdn_tty_bsent

   1 /* $Id: isdn_tty.c,v 1.4 1996/04/20 16:39:54 fritz Exp $
   2  *
   3  * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
   4  *
   5  * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
   6  * Copyright 1995,96    by Thinking Objects Software GmbH Wuerzburg
   7  * 
   8  * This program is free software; you can redistribute it and/or modify
   9  * it under the terms of the GNU General Public License as published by
  10  * the Free Software Foundation; either version 2, or (at your option)
  11  * any later version.
  12  *
  13  * This program is distributed in the hope that it will be useful,
  14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16  * GNU General Public License for more details.
  17  *
  18  * You should have received a copy of the GNU General Public License
  19  * along with this program; if not, write to the Free Software
  20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  21  *
  22  * $Log: isdn_tty.c,v $
  23  * Revision 1.4  1996/04/20 16:39:54  fritz
  24  * Changed all io to go through generic routines in isdn_common.c
  25  * Fixed a real ugly bug in modem-emulator: 'ATA' had been accepted
  26  * even when a call has been cancelled from the remote machine.
  27  *
  28  * Revision 1.3  1996/02/11 02:12:32  fritz
  29  * Bugfixes according to similar fixes in standard serial.c of kernel.
  30  *
  31  * Revision 1.2  1996/01/22 05:12:25  fritz
  32  * replaced my_atoi by simple_strtoul
  33  *
  34  * Revision 1.1  1996/01/09 04:13:18  fritz
  35  * Initial revision
  36  *
  37  */
  38 
  39 #define __NO_VERSION__
  40 #include <linux/module.h>
  41 #include <linux/isdn.h>
  42 #include "isdn_common.h"
  43 #include "isdn_tty.h"
  44 
  45 /* Prototypes */
  46 
  47 static int  isdn_tty_edit_at(const char *, int, modem_info *, int);
  48 static void isdn_tty_check_esc(const u_char *, u_char, int, int *, int *, int);
  49 static void isdn_tty_modem_reset_regs(atemu *, int);
  50 
  51 /* Leave this unchanged unless you know what you do! */
  52 #define MODEM_PARANOIA_CHECK
  53 #define MODEM_DO_RESTART
  54 
  55 static char *isdn_ttyname_ttyI = "ttyI";
  56 static char *isdn_ttyname_cui  = "cui";
  57 char *isdn_tty_revision        = "$Revision: 1.4 $";
  58 
  59 int isdn_tty_try_read(int i, u_char * buf, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
  60 {
  61         int c;
  62         struct tty_struct *tty;
  63 
  64         if (i < 0)
  65                 return 0;
  66         if (dev->mdm.online[i]) {
  67                 if ((tty = dev->mdm.info[i].tty)) {
  68                         if (dev->mdm.info[i].MCR & UART_MCR_RTS) {
  69                                 c = TTY_FLIPBUF_SIZE - tty->flip.count - 1;
  70                                 if (c >= len) {
  71                                         if (len > 1) {
  72                                                 memcpy(tty->flip.char_buf_ptr, buf, len);
  73                                                 tty->flip.count += len;
  74                                                 memset(tty->flip.flag_buf_ptr, 0, len);
  75                                                 if (dev->mdm.atmodem[i].mdmreg[12] & 128)
  76                                                         tty->flip.flag_buf_ptr[len - 1] = 0xff;
  77                                                 tty->flip.flag_buf_ptr += len;
  78                                                 tty->flip.char_buf_ptr += len;
  79                                         } else
  80                                                 tty_insert_flip_char(tty, buf[0], 0);
  81                                         queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
  82                                         return 1;
  83                                 }
  84                         }
  85                 }
  86         }
  87         return 0;
  88 }
  89 
  90 void isdn_tty_readmodem(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  91 {
  92         int resched = 0;
  93         int midx;
  94         int i;
  95         int c;
  96         int r;
  97         ulong flags;
  98         struct tty_struct *tty;
  99         modem_info *info;
 100 
 101         for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 102                 if ((midx = dev->m_idx[i]) >= 0)
 103                         if (dev->mdm.online[midx]) {
 104                                 save_flags(flags);
 105                                 cli();
 106                                 r = 0;
 107                                 info = &dev->mdm.info[midx];
 108                                 if ((tty = info->tty)) {
 109                                         if (info->MCR & UART_MCR_RTS) {
 110                                                 c = TTY_FLIPBUF_SIZE - tty->flip.count - 1;
 111                                                 if (c > 0) {
 112                                                         r = isdn_readbchan(info->isdn_driver, info->isdn_channel,
 113                                                                       tty->flip.char_buf_ptr,
 114                                                                       tty->flip.flag_buf_ptr, c, 0);
 115                                                         if (!(dev->mdm.atmodem[midx].mdmreg[12] & 128))
 116                                                                 memset(tty->flip.flag_buf_ptr, 0, r);
 117                                                         tty->flip.count += r;
 118                                                         tty->flip.flag_buf_ptr += r;
 119                                                         tty->flip.char_buf_ptr += r;
 120                                                         if (r)
 121                                                                 queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
 122                                                 }
 123                                         } else
 124                                                 r = 1;
 125                                 } else
 126                                         r = 1;
 127                                 restore_flags(flags);
 128                                 if (r) {
 129                                         dev->mdm.rcvsched[midx] = 0;
 130                                         resched = 1;
 131                                 } else
 132                                         dev->mdm.rcvsched[midx] = 1;
 133                         }
 134         }
 135         if (!resched)
 136                 isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0);
 137 }
 138 
 139 /************************************************************
 140  *
 141  * Modem-functions
 142  *
 143  * mostly "stolen" from original Linux-serial.c and friends.
 144  *
 145  ************************************************************/
 146 
 147 static void isdn_tty_dial(char *n, modem_info * info, atemu * m)
     /* [previous][next][first][last][top][bottom][index][help] */
 148 {
 149         isdn_ctrl cmd;
 150         ulong flags;
 151         int i;
 152 
 153         save_flags(flags);
 154         cli();
 155         i = isdn_get_free_channel(ISDN_USAGE_MODEM, m->mdmreg[14], m->mdmreg[15], -1, -1);
 156         if (i < 0) {
 157                 restore_flags(flags);
 158                 isdn_tty_modem_result(6, info);
 159         } else {
 160                 if (strlen(m->msn)) {
 161                         info->isdn_driver = dev->drvmap[i];
 162                         info->isdn_channel = dev->chanmap[i];
 163                         info->drv_index = i;
 164                         dev->m_idx[i] = info->line;
 165                         dev->usage[i] |= ISDN_USAGE_OUTGOING;
 166                         isdn_info_update();
 167                         restore_flags(flags);
 168                         cmd.driver = info->isdn_driver;
 169                         cmd.arg = info->isdn_channel;
 170                         cmd.command = ISDN_CMD_CLREAZ;
 171                         dev->drv[info->isdn_driver]->interface->command(&cmd);
 172                         strcpy(cmd.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
 173                         cmd.driver = info->isdn_driver;
 174                         cmd.command = ISDN_CMD_SETEAZ;
 175                         dev->drv[info->isdn_driver]->interface->command(&cmd);
 176                         cmd.driver = info->isdn_driver;
 177                         cmd.command = ISDN_CMD_SETL2;
 178                         cmd.arg = info->isdn_channel + (m->mdmreg[14] << 8);
 179                         dev->drv[info->isdn_driver]->interface->command(&cmd);
 180                         cmd.driver = info->isdn_driver;
 181                         cmd.command = ISDN_CMD_SETL3;
 182                         cmd.arg = info->isdn_channel + (m->mdmreg[15] << 8);
 183                         dev->drv[info->isdn_driver]->interface->command(&cmd);
 184                         cmd.driver = info->isdn_driver;
 185                         cmd.arg = info->isdn_channel;
 186                         sprintf(cmd.num, "%s,%s,%d,%d", n, isdn_map_eaz2msn(m->msn, info->isdn_driver),
 187                                 m->mdmreg[18], m->mdmreg[19]);
 188                         cmd.command = ISDN_CMD_DIAL;
 189                         dev->mdm.dialing[info->line] = 1;
 190                         strcpy(dev->num[i], n);
 191                         isdn_info_update();
 192                         dev->drv[info->isdn_driver]->interface->command(&cmd);
 193                 } else
 194                         restore_flags(flags);
 195         }
 196 }
 197 
 198 void isdn_tty_modem_hup(modem_info * info)
     /* [previous][next][first][last][top][bottom][index][help] */
 199 {
 200         isdn_ctrl cmd;
 201 
 202         if (!info)
 203                 return;
 204         dev->mdm.rcvsched[info->line] = 0;
 205         dev->mdm.online[info->line] = 0;
 206         if (info->isdn_driver >= 0) {
 207                 cmd.driver = info->isdn_driver;
 208                 cmd.command = ISDN_CMD_HANGUP;
 209                 cmd.arg = info->isdn_channel;
 210                 dev->drv[info->isdn_driver]->interface->command(&cmd);
 211                 isdn_all_eaz(info->isdn_driver, info->isdn_channel);
 212                 isdn_free_channel(info->isdn_driver, info->isdn_channel, ISDN_USAGE_MODEM);
 213         }
 214         info->isdn_driver = -1;
 215         info->isdn_channel = -1;
 216         if (info->drv_index >= 0) {
 217                 info->drv_index = -1;
 218                 dev->m_idx[info->drv_index] = -1;
 219         }
 220 }
 221 
 222 static inline int isdn_tty_paranoia_check(modem_info * info, dev_t device, const char *routine)
     /* [previous][next][first][last][top][bottom][index][help] */
 223 {
 224 #ifdef MODEM_PARANOIA_CHECK
 225         if (!info) {
 226                 printk(KERN_WARNING "isdn_tty: null info_struct for (%d, %d) in %s\n",
 227                        MAJOR(device), MINOR(device), routine);
 228                 return 1;
 229         }
 230         if (info->magic != ISDN_ASYNC_MAGIC) {
 231                 printk(KERN_WARNING "isdn_tty: bad magic for modem struct (%d, %d) in %s\n",
 232                        MAJOR(device), MINOR(device), routine);
 233                 return 1;
 234         }
 235 #endif
 236         return 0;
 237 }
 238 
 239 /*
 240  * This routine is called to set the UART divisor registers to match
 241  * the specified baud rate for a serial port.
 242  */
 243 static void isdn_tty_change_speed(modem_info * info)
     /* [previous][next][first][last][top][bottom][index][help] */
 244 {
 245         uint cflag, cval, fcr, quot;
 246         int i;
 247 
 248         if (!info->tty || !info->tty->termios)
 249                 return;
 250         cflag = info->tty->termios->c_cflag;
 251 
 252         quot = i = cflag & CBAUD;
 253         if (i & CBAUDEX) {
 254                 i &= ~CBAUDEX;
 255                 if (i < 1 || i > 2)
 256                         info->tty->termios->c_cflag &= ~CBAUDEX;
 257                 else
 258                         i += 15;
 259         }
 260         if (quot) {
 261                 info->MCR |= UART_MCR_DTR;
 262         } else {
 263                 info->MCR &= ~UART_MCR_DTR;
 264                 isdn_tty_modem_reset_regs(&dev->mdm.atmodem[info->line], 0);
 265 #ifdef ISDN_DEBUG_MODEM_HUP
 266                 printk(KERN_DEBUG "Mhup in changespeed\n");
 267 #endif
 268                 isdn_tty_modem_hup(info);
 269                 if (dev->mdm.online[info->line])
 270                         isdn_tty_modem_result(3, info);
 271                 return;
 272         }
 273         /* byte size and parity */
 274         cval = cflag & (CSIZE | CSTOPB);
 275         cval >>= 4;
 276         if (cflag & PARENB)
 277                 cval |= UART_LCR_PARITY;
 278         if (!(cflag & PARODD))
 279                 cval |= UART_LCR_EPAR;
 280         fcr = 0;
 281 
 282         /* CTS flow control flag and modem status interrupts */
 283         if (cflag & CRTSCTS) {
 284                 info->flags |= ISDN_ASYNC_CTS_FLOW;
 285         } else
 286                 info->flags &= ~ISDN_ASYNC_CTS_FLOW;
 287         if (cflag & CLOCAL)
 288                 info->flags &= ~ISDN_ASYNC_CHECK_CD;
 289         else {
 290                 info->flags |= ISDN_ASYNC_CHECK_CD;
 291         }
 292 }
 293 
 294 static int isdn_tty_startup(modem_info * info)
     /* [previous][next][first][last][top][bottom][index][help] */
 295 {
 296         ulong flags;
 297 
 298         if (info->flags & ISDN_ASYNC_INITIALIZED)
 299                 return 0;
 300         if (!info->type) {
 301                 if (info->tty)
 302                         set_bit(TTY_IO_ERROR, &info->tty->flags);
 303                 return 0;
 304         }
 305         save_flags(flags);
 306         cli();
 307 
 308 #ifdef ISDN_DEBUG_MODEM_OPEN
 309         printk(KERN_DEBUG "starting up ttyi%d ...\n", info->line);
 310 #endif
 311         /*
 312          * Now, initialize the UART 
 313          */
 314         info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
 315         if (info->tty)
 316                 clear_bit(TTY_IO_ERROR, &info->tty->flags);
 317         /*
 318          * and set the speed of the serial port
 319          */
 320         isdn_tty_change_speed(info);
 321 
 322         info->flags |= ISDN_ASYNC_INITIALIZED;
 323         dev->mdm.msr[info->line] |= UART_MSR_DSR;
 324 #if FUTURE
 325         info->send_outstanding = 0;
 326 #endif
 327         restore_flags(flags);
 328         return 0;
 329 }
 330 
 331 /*
 332  * This routine will shutdown a serial port; interrupts are disabled, and
 333  * DTR is dropped if the hangup on close termio flag is on.
 334  */
 335 static void isdn_tty_shutdown(modem_info * info)
     /* [previous][next][first][last][top][bottom][index][help] */
 336 {
 337         ulong flags;
 338 
 339         if (!(info->flags & ISDN_ASYNC_INITIALIZED))
 340                 return;
 341 #ifdef ISDN_DEBUG_MODEM_OPEN
 342         printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line);
 343 #endif
 344         save_flags(flags);
 345         cli();                  /* Disable interrupts */
 346         if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
 347                 info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
 348                 isdn_tty_modem_reset_regs(&dev->mdm.atmodem[info->line], 0);
 349 #ifdef ISDN_DEBUG_MODEM_HUP
 350                 printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n");
 351 #endif
 352                 isdn_tty_modem_hup(info);
 353         }
 354         if (info->tty)
 355                 set_bit(TTY_IO_ERROR, &info->tty->flags);
 356 
 357         info->flags &= ~ISDN_ASYNC_INITIALIZED;
 358         restore_flags(flags);
 359 }
 360 
 361 static int isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 362 {
 363         int c, total = 0;
 364         modem_info *info = (modem_info *) tty->driver_data;
 365         ulong flags;
 366         int i;
 367 
 368         if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_write"))
 369                 return 0;
 370         if (!tty)
 371                 return 0;
 372         save_flags(flags);
 373         cli();
 374         while (1) {
 375                 c = MIN(count, info->xmit_size - info->xmit_count - 1);
 376                 if (info->isdn_driver >= 0) {
 377 #if 0
 378                         if (info->isdn_driver != 0) {
 379                                 printk(KERN_DEBUG "FIDO: Zwei HW-Treiber geladen? Ansonsten ist was faul.\n");
 380                                 break;
 381                         }
 382                         int drvidx = info->isdn_driver;
 383                         driver *driv = dev->drv[drvidx];
 384                         i = driv->maxbufsize;
 385 #else
 386                         i = dev->drv[info->isdn_driver]->maxbufsize;
 387 #endif
 388                         c = MIN(c, i);
 389                 }
 390                 if (c <= 0)
 391                         break;
 392                 i = info->line;
 393                 if (dev->mdm.online[i]) {
 394                         isdn_tty_check_esc(buf, dev->mdm.atmodem[i].mdmreg[2], c,
 395                                        &(dev->mdm.atmodem[i].pluscount),
 396                              &(dev->mdm.atmodem[i].lastplus), from_user);
 397                         if (from_user)
 398                                 memcpy_fromfs(&(info->xmit_buf[info->xmit_count]), buf, c);
 399                         else
 400                                 memcpy(&(info->xmit_buf[info->xmit_count]), buf, c);
 401                         info->xmit_count += c;
 402                         if (dev->mdm.atmodem[i].mdmreg[13] & 1) {
 403                                 char *bufptr;
 404                                 int buflen;
 405 #if 0
 406                                 printk(KERN_DEBUG "WB1: %d\n", info->xmit_count);
 407 #endif
 408                                 bufptr = info->xmit_buf;
 409                                 buflen = info->xmit_count;
 410                                 if (dev->mdm.atmodem[i].mdmreg[13] & 2) {
 411                                         /* Add T.70 simplified header */
 412 
 413 #ifdef ISDN_DEBUG_MODEM_DUMP
 414                                         isdn_dumppkt("T70pack1:", bufptr, buflen, 40);
 415 #endif
 416                                         bufptr -= 4;
 417                                         buflen += 4;
 418                                         memcpy(bufptr, "\1\0\1\0", 4);
 419 #ifdef ISDN_DEBUG_MODEM_DUMP
 420                                         isdn_dumppkt("T70pack2:", bufptr, buflen, 40);
 421 #endif
 422                                 }
 423                                 if (isdn_writebuf_stub(info->isdn_driver, info->isdn_channel, bufptr,
 424                                                        buflen, 0) > 0) {
 425                                         info->xmit_count = 0;
 426                                         info->xmit_size = dev->mdm.atmodem[i].mdmreg[16] * 16;
 427 #if FUTURE
 428                                         info->send_outstanding++;
 429                                         dev->mdm.msr[i] &= ~UART_MSR_CTS;
 430 #endif
 431                                         if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
 432                                             tty->ldisc.write_wakeup)
 433                                                 (tty->ldisc.write_wakeup) (tty);
 434                                         wake_up_interruptible(&tty->write_wait);
 435                                 }
 436                         }
 437                 } else {
 438                         if (dev->mdm.dialing[i]) {
 439                                 dev->mdm.dialing[i] = 0;
 440 #ifdef ISDN_DEBUG_MODEM_HUP
 441                                 printk(KERN_DEBUG "Mhup in isdn_tty_write\n");
 442 #endif
 443                                 isdn_tty_modem_hup(info);
 444                                 isdn_tty_modem_result(3, info);
 445                         } else
 446                                 c = isdn_tty_edit_at(buf, c, info, from_user);
 447                 }
 448                 buf += c;
 449                 count -= c;
 450                 total += c;
 451         }
 452         if (info->xmit_count)
 453                 isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
 454         restore_flags(flags);
 455         return total;
 456 }
 457 
 458 static int isdn_tty_write_room(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 459 {
 460         modem_info *info = (modem_info *) tty->driver_data;
 461         int ret;
 462 
 463         if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_write_room"))
 464                 return 0;
 465         if (!dev->mdm.online[info->line])
 466                 return info->xmit_size - 1;
 467         ret = info->xmit_size - info->xmit_count - 1;
 468         return (ret < 0) ? 0 : ret;
 469 }
 470 
 471 static int isdn_tty_chars_in_buffer(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 472 {
 473         modem_info *info = (modem_info *) tty->driver_data;
 474 
 475         if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_chars_in_buffer"))
 476                 return 0;
 477         if (!dev->mdm.online[info->line])
 478                 return 0;
 479         return (info->xmit_count);
 480 }
 481 
 482 static void isdn_tty_flush_buffer(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 483 {
 484         modem_info *info = (modem_info *) tty->driver_data;
 485         uint flags;
 486 
 487         if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_flush_buffer"))
 488                 return;
 489         save_flags(flags);
 490         cli();
 491         info->xmit_count = 0;
 492         restore_flags(flags);
 493         wake_up_interruptible(&tty->write_wait);
 494         if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
 495             tty->ldisc.write_wakeup)
 496                 (tty->ldisc.write_wakeup) (tty);
 497 }
 498 
 499 static void isdn_tty_flush_chars(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 500 {
 501         modem_info *info = (modem_info *) tty->driver_data;
 502 
 503         if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_flush_chars"))
 504                 return;
 505         if (info->xmit_count > 0)
 506                 isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
 507 }
 508 
 509 /*
 510  * ------------------------------------------------------------
 511  * isdn_tty_throttle()
 512  * 
 513  * This routine is called by the upper-layer tty layer to signal that
 514  * incoming characters should be throttled.
 515  * ------------------------------------------------------------
 516  */
 517 static void isdn_tty_throttle(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 518 {
 519         modem_info *info = (modem_info *) tty->driver_data;
 520 
 521         if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_throttle"))
 522                 return;
 523         if (I_IXOFF(tty))
 524                 info->x_char = STOP_CHAR(tty);
 525         info->MCR &= ~UART_MCR_RTS;
 526 }
 527 
 528 static void isdn_tty_unthrottle(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 529 {
 530         modem_info *info = (modem_info *) tty->driver_data;
 531 
 532         if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_unthrottle"))
 533                 return;
 534         if (I_IXOFF(tty)) {
 535                 if (info->x_char)
 536                         info->x_char = 0;
 537                 else
 538                         info->x_char = START_CHAR(tty);
 539         }
 540         info->MCR |= UART_MCR_RTS;
 541 }
 542 
 543 /*
 544  * ------------------------------------------------------------
 545  * isdn_tty_ioctl() and friends
 546  * ------------------------------------------------------------
 547  */
 548 
 549 /*
 550  * isdn_tty_get_lsr_info - get line status register info
 551  *
 552  * Purpose: Let user call ioctl() to get info when the UART physically
 553  *          is emptied.  On bus types like RS485, the transmitter must
 554  *          release the bus after transmitting. This must be done when
 555  *          the transmit shift register is empty, not be done when the
 556  *          transmit holding register is empty.  This functionality
 557  *          allows RS485 driver to be written in user space. 
 558  */
 559 static int isdn_tty_get_lsr_info(modem_info * info, uint * value)
     /* [previous][next][first][last][top][bottom][index][help] */
 560 {
 561         u_char status;
 562         uint result;
 563         ulong flags;
 564 
 565         save_flags(flags);
 566         cli();
 567         status = dev->mdm.msr[info->line];
 568         restore_flags(flags);
 569         result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
 570         put_fs_long(result, (ulong *) value);
 571         return 0;
 572 }
 573 
 574 
 575 static int isdn_tty_get_modem_info(modem_info * info, uint * value)
     /* [previous][next][first][last][top][bottom][index][help] */
 576 {
 577         u_char control, status;
 578         uint result;
 579         ulong flags;
 580 
 581         control = info->MCR;
 582         save_flags(flags);
 583         cli();
 584         status = dev->mdm.msr[info->line];
 585         restore_flags(flags);
 586         result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
 587             | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
 588             | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0)
 589             | ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
 590             | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
 591             | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
 592         put_fs_long(result, (ulong *) value);
 593         return 0;
 594 }
 595 
 596 static int isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value)
     /* [previous][next][first][last][top][bottom][index][help] */
 597 {
 598         uint arg = get_fs_long((ulong *) value);
 599 
 600         switch (cmd) {
 601         case TIOCMBIS:
 602                 if (arg & TIOCM_RTS) {
 603                         info->MCR |= UART_MCR_RTS;
 604                 }
 605                 if (arg & TIOCM_DTR) {
 606                         info->MCR |= UART_MCR_DTR;
 607                 }
 608                 break;
 609         case TIOCMBIC:
 610                 if (arg & TIOCM_RTS) {
 611                         info->MCR &= ~UART_MCR_RTS;
 612                 }
 613                 if (arg & TIOCM_DTR) {
 614                         info->MCR &= ~UART_MCR_DTR;
 615                         isdn_tty_modem_reset_regs(&dev->mdm.atmodem[info->line], 0);
 616 #ifdef ISDN_DEBUG_MODEM_HUP
 617                         printk(KERN_DEBUG "Mhup in TIOCMBIC\n");
 618 #endif
 619                         isdn_tty_modem_hup(info);
 620                         if (dev->mdm.online[info->line])
 621                                 isdn_tty_modem_result(3, info);
 622                 }
 623                 break;
 624         case TIOCMSET:
 625                 info->MCR = ((info->MCR & ~(UART_MCR_RTS | UART_MCR_DTR))
 626                              | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
 627                              | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
 628                 if (!(info->MCR & UART_MCR_DTR)) {
 629                         isdn_tty_modem_reset_regs(&dev->mdm.atmodem[info->line], 0);
 630 #ifdef ISDN_DEBUG_MODEM_HUP
 631                         printk(KERN_DEBUG "Mhup in TIOCMSET\n");
 632 #endif
 633                         isdn_tty_modem_hup(info);
 634                         if (dev->mdm.online[info->line])
 635                                 isdn_tty_modem_result(3, info);
 636                 }
 637                 break;
 638         default:
 639                 return -EINVAL;
 640         }
 641         return 0;
 642 }
 643 
 644 static int isdn_tty_ioctl(struct tty_struct *tty, struct file *file,
     /* [previous][next][first][last][top][bottom][index][help] */
 645                        uint cmd, ulong arg)
 646 {
 647         modem_info *info = (modem_info *) tty->driver_data;
 648         int error;
 649         int retval;
 650 
 651         if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_ioctl"))
 652                 return -ENODEV;
 653         switch (cmd) {
 654         case TCSBRK:            /* SVID version: non-zero arg --> no break */
 655                 retval = tty_check_change(tty);
 656                 if (retval)
 657                         return retval;
 658                 tty_wait_until_sent(tty, 0);
 659                 return 0;
 660         case TCSBRKP:           /* support for POSIX tcsendbreak() */
 661                 retval = tty_check_change(tty);
 662                 if (retval)
 663                         return retval;
 664                 tty_wait_until_sent(tty, 0);
 665                 return 0;
 666         case TIOCGSOFTCAR:
 667                 error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
 668                 if (error)
 669                         return error;
 670                 put_fs_long(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
 671                 return 0;
 672         case TIOCSSOFTCAR:
 673                 arg = get_fs_long((ulong *) arg);
 674                 tty->termios->c_cflag =
 675                     ((tty->termios->c_cflag & ~CLOCAL) |
 676                      (arg ? CLOCAL : 0));
 677                 return 0;
 678         case TIOCMGET:
 679                 error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
 680                 if (error)
 681                         return error;
 682                 return isdn_tty_get_modem_info(info, (uint *) arg);
 683         case TIOCMBIS:
 684         case TIOCMBIC:
 685         case TIOCMSET:
 686                 return isdn_tty_set_modem_info(info, cmd, (uint *) arg);
 687         case TIOCSERGETLSR:     /* Get line status register */
 688                 error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
 689                 if (error)
 690                         return error;
 691                 else
 692                         return isdn_tty_get_lsr_info(info, (uint *) arg);
 693 
 694         case TIOCGSERIAL:
 695                 return -ENOIOCTLCMD;
 696 #if 0
 697                 error = verify_area(VERIFY_WRITE, (void *) arg,
 698                                     sizeof(struct serial_struct));
 699                 if (error)
 700                         return error;
 701                 return get_serial_info(info,
 702                                        (struct serial_struct *) arg);
 703 #endif
 704         case TIOCSSERIAL:
 705                 return -ENOIOCTLCMD;
 706 #if 0
 707                 return set_serial_info(info,
 708                                        (struct serial_struct *) arg);
 709 #endif
 710         case TIOCSERCONFIG:
 711                 return -ENOIOCTLCMD;
 712 #if 0
 713                 return do_autoconfig(info);
 714 #endif
 715 
 716         case TIOCSERGWILD:
 717                 return -ENOIOCTLCMD;
 718 #if 0
 719                 error = verify_area(VERIFY_WRITE, (void *) arg,
 720                                     sizeof(int));
 721                 if (error)
 722                         return error;
 723                 put_fs_long(modem_wild_int_mask, (ulong *) arg);
 724                 return 0;
 725 #endif
 726         case TIOCSERSWILD:
 727                 return -ENOIOCTLCMD;
 728 #if 0
 729                 if (!suser())
 730                         return -EPERM;
 731                 modem_wild_int_mask = get_fs_long((ulong *) arg);
 732                 if (modem_wild_int_mask < 0)
 733                         modem_wild_int_mask = check_wild_interrupts(0);
 734                 return 0;
 735 #endif
 736         case TIOCSERGSTRUCT:
 737                 return -ENOIOCTLCMD;
 738 #if 0
 739                 error = verify_area(VERIFY_WRITE, (void *) arg,
 740                                     sizeof(modem_info));
 741                 if (error)
 742                         return error;
 743                 memcpy_tofs((modem_info *) arg,
 744                             info, sizeof(modem_info));
 745                 return 0;
 746 #endif
 747         default:
 748 #ifdef ISDN_DEBUG_MODEM_IOCTL
 749                 printk(KERN_DEBUG "unsupp. ioctl 0x%08x on ttyi%d\n", cmd, info->line);
 750 #endif
 751                 return -ENOIOCTLCMD;
 752         }
 753         return 0;
 754 }
 755 
 756 static void isdn_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
     /* [previous][next][first][last][top][bottom][index][help] */
 757 {
 758         modem_info *info = (modem_info *) tty->driver_data;
 759 
 760         if (tty->termios->c_cflag == old_termios->c_cflag)
 761                 return;
 762         isdn_tty_change_speed(info);
 763         if ((old_termios->c_cflag & CRTSCTS) &&
 764             !(tty->termios->c_cflag & CRTSCTS)) {
 765                 tty->hw_stopped = 0;
 766         }
 767 }
 768 
 769 /*
 770  * ------------------------------------------------------------
 771  * isdn_tty_open() and friends
 772  * ------------------------------------------------------------
 773  */
 774 static int isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info * info)
     /* [previous][next][first][last][top][bottom][index][help] */
 775 {
 776         struct wait_queue wait = {current, NULL};
 777         int do_clocal = 0;
 778         unsigned long flags;
 779         int retval;
 780 
 781         /*
 782          * If the device is in the middle of being closed, then block
 783          * until it's done, and then try again.
 784          */
 785         if (tty_hung_up_p(filp) ||
 786             (info->flags & ISDN_ASYNC_CLOSING)) {
 787                 if (info->flags & ISDN_ASYNC_CLOSING)
 788                         interruptible_sleep_on(&info->close_wait);
 789 #ifdef MODEM_DO_RESTART
 790                 if (info->flags & ISDN_ASYNC_HUP_NOTIFY)
 791                         return -EAGAIN;
 792                 else
 793                         return -ERESTARTSYS;
 794 #else
 795                 return -EAGAIN;
 796 #endif
 797         }
 798         /*
 799          * If this is a callout device, then just make sure the normal
 800          * device isn't being used.
 801          */
 802         if (tty->driver.subtype == ISDN_SERIAL_TYPE_CALLOUT) {
 803                 if (info->flags & ISDN_ASYNC_NORMAL_ACTIVE)
 804                         return -EBUSY;
 805                 if ((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
 806                     (info->flags & ISDN_ASYNC_SESSION_LOCKOUT) &&
 807                     (info->session != current->session))
 808                         return -EBUSY;
 809                 if ((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
 810                     (info->flags & ISDN_ASYNC_PGRP_LOCKOUT) &&
 811                     (info->pgrp != current->pgrp))
 812                         return -EBUSY;
 813                 info->flags |= ISDN_ASYNC_CALLOUT_ACTIVE;
 814                 return 0;
 815         }
 816         /*
 817          * If non-blocking mode is set, then make the check up front
 818          * and then exit.
 819          */
 820         if (filp->f_flags & O_NONBLOCK) {
 821                 if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
 822                         return -EBUSY;
 823                 info->flags |= ISDN_ASYNC_NORMAL_ACTIVE;
 824                 return 0;
 825         }
 826         if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) {
 827                 if (info->normal_termios.c_cflag & CLOCAL)
 828                         do_clocal = 1;
 829         } else {
 830                 if (tty->termios->c_cflag & CLOCAL)
 831                         do_clocal = 1;
 832         }
 833         /*
 834          * Block waiting for the carrier detect and the line to become
 835          * free (i.e., not in use by the callout).  While we are in
 836          * this loop, info->count is dropped by one, so that
 837          * isdn_tty_close() knows when to free things.  We restore it upon
 838          * exit, either normal or abnormal.
 839          */
 840         retval = 0;
 841         add_wait_queue(&info->open_wait, &wait);
 842 #ifdef ISDN_DEBUG_MODEM_OPEN
 843         printk(KERN_DEBUG "isdn_tty_block_til_ready before block: ttyi%d, count = %d\n",
 844                info->line, info->count);
 845 #endif
 846         save_flags(flags);
 847         cli();
 848         if (!(tty_hung_up_p(filp)))
 849                 info->count--;
 850         restore_flags(flags);
 851         info->blocked_open++;
 852         while (1) {
 853                 current->state = TASK_INTERRUPTIBLE;
 854                 if (tty_hung_up_p(filp) ||
 855                     !(info->flags & ISDN_ASYNC_INITIALIZED)) {
 856 #ifdef MODEM_DO_RESTART
 857                         if (info->flags & ISDN_ASYNC_HUP_NOTIFY)
 858                                 retval = -EAGAIN;
 859                         else
 860                                 retval = -ERESTARTSYS;
 861 #else
 862                         retval = -EAGAIN;
 863 #endif
 864                         break;
 865                 }
 866                 if (!(info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
 867                     !(info->flags & ISDN_ASYNC_CLOSING) &&
 868                     (do_clocal || (
 869                                           dev->mdm.msr[info->line] &
 870                                           UART_MSR_DCD))) {
 871                         break;
 872                 }
 873                 if (current->signal & ~current->blocked) {
 874                         retval = -ERESTARTSYS;
 875                         break;
 876                 }
 877 #ifdef ISDN_DEBUG_MODEM_OPEN
 878                 printk(KERN_DEBUG "isdn_tty_block_til_ready blocking: ttyi%d, count = %d\n",
 879                        info->line, info->count);
 880 #endif
 881                 schedule();
 882         }
 883         current->state = TASK_RUNNING;
 884         remove_wait_queue(&info->open_wait, &wait);
 885         if (!tty_hung_up_p(filp))
 886                 info->count++;
 887         info->blocked_open--;
 888 #ifdef ISDN_DEBUG_MODEM_OPEN
 889         printk(KERN_DEBUG "isdn_tty_block_til_ready after blocking: ttyi%d, count = %d\n",
 890                info->line, info->count);
 891 #endif
 892         if (retval)
 893                 return retval;
 894         info->flags |= ISDN_ASYNC_NORMAL_ACTIVE;
 895         return 0;
 896 }
 897 
 898 /*
 899  * This routine is called whenever a serial port is opened.  It
 900  * enables interrupts for a serial port, linking in its async structure into
 901  * the IRQ chain.   It also performs the serial-specific
 902  * initialization for the tty structure.
 903  */
 904 static int isdn_tty_open(struct tty_struct *tty, struct file *filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 905 {
 906         modem_info *info;
 907         int retval, line;
 908 
 909         line = MINOR(tty->device) - tty->driver.minor_start;
 910         if (line < 0 || line > ISDN_MAX_CHANNELS)
 911                 return -ENODEV;
 912         info = &dev->mdm.info[line];
 913         if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_open"))
 914                 return -ENODEV;
 915 #ifdef ISDN_DEBUG_MODEM_OPEN
 916         printk(KERN_DEBUG "isdn_tty_open %s%d, count = %d\n", tty->driver.name,
 917                info->line, info->count);
 918 #endif
 919         info->count++;
 920         tty->driver_data = info;
 921         info->tty = tty;
 922         /*
 923          * Start up serial port
 924          */
 925         retval = isdn_tty_startup(info);
 926         if (retval) {
 927 #ifdef ISDN_DEBUG_MODEM_OPEN
 928                 printk(KERN_DEBUG "isdn_tty_open return after startup\n");
 929 #endif
 930                 return retval;
 931         }
 932         retval = isdn_tty_block_til_ready(tty, filp, info);
 933         if (retval) {
 934 #ifdef ISDN_DEBUG_MODEM_OPEN
 935                 printk(KERN_DEBUG "isdn_tty_open return after isdn_tty_block_til_ready \n");
 936 #endif
 937                 return retval;
 938         }
 939         if ((info->count == 1) && (info->flags & ISDN_ASYNC_SPLIT_TERMIOS)) {
 940                 if (tty->driver.subtype == ISDN_SERIAL_TYPE_NORMAL)
 941                         *tty->termios = info->normal_termios;
 942                 else
 943                         *tty->termios = info->callout_termios;
 944                 isdn_tty_change_speed(info);
 945         }
 946         info->session = current->session;
 947         info->pgrp = current->pgrp;
 948 #ifdef ISDN_DEBUG_MODEM_OPEN
 949         printk(KERN_DEBUG "isdn_tty_open ttyi%d successful...\n", info->line);
 950 #endif
 951         dev->modempoll++;
 952 #ifdef ISDN_DEBUG_MODEM_OPEN
 953         printk(KERN_DEBUG "isdn_tty_open normal exit\n");
 954 #endif
 955         return 0;
 956 }
 957 
 958 static void isdn_tty_close(struct tty_struct *tty, struct file *filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 959 {
 960         modem_info *info = (modem_info *) tty->driver_data;
 961         ulong flags;
 962         ulong timeout;
 963 
 964         if (!info || isdn_tty_paranoia_check(info, tty->device, "isdn_tty_close"))
 965                 return;
 966         save_flags(flags);
 967         cli();
 968         if (tty_hung_up_p(filp)) {
 969                 restore_flags(flags);
 970 #ifdef ISDN_DEBUG_MODEM_OPEN
 971                 printk(KERN_DEBUG "isdn_tty_close return after tty_hung_up_p\n");
 972 #endif
 973                 return;
 974         }
 975         dev->modempoll--;
 976         if ((tty->count == 1) && (info->count != 1)) {
 977                 /*
 978                  * Uh, oh.  tty->count is 1, which means that the tty
 979                  * structure will be freed.  Info->count should always
 980                  * be one in these conditions.  If it's greater than
 981                  * one, we've got real problems, since it means the
 982                  * serial port won't be shutdown.
 983                  */
 984                 printk(KERN_ERR "isdn_tty_close: bad port count; tty->count is 1, "
 985                        "info->count is %d\n", info->count);
 986                 info->count = 1;
 987         }
 988         if (--info->count < 0) {
 989                 printk(KERN_ERR "isdn_tty_close: bad port count for ttyi%d: %d\n",
 990                        info->line, info->count);
 991                 info->count = 0;
 992         }
 993         if (info->count) {
 994                 restore_flags(flags);
 995 #ifdef ISDN_DEBUG_MODEM_OPEN
 996                 printk(KERN_DEBUG "isdn_tty_close after info->count != 0\n");
 997 #endif
 998                 return;
 999         }
1000         info->flags |= ISDN_ASYNC_CLOSING;
1001         /*
1002          * Save the termios structure, since this port may have
1003          * separate termios for callout and dialin.
1004          */
1005         if (info->flags & ISDN_ASYNC_NORMAL_ACTIVE)
1006                 info->normal_termios = *tty->termios;
1007         if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
1008                 info->callout_termios = *tty->termios;
1009 
1010         tty->closing = 1;
1011 
1012         /*
1013          * At this point we stop accepting input.  To do this, we
1014          * disable the receive line status interrupts, and tell the
1015          * interrupt driver to stop checking the data ready bit in the
1016          * line status register.
1017          */
1018         if (info->flags & ISDN_ASYNC_INITIALIZED) {
1019                 tty_wait_until_sent(tty, 3000);         /* 30 seconds timeout */
1020                 /*
1021                  * Before we drop DTR, make sure the UART transmitter
1022                  * has completely drained; this is especially
1023                  * important if there is a transmit FIFO!
1024                  */
1025                 timeout = jiffies + HZ;
1026                 while (!(dev->mdm.mlr[info->line]
1027                          & UART_LSR_TEMT)) {
1028                         current->state = TASK_INTERRUPTIBLE;
1029                         current->timeout = jiffies + 20;
1030                         schedule();
1031                         if (jiffies > timeout)
1032                                 break;
1033                 }
1034         }
1035         isdn_tty_shutdown(info);
1036         if (tty->driver.flush_buffer)
1037                 tty->driver.flush_buffer(tty);
1038         if (tty->ldisc.flush_buffer)
1039                 tty->ldisc.flush_buffer(tty);
1040         info->tty = 0;
1041         tty->closing = 0;
1042 #if 00
1043         if (tty->ldisc.num != ldiscs[N_TTY].num) {
1044                 if (tty->ldisc.close)
1045                         (tty->ldisc.close) (tty);
1046                 tty->ldisc = ldiscs[N_TTY];
1047                 tty->termios->c_line = N_TTY;
1048                 if (tty->ldisc.open)
1049                         (tty->ldisc.open) (tty);
1050         }
1051 #endif
1052         if (info->blocked_open) {
1053                 if (info->close_delay) {
1054                         current->state = TASK_INTERRUPTIBLE;
1055                         current->timeout = jiffies + info->close_delay;
1056                         schedule();
1057                 }
1058                 wake_up_interruptible(&info->open_wait);
1059         }
1060         info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE |
1061                          ISDN_ASYNC_CLOSING);
1062         wake_up_interruptible(&info->close_wait);
1063         restore_flags(flags);
1064 #ifdef ISDN_DEBUG_MODEM_OPEN
1065         printk(KERN_DEBUG "isdn_tty_close normal exit\n");
1066 #endif
1067 }
1068 
1069 /*
1070  * isdn_tty_hangup() --- called by tty_hangup() when a hangup is signaled.
1071  */
1072 static void isdn_tty_hangup(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
1073 {
1074         modem_info *info = (modem_info *) tty->driver_data;
1075 
1076         if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_hangup"))
1077                 return;
1078         isdn_tty_shutdown(info);
1079         info->count = 0;
1080         info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE);
1081         info->tty = 0;
1082         wake_up_interruptible(&info->open_wait);
1083 }
1084 
1085 static void isdn_tty_reset_profile(atemu * m)
     /* [previous][next][first][last][top][bottom][index][help] */
1086 {
1087         m->profile[0] = 0;
1088         m->profile[1] = 0;
1089         m->profile[2] = 43;
1090         m->profile[3] = 13;
1091         m->profile[4] = 10;
1092         m->profile[5] = 8;
1093         m->profile[6] = 3;
1094         m->profile[7] = 60;
1095         m->profile[8] = 2;
1096         m->profile[9] = 6;
1097         m->profile[10] = 7;
1098         m->profile[11] = 70;
1099         m->profile[12] = 0x45;
1100         m->profile[13] = 0;
1101         m->profile[14] = ISDN_PROTO_L2_X75I;
1102         m->profile[15] = ISDN_PROTO_L3_TRANS;
1103         m->profile[16] = ISDN_SERIAL_XMIT_SIZE / 16;
1104         m->profile[17] = ISDN_MODEM_WINSIZE;
1105         m->profile[18] = 7;
1106         m->profile[19] = 0;
1107         m->pmsn[0] = '\0';
1108 }
1109 
1110 static void isdn_tty_modem_reset_regs(atemu * m, int force)
     /* [previous][next][first][last][top][bottom][index][help] */
1111 {
1112         if ((m->mdmreg[12] & 32) || force) {
1113                 memcpy(m->mdmreg, m->profile, ISDN_MODEM_ANZREG);
1114                 memcpy(m->msn, m->pmsn, ISDN_MSNLEN);
1115         }
1116         m->mdmcmdl = 0;
1117 }
1118 
1119 static void modem_write_profile(atemu * m)
     /* [previous][next][first][last][top][bottom][index][help] */
1120 {
1121         memcpy(m->profile, m->mdmreg, ISDN_MODEM_ANZREG);
1122         memcpy(m->pmsn, m->msn, ISDN_MSNLEN);
1123         if (dev->profd)
1124                 send_sig(SIGIO, dev->profd, 1);
1125 }
1126 
1127 int isdn_tty_modem_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1128 {
1129         modem *m;
1130         int i;
1131         modem_info *info;
1132 
1133         m = &dev->mdm;
1134         for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
1135                 isdn_tty_reset_profile(&(m->atmodem[i]));
1136                 isdn_tty_modem_reset_regs(&(m->atmodem[i]), 1);
1137         }
1138         memset(&m->tty_modem, 0, sizeof(struct tty_driver));
1139         m->tty_modem.magic = TTY_DRIVER_MAGIC;
1140         m->tty_modem.name = isdn_ttyname_ttyI;
1141         m->tty_modem.major = ISDN_TTY_MAJOR;
1142         m->tty_modem.minor_start = 0;
1143         m->tty_modem.num = ISDN_MAX_CHANNELS;
1144         m->tty_modem.type = TTY_DRIVER_TYPE_SERIAL;
1145         m->tty_modem.subtype = ISDN_SERIAL_TYPE_NORMAL;
1146         m->tty_modem.init_termios = tty_std_termios;
1147         m->tty_modem.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
1148         m->tty_modem.flags = TTY_DRIVER_REAL_RAW;
1149         m->tty_modem.refcount = &m->refcount;
1150         m->tty_modem.table = m->modem_table;
1151         m->tty_modem.termios = m->modem_termios;
1152         m->tty_modem.termios_locked = m->modem_termios_locked;
1153         m->tty_modem.open = isdn_tty_open;
1154         m->tty_modem.close = isdn_tty_close;
1155         m->tty_modem.write = isdn_tty_write;
1156         m->tty_modem.put_char = NULL;
1157         m->tty_modem.flush_chars = isdn_tty_flush_chars;
1158         m->tty_modem.write_room = isdn_tty_write_room;
1159         m->tty_modem.chars_in_buffer = isdn_tty_chars_in_buffer;
1160         m->tty_modem.flush_buffer = isdn_tty_flush_buffer;
1161         m->tty_modem.ioctl = isdn_tty_ioctl;
1162         m->tty_modem.throttle = isdn_tty_throttle;
1163         m->tty_modem.unthrottle = isdn_tty_unthrottle;
1164         m->tty_modem.set_termios = isdn_tty_set_termios;
1165         m->tty_modem.stop = NULL;
1166         m->tty_modem.start = NULL;
1167         m->tty_modem.hangup = isdn_tty_hangup;
1168         /*
1169          * The callout device is just like normal device except for
1170          * major number and the subtype code.
1171          */
1172         m->cua_modem = m->tty_modem;
1173         m->cua_modem.name = isdn_ttyname_cui;
1174         m->cua_modem.major = ISDN_TTYAUX_MAJOR;
1175         m->tty_modem.minor_start = 0;
1176         m->cua_modem.subtype = ISDN_SERIAL_TYPE_CALLOUT;
1177 
1178         if (tty_register_driver(&m->tty_modem)) {
1179                 printk(KERN_WARNING "isdn_tty: Couldn't register modem-device\n");
1180                 return -1;
1181         }
1182         if (tty_register_driver(&m->cua_modem)) {
1183                 printk(KERN_WARNING "isdn_tty: Couldn't register modem-callout-device\n");
1184                 return -2;
1185         }
1186         for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
1187                 info = &(m->info[i]);
1188                 info->magic = ISDN_ASYNC_MAGIC;
1189                 info->line = i;
1190                 info->tty = 0;
1191                 info->close_delay = 50;
1192                 info->x_char = 0;
1193                 info->count = 0;
1194                 info->blocked_open = 0;
1195                 info->callout_termios = m->cua_modem.init_termios;
1196                 info->normal_termios = m->tty_modem.init_termios;
1197                 info->open_wait = 0;
1198                 info->close_wait = 0;
1199                 info->type = ISDN_PORT_16550A;
1200                 info->isdn_driver = -1;
1201                 info->isdn_channel = -1;
1202                 info->drv_index = -1;
1203                 info->xmit_size = ISDN_SERIAL_XMIT_SIZE;
1204                 if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_SIZE + 5, GFP_KERNEL))) {
1205                         printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
1206                         return -3;
1207                 }
1208                 info->xmit_buf += 4;    /* Make room for T.70 header */
1209         }
1210         return 0;
1211 }
1212 
1213 /*
1214  * An incoming call-request has arrived.
1215  * Search the tty-devices for an appropriate device and bind
1216  * it to the ISDN-Channel.
1217  * Return Index to dev->mdm or -1 if none found.
1218  */
1219 int isdn_tty_find_icall(int di, int ch, char *num)
     /* [previous][next][first][last][top][bottom][index][help] */
1220 {
1221         char *eaz;
1222         int i;
1223         int idx;
1224         int si1;
1225         int si2;
1226         char *s;
1227         char nr[31];
1228         ulong flags;
1229 
1230         save_flags(flags);
1231         cli();
1232         if (num[0] == ',') {
1233                 nr[0] = '0';
1234                 strncpy(&nr[1], num, 29);
1235                 printk(KERN_WARNING "isdn_tty: Incoming call without OAD, assuming '0'\n");
1236         } else
1237                 strncpy(nr, num, 30);
1238         s = strtok(nr, ",");
1239         s = strtok(NULL, ",");
1240         if (!s) {
1241                 printk(KERN_WARNING "isdn_tty: Incoming callinfo garbled, ignored: %s\n",
1242                        num);
1243                 restore_flags(flags);
1244                 return -1;
1245         }
1246         si1 = (int)simple_strtoul(s,NULL,10);
1247         s = strtok(NULL, ",");
1248         if (!s) {
1249                 printk(KERN_WARNING "isdn_tty: Incoming callinfo garbled, ignored: %s\n",
1250                        num);
1251                 restore_flags(flags);
1252                 return -1;
1253         }
1254         si2 = (int)simple_strtoul(s,NULL,10);
1255         eaz = strtok(NULL, ",");
1256         if (!eaz) {
1257                 printk(KERN_WARNING "isdn_tty: Incoming call without CPN, assuming '0'\n");
1258                 eaz = "0";
1259         }
1260 #ifdef ISDN_DEBUG_MODEM_ICALL
1261         printk(KERN_DEBUG "m_fi: eaz=%s si1=%d si2=%d\n", eaz, si1, si2);
1262 #endif
1263         for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
1264 #ifdef ISDN_DEBUG_MODEM_ICALL
1265                 printk(KERN_DEBUG "m_fi: i=%d msn=%s mmsn=%s mreg18=%d mreg19=%d\n", i,
1266                        dev->mdm.atmodem[i].msn, isdn_map_eaz2msn(dev->mdm.atmodem[i].msn, di),
1267                        dev->mdm.atmodem[i].mdmreg[18], dev->mdm.atmodem[i].mdmreg[19]);
1268 #endif
1269                 if ((!strcmp(isdn_map_eaz2msn(dev->mdm.atmodem[i].msn, di)
1270                              ,eaz)) &&  /* EAZ is matching   */
1271                     (dev->mdm.atmodem[i].mdmreg[18] == si1) &&  /* SI1 is matching   */
1272                     (dev->mdm.atmodem[i].mdmreg[19] == si2)) {  /* SI2 is matching   */
1273                         modem_info *info = &dev->mdm.info[i];
1274                         idx = isdn_dc2minor(di, ch);
1275 #ifdef ISDN_DEBUG_MODEM_ICALL
1276                         printk(KERN_DEBUG "m_fi: match1\n");
1277                         printk(KERN_DEBUG "m_fi: idx=%d flags=%08lx drv=%d ch=%d usg=%d\n", idx,
1278                                info->flags, info->isdn_driver, info->isdn_channel,
1279                                dev->usage[idx]);
1280 #endif
1281                         if ((info->flags & ISDN_ASYNC_NORMAL_ACTIVE) &&
1282                             (info->isdn_driver == -1) &&
1283                             (info->isdn_channel == -1) &&
1284                             (USG_NONE(dev->usage[idx]))) {
1285                                 info->isdn_driver = di;
1286                                 info->isdn_channel = ch;
1287                                 info->drv_index = idx;
1288                                 dev->m_idx[idx] = info->line;
1289                                 dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
1290                                 dev->usage[idx] |= ISDN_USAGE_MODEM;
1291                                 strcpy(dev->num[idx], nr);
1292                                 isdn_info_update();
1293                                 restore_flags(flags);
1294                                 printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr,
1295                                        info->line);
1296                                 return info->line;
1297                         }
1298                 }
1299         }
1300         printk(KERN_INFO "isdn_tty: call from %s -> %s %s\n", nr, eaz,
1301                dev->drv[di]->reject_bus ? "rejected" : "ignored");
1302         restore_flags(flags);
1303         return -1;
1304 }
1305 
1306 /*********************************************************************
1307  Modem-Emulator-Routines
1308  *********************************************************************/
1309 
1310 #define cmdchar(c) ((c>' ')&&(c<=0x7f))
1311 
1312 /*
1313  * Put a message from the AT-emulator into receive-buffer of tty,
1314  * convert CR, LF, and BS to values in modem-registers 3, 4 and 5.
1315  */
1316 static void isdn_tty_at_cout(char *msg, modem_info * info)
     /* [previous][next][first][last][top][bottom][index][help] */
1317 {
1318         struct tty_struct *tty;
1319         atemu *m = &(dev->mdm.atmodem[info->line]);
1320         char *p;
1321         char c;
1322         ulong flags;
1323 
1324         if (!msg) {
1325                 printk(KERN_WARNING "isdn_tty: Null-Message in isdn_tty_at_cout\n");
1326                 return;
1327         }
1328         save_flags(flags);
1329         cli();
1330         tty = info->tty;
1331         for (p = msg; *p; p++) {
1332                 switch (*p) {
1333                 case '\r':
1334                         c = m->mdmreg[3];
1335                         break;
1336                 case '\n':
1337                         c = m->mdmreg[4];
1338                         break;
1339                 case '\b':
1340                         c = m->mdmreg[5];
1341                         break;
1342                 default:
1343                         c = *p;
1344                 }
1345                 if ((info->flags & ISDN_ASYNC_CLOSING) || (!tty)) {
1346                         restore_flags(flags);
1347                         return;
1348                 }
1349                 if (tty->flip.count >= TTY_FLIPBUF_SIZE)
1350                         break;
1351                 tty_insert_flip_char(tty, c, 0);
1352         }
1353         restore_flags(flags);
1354         queue_task(&tty->flip.tqueue, &tq_timer);
1355 }
1356 
1357 /*
1358  * Perform ATH Hangup
1359  */
1360 static void isdn_tty_on_hook(modem_info * info)
     /* [previous][next][first][last][top][bottom][index][help] */
1361 {
1362         if (info->isdn_channel >= 0) {
1363 #ifdef ISDN_DEBUG_MODEM_HUP
1364                 printk(KERN_DEBUG "Mhup in isdn_tty_on_hook\n");
1365 #endif
1366                 isdn_tty_modem_hup(info);
1367                 isdn_tty_modem_result(3, info);
1368         }
1369 }
1370 
1371 static void isdn_tty_off_hook(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1372 {
1373         printk(KERN_DEBUG "isdn_tty_off_hook\n");
1374 }
1375 
1376 #define PLUSWAIT1 (HZ/2)        /* 0.5 sec. */
1377 #define PLUSWAIT2 (HZ*3/2)      /* 1.5 sec */
1378 
1379 /*
1380  * Check Buffer for Modem-escape-sequence, activate timer-callback to
1381  * isdn_tty_modem_escape() if sequence found.
1382  *
1383  * Parameters:
1384  *   p          pointer to databuffer
1385  *   plus       escape-character
1386  *   count      length of buffer
1387  *   pluscount  count of valid escape-characters so far
1388  *   lastplus   timestamp of last character
1389  */
1390 static void isdn_tty_check_esc(const u_char * p, u_char plus, int count, int *pluscount,
     /* [previous][next][first][last][top][bottom][index][help] */
1391                            int *lastplus, int from_user)
1392 {
1393         char cbuf[3];
1394 
1395         if (plus > 127)
1396                 return;
1397         if (count > 3) {
1398                 p += count - 3;
1399                 count = 3;
1400                 *pluscount = 0;
1401         }
1402         if (from_user) {
1403                 memcpy_fromfs(cbuf, p, count);
1404                 p = cbuf;
1405         }
1406         while (count > 0) {
1407                 if (*(p++) == plus) {
1408                         if ((*pluscount)++) {
1409                                 /* Time since last '+' > 0.5 sec. ? */
1410                                 if ((jiffies - *lastplus) > PLUSWAIT1)
1411                                         *pluscount = 1;
1412                         } else {
1413                                 /* Time since last non-'+' < 1.5 sec. ? */
1414                                 if ((jiffies - *lastplus) < PLUSWAIT2)
1415                                         *pluscount = 0;
1416                         }
1417                         if ((*pluscount == 3) && (count = 1))
1418                                 isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, 1);
1419                         if (*pluscount > 3)
1420                                 *pluscount = 1;
1421                 } else
1422                         *pluscount = 0;
1423                 *lastplus = jiffies;
1424                 count--;
1425         }
1426 }
1427 
1428 /*
1429  * Return result of AT-emulator to tty-receive-buffer, depending on
1430  * modem-register 12, bit 0 and 1.
1431  * For CONNECT-messages also switch to online-mode.
1432  * For RING-message handle auto-ATA if register 0 != 0
1433  */
1434 void isdn_tty_modem_result(int code, modem_info * info)
     /* [previous][next][first][last][top][bottom][index][help] */
1435 {
1436         atemu *m = &dev->mdm.atmodem[info->line];
1437         static char *msg[] =
1438         {"OK", "CONNECT", "RING", "NO CARRIER", "ERROR",
1439          "CONNECT 64000", "NO DIALTONE", "BUSY", "NO ANSWER",
1440          "RINGING", "NO MSN/EAZ"};
1441         ulong flags;
1442         char s[4];
1443 
1444         switch (code) {
1445         case 2:
1446                 m->mdmreg[1]++; /* RING */
1447                 if (m->mdmreg[1] == m->mdmreg[0]) {
1448                         /* Accept incoming call */
1449                         isdn_ctrl cmd;
1450                         m->mdmreg[1] = 0;
1451                         dev->mdm.msr[info->line] &= ~UART_MSR_RI;
1452                         cmd.driver = info->isdn_driver;
1453                         cmd.arg = info->isdn_channel;
1454                         cmd.command = ISDN_CMD_ACCEPTD;
1455                         dev->drv[info->isdn_driver]->interface->command(&cmd);
1456                 }
1457                 break;
1458         case 3:
1459                 /* NO CARRIER */
1460                 save_flags(flags);
1461                 cli();
1462                 dev->mdm.msr[info->line] &= ~(UART_MSR_DCD | UART_MSR_RI);
1463                 if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
1464                         restore_flags(flags);
1465                         return;
1466                 }
1467                 restore_flags(flags);
1468                 break;
1469         case 1:
1470         case 5:
1471                 dev->mdm.online[info->line] = 1;
1472                 break;
1473         }
1474         if (m->mdmreg[12] & 1) {
1475                 /* Show results */
1476                 isdn_tty_at_cout("\r\n", info);
1477                 if (m->mdmreg[12] & 2) {
1478                         /* Show numeric results */
1479                         sprintf(s, "%d", code);
1480                         isdn_tty_at_cout(s, info);
1481                 } else {
1482                         if (code == 2) {
1483                                 isdn_tty_at_cout("CALLER NUMBER: ", info);
1484                                 isdn_tty_at_cout(dev->num[info->drv_index], info);
1485                                 isdn_tty_at_cout("\r\n", info);
1486                         }
1487                         isdn_tty_at_cout(msg[code], info);
1488                         if (code == 5) {
1489                                 /* Append Protocol to CONNECT message */
1490                                 isdn_tty_at_cout((m->mdmreg[14] != 3) ? "/X.75" : "/HDLC", info);
1491                                 if (m->mdmreg[13] & 2)
1492                                         isdn_tty_at_cout("/T.70", info);
1493                         }
1494                 }
1495                 isdn_tty_at_cout("\r\n", info);
1496         }
1497         if (code == 3) {
1498                 save_flags(flags);
1499                 cli();
1500                 if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
1501                         restore_flags(flags);
1502                         return;
1503                 }
1504                 if ((info->flags & ISDN_ASYNC_CHECK_CD) &&
1505                     (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
1506                        (info->flags & ISDN_ASYNC_CALLOUT_NOHUP))))
1507                         tty_hangup(info->tty);
1508                 restore_flags(flags);
1509         }
1510 }
1511 
1512 /*
1513  * Display a modem-register-value.
1514  */
1515 static void isdn_tty_show_profile(int ridx, modem_info * info)
     /* [previous][next][first][last][top][bottom][index][help] */
1516 {
1517         char v[6];
1518 
1519         sprintf(v, "%d\r\n", dev->mdm.atmodem[info->line].mdmreg[ridx]);
1520         isdn_tty_at_cout(v, info);
1521 }
1522 
1523 /*
1524  * Get MSN-string from char-pointer, set pointer to end of number
1525  */
1526 static void isdn_tty_get_msnstr(char *n, char **p)
     /* [previous][next][first][last][top][bottom][index][help] */
1527 {
1528         while ((*p[0] >= '0' && *p[0] <= '9') || (*p[0] == ','))
1529                 *n++ = *p[0]++;
1530         *n = '\0';
1531 }
1532 
1533 /*
1534  * Get phone-number from modem-commandbuffer
1535  */
1536 static void isdn_tty_getdial(char *p, char *q)
     /* [previous][next][first][last][top][bottom][index][help] */
1537 {
1538         int first = 1;
1539 
1540         while (strchr("0123456789,#.*WPTS-", *p) && *p) {
1541                 if ((*p >= '0' && *p <= '9') || ((*p == 'S') && first))
1542                         *q++ = *p;
1543                 p++;
1544                 first = 0;
1545         }
1546         *q = 0;
1547 }
1548 
1549 /*
1550  * Parse and perform an AT-command-line.
1551  *
1552  * Parameter:
1553  *   channel   index to line (minor-device)
1554  */
1555 static void isdn_tty_parse_at(modem_info * info)
     /* [previous][next][first][last][top][bottom][index][help] */
1556 {
1557         atemu *m = &dev->mdm.atmodem[info->line];
1558         char *p;
1559         int mreg;
1560         int mval;
1561         int i;
1562         char rb[100];
1563         char ds[40];
1564         isdn_ctrl cmd;
1565 
1566 #ifdef ISDN_DEBUG_AT
1567         printk(KERN_DEBUG "AT: '%s'\n", m->mdmcmd);
1568 #endif
1569         for (p = &m->mdmcmd[2]; *p;) {
1570                 switch (*p) {
1571                 case 'A':
1572                         /* A - Accept incoming call */
1573                         p++;
1574                         if (dev->mdm.msr[info->line] & UART_MSR_RI) {
1575 #define FIDOBUG
1576 #ifdef FIDOBUG
1577 /* Variables fido... defined temporarily for finding a strange bug */
1578                                 driver *fido_drv;
1579                                 isdn_if *fido_if;
1580                                 int fido_isdn_driver;
1581                                 modem_info *fido_modem_info;
1582                                 int (*fido_command) (isdn_ctrl *);
1583 #endif
1584                                 /* Accept incoming call */
1585                                 m->mdmreg[1] = 0;
1586                                 dev->mdm.msr[info->line] &= ~UART_MSR_RI;
1587                                 cmd.driver = info->isdn_driver;
1588                                 cmd.command = ISDN_CMD_SETL2;
1589                                 cmd.arg = info->isdn_channel + (m->mdmreg[14] << 8);
1590                                 dev->drv[info->isdn_driver]->interface->command(&cmd);
1591                                 cmd.driver = info->isdn_driver;
1592                                 cmd.command = ISDN_CMD_SETL3;
1593                                 cmd.arg = info->isdn_channel + (m->mdmreg[15] << 8);
1594                                 dev->drv[info->isdn_driver]->interface->command(&cmd);
1595                                 cmd.driver = info->isdn_driver;
1596                                 cmd.arg = info->isdn_channel;
1597                                 cmd.command = ISDN_CMD_ACCEPTD;
1598 #ifdef FIDOBUG
1599                                 fido_modem_info = info;
1600                                 fido_isdn_driver = fido_modem_info->isdn_driver;
1601                                 fido_drv = dev->drv[fido_isdn_driver];
1602                                 fido_if = fido_drv->interface;
1603                                 fido_command = fido_if->command;
1604                                 fido_command(&cmd);
1605 #else
1606                                 dev->drv[info->isdn_driver]->interface->command(&cmd);
1607 #endif
1608                         } else {
1609                                 isdn_tty_modem_result(8, info);
1610                                 return;
1611                         }
1612                         break;
1613                 case 'D':
1614                         /* D - Dial */
1615                         isdn_tty_getdial(++p, ds);
1616                         p += strlen(p);
1617                         if (!strlen(m->msn))
1618                                 isdn_tty_modem_result(10, info);
1619                         else if (strlen(ds))
1620                                 isdn_tty_dial(ds, info, m);
1621                         else
1622                                 isdn_tty_modem_result(4, info);
1623                         return;
1624                 case 'E':
1625                         /* E - Turn Echo on/off */
1626                         p++;
1627                         switch (*p) {
1628                         case '0':
1629                                 p++;
1630                                 m->mdmreg[12] &= ~4;
1631                                 break;
1632                         case '1':
1633                                 p++;
1634                                 m->mdmreg[12] |= 4;
1635                                 break;
1636                         default:
1637                                 isdn_tty_modem_result(4, info);
1638                                 return;
1639                         }
1640                         break;
1641                 case 'H':
1642                         /* H - On/Off-hook */
1643                         p++;
1644                         switch (*p) {
1645                         case '0':
1646                                 p++;
1647                                 isdn_tty_on_hook(info);
1648                                 break;
1649                         case '1':
1650                                 p++;
1651                                 isdn_tty_off_hook();
1652                                 break;
1653                         default:
1654                                 isdn_tty_on_hook(info);
1655                                 break;
1656                         }
1657                         break;
1658                 case 'I':
1659                         /* I - Information */
1660                         p++;
1661                         isdn_tty_at_cout("ISDN for Linux  (c) by Fritz Elfert\r\n", info);
1662                         switch (*p) {
1663                         case '0':
1664                         case '1':
1665                                 p++;
1666                                 break;
1667                         default:
1668                         }
1669                         break;
1670                 case 'O':
1671                         /* O - Go online */
1672                         p++;
1673                         if (dev->mdm.msr[info->line] & UART_MSR_DCD)    /* if B-Channel is up */
1674                                 isdn_tty_modem_result(5, info);
1675                         else
1676                                 isdn_tty_modem_result(3, info);
1677                         return;
1678                 case 'Q':
1679                         /* Q - Turn Emulator messages on/off */
1680                         p++;
1681                         switch (*p) {
1682                         case '0':
1683                                 p++;
1684                                 m->mdmreg[12] |= 1;
1685                                 break;
1686                         case '1':
1687                                 p++;
1688                                 m->mdmreg[12] &= ~1;
1689                                 break;
1690                         default:
1691                                 isdn_tty_modem_result(4, info);
1692                                 return;
1693                         }
1694                         break;
1695                 case 'S':
1696                         /* S - Set/Get Register */
1697                         p++;
1698                         mreg = isdn_getnum(&p);
1699                         if (mreg < 0 || mreg > ISDN_MODEM_ANZREG) {
1700                                 isdn_tty_modem_result(4, info);
1701                                 return;
1702                         }
1703                         switch (*p) {
1704                         case '=':
1705                                 p++;
1706                                 mval = isdn_getnum(&p);
1707                                 if (mval >= 0 && mval <= 255) {
1708                                         if ((mreg == 16) && ((mval * 16) > ISDN_SERIAL_XMIT_SIZE)) {
1709                                                 isdn_tty_modem_result(4, info);
1710                                                 return;
1711                                         }
1712                                         m->mdmreg[mreg] = mval;
1713                                 } else {
1714                                         isdn_tty_modem_result(4, info);
1715                                         return;
1716                                 }
1717                                 break;
1718                         case '?':
1719                                 p++;
1720                                 isdn_tty_show_profile(mreg, info);
1721                                 return;
1722                                 break;
1723                         default:
1724                                 isdn_tty_modem_result(4, info);
1725                                 return;
1726                         }
1727                         break;
1728                 case 'V':
1729                         /* V - Numeric or ASCII Emulator-messages */
1730                         p++;
1731                         switch (*p) {
1732                         case '0':
1733                                 p++;
1734                                 m->mdmreg[12] |= 2;
1735                                 break;
1736                         case '1':
1737                                 p++;
1738                                 m->mdmreg[12] &= ~2;
1739                                 break;
1740                         default:
1741                                 isdn_tty_modem_result(4, info);
1742                                 return;
1743                         }
1744                         break;
1745                 case 'Z':
1746                         /* Z - Load Registers from Profile */
1747                         p++;
1748                         isdn_tty_modem_reset_regs(m, 1);
1749                         break;
1750                 case '+':
1751                         p++;
1752                         switch (*p) {
1753                         case 'F':
1754                                 break;
1755                         }
1756                         break;
1757                 case '&':
1758                         p++;
1759                         switch (*p) {
1760                         case 'B':
1761                                 /* &B - Set Buffersize */
1762                                 p++;
1763                                 i = isdn_getnum(&p);
1764                                 if ((i < 0) || (i > ISDN_SERIAL_XMIT_SIZE)) {
1765                                         isdn_tty_modem_result(4, info);
1766                                         return;
1767                                 }
1768                                 m->mdmreg[16] = i / 16;
1769                                 break;
1770                         case 'D':
1771                                 /* &D - Set DCD-Low-behavior */
1772                                 p++;
1773                                 switch (isdn_getnum(&p)) {
1774                                 case 2:
1775                                         m->mdmreg[12] &= ~32;
1776                                         break;
1777                                 case 3:
1778                                         m->mdmreg[12] |= 32;
1779                                         break;
1780                                 default:
1781                                         isdn_tty_modem_result(4, info);
1782                                         return;
1783                                 }
1784                                 break;
1785                         case 'E':
1786                                 /* &E -Set EAZ/MSN */
1787                                 p++;
1788                                 isdn_tty_get_msnstr(m->msn, &p);
1789                                 break;
1790                         case 'F':
1791                                 /* &F -Set Factory-Defaults */
1792                                 p++;
1793                                 isdn_tty_reset_profile(m);
1794                                 isdn_tty_modem_reset_regs(m, 1);
1795                                 break;
1796                         case 'S':
1797                                 /* &S - Set Windowsize */
1798                                 p++;
1799                                 i = isdn_getnum(&p);
1800                                 if ((i > 0) && (i < 9))
1801                                         m->mdmreg[17] = i;
1802                                 else {
1803                                         isdn_tty_modem_result(4, info);
1804                                         return;
1805                                 }
1806                                 break;
1807                         case 'V':
1808                                 /* &V - Show registers */
1809                                 p++;
1810                                 for (i = 0; i < ISDN_MODEM_ANZREG; i++) {
1811                                         sprintf(rb, "S%d=%d%s", i, m->mdmreg[i], (i == 6) ? "\r\n" : " ");
1812                                         isdn_tty_at_cout(rb, info);
1813                                 }
1814                                 sprintf(rb, "\r\nEAZ/MSN: %s\r\n", strlen(m->msn) ? m->msn : "None");
1815                                 isdn_tty_at_cout(rb, info);
1816                                 break;
1817                         case 'W':
1818                                 /* &W - Write Profile */
1819                                 p++;
1820                                 switch (*p) {
1821                                 case '0':
1822                                         p++;
1823                                         modem_write_profile(m);
1824                                         break;
1825                                 default:
1826                                         isdn_tty_modem_result(4, info);
1827                                         return;
1828                                 }
1829                                 break;
1830                         case 'X':
1831                                 /* &X - Switch to BTX-Mode */
1832                                 p++;
1833                                 switch (*p) {
1834                                 case '0':
1835                                         p++;
1836                                         m->mdmreg[13] &= ~2;
1837                                         break;
1838                                 case '1':
1839                                         p++;
1840                                         m->mdmreg[13] |= 2;
1841                                         m->mdmreg[14] = 0;
1842                                         m->mdmreg[16] = 7;
1843                                         m->mdmreg[18] = 7;
1844                                         m->mdmreg[19] = 0;
1845                                         break;
1846                                 default:
1847                                         isdn_tty_modem_result(4, info);
1848                                         return;
1849                                 }
1850                                 break;
1851                         default:
1852                                 isdn_tty_modem_result(4, info);
1853                                 return;
1854                         }
1855                         break;
1856                 default:
1857                         isdn_tty_modem_result(4, info);
1858                         return;
1859                 }
1860         }
1861         isdn_tty_modem_result(0, info);
1862 }
1863 
1864 /* Need own toupper() because standard-toupper is not available
1865  * within modules.
1866  */
1867 #define my_toupper(c) (((c>='a')&&(c<='z'))?(c&0xdf):c)
1868 
1869 /*
1870  * Perform line-editing of AT-commands
1871  *
1872  * Parameters:
1873  *   p        inputbuffer
1874  *   count    length of buffer
1875  *   channel  index to line (minor-device)
1876  *   user     flag: buffer is in userspace
1877  */
1878 static int isdn_tty_edit_at(const char *p, int count, modem_info * info, int user)
     /* [previous][next][first][last][top][bottom][index][help] */
1879 {
1880         atemu *m = &dev->mdm.atmodem[info->line];
1881         int total = 0;
1882         u_char c;
1883         char eb[2];
1884         int cnt;
1885 
1886         for (cnt = count; cnt > 0; p++, cnt--) {
1887                 if (user)
1888                         c = get_fs_byte(p);
1889                 else
1890                         c = *p;
1891                 total++;
1892                 if (c == m->mdmreg[3] || c == m->mdmreg[4]) {
1893                         /* Separator (CR oder LF) */
1894                         m->mdmcmd[m->mdmcmdl] = 0;
1895                         if (m->mdmreg[12] & 4) {
1896                                 eb[0] = c;
1897                                 eb[1] = 0;
1898                                 isdn_tty_at_cout(eb, info);
1899                         }
1900                         if (m->mdmcmdl >= 2)
1901                                 isdn_tty_parse_at(info);
1902                         m->mdmcmdl = 0;
1903                         continue;
1904                 }
1905                 if (c == m->mdmreg[5] && m->mdmreg[5] < 128) {
1906                         /* Backspace-Funktion */
1907                         if ((m->mdmcmdl > 2) || (!m->mdmcmdl)) {
1908                                 if (m->mdmcmdl)
1909                                         m->mdmcmdl--;
1910                                 if (m->mdmreg[12] & 4)
1911                                         isdn_tty_at_cout("\b", info);
1912                         }
1913                         continue;
1914                 }
1915                 if (cmdchar(c)) {
1916                         if (m->mdmreg[12] & 4) {
1917                                 eb[0] = c;
1918                                 eb[1] = 0;
1919                                 isdn_tty_at_cout(eb, info);
1920                         }
1921                         if (m->mdmcmdl < 255) {
1922                                 c = my_toupper(c);
1923                                 switch (m->mdmcmdl) {
1924                                 case 0:
1925                                         if (c == 'A')
1926                                                 m->mdmcmd[m->mdmcmdl++] = c;
1927                                         break;
1928                                 case 1:
1929                                         if (c == 'T')
1930                                                 m->mdmcmd[m->mdmcmdl++] = c;
1931                                         break;
1932                                 default:
1933                                         m->mdmcmd[m->mdmcmdl++] = c;
1934                                 }
1935                         }
1936                 }
1937         }
1938         return total;
1939 }
1940 
1941 /*
1942  * Switch all modem-channels who are online and got a valid
1943  * escape-sequence 1.5 seconds ago, to command-mode.
1944  * This function is called every second via timer-interrupt from within 
1945  * timer-dispatcher isdn_timer_function()
1946  */
1947 void isdn_tty_modem_escape(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1948 {
1949         int ton = 0;
1950         int i;
1951         int midx;
1952 
1953         for (i = 0; i < ISDN_MAX_CHANNELS; i++)
1954                 if (USG_MODEM(dev->usage[i]))
1955                         if ((midx = dev->m_idx[i]) >= 0)
1956                                 if (dev->mdm.online[midx]) {
1957                                         ton = 1;
1958                                         if ((dev->mdm.atmodem[midx].pluscount == 3) &&
1959                                             ((jiffies - dev->mdm.atmodem[midx].lastplus) > PLUSWAIT2)) {
1960                                                 dev->mdm.atmodem[midx].pluscount = 0;
1961                                                 dev->mdm.online[midx] = 0;
1962                                                 isdn_tty_modem_result(0, &dev->mdm.info[midx]);
1963                                         }
1964                                 }
1965         isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, ton);
1966 }
1967 
1968 /*
1969  * Put a RING-message to all modem-channels who have the RI-bit set.
1970  * This function is called every second via timer-interrupt from within 
1971  * timer-dispatcher isdn_timer_function()
1972  */
1973 void isdn_tty_modem_ring(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1974 {
1975         int ton = 0;
1976         int i;
1977         int midx;
1978 
1979         for (i = 0; i < ISDN_MAX_CHANNELS; i++)
1980                 if (USG_MODEM(dev->usage[i]))
1981                         if ((midx = dev->m_idx[i]) >= 0)
1982                                 if (dev->mdm.msr[midx] & UART_MSR_RI) {
1983                                         ton = 1;
1984                                         isdn_tty_modem_result(2, &dev->mdm.info[midx]);
1985                                 }
1986         isdn_timer_ctrl(ISDN_TIMER_MODEMRING, ton);
1987 }
1988 
1989 void isdn_tty_modem_xmit(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1990 {
1991         int ton = 0;
1992         int i;
1993         int midx;
1994         char *bufptr;
1995         int buflen;
1996 
1997         for (i = 0; i < ISDN_MAX_CHANNELS; i++)
1998                 if (USG_MODEM(dev->usage[i]))
1999                         if ((midx = dev->m_idx[i]) >= 0)
2000                                 if (dev->mdm.online[midx]) {
2001                                         modem_info *info = &(dev->mdm.info[midx]);
2002                                         ulong flags;
2003 
2004                                         save_flags(flags);
2005                                         cli();
2006                                         if (info->xmit_count > 0) {
2007                                                 struct tty_struct *tty = info->tty;
2008                                                 ton = 1;
2009 #if 0
2010                                                 printk(KERN_DEBUG "WB2: %d\n", info->xmit_count);
2011 #endif
2012                                                 bufptr = info->xmit_buf;
2013                                                 buflen = info->xmit_count;
2014                                                 if (dev->mdm.atmodem[midx].mdmreg[13] & 2) {
2015                                                         /* Add T.70 simplified header */
2016 #ifdef ISDN_DEBUG_MODEM_DUMP
2017                                                         isdn_dumppkt("T70pack3:", bufptr, buflen, 40);
2018 #endif
2019                                                         bufptr -= 4;
2020                                                         buflen += 4;
2021                                                         memcpy(bufptr, "\1\0\1\0", 4);
2022 #ifdef ISDN_DEBUG_MODEM_DUMP
2023                                                         isdn_dumppkt("T70pack4:", bufptr, buflen, 40);
2024 #endif
2025                                                 }
2026                                                 if (isdn_writebuf_stub(info->isdn_driver, info->isdn_channel,
2027                                                                        bufptr, buflen, 0) > 0) {
2028                                                         info->xmit_count = 0;
2029                                                         info->xmit_size = dev->mdm.atmodem[midx].mdmreg[16] * 16;
2030 #if FUTURE
2031                                                         info->send_outstanding++;
2032                                                         dev->mdm.msr[midx] &= ~UART_MSR_CTS;
2033 #endif
2034                                                         if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
2035                                                             tty->ldisc.write_wakeup)
2036                                                                 (tty->ldisc.write_wakeup) (tty);
2037                                                         wake_up_interruptible(&tty->write_wait);
2038                                                 }
2039                                         }
2040                                         restore_flags(flags);
2041                                 }
2042         isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, ton);
2043 }
2044 
2045 #if FUTURE
2046 /*
2047  * A packet has been output successfully.
2048  * Search the tty-devices for an appropriate device, decrement its
2049  * counter for outstanding packets, and set CTS if this counter reaches 0.
2050  */
2051 void isdn_tty_bsent(int drv, int chan)
     /* [previous][next][first][last][top][bottom][index][help] */
2052 {
2053         int i;
2054         ulong flags;
2055 
2056         save_flags(flags);
2057         cli();
2058         for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
2059                 modem_info *info = &dev->mdm.info[i];
2060                 if ((info->isdn_driver == drv) &&
2061                     (info->isdn_channel == chan) &&
2062                     (info->send_outstanding)) {
2063                         if (!(--info->send_outstanding))
2064                                 dev->mdm.msr[i] |= UART_MSR_CTS;
2065                         restore_flags(flags);
2066                         return;
2067                 }
2068         }
2069         restore_flags(flags);
2070         return;
2071 }
2072 #endif                          /* FUTURE */

/* [previous][next][first][last][top][bottom][index][help] */