2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4 * Copyright (C) 1999 Red Hat, Inc.
6 * Implementation of the WvModem class. Inherits from WvFile, but
7 * handles various important details related to modems, like setting
8 * the baud rate, checking carrier detect, and dropping DTR.
13 #include <sys/ioctl.h>
15 #if HAVE_LINUX_SERIAL_H
16 # include <linux/serial.h>
20 static inline void cfmakeraw(struct termios
*termios_p
)
22 termios_p
->c_iflag
&= ~(IGNBRK
|BRKINT
|PARMRK
|ISTRIP
|INLCR
|IGNCR
|ICRNL
|IXON
);
23 termios_p
->c_oflag
&= ~OPOST
;
24 termios_p
->c_lflag
&= ~(ECHO
|ECHONL
|ICANON
|ISIG
|IEXTEN
);
25 termios_p
->c_cflag
&= ~(CSIZE
|PARENB
);
26 termios_p
->c_cflag
|= CS8
;
36 static SpeedLookup speeds
[] = {
55 WvModemBase::WvModemBase(int _fd
) : WvFile(_fd
)
61 WvModemBase::~WvModemBase()
67 int WvModemBase::get_real_speed()
71 if (!isok()) return 0;
73 tcgetattr( getrfd(), &t
);
74 s
= cfgetospeed( &t
);
75 for (unsigned int i
= 0; i
< sizeof(speeds
) / sizeof(*speeds
); i
++)
77 if (speeds
[i
].speedt
== s
)
79 baud
= speeds
[i
].baud
;
88 void WvModemBase::close()
90 // no file open, no need to close it
94 bool WvModemBase::carrier()
100 int WvModemBase::speed(int)
106 void WvModemBase::hangup()
108 int i
, oldbaud
= baud
;
110 if (die_fast
|| !isok()) return;
112 // politely abort any dial in progress, to avoid locking USR modems.
113 // we should only do this if we have received any response from the modem,
114 // so that WvModemScan can run faster.
117 // FIXME: should be iswritable, but based on the numer of msec params
118 // tossed around I assume modems are very timing-sensitive
119 for (i
= 0; !select(200, false, true) && i
< 10; i
++)
123 // drop DTR for a while, if still online
126 cfsetospeed( &t
, B0
);
127 tcsetattr( getrfd(), TCSANOW
, &t
);
128 for (i
= 0; carrier() && i
< 10; i
++)
129 usleep( 100 * 1000 );
131 // raise DTR again, restoring the old baud rate
137 // need to do +++ manual-disconnect stuff
139 usleep( 1500 * 1000 );
142 for (i
= 0; carrier() && i
< 5; i
++)
143 usleep( 100 * 1000 );
149 WvModem::WvModem(WvStringParm filename
, int _baud
, bool rtscts
, bool _no_reset
)
150 : WvModemBase(), lock(filename
), log("WvModem", WvLog::Debug1
)
155 no_reset
= _no_reset
;
164 // note: if CLOCAL is not set on the modem, open will
165 // block until a carrier detect. Since we have to open the modem to
166 // generate a carrier detect, we have a problem. So we open the modem
167 // nonblocking. It would then be safe to switch to blocking mode,
168 // but that is no longer recommended for WvStream.
169 open(filename
, O_RDWR
|O_NONBLOCK
|O_NOCTTY
);
182 void WvModem::setup_modem(bool rtscts
)
186 if (tcgetattr(getrfd(), &t
) || tcgetattr(getrfd(), &old_t
))
196 #if HAVE_LINUX_SERIAL_H
197 struct serial_struct old_sinfo
, sinfo
;
198 sinfo
.reserved_char
[0] = 0;
199 if (ioctl(getrfd(), TIOCGSERIAL
, &old_sinfo
) < 0)
200 log("Cannot get information for serial port.");
204 // Why there are two closing wait timeouts, is beyond me
205 // but there are... apparently the second one is deprecated
206 // but why take a chance...
207 sinfo
.closing_wait
= ASYNC_CLOSING_WAIT_NONE
;
208 sinfo
.closing_wait2
= ASYNC_CLOSING_WAIT_NONE
;
210 if (ioctl(getrfd(), TIOCSSERIAL
, &sinfo
) < 0)
211 log("Cannot set information for serial port.");
215 // set up the terminal characteristics.
216 // see "man tcsetattr" for more information about these options.
217 t
.c_iflag
&= ~(BRKINT
| ISTRIP
| IUCLC
| IXON
| IXANY
| IXOFF
| IMAXBEL
);
218 t
.c_iflag
|= (IGNBRK
| IGNPAR
);
219 t
.c_oflag
&= ~(OLCUC
);
220 t
.c_cflag
&= ~(CSIZE
| CSTOPB
| PARENB
| PARODD
);
221 t
.c_cflag
|= (CS8
| CREAD
| HUPCL
| CLOCAL
);
223 t
.c_cflag
|= CRTSCTS
;
224 t
.c_lflag
&= ~(ISIG
| XCASE
| ECHO
);
225 tcsetattr(getrfd(), TCSANOW
, &t
);
227 // make sure we leave the modem in CLOCAL when we exit, so normal user
228 // tasks can open the modem without using nonblocking.
229 old_t
.c_cflag
|= CLOCAL
;
231 // Send a few returns to make sure the modem is "good and zonked".
232 if (cfgetospeed(&t
) != B0
&& !no_reset
)
234 for(int i
=0; i
<5; i
++)
241 // Set the baud rate to 0 for half a second to drop DTR...
245 tcsetattr(getrfd(), TCSANOW
, &t
);
256 void WvModem::close()
277 tcflush(getrfd(), TCIOFLUSH
);
279 tcsetattr(getrfd(), TCSANOW
, &old_t
);
280 tcflush(getrfd(), TCIOFLUSH
);
288 int WvModem::speed(int _baud
)
292 for (unsigned int i
= 0; i
< sizeof(speeds
) / sizeof(*speeds
); i
++)
294 if (speeds
[i
].baud
<= _baud
)
296 s
= speeds
[i
].speedt
;
301 cfsetispeed(&t
, B0
); // auto-match to output speed
303 tcsetattr(getrfd(), TCSANOW
, &t
);
305 return get_real_speed();
309 int WvModem::getstatus()
311 if (!isok()) return 0;
313 ioctl(getrfd(), TIOCMGET
, &status
);
318 bool WvModem::carrier()
320 return (getstatus() & TIOCM_CD
) ? 1 : 0;