ostroff@oswego.Oswego.EDU (Boyd Ostroff) (09/26/88)
I keep reading about the problems everyone is having with external modems on the UNIX PC. I have seen several solutions posted, but they either involved getting HDB UUCP (how?), having a modem with non-volatile memory, or required a number of various background processes to be run from the crontab. After rejecting these, I came up with my own. I feel it is a simple and reliable solution. The enclosed "modemon" is run in place of /etc/getty from the /etc/inittab and will enable you to use one modem connected to tty000 for both incoming and outgoing calls. Be sure to look at the enclosed README file before installing this on your system. I'm posting it in the hope that it will save others from spending the many frustrating hours of "trial and error" that I had to..... ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: Boyd Ostroff, Technical Director :::::: System Operator, "The CallBoard" ::: :::: Dept of Theatre, SUNY Oswego ::::::: (315) 947-6414 300/1200/2400 baud ::: ::::: ostroff@oswego.Oswego.EDU :::::::: rutgers!sunybcs!oswego!cboard!sysop :: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: #--------------------------------CUT HERE------------------------------------- #! /bin/sh # # This is a shell archive. Save this into a file, edit it # and delete all lines above this comment. Then give this # file to sh by executing the command "sh file". The files # will be extracted into the current directory owned by # you with default permissions. # # The files contained herein are: # # -rw-r--r-- 1 ostroff prog 5707 Sep 25 14:36 README # -rw-r--r-- 1 ostroff prog 1258 Sep 25 14:23 modemon.sh # -rw-r--r-- 1 ostroff prog 5463 Sep 25 19:56 modemon.c # echo 'x - README' if test -f README; then echo 'shar: not overwriting README'; else sed 's/^X//' << '________This_Is_The_END________' > README X+-----------------------------------------------------------------------+ X| MODEMON - configure an external modem for use on a Unix PC RS232 port | X| by Boyd Ostroff (ostroff@oswego.Oswego.EDU) 9/20/88 | X+-----------------------------------------------------------------------+ X XThis program was developed and tested using version 3.51a of the OS; it X*should* work with other versions, but I haven't tried it. I am running Xthe stock, "out-of-the-box" uucp and uucico (not HDB). My modem is an XEverex EMAC MD2400+ with MNP, but it should be pretty simple to modify this Xprogram work with your modem. X X XHOW IT WORKS X------------ XThree things are necessary to use a modem bi-directionally: X X1) For outgoing calls, the getty on the port must be killed and then Xre-started for incoming calls. The /usr/bin/getoff.sh and /usr/bin/geton.sh Xscripts provide this function on the Unix PC by "commenting out" the Xappropriate line in /etc/inittab. They are called by uucico and cu. X X2) The modem must be configured for outgoing calls. This is done by Xcreating an entry in /usr/lib/uucp/modemcap. X X3) The modem must be configured for incoming calls - this is the missing Xfunction. The short program "modemon" sends commands to the modem Xand provides some error checking and logging. A very simple shell script Xcalled "modemon.sh" is placed in /etc/inittab instead of the getty for Xtty000. This shell script calls modemon to initialize the modem and then Xexecs getty. X X XSETTING HARDWARE SWITCHES X------------------------- XFollowing is my modem's switch configuration - yours may be different, but Xnotice the *function* of each switch. X XSW1 - ON - DTR must be high for modem to accept input or answer a call XSW2 - OFF - Result codes sent as words XSW3 - ON - Result codes are not sent XSW4 - ON - Commands are not echoed XSW5 - ON - Auto-answer enabled (but only if DTR is high) XSW6 - ON - DCD follows received carrier signal XSW7 - OFF - RJ11 phone jack XSW8 - OFF - Enable AT command recognition XSW9 - OFF - Use Bell 212A protocol X X XINSTALLATION PROCEDURE X---------------------- XThe easiest way to start is probably to login as install and use the UA Xto configure tty000 for a Hayes modem. After that, follow the steps Xbelow: X X1. Look at the #defines at the beginning of the modemon.c program. As Xsupplied it will use tty000 at 2400 baud - change this as needed. Compile Xthe program by typing "cc -o modemon modemon.c". X X X2. Take a look at the "modemon.sh" shell script. It was written specifically Xfor the Everex, so you may need to modify it to suit your needs. Generally Xspeaking, you should turn off command responses and echo. Also note the final Xline which exec's /etc/getty. I am using 2400 baud and also setting a timeout Xvalue of 30 seconds (-t30). X X X3. Become root and do the following: X X$ cp modemon.sh /etc X$ chmod 700 /etc/modemon.sh X$ cp modemon /etc X$ chmod 700 /etc/modemon X X4. Now you'll need to create the character special file /dev/modem. To do Xthis, simply type: X X$ mknod /dev/modem c 0 128 X XThis will allow you to talk to the modem while DCD is still low. XIf you're not using tty000 for your modem this will need to be modified X(I don't have any other ports, so I couldn't test that :-( X X X5. Before proceeding, test the modemon program. Make sure that tty000 Xis not in use first, then kill the getty on it by typing "getoff.sh 000". XTry sending some commands to your modem and observe the response, for Xexample: X X$ /etc/modemon ATZ Xmodemon: sending "ATZ" XATZ XOK X XIf nothing happens check your hardware switches and also modem cable - Xfor full control you will generally need pins 1 through 8 and 20 all wired Xstraight through. X XWhen you're satisfied that the program works, type "geton.sh 000". X X X6. Next you need to change your /etc/inittab entry so that init will run Xmodemon.sh. Mine looks like this: X X 000:2:respawn:/etc/modemon.sh X^ X| note blank space at the beginning of the line - important! X X X7. You might need to change your entry in /usr/lib/uucp/modemcap. This Xconfigures the modem for dial-out use by cu and uucico. You usually want Xto turn on command echo (E1) and responses (Q0) and turn off auto-answer X(S0=0) for dial-out use. In the example below, note that the line starting Xwith :ta= is the one which does the configuration: X X# Everex EMAC MD2400 X# Name=everex Xev|everex|everex 2400:tr=\r:wp=\r:wk=K:wt=T:wx=0:\ X :ta=at e1 q0 s0=0 \\n1\r:tb=ATDW:\ X :es=\r:\ X :d1#1:d5#9:\ X :pl=tad1wpwkwptbphtrd5wpd5wpwxwxwp: X XThere should be a corresponding entry in /usr/lib/uucp/L-devices: X XACU tty000 everex 2400 X X X8. Finally, type "telinit q", which will cause the system to read the Xnew inittab and then type "kill <pid>", where <pid> is the process id X(as shown by ps -ef) of the getty running on tty000. You should be Xall set! X X X9. Try to log in at various baud rates on your external modem. If you Xhave problems, you'll probably have to change the initialization string Xthat /etc/modemon.sh sends. X XTry placing an outgoing call with uucico -x6 and watch the output for Xerrors; edit /usr/lib/uucp/modemcap as needed to send the correct modem Xcommands. X XWith a little experimentation you should be able to get your modem Xworking reliably in both directions. X X X::::::::::::::::::::::::::::::::::::::::: X:: Boyd Ostroff, Technical Director :: System Operator, "The CallBoard" X:: Department of Theatre, SUNY Oswego :: - Serving the performing arts - X:: Internet: ostroff@oswego.Oswego.EDU :: (315) 947-6414 300/1200/2400 baud X:: Voice: (315) 341-2987 :: UUCP ...sunybcs!oswego!cboard!ostroff X::::::::::::::::::::::::::::::::::::::::: X X ________This_Is_The_END________ if test `wc -l < README` -ne 153; then echo 'shar: README was damaged during transit (should have been 153 bytes)' fi fi ; : end of overwriting check echo 'x - modemon.sh' if test -f modemon.sh; then echo 'shar: not overwriting modemon.sh'; else sed 's/^X//' << '________This_Is_The_END________' > modemon.sh X# modemon.sh - initialize external modem for dial-in use on tty000 X# by Boyd Ostroff (ostroff@oswego.Oswego.EDU) 9/20/88 X X# this program is run by init, and it execs getty after initializing the modem X# you must also have the modemon.c program X X# the following line should be added to /etc/inittab: X# X# 000:2:respawn:/etc/modemon X# X# the meaning of the modem commands are as follows: X# (this version for Everex MD2400+, edit as needed to suit your requirements) X# X# m0 turn off monitor speaker X# e0 disable command echoing X# q1 turn off response display X# s0=2 answer phone on 2nd ring X# s9=2 drop line .2 seconds after carrier drops X# \n3 set MNP auto-reliable mode X# \j0 baud adjust off - modem & computer always talk at 2400 baud X# \q0 disable xon/xoff between computer & modem X# \k5 send break directly X# \t5 set inactivity timer for 5 minutes X# &t5 prohibit modem from entering test mode X Xdate > /usr/adm/modemlog Xecho 'initializing modem...' >> /usr/adm/modemlog X X# first, reset the modem to get to a known state X/etc/modemon "atz" >> /usr/adm/modemlog Xsleep 1 X X# now send the command string X/etc/modemon "at m0 e0 q1 s0=2 s9=2 \j0 \q0 \k5 \n3 \t5 &t5" >> /usr/adm/modemlog X X# finally, fire up a getty on the port Xexec /etc/getty -t30 tty000 2400 ________This_Is_The_END________ if test `wc -l < modemon.sh` -ne 37; then echo 'shar: modemon.sh was damaged during transit (should have been 37 bytes)' fi fi ; : end of overwriting check echo 'x - modemon.c' if test -f modemon.c; then echo 'shar: not overwriting modemon.c'; else sed 's/^X//' << '________This_Is_The_END________' > modemon.c X/*--------------------------------------------------------------------------*/ X/* modemon.c - send commands to an external modem on Unix PC port tty000 */ X/* by Boyd Ostroff (ostroff@oswego.Oswego.EDU) 9/19/88 */ X/*--------------------------------------------------------------------------*/ X/* May be freely modified and distributed as you see fit. */ X/* Designed to work with the shell script "modemon.sh". Please read the */ X/* accompanying README file before using. */ X/*--------------------------------------------------------------------------*/ X X#include <stdio.h> X#include <signal.h> X#include <fcntl.h> X#include <termio.h> X X#define FALSE 0 X#define TRUE 1 X#define ERROR -1 X X/* change these next four lines as needed to suit your needs */ X X#define TIMEOUT 2 /* delay before open on /dev/modem will time out */ X#define SLEEPTIME 2 /* delay to wait while modem executes a command */ X#define MODEMPORT "/dev/modem" /* you must create this - see the README file */ X#define PORTSPEED B2400 /* baud rate as given in termio.h */ X Xstatic int timeout = FALSE; Xstatic char *termname; X X/*--------------------------------------------------------------------------*/ Xmain(argc,argv) /* program should be called with one argument, which is */ Xint argc; /* the command string to be sent to the modem. Use */ Xchar *argv[]; /* double quotes (") to protect whitespace. A carriage */ X{ /* return will be appended to the command string. */ Xint line; Xint pid; Xchar *cmd; Xstruct termio original; X X if ((cmd = argv[1]) == NULL) X { X printf("modemon: no argument given. Usage: modemon \"command\"\n"); X exit(ERROR); X } X if (argc > 2) X { X printf("modemon: too many arguments. Usage: modemon \"command\"\n"); X exit(ERROR); X } X printf("modemon: sending \"%s\"\n", cmd); X if( (line = ttyopen(MODEMPORT, O_RDWR)) == ERROR) X { X exit(ERROR); X } X ioctl(line, TCGETA, &original); /* save initial port settings */ X if (set_line(line, PORTSPEED) == ERROR) X { X exit(ERROR); X } X if ((pid = fork()) != ERROR) /* start a process to read MODEMPORT */ X { X if (pid == 0) /* now we're in the child process */ X listen(line); /* this function never returns - */ X } /* it keeps running until killed */ X send_cmd(line, cmd); X kill(pid, SIGTERM); /* kill the child process */ X wait((int *)0); X ioctl(line, TCSETAW, &original); /* restore initial port settings */ X close(line); X exit(0); X} X X/*--------------------------------------------------------------------------*/ Xsend_cmd(line, what) /* send the command string to the modem */ Xint line; /* tty file descriptor */ Xchar *what; /* modem command */ X{ Xint length; Xint i; Xunsigned char c = '\r'; X X length = strlen(what); X for (i=0; i <= length; i++) X { X write(line, what+i, 1); X } X write(line, &c, 1); /* append a carriage return to end of cmd */ X sleep(SLEEPTIME); /* give modem time to execute the command */ X} X/*--------------------------------------------------------------------------*/ Xstatic int set_timeout() X{ X printf("modemon: timeout on opening %s\n", termname); X timeout = TRUE; X} X X/*--------------------------------------------------------------------------*/ Xset_line(fd, speed) /* configure the port so we can talk to the modem */ Xint fd, speed; X{ Xstruct termio tt; X X if (!isatty(fd)) X { X printf("modemon: not a valid terminal file descriptor\n"); X return(ERROR); X } X if( ioctl(fd, TCGETA, &tt) == ERROR) X { X printf("modemon: can't get current line settings\n"); X return(ERROR); X } /* set the terminal control flags as needed */ X tt.c_iflag = (IXON|IXOFF); /* xon/xoff flow control enabled */ X tt.c_oflag = 0; X tt.c_lflag = 0; X tt.c_cflag &=~CBAUD; X tt.c_cflag |= speed; X tt.c_cc[VMIN] = 1; X tt.c_cc[VTIME] = 0; X if (ioctl(fd, TCSETAW, &tt) == ERROR) /* flush & reset line */ X { X printf("modemon: can't change current line settings\n"); X return(ERROR); X } X X X} X/*--------------------------------------------------------------------------*/ Xttyopen(filename, flags) /* open the modem port */ Xchar *filename; /* will wait for TIMEOUT seconds, then give up */ Xint flags; /* see p214 of UNIX SYSTEM PROGRAMMING */ X{ /* by Haviland and Salama */ Xint (*sigfn)(); Xint fd = -1; X X termname = filename; X timeout = FALSE; X sigfn = signal(SIGALRM, set_timeout); X alarm(TIMEOUT); X fd = open(filename, flags); X alarm(0); X signal(SIGALRM, sigfn); X return(timeout ? -1: fd); X} X/*--------------------------------------------------------------------------*/ Xlisten(line) /* send everything that is read from MODEMPORT to stdout */ Xint line; /* this is a child process forked off from the original */ X{ Xunsigned char c; X X for(;;) /* loops forever until killed */ X { X read(line, &c, 1); X write(1, &c, 1); X } X} X/*--------------------------------------------------------------------------*/ ________This_Is_The_END________ if test `wc -l < modemon.c` -ne 156; then echo 'shar: modemon.c was damaged during transit (should have been 156 bytes)' fi fi ; : end of overwriting check exit 0