pre-2.3.4..
[davej-history.git] / drivers / isdn / isdn_tty.c
blobbfa895424886acc7c8aa5f4bc19ccfc0f21072b5
1 /* $Id: isdn_tty.c,v 1.63 1999/04/12 12:33:39 fritz Exp $
3 * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
5 * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
6 * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
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.
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.
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.
22 * $Log: isdn_tty.c,v $
23 * Revision 1.63 1999/04/12 12:33:39 fritz
24 * Changes from 2.0 tree.
26 * Revision 1.62 1999/03/02 12:04:48 armin
27 * -added ISDN_STAT_ADDCH to increase supported channels after
28 * register_isdn().
29 * -ttyI now goes on-hook on ATZ when B-Ch is connected.
30 * -added timer-function for register S7 (Wait for Carrier).
31 * -analog modem (ISDN_PROTO_L2_MODEM) implementations.
32 * -on L2_MODEM a string will be appended to the CONNECT-Message,
33 * which is provided by the HL-Driver in parm.num in ISDN_STAT_BCONN.
34 * -variable "dialing" used for ATA also, for interrupting call
35 * establishment and register S7.
37 * Revision 1.61 1999/01/27 22:53:11 he
38 * minor updates (spellings, jiffies wrap around in isdn_tty)
40 * Revision 1.60 1998/11/15 23:57:32 keil
41 * changes for 2.1.127
43 * Revision 1.59 1998/08/20 13:50:15 keil
44 * More support for hybrid modem (not working yet)
46 * Revision 1.58 1998/07/26 18:48:45 armin
47 * Added silence detection in voice receive mode.
49 * Revision 1.57 1998/06/26 15:12:36 fritz
50 * Added handling of STAT_ICALL with incomplete CPN.
51 * Added AT&L for ttyI emulator.
52 * Added more locking stuff in tty_write.
54 * Revision 1.56 1998/06/18 23:31:51 fritz
55 * Replaced cli()/restore_flags() in isdn_tty_write() by locking.
56 * Removed direct-senddown feature in isdn_tty_write because it will
57 * never succeed with locking and is useless anyway.
59 * Revision 1.55 1998/06/17 19:50:55 he
60 * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay())
61 * brute force fix to avoid Ugh's in isdn_tty_write()
62 * cleaned up some dead code
64 * Revision 1.54 1998/06/07 00:20:13 fritz
65 * abc cleanup.
67 * Revision 1.53 1998/06/02 12:10:16 detabc
68 * wegen einer einstweiliger verfuegung gegen DW ist zur zeit
69 * die abc-extension bis zur klaerung der rechtslage nicht verfuegbar
71 * Revision 1.52 1998/03/19 13:18:21 keil
72 * Start of a CAPI like interface for supplementary Service
73 * first service: SUSPEND
75 * Revision 1.51 1998/03/08 14:26:11 detabc
76 * change kfree_skb to dev_kfree_skb
77 * remove SET_SKB_FREE
79 * Revision 1.50 1998/03/08 13:14:28 detabc
80 * abc-extension support for kernels > 2.1.x
81 * first try (sorry experimental)
83 * Revision 1.49 1998/03/08 00:01:59 fritz
84 * Bugfix: Lowlevel module usage and channel usage were not
85 * reset on NO DCHANNEL.
87 * Revision 1.48 1998/03/07 12:28:15 tsbogend
88 * fixed kernel unaligned traps on Linux/Alpha
90 * Revision 1.47 1998/02/22 19:44:14 fritz
91 * Bugfixes and improvements regarding V.110, V.110 now running.
93 * Revision 1.46 1998/02/20 17:23:08 fritz
94 * Changes for recent kernels.
95 * Merged in contributions by Thomas Pfeiffer (V.110 T.70+ Extended FAX stuff)
96 * Added symbolic constants for Modem-Registers.
98 * Revision 1.45 1998/01/31 22:07:49 keil
99 * changes for newer kernels
101 * Revision 1.44 1998/01/31 19:30:02 calle
102 * Merged changes from and for 2.1.82, not tested only compiled ...
104 * Revision 1.43 1997/10/09 21:29:04 fritz
105 * New HL<->LL interface:
106 * New BSENT callback with nr. of bytes included.
107 * Sending without ACK.
108 * New L1 error status (not yet in use).
109 * Cleaned up obsolete structures.
110 * Implemented Cisco-SLARP.
111 * Changed local net-interface data to be dynamically allocated.
112 * Removed old 2.0 compatibility stuff.
114 * Revision 1.42 1997/10/01 09:20:49 fritz
115 * Removed old compatibility stuff for 2.0.X kernels.
116 * From now on, this code is for 2.1.X ONLY!
117 * Old stuff is still in the separate branch.
119 * Revision 1.41 1997/05/27 15:17:31 fritz
120 * Added changes for recent 2.1.x kernels:
121 * changed return type of isdn_close
122 * queue_task_* -> queue_task
123 * clear/set_bit -> test_and_... where apropriate.
124 * changed type of hard_header_cache parameter.
126 * Revision 1.40 1997/03/24 22:55:27 fritz
127 * Added debug code for status callbacks.
129 * Revision 1.39 1997/03/21 18:25:56 fritz
130 * Corrected CTS handling.
132 * Revision 1.38 1997/03/07 12:13:35 fritz
133 * Bugfix: Send audio in adpcm format was broken.
134 * Bugfix: CTS handling was wrong.
136 * Revision 1.37 1997/03/07 01:37:34 fritz
137 * Bugfix: Did not compile with CONFIG_ISDN_AUDIO disabled.
138 * Bugfix: isdn_tty_tint() did not handle lowlevel errors correctly.
139 * Bugfix: conversion was wrong when sending ulaw audio.
140 * Added proper ifdef's for CONFIG_ISDN_AUDIO
142 * Revision 1.36 1997/03/04 21:41:55 fritz
143 * Fix: Excessive stack usage of isdn_tty_senddown()
144 * and isdn_tty_end_vrx() could lead to problems.
146 * Revision 1.35 1997/03/02 19:05:52 fritz
147 * Bugfix: Avoid recursion.
149 * Revision 1.34 1997/03/02 14:29:22 fritz
150 * More ttyI related cleanup.
152 * Revision 1.33 1997/02/28 02:32:45 fritz
153 * Cleanup: Moved some tty related stuff from isdn_common.c
154 * to isdn_tty.c
155 * Bugfix: Bisync protocol did not behave like documented.
157 * Revision 1.32 1997/02/23 15:43:03 fritz
158 * Small change in handling of incoming calls
159 * documented in newest version of ttyI.4
161 * Revision 1.31 1997/02/21 13:05:57 fritz
162 * Bugfix: Remote hangup did not set location-info on ttyI's
164 * Revision 1.30 1997/02/18 09:41:05 fritz
165 * Added support for bitwise access to modem registers (ATSx.y=n, ATSx.y?).
166 * Beautified output of AT&V.
168 * Revision 1.29 1997/02/16 12:11:51 fritz
169 * Added S13,Bit4 option.
171 * Revision 1.28 1997/02/10 22:07:08 fritz
172 * Added 2 modem registers for numbering plan and screening info.
174 * Revision 1.27 1997/02/10 21:31:14 fritz
175 * Changed setup-interface (incoming and outgoing).
177 * Revision 1.26 1997/02/10 20:12:48 fritz
178 * Changed interface for reporting incoming calls.
180 * Revision 1.25 1997/02/03 23:04:30 fritz
181 * Reformatted according CodingStyle.
182 * skb->free stuff replaced by macro.
183 * Finished full-duplex audio.
185 * Revision 1.24 1997/01/14 01:32:42 fritz
186 * Changed audio receive not to rely on skb->users and skb->lock.
187 * Added ATI2 and related variables.
188 * Started adding full-duplex audio capability.
190 * Revision 1.23 1996/10/22 23:14:02 fritz
191 * Changes for compatibility to 2.0.X and 2.1.X kernels.
193 * Revision 1.22 1996/10/19 18:56:43 fritz
194 * ATZ did not change the xmitbuf size.
196 * Revision 1.21 1996/06/24 17:40:28 fritz
197 * Bugfix: Did not compile without CONFIG_ISDN_AUDIO
199 * Revision 1.20 1996/06/15 14:59:39 fritz
200 * Fixed isdn_tty_tint() to handle partially sent
201 * sk_buffs.
203 * Revision 1.19 1996/06/12 15:53:56 fritz
204 * Bugfix: AT+VTX and AT+VRX could be executed without
205 * having a connection.
206 * Missing check for NULL tty in isdn_tty_flush_buffer().
208 * Revision 1.18 1996/06/07 11:17:33 tsbogend
209 * added missing #ifdef CONFIG_ISDN_AUDIO to make compiling without
210 * audio support possible
212 * Revision 1.17 1996/06/06 14:55:47 fritz
213 * Changed to support DTMF decoding on audio playback also.
214 * Bugfix: Added check for invalid info->isdn_driver in
215 * isdn_tty_senddown().
216 * Clear ncarrier flag on last close() of a tty.
218 * Revision 1.16 1996/06/05 02:24:12 fritz
219 * Added DTMF decoder for audio mode.
221 * Revision 1.15 1996/06/03 20:35:01 fritz
222 * Fixed typos.
224 * Revision 1.14 1996/06/03 20:12:19 fritz
225 * Fixed typos.
226 * Added call to write_wakeup via isdn_tty_flush_buffer()
227 * in isdn_tty_modem_hup().
229 * Revision 1.13 1996/05/31 01:33:29 fritz
230 * Changed buffering due to bad performance with mgetty.
231 * Now sk_buff is delayed allocated in isdn_tty_senddown
232 * using xmit_buff like in standard serial driver.
233 * Fixed module locking.
234 * Added DLE-DC4 handling in voice mode.
236 * Revision 1.12 1996/05/19 01:34:40 fritz
237 * Bugfix: ATS returned error.
238 * Register 20 made readonly.
240 * Revision 1.11 1996/05/18 01:37:03 fritz
241 * Added spelling corrections and some minor changes
242 * to stay in sync with kernel.
244 * Revision 1.10 1996/05/17 03:51:49 fritz
245 * Changed DLE handling for audio receive.
247 * Revision 1.9 1996/05/11 21:52:07 fritz
248 * Changed queue management to use sk_buffs.
250 * Revision 1.8 1996/05/10 08:49:43 fritz
251 * Checkin before major changes of tty-code.
253 * Revision 1.7 1996/05/07 09:15:09 fritz
254 * Reorganized and general cleanup.
255 * Bugfixes:
256 * - Audio-transmit working now.
257 * - "NO CARRIER" now reported, when hanging up with DTR low.
258 * - Corrected CTS handling.
260 * Revision 1.6 1996/05/02 03:59:25 fritz
261 * Bugfixes:
262 * - On dialout, layer-2 setup had been incomplete
263 * when using new auto-layer2 feature.
264 * - On hangup, "NO CARRIER" message sometimes missing.
266 * Revision 1.5 1996/04/30 21:05:25 fritz
267 * Test commit
269 * Revision 1.4 1996/04/20 16:39:54 fritz
270 * Changed all io to go through generic routines in isdn_common.c
271 * Fixed a real ugly bug in modem-emulator: 'ATA' had been accepted
272 * even when a call has been cancelled from the remote machine.
274 * Revision 1.3 1996/02/11 02:12:32 fritz
275 * Bugfixes according to similar fixes in standard serial.c of kernel.
277 * Revision 1.2 1996/01/22 05:12:25 fritz
278 * replaced my_atoi by simple_strtoul
280 * Revision 1.1 1996/01/09 04:13:18 fritz
281 * Initial revision
284 #undef ISDN_TTY_STAT_DEBUG
286 #define __NO_VERSION__
287 #include <linux/config.h>
288 #include <linux/module.h>
289 #include <linux/isdn.h>
290 #include "isdn_common.h"
291 #include "isdn_tty.h"
292 #ifdef CONFIG_ISDN_AUDIO
293 #include "isdn_audio.h"
294 #define VBUF 0x3e0
295 #define VBUFX (VBUF/16)
296 #endif
298 #define FIX_FILE_TRANSFER
300 /* Prototypes */
302 static int isdn_tty_edit_at(const char *, int, modem_info *, int);
303 static void isdn_tty_check_esc(const u_char *, u_char, int, int *, int *, int);
304 static void isdn_tty_modem_reset_regs(modem_info *, int);
305 static void isdn_tty_cmd_ATA(modem_info *);
306 static void isdn_tty_at_cout(char *, modem_info *);
307 static void isdn_tty_flush_buffer(struct tty_struct *);
308 static void isdn_tty_modem_result(int, modem_info *);
309 #ifdef CONFIG_ISDN_AUDIO
310 static int isdn_tty_countDLE(unsigned char *, int);
311 #endif
313 /* Leave this unchanged unless you know what you do! */
314 #define MODEM_PARANOIA_CHECK
315 #define MODEM_DO_RESTART
317 static char *isdn_ttyname_ttyI = "ttyI";
318 static char *isdn_ttyname_cui = "cui";
319 static int bit2si[8] =
320 {1, 5, 7, 7, 7, 7, 7, 7};
321 static int si2bit[8] =
322 {4, 1, 4, 4, 4, 4, 4, 4};
324 char *isdn_tty_revision = "$Revision: 1.63 $";
326 #define DLE 0x10
327 #define ETX 0x03
328 #define DC4 0x14
331 * Definition of some special Registers of AT-Emulator
333 #define REG_RINGATA 0
334 #define REG_RINGCNT 1
335 #define REG_ESC 2
336 #define REG_CR 3
337 #define REG_LF 4
338 #define REG_BS 5
340 #define REG_WAITC 7
342 #define REG_RESP 12
343 #define BIT_RESP 1
344 #define REG_RESPNUM 12
345 #define BIT_RESPNUM 2
346 #define REG_ECHO 12
347 #define BIT_ECHO 4
348 #define REG_DCD 12
349 #define BIT_DCD 8
350 #define REG_CTS 12
351 #define BIT_CTS 16
352 #define REG_DTRR 12
353 #define BIT_DTRR 32
354 #define REG_DSR 12
355 #define BIT_DSR 64
356 #define REG_CPPP 12
357 #define BIT_CPPP 128
359 #define REG_T70 13
360 #define BIT_T70 2
361 #define BIT_T70_EXT 32
362 #define REG_DTRHUP 13
363 #define BIT_DTRHUP 4
364 #define REG_RESPXT 13
365 #define BIT_RESPXT 8
366 #define REG_CIDONCE 13
367 #define BIT_CIDONCE 16
368 #define REG_RUNG 13
369 #define BIT_RUNG 64
370 #define REG_RESRXT 13
371 #define BIT_RESRXT 128
373 #define REG_L2PROT 14
374 #define REG_L3PROT 15
375 #define REG_PSIZE 16
376 #define REG_WSIZE 17
377 #define REG_SI1 18
378 #define REG_SI2 19
379 #define REG_SI1I 20
380 #define REG_PLAN 21
381 #define REG_SCREEN 22
383 /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
384 * to stuff incoming data directly into a tty's flip-buffer. This
385 * is done to speed up tty-receiving if the receive-queue is empty.
386 * This routine MUST be called with interrupts off.
387 * Return:
388 * 1 = Success
389 * 0 = Failure, data has to be buffered and later processed by
390 * isdn_tty_readmodem().
392 static int
393 isdn_tty_try_read(modem_info * info, struct sk_buff *skb)
395 int c;
396 int len;
397 struct tty_struct *tty;
399 if (info->online) {
400 if ((tty = info->tty)) {
401 if (info->mcr & UART_MCR_RTS) {
402 c = TTY_FLIPBUF_SIZE - tty->flip.count;
403 len = skb->len
404 #ifdef CONFIG_ISDN_AUDIO
405 + ISDN_AUDIO_SKB_DLECOUNT(skb)
406 #endif
408 if (c >= len) {
409 #ifdef CONFIG_ISDN_AUDIO
410 if (ISDN_AUDIO_SKB_DLECOUNT(skb))
411 while (skb->len--) {
412 if (*skb->data == DLE)
413 tty_insert_flip_char(tty, DLE, 0);
414 tty_insert_flip_char(tty, *skb->data++, 0);
415 } else {
416 #endif
417 memcpy(tty->flip.char_buf_ptr,
418 skb->data, len);
419 tty->flip.count += len;
420 tty->flip.char_buf_ptr += len;
421 memset(tty->flip.flag_buf_ptr, 0, len);
422 tty->flip.flag_buf_ptr += len;
423 #ifdef CONFIG_ISDN_AUDIO
425 #endif
426 if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP)
427 tty->flip.flag_buf_ptr[len - 1] = 0xff;
428 queue_task(&tty->flip.tqueue, &tq_timer);
429 kfree_skb(skb);
430 return 1;
435 return 0;
438 /* isdn_tty_readmodem() is called periodically from within timer-interrupt.
439 * It tries getting received data from the receive queue an stuff it into
440 * the tty's flip-buffer.
442 void
443 isdn_tty_readmodem(void)
445 int resched = 0;
446 int midx;
447 int i;
448 int c;
449 int r;
450 ulong flags;
451 struct tty_struct *tty;
452 modem_info *info;
454 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
455 if ((midx = dev->m_idx[i]) >= 0) {
456 info = &dev->mdm.info[midx];
457 if (info->online) {
458 r = 0;
459 #ifdef CONFIG_ISDN_AUDIO
460 isdn_audio_eval_dtmf(info);
461 if ((info->vonline & 1) && (info->emu.vpar[1]))
462 isdn_audio_eval_silence(info);
463 #endif
464 if ((tty = info->tty)) {
465 if (info->mcr & UART_MCR_RTS) {
466 c = TTY_FLIPBUF_SIZE - tty->flip.count;
467 if (c > 0) {
468 save_flags(flags);
469 cli();
470 r = isdn_readbchan(info->isdn_driver, info->isdn_channel,
471 tty->flip.char_buf_ptr,
472 tty->flip.flag_buf_ptr, c, 0);
473 /* CISCO AsyncPPP Hack */
474 if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
475 memset(tty->flip.flag_buf_ptr, 0, r);
476 tty->flip.count += r;
477 tty->flip.flag_buf_ptr += r;
478 tty->flip.char_buf_ptr += r;
479 if (r)
480 queue_task(&tty->flip.tqueue, &tq_timer);
481 restore_flags(flags);
483 } else
484 r = 1;
485 } else
486 r = 1;
487 if (r) {
488 info->rcvsched = 0;
489 resched = 1;
490 } else
491 info->rcvsched = 1;
495 if (!resched)
496 isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0);
500 isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
502 ulong flags;
503 int midx;
504 #ifdef CONFIG_ISDN_AUDIO
505 int ifmt;
506 #endif
507 modem_info *info;
509 if ((midx = dev->m_idx[i]) < 0) {
510 /* if midx is invalid, packet is not for tty */
511 return 0;
513 info = &dev->mdm.info[midx];
514 #ifdef CONFIG_ISDN_AUDIO
515 ifmt = 1;
517 if (info->vonline)
518 isdn_audio_calc_dtmf(info, skb->data, skb->len, ifmt);
519 if ((info->vonline & 1) && (info->emu.vpar[1]))
520 isdn_audio_calc_silence(info, skb->data, skb->len, ifmt);
521 #endif
522 if ((info->online < 2)
523 #ifdef CONFIG_ISDN_AUDIO
524 && (!(info->vonline & 1))
525 #endif
527 /* If Modem not listening, drop data */
528 kfree_skb(skb);
529 return 1;
531 if (info->emu.mdmreg[REG_T70] & BIT_T70) {
532 if (info->emu.mdmreg[REG_T70] & BIT_T70_EXT) {
533 /* T.70 decoding: throw away the T.70 header (2 or 4 bytes) */
534 if (skb->data[0] == 3) /* pure data packet -> 4 byte headers */
535 skb_pull(skb, 4);
536 else
537 if (skb->data[0] == 1) /* keepalive packet -> 2 byte hdr */
538 skb_pull(skb, 2);
539 } else
540 /* T.70 decoding: Simply throw away the T.70 header (4 bytes) */
541 if ((skb->data[0] == 1) && ((skb->data[1] == 0) || (skb->data[1] == 1)))
542 skb_pull(skb, 4);
544 #ifdef CONFIG_ISDN_AUDIO
545 if (skb_headroom(skb) < sizeof(isdn_audio_skb)) {
546 printk(KERN_WARNING
547 "isdn_audio: insufficient skb_headroom, dropping\n");
548 kfree_skb(skb);
549 return 1;
551 ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
552 ISDN_AUDIO_SKB_LOCK(skb) = 0;
553 if (info->vonline & 1) {
554 /* voice conversion/compression */
555 switch (info->emu.vpar[3]) {
556 case 2:
557 case 3:
558 case 4:
559 /* adpcm
560 * Since compressed data takes less
561 * space, we can overwrite the buffer.
563 skb_trim(skb, isdn_audio_xlaw2adpcm(info->adpcmr,
564 ifmt,
565 skb->data,
566 skb->data,
567 skb->len));
568 break;
569 case 5:
570 /* a-law */
571 if (!ifmt)
572 isdn_audio_ulaw2alaw(skb->data, skb->len);
573 break;
574 case 6:
575 /* u-law */
576 if (ifmt)
577 isdn_audio_alaw2ulaw(skb->data, skb->len);
578 break;
580 ISDN_AUDIO_SKB_DLECOUNT(skb) =
581 isdn_tty_countDLE(skb->data, skb->len);
583 #endif
584 /* Try to deliver directly via tty-flip-buf if queue is empty */
585 save_flags(flags);
586 cli();
587 if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
588 if (isdn_tty_try_read(info, skb)) {
589 restore_flags(flags);
590 return 1;
592 /* Direct deliver failed or queue wasn't empty.
593 * Queue up for later dequeueing via timer-irq.
595 __skb_queue_tail(&dev->drv[di]->rpqueue[channel], skb);
596 dev->drv[di]->rcvcount[channel] +=
597 (skb->len
598 #ifdef CONFIG_ISDN_AUDIO
599 + ISDN_AUDIO_SKB_DLECOUNT(skb)
600 #endif
602 restore_flags(flags);
603 /* Schedule dequeuing */
604 if ((dev->modempoll) && (info->rcvsched))
605 isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
606 return 1;
609 void
610 isdn_tty_cleanup_xmit(modem_info * info)
612 struct sk_buff *skb;
613 unsigned long flags;
615 save_flags(flags);
616 cli();
617 if (skb_queue_len(&info->xmit_queue))
618 while ((skb = skb_dequeue(&info->xmit_queue)))
619 kfree_skb(skb);
620 #ifdef CONFIG_ISDN_AUDIO
621 if (skb_queue_len(&info->dtmf_queue))
622 while ((skb = skb_dequeue(&info->dtmf_queue)))
623 kfree_skb(skb);
624 #endif
625 restore_flags(flags);
628 static void
629 isdn_tty_tint(modem_info * info)
631 struct sk_buff *skb = skb_dequeue(&info->xmit_queue);
632 int len,
633 slen;
635 if (!skb)
636 return;
637 len = skb->len;
638 if ((slen = isdn_writebuf_skb_stub(info->isdn_driver,
639 info->isdn_channel, 1, skb)) == len) {
640 struct tty_struct *tty = info->tty;
641 info->send_outstanding++;
642 info->msr &= ~UART_MSR_CTS;
643 info->lsr &= ~UART_LSR_TEMT;
644 if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
645 tty->ldisc.write_wakeup)
646 (tty->ldisc.write_wakeup) (tty);
647 wake_up_interruptible(&tty->write_wait);
648 return;
650 if (slen < 0) {
651 /* Error: no channel, already shutdown, or wrong parameter */
652 dev_kfree_skb(skb);
653 return;
655 skb_queue_head(&info->xmit_queue, skb);
658 #ifdef CONFIG_ISDN_AUDIO
659 static int
660 isdn_tty_countDLE(unsigned char *buf, int len)
662 int count = 0;
664 while (len--)
665 if (*buf++ == DLE)
666 count++;
667 return count;
670 /* This routine is called from within isdn_tty_write() to perform
671 * DLE-decoding when sending audio-data.
673 static int
674 isdn_tty_handleDLEdown(modem_info * info, atemu * m, int len)
676 unsigned char *p = &info->xmit_buf[info->xmit_count];
677 int count = 0;
679 while (len > 0) {
680 if (m->lastDLE) {
681 m->lastDLE = 0;
682 switch (*p) {
683 case DLE:
684 /* Escape code */
685 if (len > 1)
686 memmove(p, p + 1, len - 1);
687 p--;
688 count++;
689 break;
690 case ETX:
691 /* End of data */
692 info->vonline |= 4;
693 return count;
694 case DC4:
695 /* Abort RX */
696 info->vonline &= ~1;
697 #ifdef ISDN_DEBUG_MODEM_VOICE
698 printk(KERN_DEBUG
699 "DLEdown: got DLE-DC4, send DLE-ETX on ttyI%d\n",
700 info->line);
701 #endif
702 isdn_tty_at_cout("\020\003", info);
703 if (!info->vonline) {
704 #ifdef ISDN_DEBUG_MODEM_VOICE
705 printk(KERN_DEBUG
706 "DLEdown: send VCON on ttyI%d\n",
707 info->line);
708 #endif
709 isdn_tty_at_cout("\r\nVCON\r\n", info);
711 /* Fall through */
712 case 'q':
713 case 's':
714 /* Silence */
715 if (len > 1)
716 memmove(p, p + 1, len - 1);
717 p--;
718 break;
720 } else {
721 if (*p == DLE)
722 m->lastDLE = 1;
723 else
724 count++;
726 p++;
727 len--;
729 if (len < 0) {
730 printk(KERN_WARNING "isdn_tty: len<0 in DLEdown\n");
731 return 0;
733 return count;
736 /* This routine is called from within isdn_tty_write() when receiving
737 * audio-data. It interrupts receiving, if an character other than
738 * ^S or ^Q is sent.
740 static int
741 isdn_tty_end_vrx(const char *buf, int c, int from_user)
743 char ch;
745 while (c--) {
746 if (from_user)
747 get_user(ch, buf);
748 else
749 ch = *buf;
750 if ((ch != 0x11) && (ch != 0x13))
751 return 1;
752 buf++;
754 return 0;
757 static int voice_cf[7] =
758 {0, 0, 4, 3, 2, 0, 0};
760 #endif /* CONFIG_ISDN_AUDIO */
762 /* isdn_tty_senddown() is called either directly from within isdn_tty_write()
763 * or via timer-interrupt from within isdn_tty_modem_xmit(). It pulls
764 * outgoing data from the tty's xmit-buffer, handles voice-decompression or
765 * T.70 if necessary, and finally queues it up for sending via isdn_tty_tint.
767 static void
768 isdn_tty_senddown(modem_info * info)
770 int buflen;
771 int skb_res;
772 #ifdef CONFIG_ISDN_AUDIO
773 int audio_len;
774 #endif
775 struct sk_buff *skb;
777 #ifdef CONFIG_ISDN_AUDIO
778 if (info->vonline & 4) {
779 info->vonline &= ~6;
780 if (!info->vonline) {
781 #ifdef ISDN_DEBUG_MODEM_VOICE
782 printk(KERN_DEBUG
783 "senddown: send VCON on ttyI%d\n",
784 info->line);
785 #endif
786 isdn_tty_at_cout("\r\nVCON\r\n", info);
789 #endif
790 if (!(buflen = info->xmit_count))
791 return;
792 if ((info->emu.mdmreg[REG_CTS] & BIT_CTS) != 0)
793 info->msr &= ~UART_MSR_CTS;
794 info->lsr &= ~UART_LSR_TEMT;
795 /* info->xmit_count is modified here and in isdn_tty_write().
796 * So we return here if isdn_tty_write() is in the
797 * critical section.
799 atomic_inc(&info->xmit_lock);
800 if (!(atomic_dec_and_test(&info->xmit_lock)))
801 return;
802 if (info->isdn_driver < 0) {
803 info->xmit_count = 0;
804 return;
806 skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4;
807 #ifdef CONFIG_ISDN_AUDIO
808 if (info->vonline & 2)
809 audio_len = buflen * voice_cf[info->emu.vpar[3]];
810 else
811 audio_len = 0;
812 skb = dev_alloc_skb(skb_res + buflen + audio_len);
813 #else
814 skb = dev_alloc_skb(skb_res + buflen);
815 #endif
816 if (!skb) {
817 printk(KERN_WARNING
818 "isdn_tty: Out of memory in ttyI%d senddown\n",
819 info->line);
820 return;
822 skb_reserve(skb, skb_res);
823 memcpy(skb_put(skb, buflen), info->xmit_buf, buflen);
824 info->xmit_count = 0;
825 #ifdef CONFIG_ISDN_AUDIO
826 if (info->vonline & 2) {
827 /* For now, ifmt is fixed to 1 (alaw), since this
828 * is used with ISDN everywhere in the world, except
829 * US, Canada and Japan.
830 * Later, when US-ISDN protocols are implemented,
831 * this setting will depend on the D-channel protocol.
833 int ifmt = 1;
835 /* voice conversion/decompression */
836 switch (info->emu.vpar[3]) {
837 case 2:
838 case 3:
839 case 4:
840 /* adpcm, compatible to ZyXel 1496 modem
841 * with ROM revision 6.01
843 audio_len = isdn_audio_adpcm2xlaw(info->adpcms,
844 ifmt,
845 skb->data,
846 skb_put(skb, audio_len),
847 buflen);
848 skb_pull(skb, buflen);
849 skb_trim(skb, audio_len);
850 break;
851 case 5:
852 /* a-law */
853 if (!ifmt)
854 isdn_audio_alaw2ulaw(skb->data,
855 buflen);
856 break;
857 case 6:
858 /* u-law */
859 if (ifmt)
860 isdn_audio_ulaw2alaw(skb->data,
861 buflen);
862 break;
865 #endif /* CONFIG_ISDN_AUDIO */
866 if (info->emu.mdmreg[REG_T70] & BIT_T70) {
867 /* Add T.70 simplified header */
868 if (info->emu.mdmreg[REG_T70] & BIT_T70_EXT)
869 memcpy(skb_push(skb, 2), "\1\0", 2);
870 else
871 memcpy(skb_push(skb, 4), "\1\0\1\0", 4);
873 skb_queue_tail(&info->xmit_queue, skb);
876 /************************************************************
878 * Modem-functions
880 * mostly "stolen" from original Linux-serial.c and friends.
882 ************************************************************/
884 /* The next routine is called once from within timer-interrupt
885 * triggered within isdn_tty_modem_ncarrier(). It calls
886 * isdn_tty_modem_result() to stuff a "NO CARRIER" Message
887 * into the tty's flip-buffer.
889 static void
890 isdn_tty_modem_do_ncarrier(unsigned long data)
892 modem_info *info = (modem_info *) data;
893 isdn_tty_modem_result(3, info);
896 /* Next routine is called, whenever the DTR-signal is raised.
897 * It checks the ncarrier-flag, and triggers the above routine
898 * when necessary. The ncarrier-flag is set, whenever DTR goes
899 * low.
901 static void
902 isdn_tty_modem_ncarrier(modem_info * info)
904 if (info->ncarrier) {
905 info->nc_timer.expires = jiffies + HZ;
906 info->nc_timer.function = isdn_tty_modem_do_ncarrier;
907 info->nc_timer.data = (unsigned long) info;
908 add_timer(&info->nc_timer);
912 /* isdn_tty_dial() performs dialing of a tty an the necessary
913 * setup of the lower levels before that.
915 static void
916 isdn_tty_dial(char *n, modem_info * info, atemu * m)
918 int usg = ISDN_USAGE_MODEM;
919 int si = 7;
920 int l2 = m->mdmreg[REG_L2PROT];
921 isdn_ctrl cmd;
922 ulong flags;
923 int i;
924 int j;
926 for (j = 7; j >= 0; j--)
927 if (m->mdmreg[REG_SI1] & (1 << j)) {
928 si = bit2si[j];
929 break;
931 #ifdef CONFIG_ISDN_AUDIO
932 if ((si == 1) && (l2 != ISDN_PROTO_L2_MODEM)) {
933 l2 = ISDN_PROTO_L2_TRANS;
934 usg = ISDN_USAGE_VOICE;
936 #endif
937 m->mdmreg[REG_SI1I] = si2bit[si];
938 save_flags(flags);
939 cli();
940 i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1);
941 if (i < 0) {
942 restore_flags(flags);
943 isdn_tty_modem_result(6, info);
944 } else {
945 info->isdn_driver = dev->drvmap[i];
946 info->isdn_channel = dev->chanmap[i];
947 info->drv_index = i;
948 dev->m_idx[i] = info->line;
949 dev->usage[i] |= ISDN_USAGE_OUTGOING;
950 info->last_dir = 1;
951 strcpy(info->last_num, n);
952 isdn_info_update();
953 restore_flags(flags);
954 cmd.driver = info->isdn_driver;
955 cmd.arg = info->isdn_channel;
956 cmd.command = ISDN_CMD_CLREAZ;
957 isdn_command(&cmd);
958 strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
959 cmd.driver = info->isdn_driver;
960 cmd.command = ISDN_CMD_SETEAZ;
961 isdn_command(&cmd);
962 cmd.driver = info->isdn_driver;
963 cmd.command = ISDN_CMD_SETL2;
964 info->last_l2 = l2;
965 cmd.arg = info->isdn_channel + (l2 << 8);
966 isdn_command(&cmd);
967 cmd.driver = info->isdn_driver;
968 cmd.command = ISDN_CMD_SETL3;
969 cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
970 isdn_command(&cmd);
971 cmd.driver = info->isdn_driver;
972 cmd.arg = info->isdn_channel;
973 sprintf(cmd.parm.setup.phone, "%s", n);
974 sprintf(cmd.parm.setup.eazmsn, "%s",
975 isdn_map_eaz2msn(m->msn, info->isdn_driver));
976 cmd.parm.setup.si1 = si;
977 cmd.parm.setup.si2 = m->mdmreg[REG_SI2];
978 cmd.command = ISDN_CMD_DIAL;
979 info->dialing = 1;
980 info->emu.carrierwait = 0;
981 strcpy(dev->num[i], n);
982 isdn_info_update();
983 isdn_command(&cmd);
984 isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
988 /* isdn_tty_hangup() disassociates a tty from the real
989 * ISDN-line (hangup). The usage-status is cleared
990 * and some cleanup is done also.
992 static void
993 isdn_tty_modem_hup(modem_info * info, int local)
995 isdn_ctrl cmd;
996 int usage;
998 if (!info)
999 return;
1000 #ifdef ISDN_DEBUG_MODEM_HUP
1001 printk(KERN_DEBUG "Mhup ttyI%d\n", info->line);
1002 #endif
1003 info->rcvsched = 0;
1004 isdn_tty_flush_buffer(info->tty);
1005 if (info->online) {
1006 info->last_lhup = local;
1007 info->online = 0;
1008 /* NO CARRIER message */
1009 isdn_tty_modem_result(3, info);
1011 #ifdef CONFIG_ISDN_AUDIO
1012 info->vonline = 0;
1013 if (info->dtmf_state) {
1014 kfree(info->dtmf_state);
1015 info->dtmf_state = NULL;
1017 if (info->silence_state) {
1018 kfree(info->silence_state);
1019 info->silence_state = NULL;
1021 if (info->adpcms) {
1022 kfree(info->adpcms);
1023 info->adpcms = NULL;
1025 if (info->adpcmr) {
1026 kfree(info->adpcmr);
1027 info->adpcmr = NULL;
1029 #endif
1030 if ((info->msr & UART_MSR_RI) &&
1031 (info->emu.mdmreg[REG_RUNG] & BIT_RUNG))
1032 isdn_tty_modem_result(12, info);
1033 info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
1034 info->lsr |= UART_LSR_TEMT;
1035 if (info->isdn_driver >= 0) {
1036 if (local) {
1037 cmd.driver = info->isdn_driver;
1038 cmd.command = ISDN_CMD_HANGUP;
1039 cmd.arg = info->isdn_channel;
1040 isdn_command(&cmd);
1042 isdn_all_eaz(info->isdn_driver, info->isdn_channel);
1043 info->emu.mdmreg[REG_RINGCNT] = 0;
1044 usage = ((info->emu.mdmreg[REG_SI1I] != 1) ||
1045 (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM)) ?
1046 ISDN_USAGE_MODEM : ISDN_USAGE_VOICE;
1047 isdn_free_channel(info->isdn_driver, info->isdn_channel,
1048 usage);
1050 info->isdn_driver = -1;
1051 info->isdn_channel = -1;
1052 if (info->drv_index >= 0) {
1053 dev->m_idx[info->drv_index] = -1;
1054 info->drv_index = -1;
1059 * Begin of a CAPI like interface, currently used only for
1060 * supplementary service (CAPI 2.0 part III)
1062 #include "avmb1/capicmd.h" /* this should be moved in a common place */
1065 isdn_tty_capi_facility(capi_msg *cm) {
1066 return(-1); /* dummy */
1069 /* isdn_tty_suspend() tries to suspend the current tty connection
1071 static void
1072 isdn_tty_suspend(char *id, modem_info * info, atemu * m)
1074 isdn_ctrl cmd;
1076 int l;
1078 if (!info)
1079 return;
1081 #ifdef ISDN_DEBUG_MODEM_SERVICES
1082 printk(KERN_DEBUG "Msusp ttyI%d\n", info->line);
1083 #endif
1084 l = strlen(id);
1085 if ((info->isdn_driver >= 0) && l) {
1086 cmd.parm.cmsg.Length = l+17;
1087 cmd.parm.cmsg.Command = CAPI_FACILITY;
1088 cmd.parm.cmsg.Subcommand = CAPI_REQ;
1089 cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
1090 cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */
1091 cmd.parm.cmsg.para[1] = 0;
1092 cmd.parm.cmsg.para[2] = l + 3;
1093 cmd.parm.cmsg.para[3] = 4; /* 16 bit 0x0004 Suspend */
1094 cmd.parm.cmsg.para[4] = 0;
1095 cmd.parm.cmsg.para[5] = l;
1096 strncpy(&cmd.parm.cmsg.para[6], id, l);
1097 cmd.command = CAPI_PUT_MESSAGE;
1098 cmd.driver = info->isdn_driver;
1099 cmd.arg = info->isdn_channel;
1100 isdn_command(&cmd);
1104 /* isdn_tty_resume() tries to resume a suspended call
1105 * setup of the lower levels before that. unfortunatly here is no
1106 * checking for compatibility of used protocols implemented by Q931
1107 * It does the same things like isdn_tty_dial, the last command
1108 * is different, may be we can merge it.
1111 static void
1112 isdn_tty_resume(char *id, modem_info * info, atemu * m)
1114 int usg = ISDN_USAGE_MODEM;
1115 int si = 7;
1116 int l2 = m->mdmreg[REG_L2PROT];
1117 isdn_ctrl cmd;
1118 ulong flags;
1119 int i;
1120 int j;
1121 int l;
1123 l = strlen(id);
1124 if (!l) {
1125 isdn_tty_modem_result(4, info);
1126 return;
1128 for (j = 7; j >= 0; j--)
1129 if (m->mdmreg[REG_SI1] & (1 << j)) {
1130 si = bit2si[j];
1131 break;
1133 #ifdef CONFIG_ISDN_AUDIO
1134 if ((si == 1) && (l2 != ISDN_PROTO_L2_MODEM)) {
1135 l2 = ISDN_PROTO_L2_TRANS;
1136 usg = ISDN_USAGE_VOICE;
1138 #endif
1139 m->mdmreg[REG_SI1I] = si2bit[si];
1140 save_flags(flags);
1141 cli();
1142 i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1);
1143 if (i < 0) {
1144 restore_flags(flags);
1145 isdn_tty_modem_result(6, info);
1146 } else {
1147 info->isdn_driver = dev->drvmap[i];
1148 info->isdn_channel = dev->chanmap[i];
1149 info->drv_index = i;
1150 dev->m_idx[i] = info->line;
1151 dev->usage[i] |= ISDN_USAGE_OUTGOING;
1152 info->last_dir = 1;
1153 // strcpy(info->last_num, n);
1154 isdn_info_update();
1155 restore_flags(flags);
1156 cmd.driver = info->isdn_driver;
1157 cmd.arg = info->isdn_channel;
1158 cmd.command = ISDN_CMD_CLREAZ;
1159 isdn_command(&cmd);
1160 strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
1161 cmd.driver = info->isdn_driver;
1162 cmd.command = ISDN_CMD_SETEAZ;
1163 isdn_command(&cmd);
1164 cmd.driver = info->isdn_driver;
1165 cmd.command = ISDN_CMD_SETL2;
1166 info->last_l2 = l2;
1167 cmd.arg = info->isdn_channel + (l2 << 8);
1168 isdn_command(&cmd);
1169 cmd.driver = info->isdn_driver;
1170 cmd.command = ISDN_CMD_SETL3;
1171 cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
1172 isdn_command(&cmd);
1173 cmd.driver = info->isdn_driver;
1174 cmd.arg = info->isdn_channel;
1175 cmd.parm.cmsg.Length = l+17;
1176 cmd.parm.cmsg.Command = CAPI_FACILITY;
1177 cmd.parm.cmsg.Subcommand = CAPI_REQ;
1178 cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
1179 cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */
1180 cmd.parm.cmsg.para[1] = 0;
1181 cmd.parm.cmsg.para[2] = l+3;
1182 cmd.parm.cmsg.para[3] = 5; /* 16 bit 0x0005 Resume */
1183 cmd.parm.cmsg.para[4] = 0;
1184 cmd.parm.cmsg.para[5] = l;
1185 strncpy(&cmd.parm.cmsg.para[6], id, l);
1186 cmd.command =CAPI_PUT_MESSAGE;
1187 /* info->dialing = 1;
1188 strcpy(dev->num[i], n);
1189 isdn_info_update();
1191 isdn_command(&cmd);
1195 /* isdn_tty_send_msg() sends a message to a HL driver
1196 * This is used for hybrid modem cards to send AT commands to it
1199 static void
1200 isdn_tty_send_msg(modem_info * info, atemu * m, char *msg)
1202 int usg = ISDN_USAGE_MODEM;
1203 int si = 7;
1204 int l2 = m->mdmreg[REG_L2PROT];
1205 isdn_ctrl cmd;
1206 ulong flags;
1207 int i;
1208 int j;
1209 int l;
1211 l = strlen(msg);
1212 if (!l) {
1213 isdn_tty_modem_result(4, info);
1214 return;
1216 for (j = 7; j >= 0; j--)
1217 if (m->mdmreg[REG_SI1] & (1 << j)) {
1218 si = bit2si[j];
1219 break;
1221 #ifdef CONFIG_ISDN_AUDIO
1222 if ((si == 1) && (l2 != ISDN_PROTO_L2_MODEM)) {
1223 l2 = ISDN_PROTO_L2_TRANS;
1224 usg = ISDN_USAGE_VOICE;
1226 #endif
1227 m->mdmreg[REG_SI1I] = si2bit[si];
1228 save_flags(flags);
1229 cli();
1230 i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1);
1231 if (i < 0) {
1232 restore_flags(flags);
1233 isdn_tty_modem_result(6, info);
1234 } else {
1235 info->isdn_driver = dev->drvmap[i];
1236 info->isdn_channel = dev->chanmap[i];
1237 info->drv_index = i;
1238 dev->m_idx[i] = info->line;
1239 dev->usage[i] |= ISDN_USAGE_OUTGOING;
1240 info->last_dir = 1;
1241 isdn_info_update();
1242 restore_flags(flags);
1243 cmd.driver = info->isdn_driver;
1244 cmd.arg = info->isdn_channel;
1245 cmd.command = ISDN_CMD_CLREAZ;
1246 isdn_command(&cmd);
1247 strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
1248 cmd.driver = info->isdn_driver;
1249 cmd.command = ISDN_CMD_SETEAZ;
1250 isdn_command(&cmd);
1251 cmd.driver = info->isdn_driver;
1252 cmd.command = ISDN_CMD_SETL2;
1253 info->last_l2 = l2;
1254 cmd.arg = info->isdn_channel + (l2 << 8);
1255 isdn_command(&cmd);
1256 cmd.driver = info->isdn_driver;
1257 cmd.command = ISDN_CMD_SETL3;
1258 cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
1259 isdn_command(&cmd);
1260 cmd.driver = info->isdn_driver;
1261 cmd.arg = info->isdn_channel;
1262 cmd.parm.cmsg.Length = l+14;
1263 cmd.parm.cmsg.Command = CAPI_MANUFACTURER;
1264 cmd.parm.cmsg.Subcommand = CAPI_REQ;
1265 cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
1266 cmd.parm.cmsg.para[0] = l+1;
1267 strncpy(&cmd.parm.cmsg.para[1], msg, l);
1268 cmd.parm.cmsg.para[l+1] = 0xd;
1269 cmd.command =CAPI_PUT_MESSAGE;
1270 /* info->dialing = 1;
1271 strcpy(dev->num[i], n);
1272 isdn_info_update();
1274 isdn_command(&cmd);
1278 static inline int
1279 isdn_tty_paranoia_check(modem_info * info, kdev_t device, const char *routine)
1281 #ifdef MODEM_PARANOIA_CHECK
1282 if (!info) {
1283 printk(KERN_WARNING "isdn_tty: null info_struct for (%d, %d) in %s\n",
1284 MAJOR(device), MINOR(device), routine);
1285 return 1;
1287 if (info->magic != ISDN_ASYNC_MAGIC) {
1288 printk(KERN_WARNING "isdn_tty: bad magic for modem struct (%d, %d) in %s\n",
1289 MAJOR(device), MINOR(device), routine);
1290 return 1;
1292 #endif
1293 return 0;
1297 * This routine is called to set the UART divisor registers to match
1298 * the specified baud rate for a serial port.
1300 static void
1301 isdn_tty_change_speed(modem_info * info)
1303 uint cflag,
1304 cval,
1305 fcr,
1306 quot;
1307 int i;
1309 if (!info->tty || !info->tty->termios)
1310 return;
1311 cflag = info->tty->termios->c_cflag;
1313 quot = i = cflag & CBAUD;
1314 if (i & CBAUDEX) {
1315 i &= ~CBAUDEX;
1316 if (i < 1 || i > 2)
1317 info->tty->termios->c_cflag &= ~CBAUDEX;
1318 else
1319 i += 15;
1321 if (quot) {
1322 info->mcr |= UART_MCR_DTR;
1323 isdn_tty_modem_ncarrier(info);
1324 } else {
1325 info->mcr &= ~UART_MCR_DTR;
1326 if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
1327 #ifdef ISDN_DEBUG_MODEM_HUP
1328 printk(KERN_DEBUG "Mhup in changespeed\n");
1329 #endif
1330 if (info->online)
1331 info->ncarrier = 1;
1332 isdn_tty_modem_reset_regs(info, 0);
1333 isdn_tty_modem_hup(info, 1);
1335 return;
1337 /* byte size and parity */
1338 cval = cflag & (CSIZE | CSTOPB);
1339 cval >>= 4;
1340 if (cflag & PARENB)
1341 cval |= UART_LCR_PARITY;
1342 if (!(cflag & PARODD))
1343 cval |= UART_LCR_EPAR;
1344 fcr = 0;
1346 /* CTS flow control flag and modem status interrupts */
1347 if (cflag & CRTSCTS) {
1348 info->flags |= ISDN_ASYNC_CTS_FLOW;
1349 } else
1350 info->flags &= ~ISDN_ASYNC_CTS_FLOW;
1351 if (cflag & CLOCAL)
1352 info->flags &= ~ISDN_ASYNC_CHECK_CD;
1353 else {
1354 info->flags |= ISDN_ASYNC_CHECK_CD;
1358 static int
1359 isdn_tty_startup(modem_info * info)
1361 ulong flags;
1363 if (info->flags & ISDN_ASYNC_INITIALIZED)
1364 return 0;
1365 save_flags(flags);
1366 cli();
1367 isdn_MOD_INC_USE_COUNT();
1368 #ifdef ISDN_DEBUG_MODEM_OPEN
1369 printk(KERN_DEBUG "starting up ttyi%d ...\n", info->line);
1370 #endif
1372 * Now, initialize the UART
1374 info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
1375 if (info->tty)
1376 clear_bit(TTY_IO_ERROR, &info->tty->flags);
1378 * and set the speed of the serial port
1380 isdn_tty_change_speed(info);
1382 info->flags |= ISDN_ASYNC_INITIALIZED;
1383 info->msr |= (UART_MSR_DSR | UART_MSR_CTS);
1384 info->send_outstanding = 0;
1385 restore_flags(flags);
1386 return 0;
1390 * This routine will shutdown a serial port; interrupts are disabled, and
1391 * DTR is dropped if the hangup on close termio flag is on.
1393 static void
1394 isdn_tty_shutdown(modem_info * info)
1396 ulong flags;
1398 if (!(info->flags & ISDN_ASYNC_INITIALIZED))
1399 return;
1400 #ifdef ISDN_DEBUG_MODEM_OPEN
1401 printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line);
1402 #endif
1403 save_flags(flags);
1404 cli(); /* Disable interrupts */
1405 isdn_MOD_DEC_USE_COUNT();
1406 info->msr &= ~UART_MSR_RI;
1407 if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
1408 info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
1409 if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
1410 isdn_tty_modem_reset_regs(info, 0);
1411 #ifdef ISDN_DEBUG_MODEM_HUP
1412 printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n");
1413 #endif
1414 isdn_tty_modem_hup(info, 1);
1417 if (info->tty)
1418 set_bit(TTY_IO_ERROR, &info->tty->flags);
1420 info->flags &= ~ISDN_ASYNC_INITIALIZED;
1421 restore_flags(flags);
1424 /* isdn_tty_write() is the main send-routine. It is called from the upper
1425 * levels within the kernel to perform sending data. Depending on the
1426 * online-flag it either directs output to the at-command-interpreter or
1427 * to the lower level. Additional tasks done here:
1428 * - If online, check for escape-sequence (+++)
1429 * - If sending audio-data, call isdn_tty_DLEdown() to parse DLE-codes.
1430 * - If receiving audio-data, call isdn_tty_end_vrx() to abort if needed.
1431 * - If dialing, abort dial.
1433 static int
1434 isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int count)
1436 int c;
1437 int total = 0;
1438 modem_info *info = (modem_info *) tty->driver_data;
1440 if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_write"))
1441 return 0;
1442 if (!tty)
1443 return 0;
1444 if (from_user)
1445 down(&info->write_sem);
1446 /* See isdn_tty_senddown() */
1447 atomic_inc(&info->xmit_lock);
1448 while (1) {
1449 c = MIN(count, info->xmit_size - info->xmit_count);
1450 if (info->isdn_driver >= 0)
1451 c = MIN(c, dev->drv[info->isdn_driver]->maxbufsize);
1452 if (c <= 0)
1453 break;
1454 if ((info->online > 1)
1455 #ifdef CONFIG_ISDN_AUDIO
1456 || (info->vonline & 3)
1457 #endif
1459 atemu *m = &info->emu;
1461 #ifdef CONFIG_ISDN_AUDIO
1462 if (!info->vonline)
1463 #endif
1464 isdn_tty_check_esc(buf, m->mdmreg[REG_ESC], c,
1465 &(m->pluscount),
1466 &(m->lastplus),
1467 from_user);
1468 if (from_user)
1469 copy_from_user(&(info->xmit_buf[info->xmit_count]), buf, c);
1470 else
1471 memcpy(&(info->xmit_buf[info->xmit_count]), buf, c);
1472 #ifdef CONFIG_ISDN_AUDIO
1473 if (info->vonline) {
1474 int cc = isdn_tty_handleDLEdown(info, m, c);
1475 if (info->vonline & 2) {
1476 if (!cc) {
1477 /* If DLE decoding results in zero-transmit, but
1478 * c originally was non-zero, do a wakeup.
1480 if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
1481 tty->ldisc.write_wakeup)
1482 (tty->ldisc.write_wakeup) (tty);
1483 wake_up_interruptible(&tty->write_wait);
1484 info->msr |= UART_MSR_CTS;
1485 info->lsr |= UART_LSR_TEMT;
1487 info->xmit_count += cc;
1489 if ((info->vonline & 3) == 1) {
1490 /* Do NOT handle Ctrl-Q or Ctrl-S
1491 * when in full-duplex audio mode.
1493 if (isdn_tty_end_vrx(buf, c, from_user)) {
1494 info->vonline &= ~1;
1495 #ifdef ISDN_DEBUG_MODEM_VOICE
1496 printk(KERN_DEBUG
1497 "got !^Q/^S, send DLE-ETX,VCON on ttyI%d\n",
1498 info->line);
1499 #endif
1500 isdn_tty_at_cout("\020\003\r\nVCON\r\n", info);
1503 } else
1504 #endif
1505 info->xmit_count += c;
1506 } else {
1507 info->msr |= UART_MSR_CTS;
1508 info->lsr |= UART_LSR_TEMT;
1509 if (info->dialing) {
1510 info->dialing = 0;
1511 #ifdef ISDN_DEBUG_MODEM_HUP
1512 printk(KERN_DEBUG "Mhup in isdn_tty_write\n");
1513 #endif
1514 isdn_tty_modem_result(3, info);
1515 isdn_tty_modem_hup(info, 1);
1516 } else
1517 c = isdn_tty_edit_at(buf, c, info, from_user);
1519 buf += c;
1520 count -= c;
1521 total += c;
1523 if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue)))
1524 isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
1525 atomic_dec(&info->xmit_lock);
1526 if (from_user)
1527 up(&info->write_sem);
1528 return total;
1531 static int
1532 isdn_tty_write_room(struct tty_struct *tty)
1534 modem_info *info = (modem_info *) tty->driver_data;
1535 int ret;
1537 if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_write_room"))
1538 return 0;
1539 if (!info->online)
1540 return info->xmit_size;
1541 ret = info->xmit_size - info->xmit_count;
1542 return (ret < 0) ? 0 : ret;
1545 static int
1546 isdn_tty_chars_in_buffer(struct tty_struct *tty)
1548 modem_info *info = (modem_info *) tty->driver_data;
1550 if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_chars_in_buffer"))
1551 return 0;
1552 if (!info->online)
1553 return 0;
1554 return (info->xmit_count);
1557 static void
1558 isdn_tty_flush_buffer(struct tty_struct *tty)
1560 modem_info *info;
1561 unsigned long flags;
1563 save_flags(flags);
1564 cli();
1565 if (!tty) {
1566 restore_flags(flags);
1567 return;
1569 info = (modem_info *) tty->driver_data;
1570 if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_flush_buffer")) {
1571 restore_flags(flags);
1572 return;
1574 isdn_tty_cleanup_xmit(info);
1575 info->xmit_count = 0;
1576 restore_flags(flags);
1577 wake_up_interruptible(&tty->write_wait);
1578 if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
1579 tty->ldisc.write_wakeup)
1580 (tty->ldisc.write_wakeup) (tty);
1583 static void
1584 isdn_tty_flush_chars(struct tty_struct *tty)
1586 modem_info *info = (modem_info *) tty->driver_data;
1588 if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_flush_chars"))
1589 return;
1590 if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue)))
1591 isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
1595 * ------------------------------------------------------------
1596 * isdn_tty_throttle()
1598 * This routine is called by the upper-layer tty layer to signal that
1599 * incoming characters should be throttled.
1600 * ------------------------------------------------------------
1602 static void
1603 isdn_tty_throttle(struct tty_struct *tty)
1605 modem_info *info = (modem_info *) tty->driver_data;
1607 if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_throttle"))
1608 return;
1609 if (I_IXOFF(tty))
1610 info->x_char = STOP_CHAR(tty);
1611 info->mcr &= ~UART_MCR_RTS;
1614 static void
1615 isdn_tty_unthrottle(struct tty_struct *tty)
1617 modem_info *info = (modem_info *) tty->driver_data;
1619 if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_unthrottle"))
1620 return;
1621 if (I_IXOFF(tty)) {
1622 if (info->x_char)
1623 info->x_char = 0;
1624 else
1625 info->x_char = START_CHAR(tty);
1627 info->mcr |= UART_MCR_RTS;
1631 * ------------------------------------------------------------
1632 * isdn_tty_ioctl() and friends
1633 * ------------------------------------------------------------
1637 * isdn_tty_get_lsr_info - get line status register info
1639 * Purpose: Let user call ioctl() to get info when the UART physically
1640 * is emptied. On bus types like RS485, the transmitter must
1641 * release the bus after transmitting. This must be done when
1642 * the transmit shift register is empty, not be done when the
1643 * transmit holding register is empty. This functionality
1644 * allows RS485 driver to be written in user space.
1646 static int
1647 isdn_tty_get_lsr_info(modem_info * info, uint * value)
1649 u_char status;
1650 uint result;
1651 ulong flags;
1653 save_flags(flags);
1654 cli();
1655 status = info->lsr;
1656 restore_flags(flags);
1657 result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
1658 put_user(result, (uint *) value);
1659 return 0;
1663 static int
1664 isdn_tty_get_modem_info(modem_info * info, uint * value)
1666 u_char control,
1667 status;
1668 uint result;
1669 ulong flags;
1671 control = info->mcr;
1672 save_flags(flags);
1673 cli();
1674 status = info->msr;
1675 restore_flags(flags);
1676 result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
1677 | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
1678 | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0)
1679 | ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
1680 | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
1681 | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
1682 put_user(result, (uint *) value);
1683 return 0;
1686 static int
1687 isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value)
1689 uint arg;
1690 int pre_dtr;
1692 get_user(arg, (uint *) value);
1693 switch (cmd) {
1694 case TIOCMBIS:
1695 #ifdef ISDN_DEBUG_MODEM_IOCTL
1696 printk(KERN_DEBUG "ttyI%d ioctl TIOCMBIS\n", info->line);
1697 #endif
1698 if (arg & TIOCM_RTS) {
1699 info->mcr |= UART_MCR_RTS;
1701 if (arg & TIOCM_DTR) {
1702 info->mcr |= UART_MCR_DTR;
1703 isdn_tty_modem_ncarrier(info);
1705 break;
1706 case TIOCMBIC:
1707 #ifdef ISDN_DEBUG_MODEM_IOCTL
1708 printk(KERN_DEBUG "ttyI%d ioctl TIOCMBIC\n", info->line);
1709 #endif
1710 if (arg & TIOCM_RTS) {
1711 info->mcr &= ~UART_MCR_RTS;
1713 if (arg & TIOCM_DTR) {
1714 info->mcr &= ~UART_MCR_DTR;
1715 if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
1716 isdn_tty_modem_reset_regs(info, 0);
1717 #ifdef ISDN_DEBUG_MODEM_HUP
1718 printk(KERN_DEBUG "Mhup in TIOCMBIC\n");
1719 #endif
1720 if (info->online)
1721 info->ncarrier = 1;
1722 isdn_tty_modem_hup(info, 1);
1725 break;
1726 case TIOCMSET:
1727 #ifdef ISDN_DEBUG_MODEM_IOCTL
1728 printk(KERN_DEBUG "ttyI%d ioctl TIOCMSET\n", info->line);
1729 #endif
1730 pre_dtr = (info->mcr & UART_MCR_DTR);
1731 info->mcr = ((info->mcr & ~(UART_MCR_RTS | UART_MCR_DTR))
1732 | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
1733 | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
1734 if (pre_dtr |= (info->mcr & UART_MCR_DTR)) {
1735 if (!(info->mcr & UART_MCR_DTR)) {
1736 if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
1737 isdn_tty_modem_reset_regs(info, 0);
1738 #ifdef ISDN_DEBUG_MODEM_HUP
1739 printk(KERN_DEBUG "Mhup in TIOCMSET\n");
1740 #endif
1741 if (info->online)
1742 info->ncarrier = 1;
1743 isdn_tty_modem_hup(info, 1);
1745 } else
1746 isdn_tty_modem_ncarrier(info);
1748 break;
1749 default:
1750 return -EINVAL;
1752 return 0;
1755 static int
1756 isdn_tty_ioctl(struct tty_struct *tty, struct file *file,
1757 uint cmd, ulong arg)
1759 modem_info *info = (modem_info *) tty->driver_data;
1760 int error;
1761 int retval;
1763 if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_ioctl"))
1764 return -ENODEV;
1765 if (tty->flags & (1 << TTY_IO_ERROR))
1766 return -EIO;
1767 switch (cmd) {
1768 case TCSBRK: /* SVID version: non-zero arg --> no break */
1769 #ifdef ISDN_DEBUG_MODEM_IOCTL
1770 printk(KERN_DEBUG "ttyI%d ioctl TCSBRK\n", info->line);
1771 #endif
1772 retval = tty_check_change(tty);
1773 if (retval)
1774 return retval;
1775 tty_wait_until_sent(tty, 0);
1776 return 0;
1777 case TCSBRKP: /* support for POSIX tcsendbreak() */
1778 #ifdef ISDN_DEBUG_MODEM_IOCTL
1779 printk(KERN_DEBUG "ttyI%d ioctl TCSBRKP\n", info->line);
1780 #endif
1781 retval = tty_check_change(tty);
1782 if (retval)
1783 return retval;
1784 tty_wait_until_sent(tty, 0);
1785 return 0;
1786 case TIOCGSOFTCAR:
1787 #ifdef ISDN_DEBUG_MODEM_IOCTL
1788 printk(KERN_DEBUG "ttyI%d ioctl TIOCGSOFTCAR\n", info->line);
1789 #endif
1790 error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
1791 if (error)
1792 return error;
1793 put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg);
1794 return 0;
1795 case TIOCSSOFTCAR:
1796 #ifdef ISDN_DEBUG_MODEM_IOCTL
1797 printk(KERN_DEBUG "ttyI%d ioctl TIOCSSOFTCAR\n", info->line);
1798 #endif
1799 error = verify_area(VERIFY_READ, (void *) arg, sizeof(long));
1800 if (error)
1801 return error;
1802 get_user(arg, (ulong *) arg);
1803 tty->termios->c_cflag =
1804 ((tty->termios->c_cflag & ~CLOCAL) |
1805 (arg ? CLOCAL : 0));
1806 return 0;
1807 case TIOCMGET:
1808 #ifdef ISDN_DEBUG_MODEM_IOCTL
1809 printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line);
1810 #endif
1811 error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
1812 if (error)
1813 return error;
1814 return isdn_tty_get_modem_info(info, (uint *) arg);
1815 case TIOCMBIS:
1816 case TIOCMBIC:
1817 case TIOCMSET:
1818 error = verify_area(VERIFY_READ, (void *) arg, sizeof(uint));
1819 if (error)
1820 return error;
1821 return isdn_tty_set_modem_info(info, cmd, (uint *) arg);
1822 case TIOCSERGETLSR: /* Get line status register */
1823 #ifdef ISDN_DEBUG_MODEM_IOCTL
1824 printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line);
1825 #endif
1826 error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint));
1827 if (error)
1828 return error;
1829 else
1830 return isdn_tty_get_lsr_info(info, (uint *) arg);
1831 default:
1832 #ifdef ISDN_DEBUG_MODEM_IOCTL
1833 printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on ttyi%d\n", cmd, info->line);
1834 #endif
1835 return -ENOIOCTLCMD;
1837 return 0;
1840 static void
1841 isdn_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
1843 modem_info *info = (modem_info *) tty->driver_data;
1845 if (!old_termios)
1846 isdn_tty_change_speed(info);
1847 else {
1848 if (tty->termios->c_cflag == old_termios->c_cflag)
1849 return;
1850 isdn_tty_change_speed(info);
1851 if ((old_termios->c_cflag & CRTSCTS) &&
1852 !(tty->termios->c_cflag & CRTSCTS)) {
1853 tty->hw_stopped = 0;
1859 * ------------------------------------------------------------
1860 * isdn_tty_open() and friends
1861 * ------------------------------------------------------------
1863 static int
1864 isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info * info)
1866 #if LINUX_VERSION_CODE < 131841
1867 struct wait_queue wait =
1868 {current, NULL};
1869 #else
1870 DECLARE_WAITQUEUE(wait, NULL);
1871 #endif
1872 int do_clocal = 0;
1873 unsigned long flags;
1874 int retval;
1877 * If the device is in the middle of being closed, then block
1878 * until it's done, and then try again.
1880 if (tty_hung_up_p(filp) ||
1881 (info->flags & ISDN_ASYNC_CLOSING)) {
1882 if (info->flags & ISDN_ASYNC_CLOSING)
1883 interruptible_sleep_on(&info->close_wait);
1884 #ifdef MODEM_DO_RESTART
1885 if (info->flags & ISDN_ASYNC_HUP_NOTIFY)
1886 return -EAGAIN;
1887 else
1888 return -ERESTARTSYS;
1889 #else
1890 return -EAGAIN;
1891 #endif
1894 * If this is a callout device, then just make sure the normal
1895 * device isn't being used.
1897 if (tty->driver.subtype == ISDN_SERIAL_TYPE_CALLOUT) {
1898 if (info->flags & ISDN_ASYNC_NORMAL_ACTIVE)
1899 return -EBUSY;
1900 if ((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
1901 (info->flags & ISDN_ASYNC_SESSION_LOCKOUT) &&
1902 (info->session != current->session))
1903 return -EBUSY;
1904 if ((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
1905 (info->flags & ISDN_ASYNC_PGRP_LOCKOUT) &&
1906 (info->pgrp != current->pgrp))
1907 return -EBUSY;
1908 info->flags |= ISDN_ASYNC_CALLOUT_ACTIVE;
1909 return 0;
1912 * If non-blocking mode is set, then make the check up front
1913 * and then exit.
1915 if ((filp->f_flags & O_NONBLOCK) ||
1916 (tty->flags & (1 << TTY_IO_ERROR))) {
1917 if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
1918 return -EBUSY;
1919 info->flags |= ISDN_ASYNC_NORMAL_ACTIVE;
1920 return 0;
1922 if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) {
1923 if (info->normal_termios.c_cflag & CLOCAL)
1924 do_clocal = 1;
1925 } else {
1926 if (tty->termios->c_cflag & CLOCAL)
1927 do_clocal = 1;
1930 * Block waiting for the carrier detect and the line to become
1931 * free (i.e., not in use by the callout). While we are in
1932 * this loop, info->count is dropped by one, so that
1933 * isdn_tty_close() knows when to free things. We restore it upon
1934 * exit, either normal or abnormal.
1936 retval = 0;
1937 add_wait_queue(&info->open_wait, &wait);
1938 #ifdef ISDN_DEBUG_MODEM_OPEN
1939 printk(KERN_DEBUG "isdn_tty_block_til_ready before block: ttyi%d, count = %d\n",
1940 info->line, info->count);
1941 #endif
1942 save_flags(flags);
1943 cli();
1944 if (!(tty_hung_up_p(filp)))
1945 info->count--;
1946 restore_flags(flags);
1947 info->blocked_open++;
1948 while (1) {
1949 current->state = TASK_INTERRUPTIBLE;
1950 if (tty_hung_up_p(filp) ||
1951 !(info->flags & ISDN_ASYNC_INITIALIZED)) {
1952 #ifdef MODEM_DO_RESTART
1953 if (info->flags & ISDN_ASYNC_HUP_NOTIFY)
1954 retval = -EAGAIN;
1955 else
1956 retval = -ERESTARTSYS;
1957 #else
1958 retval = -EAGAIN;
1959 #endif
1960 break;
1962 if (!(info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
1963 !(info->flags & ISDN_ASYNC_CLOSING) &&
1964 (do_clocal || (info->msr & UART_MSR_DCD))) {
1965 break;
1967 if (signal_pending(current)) {
1968 retval = -ERESTARTSYS;
1969 break;
1971 #ifdef ISDN_DEBUG_MODEM_OPEN
1972 printk(KERN_DEBUG "isdn_tty_block_til_ready blocking: ttyi%d, count = %d\n",
1973 info->line, info->count);
1974 #endif
1975 schedule();
1977 current->state = TASK_RUNNING;
1978 remove_wait_queue(&info->open_wait, &wait);
1979 if (!tty_hung_up_p(filp))
1980 info->count++;
1981 info->blocked_open--;
1982 #ifdef ISDN_DEBUG_MODEM_OPEN
1983 printk(KERN_DEBUG "isdn_tty_block_til_ready after blocking: ttyi%d, count = %d\n",
1984 info->line, info->count);
1985 #endif
1986 if (retval)
1987 return retval;
1988 info->flags |= ISDN_ASYNC_NORMAL_ACTIVE;
1989 return 0;
1993 * This routine is called whenever a serial port is opened. It
1994 * enables interrupts for a serial port, linking in its async structure into
1995 * the IRQ chain. It also performs the serial-specific
1996 * initialization for the tty structure.
1998 static int
1999 isdn_tty_open(struct tty_struct *tty, struct file *filp)
2001 modem_info *info;
2002 int retval,
2003 line;
2005 line = MINOR(tty->device) - tty->driver.minor_start;
2006 if (line < 0 || line > ISDN_MAX_CHANNELS)
2007 return -ENODEV;
2008 info = &dev->mdm.info[line];
2009 if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_open"))
2010 return -ENODEV;
2011 #ifdef ISDN_DEBUG_MODEM_OPEN
2012 printk(KERN_DEBUG "isdn_tty_open %s%d, count = %d\n", tty->driver.name,
2013 info->line, info->count);
2014 #endif
2015 info->count++;
2016 tty->driver_data = info;
2017 info->tty = tty;
2019 * Start up serial port
2021 retval = isdn_tty_startup(info);
2022 if (retval) {
2023 #ifdef ISDN_DEBUG_MODEM_OPEN
2024 printk(KERN_DEBUG "isdn_tty_open return after startup\n");
2025 #endif
2026 return retval;
2028 retval = isdn_tty_block_til_ready(tty, filp, info);
2029 if (retval) {
2030 #ifdef ISDN_DEBUG_MODEM_OPEN
2031 printk(KERN_DEBUG "isdn_tty_open return after isdn_tty_block_til_ready \n");
2032 #endif
2033 return retval;
2035 if ((info->count == 1) && (info->flags & ISDN_ASYNC_SPLIT_TERMIOS)) {
2036 if (tty->driver.subtype == ISDN_SERIAL_TYPE_NORMAL)
2037 *tty->termios = info->normal_termios;
2038 else
2039 *tty->termios = info->callout_termios;
2040 isdn_tty_change_speed(info);
2042 info->session = current->session;
2043 info->pgrp = current->pgrp;
2044 #ifdef ISDN_DEBUG_MODEM_OPEN
2045 printk(KERN_DEBUG "isdn_tty_open ttyi%d successful...\n", info->line);
2046 #endif
2047 dev->modempoll++;
2048 #ifdef ISDN_DEBUG_MODEM_OPEN
2049 printk(KERN_DEBUG "isdn_tty_open normal exit\n");
2050 #endif
2051 return 0;
2054 static void
2055 isdn_tty_close(struct tty_struct *tty, struct file *filp)
2057 modem_info *info = (modem_info *) tty->driver_data;
2058 ulong flags;
2059 ulong timeout;
2061 if (!info || isdn_tty_paranoia_check(info, tty->device, "isdn_tty_close"))
2062 return;
2063 save_flags(flags);
2064 cli();
2065 if (tty_hung_up_p(filp)) {
2066 restore_flags(flags);
2067 #ifdef ISDN_DEBUG_MODEM_OPEN
2068 printk(KERN_DEBUG "isdn_tty_close return after tty_hung_up_p\n");
2069 #endif
2070 return;
2072 if ((tty->count == 1) && (info->count != 1)) {
2074 * Uh, oh. tty->count is 1, which means that the tty
2075 * structure will be freed. Info->count should always
2076 * be one in these conditions. If it's greater than
2077 * one, we've got real problems, since it means the
2078 * serial port won't be shutdown.
2080 printk(KERN_ERR "isdn_tty_close: bad port count; tty->count is 1, "
2081 "info->count is %d\n", info->count);
2082 info->count = 1;
2084 if (--info->count < 0) {
2085 printk(KERN_ERR "isdn_tty_close: bad port count for ttyi%d: %d\n",
2086 info->line, info->count);
2087 info->count = 0;
2089 if (info->count) {
2090 restore_flags(flags);
2091 #ifdef ISDN_DEBUG_MODEM_OPEN
2092 printk(KERN_DEBUG "isdn_tty_close after info->count != 0\n");
2093 #endif
2094 return;
2096 info->flags |= ISDN_ASYNC_CLOSING;
2098 * Save the termios structure, since this port may have
2099 * separate termios for callout and dialin.
2101 if (info->flags & ISDN_ASYNC_NORMAL_ACTIVE)
2102 info->normal_termios = *tty->termios;
2103 if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
2104 info->callout_termios = *tty->termios;
2106 tty->closing = 1;
2108 * At this point we stop accepting input. To do this, we
2109 * disable the receive line status interrupts, and tell the
2110 * interrupt driver to stop checking the data ready bit in the
2111 * line status register.
2113 if (info->flags & ISDN_ASYNC_INITIALIZED) {
2114 tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
2116 * Before we drop DTR, make sure the UART transmitter
2117 * has completely drained; this is especially
2118 * important if there is a transmit FIFO!
2120 timeout = jiffies + HZ;
2121 while (!(info->lsr & UART_LSR_TEMT)) {
2122 current->state = TASK_INTERRUPTIBLE;
2123 schedule_timeout(20);
2124 if (time_after(jiffies,timeout))
2125 break;
2128 dev->modempoll--;
2129 isdn_tty_shutdown(info);
2130 if (tty->driver.flush_buffer)
2131 tty->driver.flush_buffer(tty);
2132 if (tty->ldisc.flush_buffer)
2133 tty->ldisc.flush_buffer(tty);
2134 info->tty = 0;
2135 info->ncarrier = 0;
2136 tty->closing = 0;
2137 if (info->blocked_open) {
2138 current->state = TASK_INTERRUPTIBLE;
2139 schedule_timeout(50);
2140 wake_up_interruptible(&info->open_wait);
2142 info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE |
2143 ISDN_ASYNC_CLOSING);
2144 wake_up_interruptible(&info->close_wait);
2145 restore_flags(flags);
2146 #ifdef ISDN_DEBUG_MODEM_OPEN
2147 printk(KERN_DEBUG "isdn_tty_close normal exit\n");
2148 #endif
2152 * isdn_tty_hangup() --- called by tty_hangup() when a hangup is signaled.
2154 static void
2155 isdn_tty_hangup(struct tty_struct *tty)
2157 modem_info *info = (modem_info *) tty->driver_data;
2159 if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_hangup"))
2160 return;
2161 isdn_tty_shutdown(info);
2162 info->count = 0;
2163 info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE);
2164 info->tty = 0;
2165 wake_up_interruptible(&info->open_wait);
2168 /* This routine initializes all emulator-data.
2170 static void
2171 isdn_tty_reset_profile(atemu * m)
2173 m->profile[0] = 0;
2174 m->profile[1] = 0;
2175 m->profile[2] = 43;
2176 m->profile[3] = 13;
2177 m->profile[4] = 10;
2178 m->profile[5] = 8;
2179 m->profile[6] = 3;
2180 m->profile[7] = 60;
2181 m->profile[8] = 2;
2182 m->profile[9] = 6;
2183 m->profile[10] = 7;
2184 m->profile[11] = 70;
2185 m->profile[12] = 0x45;
2186 m->profile[13] = 4;
2187 m->profile[14] = ISDN_PROTO_L2_X75I;
2188 m->profile[15] = ISDN_PROTO_L3_TRANS;
2189 m->profile[16] = ISDN_SERIAL_XMIT_SIZE / 16;
2190 m->profile[17] = ISDN_MODEM_WINSIZE;
2191 m->profile[18] = 4;
2192 m->profile[19] = 0;
2193 m->profile[20] = 0;
2194 m->pmsn[0] = '\0';
2195 m->plmsn[0] = '\0';
2198 #ifdef CONFIG_ISDN_AUDIO
2199 static void
2200 isdn_tty_modem_reset_vpar(atemu * m)
2202 m->vpar[0] = 2; /* Voice-device (2 = phone line) */
2203 m->vpar[1] = 0; /* Silence detection level (0 = none ) */
2204 m->vpar[2] = 70; /* Silence interval (7 sec. ) */
2205 m->vpar[3] = 2; /* Compression type (1 = ADPCM-2 ) */
2207 #endif
2209 static void
2210 isdn_tty_modem_reset_regs(modem_info * info, int force)
2212 atemu *m = &info->emu;
2213 if ((m->mdmreg[REG_DTRR] & BIT_DTRR) || force) {
2214 memcpy(m->mdmreg, m->profile, ISDN_MODEM_ANZREG);
2215 memcpy(m->msn, m->pmsn, ISDN_MSNLEN);
2216 memcpy(m->lmsn, m->plmsn, ISDN_LMSNLEN);
2217 info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
2219 #ifdef CONFIG_ISDN_AUDIO
2220 isdn_tty_modem_reset_vpar(m);
2221 #endif
2222 m->mdmcmdl = 0;
2225 static void
2226 modem_write_profile(atemu * m)
2228 memcpy(m->profile, m->mdmreg, ISDN_MODEM_ANZREG);
2229 memcpy(m->pmsn, m->msn, ISDN_MSNLEN);
2230 memcpy(m->plmsn, m->lmsn, ISDN_LMSNLEN);
2231 if (dev->profd)
2232 send_sig(SIGIO, dev->profd, 1);
2236 isdn_tty_modem_init(void)
2238 modem *m;
2239 int i;
2240 modem_info *info;
2242 m = &dev->mdm;
2243 memset(&m->tty_modem, 0, sizeof(struct tty_driver));
2244 m->tty_modem.magic = TTY_DRIVER_MAGIC;
2245 m->tty_modem.name = isdn_ttyname_ttyI;
2246 m->tty_modem.major = ISDN_TTY_MAJOR;
2247 m->tty_modem.minor_start = 0;
2248 m->tty_modem.num = ISDN_MAX_CHANNELS;
2249 m->tty_modem.type = TTY_DRIVER_TYPE_SERIAL;
2250 m->tty_modem.subtype = ISDN_SERIAL_TYPE_NORMAL;
2251 m->tty_modem.init_termios = tty_std_termios;
2252 m->tty_modem.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
2253 m->tty_modem.flags = TTY_DRIVER_REAL_RAW;
2254 m->tty_modem.refcount = &m->refcount;
2255 m->tty_modem.table = m->modem_table;
2256 m->tty_modem.termios = m->modem_termios;
2257 m->tty_modem.termios_locked = m->modem_termios_locked;
2258 m->tty_modem.open = isdn_tty_open;
2259 m->tty_modem.close = isdn_tty_close;
2260 m->tty_modem.write = isdn_tty_write;
2261 m->tty_modem.put_char = NULL;
2262 m->tty_modem.flush_chars = isdn_tty_flush_chars;
2263 m->tty_modem.write_room = isdn_tty_write_room;
2264 m->tty_modem.chars_in_buffer = isdn_tty_chars_in_buffer;
2265 m->tty_modem.flush_buffer = isdn_tty_flush_buffer;
2266 m->tty_modem.ioctl = isdn_tty_ioctl;
2267 m->tty_modem.throttle = isdn_tty_throttle;
2268 m->tty_modem.unthrottle = isdn_tty_unthrottle;
2269 m->tty_modem.set_termios = isdn_tty_set_termios;
2270 m->tty_modem.stop = NULL;
2271 m->tty_modem.start = NULL;
2272 m->tty_modem.hangup = isdn_tty_hangup;
2273 m->tty_modem.driver_name = "isdn_tty";
2275 * The callout device is just like normal device except for
2276 * major number and the subtype code.
2278 m->cua_modem = m->tty_modem;
2279 m->cua_modem.name = isdn_ttyname_cui;
2280 m->cua_modem.major = ISDN_TTYAUX_MAJOR;
2281 m->tty_modem.minor_start = 0;
2282 m->cua_modem.subtype = ISDN_SERIAL_TYPE_CALLOUT;
2284 if (tty_register_driver(&m->tty_modem)) {
2285 printk(KERN_WARNING "isdn_tty: Couldn't register modem-device\n");
2286 return -1;
2288 if (tty_register_driver(&m->cua_modem)) {
2289 printk(KERN_WARNING "isdn_tty: Couldn't register modem-callout-device\n");
2290 return -2;
2292 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
2293 info = &m->info[i];
2294 #if LINUX_VERSION_CODE < 131841
2295 info->write_sem = MUTEX;
2296 #else
2297 init_MUTEX(&info->write_sem);
2298 #endif
2299 sprintf(info->last_cause, "0000");
2300 sprintf(info->last_num, "none");
2301 info->last_dir = 0;
2302 info->last_lhup = 1;
2303 info->last_l2 = -1;
2304 info->last_si = 0;
2305 isdn_tty_reset_profile(&info->emu);
2306 isdn_tty_modem_reset_regs(info, 1);
2307 info->magic = ISDN_ASYNC_MAGIC;
2308 info->line = i;
2309 info->tty = 0;
2310 info->x_char = 0;
2311 info->count = 0;
2312 info->blocked_open = 0;
2313 info->callout_termios = m->cua_modem.init_termios;
2314 info->normal_termios = m->tty_modem.init_termios;
2315 #if LINUX_VERSION_CODE < 131841
2316 info->open_wait = 0;
2317 info->close_wait = 0;
2318 #else
2319 init_waitqueue_head(&info->open_wait);
2320 init_waitqueue_head(&info->close_wait);
2321 #endif
2322 info->isdn_driver = -1;
2323 info->isdn_channel = -1;
2324 info->drv_index = -1;
2325 info->xmit_size = ISDN_SERIAL_XMIT_SIZE;
2326 skb_queue_head_init(&info->xmit_queue);
2327 #ifdef CONFIG_ISDN_AUDIO
2328 skb_queue_head_init(&info->dtmf_queue);
2329 #endif
2330 if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5, GFP_KERNEL))) {
2331 printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
2332 return -3;
2334 /* Make room for T.70 header */
2335 info->xmit_buf += 4;
2337 return 0;
2340 static int
2341 isdn_tty_match_icall(char *cid, atemu *emu, int di)
2343 #ifdef ISDN_DEBUG_MODEM_ICALL
2344 printk(KERN_DEBUG "m_fi: msn=%s lmsn=%s mmsn=%s mreg[SI1]=%d mreg[SI2]=%d\n",
2345 emu->msn, emu->lmsn, isdn_map_eaz2msn(emu->msn, di),
2346 emu->mdmreg[REG_SI1], emu->mdmreg[REG_SI2]);
2347 #endif
2348 if (strlen(emu->lmsn)) {
2349 char *p = emu->lmsn;
2350 char *q;
2351 int tmp;
2352 int ret = 0;
2354 while (1) {
2355 if ((q = strchr(p, ';')))
2356 *q = '\0';
2357 if ((tmp = isdn_wildmat(cid, isdn_map_eaz2msn(p, di))) > ret)
2358 ret = tmp;
2359 #ifdef ISDN_DEBUG_MODEM_ICALL
2360 printk(KERN_DEBUG "m_fi: lmsnX=%s mmsn=%s -> tmp=%d\n",
2361 p, isdn_map_eaz2msn(emu->msn, di), tmp);
2362 #endif
2363 if (q) {
2364 *q = ';';
2365 p = q;
2366 p++;
2368 if (!tmp)
2369 return 0;
2370 if (!q)
2371 break;
2373 return ret;
2374 } else
2375 return isdn_wildmat(cid, isdn_map_eaz2msn(emu->msn, di));
2379 * An incoming call-request has arrived.
2380 * Search the tty-devices for an appropriate device and bind
2381 * it to the ISDN-Channel.
2382 * Return:
2384 * 0 = No matching device found.
2385 * 1 = A matching device found.
2386 * 3 = No match found, but eventually would match, if
2387 * CID is longer.
2390 isdn_tty_find_icall(int di, int ch, setup_parm setup)
2392 char *eaz;
2393 int i;
2394 int wret;
2395 int idx;
2396 int si1;
2397 int si2;
2398 char nr[32];
2399 ulong flags;
2401 if (!setup.phone[0]) {
2402 nr[0] = '0';
2403 nr[1] = '\0';
2404 printk(KERN_INFO "isdn_tty: Incoming call without OAD, assuming '0'\n");
2405 } else
2406 strcpy(nr, setup.phone);
2407 si1 = (int) setup.si1;
2408 si2 = (int) setup.si2;
2409 if (!setup.eazmsn[0]) {
2410 printk(KERN_WARNING "isdn_tty: Incoming call without CPN, assuming '0'\n");
2411 eaz = "0";
2412 } else
2413 eaz = setup.eazmsn;
2414 #ifdef ISDN_DEBUG_MODEM_ICALL
2415 printk(KERN_DEBUG "m_fi: eaz=%s si1=%d si2=%d\n", eaz, si1, si2);
2416 #endif
2417 wret = 0;
2418 save_flags(flags);
2419 cli();
2420 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
2421 modem_info *info = &dev->mdm.info[i];
2423 if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) && /* SI1 is matching */
2424 (info->emu.mdmreg[REG_SI2] == si2)) { /* SI2 is matching */
2425 idx = isdn_dc2minor(di, ch);
2426 #ifdef ISDN_DEBUG_MODEM_ICALL
2427 printk(KERN_DEBUG "m_fi: match1\n");
2428 printk(KERN_DEBUG "m_fi: idx=%d flags=%08lx drv=%d ch=%d usg=%d\n", idx,
2429 info->flags, info->isdn_driver, info->isdn_channel,
2430 dev->usage[idx]);
2431 #endif
2432 if (
2433 #ifndef FIX_FILE_TRANSFER
2434 (info->flags & ISDN_ASYNC_NORMAL_ACTIVE) &&
2435 #endif
2436 (info->isdn_driver == -1) &&
2437 (info->isdn_channel == -1) &&
2438 (USG_NONE(dev->usage[idx]))) {
2439 int matchret;
2441 if ((matchret = isdn_tty_match_icall(eaz, &info->emu, di)) > wret)
2442 wret = matchret;
2443 if (!matchret) { /* EAZ is matching */
2444 info->isdn_driver = di;
2445 info->isdn_channel = ch;
2446 info->drv_index = idx;
2447 dev->m_idx[idx] = info->line;
2448 dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
2449 dev->usage[idx] |= ((si1 != 1) || (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM)) ?
2450 ISDN_USAGE_MODEM : ISDN_USAGE_VOICE;
2451 strcpy(dev->num[idx], nr);
2452 strcpy(info->emu.cpn, eaz);
2453 info->emu.mdmreg[REG_SI1I] = si2bit[si1];
2454 info->emu.mdmreg[REG_PLAN] = setup.plan;
2455 info->emu.mdmreg[REG_SCREEN] = setup.screen;
2456 isdn_info_update();
2457 restore_flags(flags);
2458 printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr,
2459 info->line);
2460 info->msr |= UART_MSR_RI;
2461 isdn_tty_modem_result(2, info);
2462 isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1);
2463 return 1;
2468 restore_flags(flags);
2469 printk(KERN_INFO "isdn_tty: call from %s -> %s %s\n", nr, eaz,
2470 ((dev->drv[di]->flags & DRV_FLAG_REJBUS) && (wret != 2))? "rejected" : "ignored");
2471 return (wret == 2)?3:0;
2474 #define TTY_IS_ACTIVE(info) \
2475 (info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE))
2478 isdn_tty_stat_callback(int i, isdn_ctrl * c)
2480 int mi;
2481 modem_info *info;
2482 char *e;
2484 if (i < 0)
2485 return 0;
2486 if ((mi = dev->m_idx[i]) >= 0) {
2487 info = &dev->mdm.info[mi];
2488 switch (c->command) {
2489 case ISDN_STAT_CINF:
2490 printk(KERN_DEBUG "CHARGEINFO on ttyI%d: %ld %s\n", info->line, c->arg, c->parm.num);
2491 info->emu.charge = (unsigned) simple_strtoul(c->parm.num, &e, 10);
2492 if (e == (char *)c->parm.num)
2493 info->emu.charge = 0;
2495 break;
2496 case ISDN_STAT_BSENT:
2497 #ifdef ISDN_TTY_STAT_DEBUG
2498 printk(KERN_DEBUG "tty_STAT_BSENT ttyI%d\n", info->line);
2499 #endif
2500 if ((info->isdn_driver == c->driver) &&
2501 (info->isdn_channel == c->arg)) {
2502 info->msr |= UART_MSR_CTS;
2503 if (info->send_outstanding)
2504 if (!(--info->send_outstanding))
2505 info->lsr |= UART_LSR_TEMT;
2506 isdn_tty_tint(info);
2507 return 1;
2509 break;
2510 case ISDN_STAT_CAUSE:
2511 #ifdef ISDN_TTY_STAT_DEBUG
2512 printk(KERN_DEBUG "tty_STAT_CAUSE ttyI%d\n", info->line);
2513 #endif
2514 /* Signal cause to tty-device */
2515 strncpy(info->last_cause, c->parm.num, 5);
2516 return 1;
2517 case ISDN_STAT_DCONN:
2518 #ifdef ISDN_TTY_STAT_DEBUG
2519 printk(KERN_DEBUG "tty_STAT_DCONN ttyI%d\n", info->line);
2520 #endif
2521 if (TTY_IS_ACTIVE(info)) {
2522 if (info->dialing == 1) {
2523 info->dialing = 2;
2524 return 1;
2527 break;
2528 case ISDN_STAT_DHUP:
2529 #ifdef ISDN_TTY_STAT_DEBUG
2530 printk(KERN_DEBUG "tty_STAT_DHUP ttyI%d\n", info->line);
2531 #endif
2532 if (TTY_IS_ACTIVE(info)) {
2533 if (info->dialing == 1)
2534 isdn_tty_modem_result(7, info);
2535 if (info->dialing > 1)
2536 isdn_tty_modem_result(3, info);
2537 info->dialing = 0;
2538 #ifdef ISDN_DEBUG_MODEM_HUP
2539 printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n");
2540 #endif
2541 isdn_tty_modem_hup(info, 0);
2542 return 1;
2544 break;
2545 case ISDN_STAT_BCONN:
2546 #ifdef ISDN_TTY_STAT_DEBUG
2547 printk(KERN_DEBUG "tty_STAT_BCONN ttyI%d\n", info->line);
2548 #endif
2549 /* Schedule CONNECT-Message to any tty
2550 * waiting for it and
2551 * set DCD-bit of its modem-status.
2553 if (TTY_IS_ACTIVE(info)) {
2554 info->msr |= UART_MSR_DCD;
2555 info->emu.charge = 0;
2556 if (info->dialing & 0xf)
2557 info->last_dir = 1;
2558 else
2559 info->last_dir = 0;
2560 info->dialing = 0;
2561 info->rcvsched = 1;
2562 if (USG_MODEM(dev->usage[i])) {
2563 if (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) {
2564 strcpy(info->emu.connmsg, c->parm.num);
2565 isdn_tty_modem_result(1, info);
2567 else
2568 isdn_tty_modem_result(5, info);
2570 if (USG_VOICE(dev->usage[i]))
2571 isdn_tty_modem_result(11, info);
2572 return 1;
2574 break;
2575 case ISDN_STAT_BHUP:
2576 #ifdef ISDN_TTY_STAT_DEBUG
2577 printk(KERN_DEBUG "tty_STAT_BHUP ttyI%d\n", info->line);
2578 #endif
2579 if (TTY_IS_ACTIVE(info)) {
2580 #ifdef ISDN_DEBUG_MODEM_HUP
2581 printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n");
2582 #endif
2583 isdn_tty_modem_hup(info, 0);
2584 return 1;
2586 break;
2587 case ISDN_STAT_NODCH:
2588 #ifdef ISDN_TTY_STAT_DEBUG
2589 printk(KERN_DEBUG "tty_STAT_NODCH ttyI%d\n", info->line);
2590 #endif
2591 if (TTY_IS_ACTIVE(info)) {
2592 if (info->dialing) {
2593 info->dialing = 0;
2594 info->last_l2 = -1;
2595 info->last_si = 0;
2596 sprintf(info->last_cause, "0000");
2597 isdn_tty_modem_result(6, info);
2599 isdn_tty_modem_hup(info, 0);
2600 return 1;
2602 break;
2603 case ISDN_STAT_UNLOAD:
2604 #ifdef ISDN_TTY_STAT_DEBUG
2605 printk(KERN_DEBUG "tty_STAT_UNLOAD ttyI%d\n", info->line);
2606 #endif
2607 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
2608 info = &dev->mdm.info[i];
2609 if (info->isdn_driver == c->driver) {
2610 if (info->online)
2611 isdn_tty_modem_hup(info, 1);
2614 return 1;
2617 return 0;
2620 /*********************************************************************
2621 Modem-Emulator-Routines
2622 *********************************************************************/
2624 #define cmdchar(c) ((c>' ')&&(c<=0x7f))
2627 * Put a message from the AT-emulator into receive-buffer of tty,
2628 * convert CR, LF, and BS to values in modem-registers 3, 4 and 5.
2630 static void
2631 isdn_tty_at_cout(char *msg, modem_info * info)
2633 struct tty_struct *tty;
2634 atemu *m = &info->emu;
2635 char *p;
2636 char c;
2637 ulong flags;
2639 if (!msg) {
2640 printk(KERN_WARNING "isdn_tty: Null-Message in isdn_tty_at_cout\n");
2641 return;
2643 save_flags(flags);
2644 cli();
2645 tty = info->tty;
2646 for (p = msg; *p; p++) {
2647 switch (*p) {
2648 case '\r':
2649 c = m->mdmreg[REG_CR];
2650 break;
2651 case '\n':
2652 c = m->mdmreg[REG_LF];
2653 break;
2654 case '\b':
2655 c = m->mdmreg[REG_BS];
2656 break;
2657 default:
2658 c = *p;
2660 if ((info->flags & ISDN_ASYNC_CLOSING) || (!tty)) {
2661 restore_flags(flags);
2662 return;
2664 if (tty->flip.count >= TTY_FLIPBUF_SIZE)
2665 break;
2666 tty_insert_flip_char(tty, c, 0);
2668 restore_flags(flags);
2669 queue_task(&tty->flip.tqueue, &tq_timer);
2673 * Perform ATH Hangup
2675 static void
2676 isdn_tty_on_hook(modem_info * info)
2678 if (info->isdn_channel >= 0) {
2679 #ifdef ISDN_DEBUG_MODEM_HUP
2680 printk(KERN_DEBUG "Mhup in isdn_tty_on_hook\n");
2681 #endif
2682 isdn_tty_modem_hup(info, 1);
2686 static void
2687 isdn_tty_off_hook(void)
2689 printk(KERN_DEBUG "isdn_tty_off_hook\n");
2692 #define PLUSWAIT1 (HZ/2) /* 0.5 sec. */
2693 #define PLUSWAIT2 (HZ*3/2) /* 1.5 sec */
2696 * Check Buffer for Modem-escape-sequence, activate timer-callback to
2697 * isdn_tty_modem_escape() if sequence found.
2699 * Parameters:
2700 * p pointer to databuffer
2701 * plus escape-character
2702 * count length of buffer
2703 * pluscount count of valid escape-characters so far
2704 * lastplus timestamp of last character
2706 static void
2707 isdn_tty_check_esc(const u_char * p, u_char plus, int count, int *pluscount,
2708 int *lastplus, int from_user)
2710 char cbuf[3];
2712 if (plus > 127)
2713 return;
2714 if (count > 3) {
2715 p += count - 3;
2716 count = 3;
2717 *pluscount = 0;
2719 if (from_user) {
2720 copy_from_user(cbuf, p, count);
2721 p = cbuf;
2723 while (count > 0) {
2724 if (*(p++) == plus) {
2725 if ((*pluscount)++) {
2726 /* Time since last '+' > 0.5 sec. ? */
2727 if ((jiffies - *lastplus) > PLUSWAIT1)
2728 *pluscount = 1;
2729 } else {
2730 /* Time since last non-'+' < 1.5 sec. ? */
2731 if ((jiffies - *lastplus) < PLUSWAIT2)
2732 *pluscount = 0;
2734 if ((*pluscount == 3) && (count = 1))
2735 isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, 1);
2736 if (*pluscount > 3)
2737 *pluscount = 1;
2738 } else
2739 *pluscount = 0;
2740 *lastplus = jiffies;
2741 count--;
2746 * Return result of AT-emulator to tty-receive-buffer, depending on
2747 * modem-register 12, bit 0 and 1.
2748 * For CONNECT-messages also switch to online-mode.
2749 * For RING-message handle auto-ATA if register 0 != 0
2751 static void
2752 isdn_tty_modem_result(int code, modem_info * info)
2754 atemu *m = &info->emu;
2755 static char *msg[] =
2756 {"OK", "CONNECT", "RING", "NO CARRIER", "ERROR",
2757 "CONNECT 64000", "NO DIALTONE", "BUSY", "NO ANSWER",
2758 "RINGING", "NO MSN/EAZ", "VCON", "RUNG"};
2759 ulong flags;
2760 char s[ISDN_MSNLEN+10];
2762 switch (code) {
2763 case 2:
2764 m->mdmreg[REG_RINGCNT]++; /* RING */
2765 if (m->mdmreg[REG_RINGCNT] == m->mdmreg[REG_RINGATA])
2766 /* Automatically accept incoming call */
2767 isdn_tty_cmd_ATA(info);
2768 break;
2769 case 3:
2770 /* NO CARRIER */
2771 #ifdef ISDN_DEBUG_MODEM_HUP
2772 printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n",
2773 (info->flags & ISDN_ASYNC_CLOSING),
2774 (!info->tty));
2775 #endif
2776 save_flags(flags);
2777 cli();
2778 m->mdmreg[REG_RINGCNT] = 0;
2779 del_timer(&info->nc_timer);
2780 info->ncarrier = 0;
2781 if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
2782 restore_flags(flags);
2783 return;
2785 restore_flags(flags);
2786 #ifdef CONFIG_ISDN_AUDIO
2787 if (info->vonline & 1) {
2788 #ifdef ISDN_DEBUG_MODEM_VOICE
2789 printk(KERN_DEBUG "res3: send DLE-ETX on ttyI%d\n",
2790 info->line);
2791 #endif
2792 /* voice-recording, add DLE-ETX */
2793 isdn_tty_at_cout("\020\003", info);
2795 if (info->vonline & 2) {
2796 #ifdef ISDN_DEBUG_MODEM_VOICE
2797 printk(KERN_DEBUG "res3: send DLE-DC4 on ttyI%d\n",
2798 info->line);
2799 #endif
2800 /* voice-playing, add DLE-DC4 */
2801 isdn_tty_at_cout("\020\024", info);
2803 #endif
2804 break;
2805 case 1:
2806 case 5:
2807 sprintf(info->last_cause, "0000");
2808 if (!info->online)
2809 info->online = 2;
2810 break;
2811 case 11:
2812 #ifdef ISDN_DEBUG_MODEM_VOICE
2813 printk(KERN_DEBUG "res3: send VCON on ttyI%d\n",
2814 info->line);
2815 #endif
2816 sprintf(info->last_cause, "0000");
2817 if (!info->online)
2818 info->online = 1;
2819 break;
2821 if (m->mdmreg[REG_RESP] & BIT_RESP) {
2822 /* Show results */
2823 isdn_tty_at_cout("\r\n", info);
2824 if (m->mdmreg[REG_RESPNUM] & BIT_RESPNUM) {
2825 /* Show numeric results */
2826 sprintf(s, "%d", code);
2827 isdn_tty_at_cout(s, info);
2828 } else {
2829 if ((code == 2) &&
2830 (m->mdmreg[REG_RUNG] & BIT_RUNG) &&
2831 (m->mdmreg[REG_RINGCNT] > 1))
2832 return;
2833 if ((code == 2) && (!(m->mdmreg[REG_CIDONCE] & BIT_CIDONCE))) {
2834 isdn_tty_at_cout("CALLER NUMBER: ", info);
2835 isdn_tty_at_cout(dev->num[info->drv_index], info);
2836 isdn_tty_at_cout("\r\n", info);
2838 isdn_tty_at_cout(msg[code], info);
2839 switch (code) {
2840 case 1:
2841 switch (m->mdmreg[REG_L2PROT]) {
2842 case ISDN_PROTO_L2_MODEM:
2843 isdn_tty_at_cout(" ", info);
2844 isdn_tty_at_cout(m->connmsg, info);
2845 break;
2847 break;
2848 case 2:
2849 /* Append CPN, if enabled */
2850 if ((m->mdmreg[REG_RESRXT] & BIT_RESRXT)) {
2851 sprintf(s, "/%s", m->cpn);
2852 isdn_tty_at_cout(s, info);
2854 /* Print CID only once, _after_ 1.st RING */
2855 if ((m->mdmreg[REG_CIDONCE] & BIT_CIDONCE) &&
2856 (m->mdmreg[REG_RINGCNT] == 1)) {
2857 isdn_tty_at_cout("\r\n", info);
2858 isdn_tty_at_cout("CALLER NUMBER: ", info);
2859 isdn_tty_at_cout(dev->num[info->drv_index], info);
2861 break;
2862 case 3:
2863 case 6:
2864 case 7:
2865 case 8:
2866 m->mdmreg[REG_RINGCNT] = 0;
2867 /* Append Cause-Message if enabled */
2868 if (m->mdmreg[REG_RESPXT] & BIT_RESPXT) {
2869 sprintf(s, "/%s", info->last_cause);
2870 isdn_tty_at_cout(s, info);
2872 break;
2873 case 5:
2874 /* Append Protocol to CONNECT message */
2875 switch (m->mdmreg[REG_L2PROT]) {
2876 case ISDN_PROTO_L2_X75I:
2877 case ISDN_PROTO_L2_X75UI:
2878 case ISDN_PROTO_L2_X75BUI:
2879 isdn_tty_at_cout("/X.75", info);
2880 break;
2881 case ISDN_PROTO_L2_HDLC:
2882 isdn_tty_at_cout("/HDLC", info);
2883 break;
2884 case ISDN_PROTO_L2_V11096:
2885 isdn_tty_at_cout("/V110/9600", info);
2886 break;
2887 case ISDN_PROTO_L2_V11019:
2888 isdn_tty_at_cout("/V110/19200", info);
2889 break;
2890 case ISDN_PROTO_L2_V11038:
2891 isdn_tty_at_cout("/V110/38400", info);
2892 break;
2894 if (m->mdmreg[REG_T70] & BIT_T70) {
2895 isdn_tty_at_cout("/T.70", info);
2896 if (m->mdmreg[REG_T70] & BIT_T70_EXT)
2897 isdn_tty_at_cout("+", info);
2899 break;
2902 isdn_tty_at_cout("\r\n", info);
2904 if (code == 3) {
2905 save_flags(flags);
2906 cli();
2907 if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
2908 restore_flags(flags);
2909 return;
2911 if (info->tty->ldisc.flush_buffer)
2912 info->tty->ldisc.flush_buffer(info->tty);
2913 if ((info->flags & ISDN_ASYNC_CHECK_CD) &&
2914 (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
2915 (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) {
2916 tty_hangup(info->tty);
2918 restore_flags(flags);
2923 * Display a modem-register-value.
2925 static void
2926 isdn_tty_show_profile(int ridx, modem_info * info)
2928 char v[6];
2930 sprintf(v, "\r\n%d", info->emu.mdmreg[ridx]);
2931 isdn_tty_at_cout(v, info);
2935 * Get MSN-string from char-pointer, set pointer to end of number
2937 static void
2938 isdn_tty_get_msnstr(char *n, char **p)
2940 while ((*p[0] >= '0' && *p[0] <= '9') ||
2941 /* Why a comma ??? */
2942 (*p[0] == ','))
2943 *n++ = *p[0]++;
2944 *n = '\0';
2948 * Get phone-number from modem-commandbuffer
2950 static void
2951 isdn_tty_getdial(char *p, char *q,int cnt)
2953 int first = 1;
2954 int limit=39; /* MUST match the size in isdn_tty_parse to avoid
2955 buffer overflow */
2957 while (strchr("0123456789,#.*WPTS-", *p) && *p && --cnt>0) {
2958 if ((*p >= '0' && *p <= '9') || ((*p == 'S') && first))
2959 *q++ = *p;
2960 p++;
2961 if(!--limit)
2962 break;
2963 first = 0;
2965 *q = 0;
2968 #define PARSE_ERROR { isdn_tty_modem_result(4, info); return; }
2969 #define PARSE_ERROR1 { isdn_tty_modem_result(4, info); return 1; }
2971 static void
2972 isdn_tty_report(modem_info * info)
2974 atemu *m = &info->emu;
2975 char s[80];
2977 isdn_tty_at_cout("\r\nStatistics of last connection:\r\n\r\n", info);
2978 sprintf(s, " Remote Number: %s\r\n", info->last_num);
2979 isdn_tty_at_cout(s, info);
2980 sprintf(s, " Direction: %s\r\n", info->last_dir ? "outgoing" : "incoming");
2981 isdn_tty_at_cout(s, info);
2982 isdn_tty_at_cout(" Layer-2 Protocol: ", info);
2983 switch (info->last_l2) {
2984 case ISDN_PROTO_L2_X75I:
2985 isdn_tty_at_cout("X.75i", info);
2986 break;
2987 case ISDN_PROTO_L2_X75UI:
2988 isdn_tty_at_cout("X.75ui", info);
2989 break;
2990 case ISDN_PROTO_L2_X75BUI:
2991 isdn_tty_at_cout("X.75bui", info);
2992 break;
2993 case ISDN_PROTO_L2_HDLC:
2994 isdn_tty_at_cout("HDLC", info);
2995 break;
2996 case ISDN_PROTO_L2_V11096:
2997 isdn_tty_at_cout("V.110 9600 Baud", info);
2998 break;
2999 case ISDN_PROTO_L2_V11019:
3000 isdn_tty_at_cout("V.110 19200 Baud", info);
3001 break;
3002 case ISDN_PROTO_L2_V11038:
3003 isdn_tty_at_cout("V.110 38400 Baud", info);
3004 break;
3005 case ISDN_PROTO_L2_TRANS:
3006 isdn_tty_at_cout("transparent", info);
3007 break;
3008 case ISDN_PROTO_L2_MODEM:
3009 isdn_tty_at_cout("modem", info);
3010 break;
3011 default:
3012 isdn_tty_at_cout("unknown", info);
3013 break;
3015 if (m->mdmreg[REG_T70] & BIT_T70) {
3016 isdn_tty_at_cout("/T.70", info);
3017 if (m->mdmreg[REG_T70] & BIT_T70_EXT)
3018 isdn_tty_at_cout("+", info);
3020 isdn_tty_at_cout("\r\n", info);
3021 isdn_tty_at_cout(" Service: ", info);
3022 switch (info->last_si) {
3023 case 1:
3024 isdn_tty_at_cout("audio\r\n", info);
3025 break;
3026 case 5:
3027 isdn_tty_at_cout("btx\r\n", info);
3028 break;
3029 case 7:
3030 isdn_tty_at_cout("data\r\n", info);
3031 break;
3032 default:
3033 sprintf(s, "%d\r\n", info->last_si);
3034 isdn_tty_at_cout(s, info);
3035 break;
3037 sprintf(s, " Hangup location: %s\r\n", info->last_lhup ? "local" : "remote");
3038 isdn_tty_at_cout(s, info);
3039 sprintf(s, " Last cause: %s\r\n", info->last_cause);
3040 isdn_tty_at_cout(s, info);
3044 * Parse AT&.. commands.
3046 static int
3047 isdn_tty_cmd_ATand(char **p, modem_info * info)
3049 atemu *m = &info->emu;
3050 int i;
3051 char rb[100];
3053 #define MAXRB (sizeof(rb) - 1)
3055 switch (*p[0]) {
3056 case 'B':
3057 /* &B - Set Buffersize */
3058 p[0]++;
3059 i = isdn_getnum(p);
3060 if ((i < 0) || (i > ISDN_SERIAL_XMIT_MAX))
3061 PARSE_ERROR1;
3062 #ifdef CONFIG_ISDN_AUDIO
3063 if ((m->mdmreg[REG_SI1] & 1) && (i > VBUF))
3064 PARSE_ERROR1;
3065 #endif
3066 m->mdmreg[REG_PSIZE] = i / 16;
3067 info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
3068 switch (m->mdmreg[REG_L2PROT]) {
3069 case ISDN_PROTO_L2_V11096:
3070 case ISDN_PROTO_L2_V11019:
3071 case ISDN_PROTO_L2_V11038:
3072 info->xmit_size /= 10;
3074 break;
3075 case 'D':
3076 /* &D - Set DCD-Low-behavior */
3077 p[0]++;
3078 switch (isdn_getnum(p)) {
3079 case 0:
3080 m->mdmreg[REG_DTRHUP] &= ~BIT_DTRHUP;
3081 m->mdmreg[REG_DTRR] &= ~BIT_DTRR;
3082 break;
3083 case 2:
3084 m->mdmreg[REG_DTRHUP] |= BIT_DTRHUP;
3085 m->mdmreg[REG_DTRR] &= ~BIT_DTRR;
3086 break;
3087 case 3:
3088 m->mdmreg[REG_DTRHUP] |= BIT_DTRHUP;
3089 m->mdmreg[REG_DTRR] |= BIT_DTRR;
3090 break;
3091 default:
3092 PARSE_ERROR1
3094 break;
3095 case 'E':
3096 /* &E -Set EAZ/MSN */
3097 p[0]++;
3098 isdn_tty_get_msnstr(m->msn, p);
3099 break;
3100 case 'F':
3101 /* &F -Set Factory-Defaults */
3102 p[0]++;
3103 isdn_tty_reset_profile(m);
3104 isdn_tty_modem_reset_regs(info, 1);
3105 break;
3106 case 'L':
3107 /* &L -Set Numbers to listen on */
3108 p[0]++;
3109 i = 0;
3110 while ((strchr("0123456789,*[]?;", *p[0])) &&
3111 (i < ISDN_LMSNLEN))
3112 m->lmsn[i++] = *p[0]++;
3113 m->lmsn[i] = '\0';
3114 break;
3115 case 'R':
3116 /* &R - Set V.110 bitrate adaption */
3117 p[0]++;
3118 i = isdn_getnum(p);
3119 switch (i) {
3120 case 0:
3121 /* Switch off V.110, back to X.75 */
3122 m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
3123 m->mdmreg[REG_SI2] = 0;
3124 info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
3125 break;
3126 case 9600:
3127 m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11096;
3128 m->mdmreg[REG_SI2] = 197;
3129 info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
3130 break;
3131 case 19200:
3132 m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11019;
3133 m->mdmreg[REG_SI2] = 199;
3134 info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
3135 break;
3136 case 38400:
3137 m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11038;
3138 m->mdmreg[REG_SI2] = 198; /* no existing standard for this */
3139 info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10;
3140 break;
3141 default:
3142 PARSE_ERROR1;
3144 /* Switch off T.70 */
3145 m->mdmreg[REG_T70] &= ~(BIT_T70 | BIT_T70_EXT);
3146 /* Set Service 7 */
3147 m->mdmreg[REG_SI1] |= 4;
3148 break;
3149 case 'S':
3150 /* &S - Set Windowsize */
3151 p[0]++;
3152 i = isdn_getnum(p);
3153 if ((i > 0) && (i < 9))
3154 m->mdmreg[REG_WSIZE] = i;
3155 else
3156 PARSE_ERROR1;
3157 break;
3158 case 'V':
3159 /* &V - Show registers */
3160 p[0]++;
3161 isdn_tty_at_cout("\r\n", info);
3162 for (i = 0; i < ISDN_MODEM_ANZREG; i++) {
3163 sprintf(rb, "S%02d=%03d%s", i,
3164 m->mdmreg[i], ((i + 1) % 10) ? " " : "\r\n");
3165 isdn_tty_at_cout(rb, info);
3167 sprintf(rb, "\r\nEAZ/MSN: %.50s\r\n",
3168 strlen(m->msn) ? m->msn : "None");
3169 isdn_tty_at_cout(rb, info);
3170 if (strlen(m->lmsn)) {
3171 isdn_tty_at_cout("\r\nListen: ", info);
3172 isdn_tty_at_cout(m->lmsn, info);
3173 isdn_tty_at_cout("\r\n", info);
3175 break;
3176 case 'W':
3177 /* &W - Write Profile */
3178 p[0]++;
3179 switch (*p[0]) {
3180 case '0':
3181 p[0]++;
3182 modem_write_profile(m);
3183 break;
3184 default:
3185 PARSE_ERROR1;
3187 break;
3188 case 'X':
3189 /* &X - Switch to BTX-Mode and T.70 */
3190 p[0]++;
3191 switch (isdn_getnum(p)) {
3192 case 0:
3193 m->mdmreg[REG_T70] &= ~(BIT_T70 | BIT_T70_EXT);
3194 info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
3195 break;
3196 case 1:
3197 m->mdmreg[REG_T70] |= BIT_T70;
3198 m->mdmreg[REG_T70] &= ~BIT_T70_EXT;
3199 m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
3200 info->xmit_size = 112;
3201 m->mdmreg[REG_SI1] = 4;
3202 m->mdmreg[REG_SI2] = 0;
3203 break;
3204 case 2:
3205 m->mdmreg[REG_T70] |= (BIT_T70 | BIT_T70_EXT);
3206 m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I;
3207 info->xmit_size = 112;
3208 m->mdmreg[REG_SI1] = 4;
3209 m->mdmreg[REG_SI2] = 0;
3210 break;
3211 default:
3212 PARSE_ERROR1;
3214 break;
3215 default:
3216 PARSE_ERROR1;
3218 return 0;
3221 static int
3222 isdn_tty_check_ats(int mreg, int mval, modem_info * info, atemu * m)
3224 /* Some plausibility checks */
3225 switch (mreg) {
3226 case REG_L2PROT:
3227 if (mval > ISDN_PROTO_L2_MAX)
3228 return 1;
3229 break;
3230 case REG_PSIZE:
3231 if ((mval * 16) > ISDN_SERIAL_XMIT_MAX)
3232 return 1;
3233 #ifdef CONFIG_ISDN_AUDIO
3234 if ((m->mdmreg[REG_SI1] & 1) && (mval > VBUFX))
3235 return 1;
3236 #endif
3237 info->xmit_size = mval * 16;
3238 switch (m->mdmreg[REG_L2PROT]) {
3239 case ISDN_PROTO_L2_V11096:
3240 case ISDN_PROTO_L2_V11019:
3241 case ISDN_PROTO_L2_V11038:
3242 info->xmit_size /= 10;
3244 break;
3245 case REG_SI1I:
3246 case REG_PLAN:
3247 case REG_SCREEN:
3248 /* readonly registers */
3249 return 1;
3251 return 0;
3255 * Perform ATS command
3257 static int
3258 isdn_tty_cmd_ATS(char **p, modem_info * info)
3260 atemu *m = &info->emu;
3261 int bitpos;
3262 int mreg;
3263 int mval;
3264 int bval;
3266 mreg = isdn_getnum(p);
3267 if (mreg < 0 || mreg > ISDN_MODEM_ANZREG)
3268 PARSE_ERROR1;
3269 switch (*p[0]) {
3270 case '=':
3271 p[0]++;
3272 mval = isdn_getnum(p);
3273 if (mval < 0 || mval > 255)
3274 PARSE_ERROR1;
3275 if (isdn_tty_check_ats(mreg, mval, info, m))
3276 PARSE_ERROR1;
3277 m->mdmreg[mreg] = mval;
3278 break;
3279 case '.':
3280 /* Set/Clear a single bit */
3281 p[0]++;
3282 bitpos = isdn_getnum(p);
3283 if ((bitpos < 0) || (bitpos > 7))
3284 PARSE_ERROR1;
3285 switch (*p[0]) {
3286 case '=':
3287 p[0]++;
3288 bval = isdn_getnum(p);
3289 if (bval < 0 || bval > 1)
3290 PARSE_ERROR1;
3291 if (bval)
3292 mval = m->mdmreg[mreg] | (1 << bitpos);
3293 else
3294 mval = m->mdmreg[mreg] & ~(1 << bitpos);
3295 if (isdn_tty_check_ats(mreg, mval, info, m))
3296 PARSE_ERROR1;
3297 m->mdmreg[mreg] = mval;
3298 break;
3299 case '?':
3300 p[0]++;
3301 isdn_tty_at_cout("\r\n", info);
3302 isdn_tty_at_cout((m->mdmreg[mreg] & (1 << bitpos)) ? "1" : "0",
3303 info);
3304 break;
3305 default:
3306 PARSE_ERROR1;
3308 break;
3309 case '?':
3310 p[0]++;
3311 isdn_tty_show_profile(mreg, info);
3312 break;
3313 default:
3314 PARSE_ERROR1;
3315 break;
3317 return 0;
3321 * Perform ATA command
3323 static void
3324 isdn_tty_cmd_ATA(modem_info * info)
3326 atemu *m = &info->emu;
3327 isdn_ctrl cmd;
3328 int l2;
3330 if (info->msr & UART_MSR_RI) {
3331 /* Accept incoming call */
3332 info->last_dir = 0;
3333 strcpy(info->last_num, dev->num[info->drv_index]);
3334 m->mdmreg[REG_RINGCNT] = 0;
3335 info->msr &= ~UART_MSR_RI;
3336 l2 = m->mdmreg[REG_L2PROT];
3337 #ifdef CONFIG_ISDN_AUDIO
3338 /* If more than one bit set in reg18, autoselect Layer2 */
3339 if ((m->mdmreg[REG_SI1] & m->mdmreg[REG_SI1I]) != m->mdmreg[REG_SI1]) {
3340 if (m->mdmreg[REG_SI1I] == 1) {
3341 if (l2 != ISDN_PROTO_L2_MODEM)
3342 l2 = ISDN_PROTO_L2_TRANS;
3343 } else
3344 l2 = ISDN_PROTO_L2_X75I;
3346 #endif
3347 cmd.driver = info->isdn_driver;
3348 cmd.command = ISDN_CMD_SETL2;
3349 cmd.arg = info->isdn_channel + (l2 << 8);
3350 info->last_l2 = l2;
3351 isdn_command(&cmd);
3352 cmd.driver = info->isdn_driver;
3353 cmd.command = ISDN_CMD_SETL3;
3354 cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
3355 isdn_command(&cmd);
3356 cmd.driver = info->isdn_driver;
3357 cmd.arg = info->isdn_channel;
3358 cmd.command = ISDN_CMD_ACCEPTD;
3359 info->dialing = 16;
3360 info->emu.carrierwait = 0;
3361 isdn_command(&cmd);
3362 isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
3363 } else
3364 isdn_tty_modem_result(8, info);
3367 #ifdef CONFIG_ISDN_AUDIO
3369 * Parse AT+F.. commands
3371 static int
3372 isdn_tty_cmd_PLUSF(char **p, modem_info * info)
3374 atemu *m = &info->emu;
3375 int par;
3376 char rs[20];
3378 if (!strncmp(p[0], "CLASS", 5)) {
3379 p[0] += 5;
3380 switch (*p[0]) {
3381 case '?':
3382 p[0]++;
3383 sprintf(rs, "\r\n%d",
3384 (m->mdmreg[REG_SI1] & 1) ? 8 : 0);
3385 isdn_tty_at_cout(rs, info);
3386 break;
3387 case '=':
3388 p[0]++;
3389 switch (*p[0]) {
3390 case '0':
3391 p[0]++;
3392 m->mdmreg[REG_SI1] = 4;
3393 info->xmit_size =
3394 m->mdmreg[REG_PSIZE] * 16;
3395 break;
3396 case '2':
3397 printk(KERN_DEBUG "isdn_tty: FCLASS=2\n");
3398 p[0]++;
3399 break;
3400 case '8':
3401 p[0]++;
3402 m->mdmreg[REG_SI1] = 5;
3403 info->xmit_size = VBUF;
3404 break;
3405 case '?':
3406 p[0]++;
3407 isdn_tty_at_cout("\r\n0,2,8",
3408 info);
3409 break;
3410 default:
3411 PARSE_ERROR1;
3413 break;
3414 default:
3415 PARSE_ERROR1;
3417 return 0;
3419 if (!strncmp(p[0], "AA", 2)) {
3420 p[0] += 2;
3421 switch (*p[0]) {
3422 case '?':
3423 p[0]++;
3424 sprintf(rs, "\r\n%d",
3425 m->mdmreg[REG_RINGATA]);
3426 isdn_tty_at_cout(rs, info);
3427 break;
3428 case '=':
3429 p[0]++;
3430 par = isdn_getnum(p);
3431 if ((par < 0) || (par > 255))
3432 PARSE_ERROR1;
3433 m->mdmreg[REG_RINGATA] = par;
3434 break;
3435 default:
3436 PARSE_ERROR1;
3438 return 0;
3440 if (!strncmp(p[0], "TBC=", 4)) { /* UNKLAR !! */
3441 p[0] += 4;
3442 printk(KERN_DEBUG "isdn_tty: Fax FTBC=%c\n", *p[0]);
3443 switch (*p[0]) {
3444 case '0':
3445 p[0]++;
3446 break;
3447 default:
3448 PARSE_ERROR1;
3450 return 0;
3452 if (!strncmp(p[0], "BOR=", 4)) { /* UNKLAR !! */
3453 p[0] += 4;
3454 printk(KERN_DEBUG "isdn_tty: Fax FBOR=%c\n", *p[0]);
3455 switch (*p[0]) {
3456 case '0':
3457 p[0]++;
3458 break;
3459 default:
3460 PARSE_ERROR1;
3462 return 0;
3464 if (!strncmp(p[0], "DCC=", 4)) { /* SETUP irgendwie !! */
3465 int i, val[]={0,0,0,0,0,0,0,0};
3467 p[0] += 4;
3468 if (*p[0] == '?') {
3469 isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0,1),(0),(0),(0-7)",info);
3470 p[0]++;
3471 } else {
3472 for (i=0; (*p[0]>='0') && (*p[0]<='9'); i++) {
3473 val[i] = *p[0] - 48;
3474 p[0]++;
3475 if (*p[0] == ',')
3476 p[0]++;
3478 printk(KERN_DEBUG "isdn_tty: Fax Setup values=%d,%d,%d,%d,%d,%d,%d,%d\n",
3479 val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7]);
3481 return 0;
3483 if (!strncmp(p[0], "LID=", 4)) { /* set sender ID !! */
3484 char senderID[80];
3485 int i;
3487 p[0] += 4;
3488 if (*p[0] =='"')
3489 p[0]++;
3490 for(i=0; (*p[0]) && (*p[0] != '"'); i++)
3491 senderID[i] = *p[0]++;
3492 senderID[i] = 0;
3493 if (*p[0] =='"')
3494 p[0]++;
3495 printk(KERN_DEBUG "isdn_tty: Fax sender=>%s<\n", senderID);
3496 return 0;
3498 if (!strncmp(p[0], "MFR?", 4)) {
3499 p[0] += 4;
3500 printk(KERN_DEBUG "isdn_tty: FMFR?\n");
3501 isdn_tty_at_cout("\r\nISDNfax", info);
3502 return 0;
3504 if (!strncmp(p[0], "MDL?", 4)) {
3505 p[0] += 4;
3506 printk(KERN_DEBUG "isdn_tty: FMDL?\n");
3507 isdn_tty_at_cout("\r\nAVM-B1", info);
3508 return 0;
3510 if (!strncmp(p[0], "AP=?", 4)) {
3511 p[0] += 4;
3512 printk(KERN_DEBUG "isdn_tty: FAP=?\n");
3513 return 0;
3515 if (!strncmp(p[0], "PHCTO=", 6)) {
3516 /* beim trace mit dem zyxel folgt der wert 30 ;*/
3517 p[0] += 6;
3518 printk(KERN_DEBUG "isdn_tty: FPHCTO=%s\n", p[0]);
3519 return 0;
3521 if (!strncmp(p[0], "CR=", 3)) {
3522 p[0] += 3;
3523 printk(KERN_DEBUG "isdn_tty: FCR=%s\n", p[0]);
3524 return 0;
3526 printk(KERN_DEBUG "isdn_tty: unknown token=>AT+F%s<\n", p[0]);
3527 PARSE_ERROR1;
3531 * Parse AT+V.. commands
3533 static int
3534 isdn_tty_cmd_PLUSV(char **p, modem_info * info)
3536 atemu *m = &info->emu;
3537 static char *vcmd[] =
3538 {"NH", "IP", "LS", "RX", "SD", "SM", "TX", NULL};
3539 int i;
3540 int par1;
3541 int par2;
3542 char rs[20];
3544 i = 0;
3545 while (vcmd[i]) {
3546 if (!strncmp(vcmd[i], p[0], 2)) {
3547 p[0] += 2;
3548 break;
3550 i++;
3552 switch (i) {
3553 case 0:
3554 /* AT+VNH - Auto hangup feature */
3555 switch (*p[0]) {
3556 case '?':
3557 p[0]++;
3558 isdn_tty_at_cout("\r\n1", info);
3559 break;
3560 case '=':
3561 p[0]++;
3562 switch (*p[0]) {
3563 case '1':
3564 p[0]++;
3565 break;
3566 case '?':
3567 p[0]++;
3568 isdn_tty_at_cout("\r\n1", info);
3569 break;
3570 default:
3571 PARSE_ERROR1;
3573 break;
3574 default:
3575 PARSE_ERROR1;
3577 break;
3578 case 1:
3579 /* AT+VIP - Reset all voice parameters */
3580 isdn_tty_modem_reset_vpar(m);
3581 break;
3582 case 2:
3583 /* AT+VLS - Select device, accept incoming call */
3584 switch (*p[0]) {
3585 case '?':
3586 p[0]++;
3587 sprintf(rs, "\r\n%d", m->vpar[0]);
3588 isdn_tty_at_cout(rs, info);
3589 break;
3590 case '=':
3591 p[0]++;
3592 switch (*p[0]) {
3593 case '0':
3594 p[0]++;
3595 m->vpar[0] = 0;
3596 break;
3597 case '2':
3598 p[0]++;
3599 m->vpar[0] = 2;
3600 break;
3601 case '?':
3602 p[0]++;
3603 isdn_tty_at_cout("\r\n0,2", info);
3604 break;
3605 default:
3606 PARSE_ERROR1;
3608 break;
3609 default:
3610 PARSE_ERROR1;
3612 break;
3613 case 3:
3614 /* AT+VRX - Start recording */
3615 if (!m->vpar[0])
3616 PARSE_ERROR1;
3617 if (info->online != 1) {
3618 isdn_tty_modem_result(8, info);
3619 return 1;
3621 info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state);
3622 if (!info->dtmf_state) {
3623 printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n");
3624 PARSE_ERROR1;
3626 info->silence_state = isdn_audio_silence_init(info->silence_state);
3627 if (!info->silence_state) {
3628 printk(KERN_WARNING "isdn_tty: Couldn't malloc silence state\n");
3629 PARSE_ERROR1;
3631 if (m->vpar[3] < 5) {
3632 info->adpcmr = isdn_audio_adpcm_init(info->adpcmr, m->vpar[3]);
3633 if (!info->adpcmr) {
3634 printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n");
3635 PARSE_ERROR1;
3638 #ifdef ISDN_DEBUG_AT
3639 printk(KERN_DEBUG "AT: +VRX\n");
3640 #endif
3641 info->vonline |= 1;
3642 isdn_tty_modem_result(1, info);
3643 return 0;
3644 break;
3645 case 4:
3646 /* AT+VSD - Silence detection */
3647 switch (*p[0]) {
3648 case '?':
3649 p[0]++;
3650 sprintf(rs, "\r\n<%d>,<%d>",
3651 m->vpar[1],
3652 m->vpar[2]);
3653 isdn_tty_at_cout(rs, info);
3654 break;
3655 case '=':
3656 p[0]++;
3657 if ((*p[0]>='0') && (*p[0]<='9')) {
3658 par1 = isdn_getnum(p);
3659 if ((par1 < 0) || (par1 > 31))
3660 PARSE_ERROR1;
3661 if (*p[0] != ',')
3662 PARSE_ERROR1;
3663 p[0]++;
3664 par2 = isdn_getnum(p);
3665 if ((par2 < 0) || (par2 > 255))
3666 PARSE_ERROR1;
3667 m->vpar[1] = par1;
3668 m->vpar[2] = par2;
3669 break;
3670 } else
3671 if (*p[0] == '?') {
3672 p[0]++;
3673 isdn_tty_at_cout("\r\n<0-31>,<0-255>",
3674 info);
3675 break;
3676 } else
3677 PARSE_ERROR1;
3678 break;
3679 default:
3680 PARSE_ERROR1;
3682 break;
3683 case 5:
3684 /* AT+VSM - Select compression */
3685 switch (*p[0]) {
3686 case '?':
3687 p[0]++;
3688 sprintf(rs, "\r\n<%d>,<%d><8000>",
3689 m->vpar[3],
3690 m->vpar[1]);
3691 isdn_tty_at_cout(rs, info);
3692 break;
3693 case '=':
3694 p[0]++;
3695 switch (*p[0]) {
3696 case '2':
3697 case '3':
3698 case '4':
3699 case '5':
3700 case '6':
3701 par1 = isdn_getnum(p);
3702 if ((par1 < 2) || (par1 > 6))
3703 PARSE_ERROR1;
3704 m->vpar[3] = par1;
3705 break;
3706 case '?':
3707 p[0]++;
3708 isdn_tty_at_cout("\r\n2;ADPCM;2;0;(8000)\r\n",
3709 info);
3710 isdn_tty_at_cout("3;ADPCM;3;0;(8000)\r\n",
3711 info);
3712 isdn_tty_at_cout("4;ADPCM;4;0;(8000)\r\n",
3713 info);
3714 isdn_tty_at_cout("5;ALAW;8;0;(8000)",
3715 info);
3716 isdn_tty_at_cout("6;ULAW;8;0;(8000)",
3717 info);
3718 break;
3719 default:
3720 PARSE_ERROR1;
3722 break;
3723 default:
3724 PARSE_ERROR1;
3726 break;
3727 case 6:
3728 /* AT+VTX - Start sending */
3729 if (!m->vpar[0])
3730 PARSE_ERROR1;
3731 if (info->online != 1) {
3732 isdn_tty_modem_result(8, info);
3733 return 1;
3735 info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state);
3736 if (!info->dtmf_state) {
3737 printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n");
3738 PARSE_ERROR1;
3740 if (m->vpar[3] < 5) {
3741 info->adpcms = isdn_audio_adpcm_init(info->adpcms, m->vpar[3]);
3742 if (!info->adpcms) {
3743 printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n");
3744 PARSE_ERROR1;
3747 #ifdef ISDN_DEBUG_AT
3748 printk(KERN_DEBUG "AT: +VTX\n");
3749 #endif
3750 m->lastDLE = 0;
3751 info->vonline |= 2;
3752 isdn_tty_modem_result(1, info);
3753 return 0;
3754 break;
3755 default:
3756 PARSE_ERROR1;
3758 return 0;
3760 #endif /* CONFIG_ISDN_AUDIO */
3763 * Parse and perform an AT-command-line.
3765 static void
3766 isdn_tty_parse_at(modem_info * info)
3768 atemu *m = &info->emu;
3769 char *p;
3770 char ds[40];
3772 #ifdef ISDN_DEBUG_AT
3773 printk(KERN_DEBUG "AT: '%s'\n", m->mdmcmd);
3774 #endif
3775 for (p = &m->mdmcmd[2]; *p;) {
3776 switch (*p) {
3777 case 'A':
3778 /* A - Accept incoming call */
3779 p++;
3780 isdn_tty_cmd_ATA(info);
3781 return;
3782 break;
3783 case 'D':
3784 /* D - Dial */
3785 isdn_tty_getdial(++p, ds, sizeof ds);
3786 p += strlen(p);
3787 if (!strlen(m->msn))
3788 isdn_tty_modem_result(10, info);
3789 else if (strlen(ds))
3790 isdn_tty_dial(ds, info, m);
3791 else
3792 PARSE_ERROR;
3793 return;
3794 case 'E':
3795 /* E - Turn Echo on/off */
3796 p++;
3797 switch (isdn_getnum(&p)) {
3798 case 0:
3799 m->mdmreg[REG_ECHO] &= ~BIT_ECHO;
3800 break;
3801 case 1:
3802 m->mdmreg[REG_ECHO] |= BIT_ECHO;
3803 break;
3804 default:
3805 PARSE_ERROR;
3807 break;
3808 case 'H':
3809 /* H - On/Off-hook */
3810 p++;
3811 switch (*p) {
3812 case '0':
3813 p++;
3814 isdn_tty_on_hook(info);
3815 break;
3816 case '1':
3817 p++;
3818 isdn_tty_off_hook();
3819 break;
3820 default:
3821 isdn_tty_on_hook(info);
3822 break;
3824 break;
3825 case 'I':
3826 /* I - Information */
3827 p++;
3828 isdn_tty_at_cout("\r\nLinux ISDN", info);
3829 switch (*p) {
3830 case '0':
3831 case '1':
3832 p++;
3833 break;
3834 case '2':
3835 p++;
3836 isdn_tty_report(info);
3837 break;
3838 case '3':
3839 p++;
3840 sprintf(ds, "\r\n%d", info->emu.charge);
3841 isdn_tty_at_cout(ds, info);
3842 break;
3843 default:
3845 break;
3846 case 'O':
3847 /* O - Go online */
3848 p++;
3849 if (info->msr & UART_MSR_DCD)
3850 /* if B-Channel is up */
3851 isdn_tty_modem_result((m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) ? 1:5, info);
3852 else
3853 isdn_tty_modem_result(3, info);
3854 return;
3855 case 'Q':
3856 /* Q - Turn Emulator messages on/off */
3857 p++;
3858 switch (isdn_getnum(&p)) {
3859 case 0:
3860 m->mdmreg[REG_RESP] |= BIT_RESP;
3861 break;
3862 case 1:
3863 m->mdmreg[REG_RESP] &= ~BIT_RESP;
3864 break;
3865 default:
3866 PARSE_ERROR;
3868 break;
3869 case 'S':
3870 /* S - Set/Get Register */
3871 p++;
3872 if (isdn_tty_cmd_ATS(&p, info))
3873 return;
3874 break;
3875 case 'V':
3876 /* V - Numeric or ASCII Emulator-messages */
3877 p++;
3878 switch (isdn_getnum(&p)) {
3879 case 0:
3880 m->mdmreg[REG_RESP] |= BIT_RESPNUM;
3881 break;
3882 case 1:
3883 m->mdmreg[REG_RESP] &= ~BIT_RESPNUM;
3884 break;
3885 default:
3886 PARSE_ERROR;
3888 break;
3889 case 'Z':
3890 /* Z - Load Registers from Profile */
3891 p++;
3892 if (info->msr & UART_MSR_DCD) {
3893 info->online = 0;
3894 isdn_tty_on_hook(info);
3896 isdn_tty_modem_reset_regs(info, 1);
3897 break;
3898 case '+':
3899 p++;
3900 switch (*p) {
3901 #ifdef CONFIG_ISDN_AUDIO
3902 case 'F':
3903 p++;
3904 if (isdn_tty_cmd_PLUSF(&p, info))
3905 return;
3906 break;
3907 case 'V':
3908 if ((!(m->mdmreg[REG_SI1] & 1)) ||
3909 (m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM))
3910 PARSE_ERROR;
3911 p++;
3912 if (isdn_tty_cmd_PLUSV(&p, info))
3913 return;
3914 break;
3915 #endif /* CONFIG_ISDN_AUDIO */
3916 case 'S': /* SUSPEND */
3917 p++;
3918 isdn_tty_get_msnstr(ds, &p);
3919 isdn_tty_suspend(ds, info, m);
3920 break;
3921 case 'R': /* RESUME */
3922 isdn_tty_get_msnstr(ds, &p);
3923 isdn_tty_resume(ds, info, m);
3924 case 'M': /* MESSAGE */
3925 p++;
3926 isdn_tty_send_msg(info, m, p);
3927 break;
3928 default:
3929 PARSE_ERROR;
3931 break;
3932 case '&':
3933 p++;
3934 if (isdn_tty_cmd_ATand(&p, info))
3935 return;
3936 break;
3937 default:
3938 PARSE_ERROR;
3941 #ifdef CONFIG_ISDN_AUDIO
3942 if (!info->vonline)
3943 #endif
3944 isdn_tty_modem_result(0, info);
3947 /* Need own toupper() because standard-toupper is not available
3948 * within modules.
3950 #define my_toupper(c) (((c>='a')&&(c<='z'))?(c&0xdf):c)
3953 * Perform line-editing of AT-commands
3955 * Parameters:
3956 * p inputbuffer
3957 * count length of buffer
3958 * channel index to line (minor-device)
3959 * user flag: buffer is in userspace
3961 static int
3962 isdn_tty_edit_at(const char *p, int count, modem_info * info, int user)
3964 atemu *m = &info->emu;
3965 int total = 0;
3966 u_char c;
3967 char eb[2];
3968 int cnt;
3970 for (cnt = count; cnt > 0; p++, cnt--) {
3971 if (user)
3972 get_user(c, p);
3973 else
3974 c = *p;
3975 total++;
3976 if (c == m->mdmreg[REG_CR] || c == m->mdmreg[REG_LF]) {
3977 /* Separator (CR oder LF) */
3978 m->mdmcmd[m->mdmcmdl] = 0;
3979 if (m->mdmreg[REG_ECHO] & BIT_ECHO) {
3980 eb[0] = c;
3981 eb[1] = 0;
3982 isdn_tty_at_cout(eb, info);
3984 if (m->mdmcmdl >= 2)
3985 isdn_tty_parse_at(info);
3986 m->mdmcmdl = 0;
3987 continue;
3989 if (c == m->mdmreg[REG_BS] && m->mdmreg[REG_BS] < 128) {
3990 /* Backspace-Funktion */
3991 if ((m->mdmcmdl > 2) || (!m->mdmcmdl)) {
3992 if (m->mdmcmdl)
3993 m->mdmcmdl--;
3994 if (m->mdmreg[REG_ECHO] & BIT_ECHO)
3995 isdn_tty_at_cout("\b", info);
3997 continue;
3999 if (cmdchar(c)) {
4000 if (m->mdmreg[REG_ECHO] & BIT_ECHO) {
4001 eb[0] = c;
4002 eb[1] = 0;
4003 isdn_tty_at_cout(eb, info);
4005 if (m->mdmcmdl < 255) {
4006 c = my_toupper(c);
4007 switch (m->mdmcmdl) {
4008 case 0:
4009 if (c == 'A')
4010 m->mdmcmd[m->mdmcmdl++] = c;
4011 break;
4012 case 1:
4013 if (c == 'T')
4014 m->mdmcmd[m->mdmcmdl++] = c;
4015 break;
4016 default:
4017 m->mdmcmd[m->mdmcmdl++] = c;
4022 return total;
4026 * Switch all modem-channels who are online and got a valid
4027 * escape-sequence 1.5 seconds ago, to command-mode.
4028 * This function is called every second via timer-interrupt from within
4029 * timer-dispatcher isdn_timer_function()
4031 void
4032 isdn_tty_modem_escape(void)
4034 int ton = 0;
4035 int i;
4036 int midx;
4038 for (i = 0; i < ISDN_MAX_CHANNELS; i++)
4039 if (USG_MODEM(dev->usage[i]))
4040 if ((midx = dev->m_idx[i]) >= 0) {
4041 modem_info *info = &dev->mdm.info[midx];
4042 if (info->online) {
4043 ton = 1;
4044 if ((info->emu.pluscount == 3) &&
4045 ((jiffies - info->emu.lastplus) > PLUSWAIT2)) {
4046 info->emu.pluscount = 0;
4047 info->online = 0;
4048 isdn_tty_modem_result(0, info);
4052 isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, ton);
4056 * Put a RING-message to all modem-channels who have the RI-bit set.
4057 * This function is called every second via timer-interrupt from within
4058 * timer-dispatcher isdn_timer_function()
4060 void
4061 isdn_tty_modem_ring(void)
4063 int ton = 0;
4064 int i;
4066 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
4067 modem_info *info = &dev->mdm.info[i];
4068 if (info->msr & UART_MSR_RI) {
4069 ton = 1;
4070 isdn_tty_modem_result(2, info);
4073 isdn_timer_ctrl(ISDN_TIMER_MODEMRING, ton);
4077 * For all online tty's, try sending data to
4078 * the lower levels.
4080 void
4081 isdn_tty_modem_xmit(void)
4083 int ton = 1;
4084 int i;
4086 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
4087 modem_info *info = &dev->mdm.info[i];
4088 if (info->online) {
4089 ton = 1;
4090 isdn_tty_senddown(info);
4091 isdn_tty_tint(info);
4094 isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, ton);
4098 * Check all channels if we have a 'no carrier' timeout.
4099 * Timeout value is set by Register S7.
4101 void
4102 isdn_tty_carrier_timeout(void)
4104 int ton = 0;
4105 int i;
4107 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
4108 modem_info *info = &dev->mdm.info[i];
4109 if (info->dialing) {
4110 if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) {
4111 info->dialing = 0;
4112 isdn_tty_modem_result(3, info);
4113 isdn_tty_modem_hup(info, 1);
4115 else
4116 ton = 1;
4119 isdn_timer_ctrl(ISDN_TIMER_CARRIER, ton);