xref: /freebsd/usr.bin/tip/libacu/t3000.c (revision 0f3bdf5df978c1d74d4b5e0429ced9613debcc3c)
10f3bdf5dSMark Murray /*	$OpenBSD: t3000.c,v 1.9 2001/10/24 18:38:58 millert Exp $	*/
20f3bdf5dSMark Murray /*	$NetBSD: t3000.c,v 1.5 1997/02/11 09:24:18 mrg Exp $	*/
30f3bdf5dSMark Murray 
40f3bdf5dSMark Murray /*
50f3bdf5dSMark Murray  * Copyright (c) 1992, 1993
60f3bdf5dSMark Murray  *	The Regents of the University of California.  All rights reserved.
70f3bdf5dSMark Murray  *
80f3bdf5dSMark Murray  * Redistribution and use in source and binary forms, with or without
90f3bdf5dSMark Murray  * modification, are permitted provided that the following conditions
100f3bdf5dSMark Murray  * are met:
110f3bdf5dSMark Murray  * 1. Redistributions of source code must retain the above copyright
120f3bdf5dSMark Murray  *    notice, this list of conditions and the following disclaimer.
130f3bdf5dSMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
140f3bdf5dSMark Murray  *    notice, this list of conditions and the following disclaimer in the
150f3bdf5dSMark Murray  *    documentation and/or other materials provided with the distribution.
160f3bdf5dSMark Murray  * 3. All advertising materials mentioning features or use of this software
170f3bdf5dSMark Murray  *    must display the following acknowledgement:
180f3bdf5dSMark Murray  *	This product includes software developed by the University of
190f3bdf5dSMark Murray  *	California, Berkeley and its contributors.
200f3bdf5dSMark Murray  * 4. Neither the name of the University nor the names of its contributors
210f3bdf5dSMark Murray  *    may be used to endorse or promote products derived from this software
220f3bdf5dSMark Murray  *    without specific prior written permission.
230f3bdf5dSMark Murray  *
240f3bdf5dSMark Murray  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
250f3bdf5dSMark Murray  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
260f3bdf5dSMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
270f3bdf5dSMark Murray  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
280f3bdf5dSMark Murray  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
290f3bdf5dSMark Murray  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
300f3bdf5dSMark Murray  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
310f3bdf5dSMark Murray  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
320f3bdf5dSMark Murray  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
330f3bdf5dSMark Murray  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
340f3bdf5dSMark Murray  * SUCH DAMAGE.
350f3bdf5dSMark Murray  */
360f3bdf5dSMark Murray 
370f3bdf5dSMark Murray #ifndef lint
380f3bdf5dSMark Murray #if 0
390f3bdf5dSMark Murray static char sccsid[] = "@(#)t3000.c	8.1 (Berkeley) 6/6/93";
400f3bdf5dSMark Murray #endif
410f3bdf5dSMark Murray static char rcsid[] = "$OpenBSD: t3000.c,v 1.9 2001/10/24 18:38:58 millert Exp $";
420f3bdf5dSMark Murray #endif /* not lint */
430f3bdf5dSMark Murray 
440f3bdf5dSMark Murray /*
450f3bdf5dSMark Murray  * Routines for calling up on a Telebit T3000 modem.
460f3bdf5dSMark Murray  * Derived from Courier driver.
470f3bdf5dSMark Murray  */
480f3bdf5dSMark Murray #include "tip.h"
490f3bdf5dSMark Murray 
500f3bdf5dSMark Murray #include <sys/ioctl.h>
510f3bdf5dSMark Murray #include <stdio.h>
520f3bdf5dSMark Murray 
530f3bdf5dSMark Murray #define	MAXRETRY	5
540f3bdf5dSMark Murray 
550f3bdf5dSMark Murray static	void sigALRM();
560f3bdf5dSMark Murray static	int timeout = 0;
570f3bdf5dSMark Murray static	int connected = 0;
580f3bdf5dSMark Murray static	jmp_buf timeoutbuf, intbuf;
590f3bdf5dSMark Murray static	int t3000_sync(), t3000_connect(), t3000_swallow();
600f3bdf5dSMark Murray static	void t3000_nap();
610f3bdf5dSMark Murray 
620f3bdf5dSMark Murray int
630f3bdf5dSMark Murray t3000_dialer(num, acu)
640f3bdf5dSMark Murray 	char *num;
650f3bdf5dSMark Murray 	char *acu;
660f3bdf5dSMark Murray {
670f3bdf5dSMark Murray 	char *cp;
680f3bdf5dSMark Murray 	struct termios cntrl;
690f3bdf5dSMark Murray #ifdef ACULOG
700f3bdf5dSMark Murray 	char line[80];
710f3bdf5dSMark Murray #endif
720f3bdf5dSMark Murray 
730f3bdf5dSMark Murray 	if (boolean(value(VERBOSE)))
740f3bdf5dSMark Murray 		printf("Using \"%s\"\n", acu);
750f3bdf5dSMark Murray 
760f3bdf5dSMark Murray 	tcgetattr(FD, &cntrl);
770f3bdf5dSMark Murray 	cntrl.c_cflag |= HUPCL;
780f3bdf5dSMark Murray 	tcsetattr(FD, TCSANOW, &cntrl);
790f3bdf5dSMark Murray 	/*
800f3bdf5dSMark Murray 	 * Get in synch.
810f3bdf5dSMark Murray 	 */
820f3bdf5dSMark Murray 	if (!t3000_sync()) {
830f3bdf5dSMark Murray badsynch:
840f3bdf5dSMark Murray 		printf("can't synchronize with t3000\n");
850f3bdf5dSMark Murray #ifdef ACULOG
860f3bdf5dSMark Murray 		logent(value(HOST), num, "t3000", "can't synch up");
870f3bdf5dSMark Murray #endif
880f3bdf5dSMark Murray 		return (0);
890f3bdf5dSMark Murray 	}
900f3bdf5dSMark Murray 	t3000_write(FD, "AT E0\r", 6);	/* turn off echoing */
910f3bdf5dSMark Murray 	sleep(1);
920f3bdf5dSMark Murray #ifdef DEBUG
930f3bdf5dSMark Murray 	if (boolean(value(VERBOSE)))
940f3bdf5dSMark Murray 		t3000_verbose_read();
950f3bdf5dSMark Murray #endif
960f3bdf5dSMark Murray 	tcflush(FD, TCIOFLUSH);
970f3bdf5dSMark Murray 	t3000_write(FD, "AT E0 H0 Q0 X4 V1\r", 18);
980f3bdf5dSMark Murray 	if (!t3000_swallow("\r\nOK\r\n"))
990f3bdf5dSMark Murray 		goto badsynch;
1000f3bdf5dSMark Murray 	fflush(stdout);
1010f3bdf5dSMark Murray 	t3000_write(FD, "AT D", 4);
1020f3bdf5dSMark Murray 	for (cp = num; *cp; cp++)
1030f3bdf5dSMark Murray 		if (*cp == '=')
1040f3bdf5dSMark Murray 			*cp = ',';
1050f3bdf5dSMark Murray 	t3000_write(FD, num, strlen(num));
1060f3bdf5dSMark Murray 	t3000_write(FD, "\r", 1);
1070f3bdf5dSMark Murray 	connected = t3000_connect();
1080f3bdf5dSMark Murray #ifdef ACULOG
1090f3bdf5dSMark Murray 	if (timeout) {
1100f3bdf5dSMark Murray 		(void)sprintf(line, "%ld second dial timeout",
1110f3bdf5dSMark Murray 			number(value(DIALTIMEOUT)));
1120f3bdf5dSMark Murray 		logent(value(HOST), num, "t3000", line);
1130f3bdf5dSMark Murray 	}
1140f3bdf5dSMark Murray #endif
1150f3bdf5dSMark Murray 	if (timeout)
1160f3bdf5dSMark Murray 		t3000_disconnect();
1170f3bdf5dSMark Murray 	return (connected);
1180f3bdf5dSMark Murray }
1190f3bdf5dSMark Murray 
1200f3bdf5dSMark Murray void
1210f3bdf5dSMark Murray t3000_disconnect()
1220f3bdf5dSMark Murray {
1230f3bdf5dSMark Murray 	 /* first hang up the modem*/
1240f3bdf5dSMark Murray 	ioctl(FD, TIOCCDTR, 0);
1250f3bdf5dSMark Murray 	sleep(1);
1260f3bdf5dSMark Murray 	ioctl(FD, TIOCSDTR, 0);
1270f3bdf5dSMark Murray 	t3000_sync();				/* reset */
1280f3bdf5dSMark Murray 	close(FD);
1290f3bdf5dSMark Murray }
1300f3bdf5dSMark Murray 
1310f3bdf5dSMark Murray void
1320f3bdf5dSMark Murray t3000_abort()
1330f3bdf5dSMark Murray {
1340f3bdf5dSMark Murray 	t3000_write(FD, "\r", 1);	/* send anything to abort the call */
1350f3bdf5dSMark Murray 	t3000_disconnect();
1360f3bdf5dSMark Murray }
1370f3bdf5dSMark Murray 
1380f3bdf5dSMark Murray static void
1390f3bdf5dSMark Murray sigALRM()
1400f3bdf5dSMark Murray {
1410f3bdf5dSMark Murray 	printf("\07timeout waiting for reply\n");
1420f3bdf5dSMark Murray 	timeout = 1;
1430f3bdf5dSMark Murray 	longjmp(timeoutbuf, 1);
1440f3bdf5dSMark Murray }
1450f3bdf5dSMark Murray 
1460f3bdf5dSMark Murray static int
1470f3bdf5dSMark Murray t3000_swallow(match)
1480f3bdf5dSMark Murray 	char *match;
1490f3bdf5dSMark Murray {
1500f3bdf5dSMark Murray 	sig_t f;
1510f3bdf5dSMark Murray 	char c;
1520f3bdf5dSMark Murray 
1530f3bdf5dSMark Murray 	f = signal(SIGALRM, sigALRM);
1540f3bdf5dSMark Murray 	timeout = 0;
1550f3bdf5dSMark Murray 	do {
1560f3bdf5dSMark Murray 		if (*match =='\0') {
1570f3bdf5dSMark Murray 			signal(SIGALRM, f);
1580f3bdf5dSMark Murray 			return (1);
1590f3bdf5dSMark Murray 		}
1600f3bdf5dSMark Murray 		if (setjmp(timeoutbuf)) {
1610f3bdf5dSMark Murray 			signal(SIGALRM, f);
1620f3bdf5dSMark Murray 			return (0);
1630f3bdf5dSMark Murray 		}
1640f3bdf5dSMark Murray 		alarm(number(value(DIALTIMEOUT)));
1650f3bdf5dSMark Murray 		read(FD, &c, 1);
1660f3bdf5dSMark Murray 		alarm(0);
1670f3bdf5dSMark Murray 		c &= 0177;
1680f3bdf5dSMark Murray #ifdef DEBUG
1690f3bdf5dSMark Murray 		if (boolean(value(VERBOSE)))
1700f3bdf5dSMark Murray 			putchar(c);
1710f3bdf5dSMark Murray #endif
1720f3bdf5dSMark Murray 	} while (c == *match++);
1730f3bdf5dSMark Murray #ifdef DEBUG
1740f3bdf5dSMark Murray 	if (boolean(value(VERBOSE)))
1750f3bdf5dSMark Murray 		fflush(stdout);
1760f3bdf5dSMark Murray #endif
1770f3bdf5dSMark Murray 	signal(SIGALRM, SIG_DFL);
1780f3bdf5dSMark Murray 	return (0);
1790f3bdf5dSMark Murray }
1800f3bdf5dSMark Murray 
1810f3bdf5dSMark Murray #ifndef B19200		/* XXX */
1820f3bdf5dSMark Murray #define	B19200	EXTA
1830f3bdf5dSMark Murray #define	B38400	EXTB
1840f3bdf5dSMark Murray #endif
1850f3bdf5dSMark Murray 
1860f3bdf5dSMark Murray struct tbaud_msg {
1870f3bdf5dSMark Murray 	char *msg;
1880f3bdf5dSMark Murray 	int baud;
1890f3bdf5dSMark Murray 	int baud2;
1900f3bdf5dSMark Murray } tbaud_msg[] = {
1910f3bdf5dSMark Murray 	"",		B300,	0,
1920f3bdf5dSMark Murray 	" 1200",	B1200,	0,
1930f3bdf5dSMark Murray 	" 2400",	B2400,	0,
1940f3bdf5dSMark Murray 	" 4800",	B4800,	0,
1950f3bdf5dSMark Murray 	" 9600",	B9600,	0,
1960f3bdf5dSMark Murray 	" 14400",	B19200,	B9600,
1970f3bdf5dSMark Murray 	" 19200",	B19200,	B9600,
1980f3bdf5dSMark Murray 	" 38400",	B38400,	B9600,
1990f3bdf5dSMark Murray 	" 57600",	B38400,	B9600,
2000f3bdf5dSMark Murray 	" 7512",	B9600,	0,
2010f3bdf5dSMark Murray 	" 1275",	B2400,	0,
2020f3bdf5dSMark Murray 	" 7200",	B9600,	0,
2030f3bdf5dSMark Murray 	" 12000",	B19200,	B9600,
2040f3bdf5dSMark Murray 	0,		0,	0,
2050f3bdf5dSMark Murray };
2060f3bdf5dSMark Murray 
2070f3bdf5dSMark Murray static int
2080f3bdf5dSMark Murray t3000_connect()
2090f3bdf5dSMark Murray {
2100f3bdf5dSMark Murray 	char c;
2110f3bdf5dSMark Murray 	int nc, nl, n;
2120f3bdf5dSMark Murray 	char dialer_buf[64];
2130f3bdf5dSMark Murray 	struct tbaud_msg *bm;
2140f3bdf5dSMark Murray 	sig_t f;
2150f3bdf5dSMark Murray 
2160f3bdf5dSMark Murray 	if (t3000_swallow("\r\n") == 0)
2170f3bdf5dSMark Murray 		return (0);
2180f3bdf5dSMark Murray 	f = signal(SIGALRM, sigALRM);
2190f3bdf5dSMark Murray again:
2200f3bdf5dSMark Murray 	nc = 0; nl = sizeof(dialer_buf)-1;
2210f3bdf5dSMark Murray 	bzero(dialer_buf, sizeof(dialer_buf));
2220f3bdf5dSMark Murray 	timeout = 0;
2230f3bdf5dSMark Murray 	for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) {
2240f3bdf5dSMark Murray 		if (setjmp(timeoutbuf))
2250f3bdf5dSMark Murray 			break;
2260f3bdf5dSMark Murray 		alarm(number(value(DIALTIMEOUT)));
2270f3bdf5dSMark Murray 		n = read(FD, &c, 1);
2280f3bdf5dSMark Murray 		alarm(0);
2290f3bdf5dSMark Murray 		if (n <= 0)
2300f3bdf5dSMark Murray 			break;
2310f3bdf5dSMark Murray 		c &= 0x7f;
2320f3bdf5dSMark Murray 		if (c == '\r') {
2330f3bdf5dSMark Murray 			if (t3000_swallow("\n") == 0)
2340f3bdf5dSMark Murray 				break;
2350f3bdf5dSMark Murray 			if (!dialer_buf[0])
2360f3bdf5dSMark Murray 				goto again;
2370f3bdf5dSMark Murray 			if (strcmp(dialer_buf, "RINGING") == 0 &&
2380f3bdf5dSMark Murray 			    boolean(value(VERBOSE))) {
2390f3bdf5dSMark Murray #ifdef DEBUG
2400f3bdf5dSMark Murray 				printf("%s\r\n", dialer_buf);
2410f3bdf5dSMark Murray #endif
2420f3bdf5dSMark Murray 				goto again;
2430f3bdf5dSMark Murray 			}
2440f3bdf5dSMark Murray 			if (strncmp(dialer_buf, "CONNECT",
2450f3bdf5dSMark Murray 				    sizeof("CONNECT")-1) != 0)
2460f3bdf5dSMark Murray 				break;
2470f3bdf5dSMark Murray 			for (bm = tbaud_msg ; bm->msg ; bm++)
2480f3bdf5dSMark Murray 				if (strcmp(bm->msg,
2490f3bdf5dSMark Murray 				    dialer_buf+sizeof("CONNECT")-1) == 0) {
2500f3bdf5dSMark Murray 					struct termios	cntrl;
2510f3bdf5dSMark Murray 
2520f3bdf5dSMark Murray 					tcgetattr(FD, &cntrl);
2530f3bdf5dSMark Murray 					cfsetospeed(&cntrl, bm->baud);
2540f3bdf5dSMark Murray 					cfsetispeed(&cntrl, bm->baud);
2550f3bdf5dSMark Murray 					tcsetattr(FD, TCSAFLUSH, &cntrl);
2560f3bdf5dSMark Murray 					signal(SIGALRM, f);
2570f3bdf5dSMark Murray #ifdef DEBUG
2580f3bdf5dSMark Murray 					if (boolean(value(VERBOSE)))
2590f3bdf5dSMark Murray 						printf("%s\r\n", dialer_buf);
2600f3bdf5dSMark Murray #endif
2610f3bdf5dSMark Murray 					return (1);
2620f3bdf5dSMark Murray 				}
2630f3bdf5dSMark Murray 			break;
2640f3bdf5dSMark Murray 		}
2650f3bdf5dSMark Murray 		dialer_buf[nc] = c;
2660f3bdf5dSMark Murray #ifdef notdef
2670f3bdf5dSMark Murray 		if (boolean(value(VERBOSE)))
2680f3bdf5dSMark Murray 			putchar(c);
2690f3bdf5dSMark Murray #endif
2700f3bdf5dSMark Murray 	}
2710f3bdf5dSMark Murray 	printf("%s\r\n", dialer_buf);
2720f3bdf5dSMark Murray 	signal(SIGALRM, f);
2730f3bdf5dSMark Murray 	return (0);
2740f3bdf5dSMark Murray }
2750f3bdf5dSMark Murray 
2760f3bdf5dSMark Murray /*
2770f3bdf5dSMark Murray  * This convoluted piece of code attempts to get
2780f3bdf5dSMark Murray  * the t3000 in sync.
2790f3bdf5dSMark Murray  */
2800f3bdf5dSMark Murray static int
2810f3bdf5dSMark Murray t3000_sync()
2820f3bdf5dSMark Murray {
2830f3bdf5dSMark Murray 	int already = 0;
2840f3bdf5dSMark Murray 	int len;
2850f3bdf5dSMark Murray 	char buf[40];
2860f3bdf5dSMark Murray 
2870f3bdf5dSMark Murray 	while (already++ < MAXRETRY) {
2880f3bdf5dSMark Murray 		tcflush(FD, TCIOFLUSH);
2890f3bdf5dSMark Murray 		t3000_write(FD, "\rAT Z\r", 6);	/* reset modem */
2900f3bdf5dSMark Murray 		bzero(buf, sizeof(buf));
2910f3bdf5dSMark Murray 		sleep(2);
2920f3bdf5dSMark Murray 		ioctl(FD, FIONREAD, &len);
2930f3bdf5dSMark Murray #if 1
2940f3bdf5dSMark Murray if (len == 0) len = 1;
2950f3bdf5dSMark Murray #endif
2960f3bdf5dSMark Murray 		if (len) {
2970f3bdf5dSMark Murray 			len = read(FD, buf, sizeof(buf));
2980f3bdf5dSMark Murray #ifdef DEBUG
2990f3bdf5dSMark Murray 			buf[len] = '\0';
3000f3bdf5dSMark Murray 			printf("t3000_sync: (\"%s\")\n\r", buf);
3010f3bdf5dSMark Murray #endif
3020f3bdf5dSMark Murray 			if (strchr(buf, '0') ||
3030f3bdf5dSMark Murray 		   	   (strchr(buf, 'O') && strchr(buf, 'K')))
3040f3bdf5dSMark Murray 				return(1);
3050f3bdf5dSMark Murray 		}
3060f3bdf5dSMark Murray 		/*
3070f3bdf5dSMark Murray 		 * If not strapped for DTR control,
3080f3bdf5dSMark Murray 		 * try to get command mode.
3090f3bdf5dSMark Murray 		 */
3100f3bdf5dSMark Murray 		sleep(1);
3110f3bdf5dSMark Murray 		t3000_write(FD, "+++", 3);
3120f3bdf5dSMark Murray 		sleep(1);
3130f3bdf5dSMark Murray 		/*
3140f3bdf5dSMark Murray 		 * Toggle DTR to force anyone off that might have left
3150f3bdf5dSMark Murray 		 * the modem connected.
3160f3bdf5dSMark Murray 		 */
3170f3bdf5dSMark Murray 		ioctl(FD, TIOCCDTR, 0);
3180f3bdf5dSMark Murray 		sleep(1);
3190f3bdf5dSMark Murray 		ioctl(FD, TIOCSDTR, 0);
3200f3bdf5dSMark Murray 	}
3210f3bdf5dSMark Murray 	t3000_write(FD, "\rAT Z\r", 6);
3220f3bdf5dSMark Murray 	return (0);
3230f3bdf5dSMark Murray }
3240f3bdf5dSMark Murray 
3250f3bdf5dSMark Murray static int
3260f3bdf5dSMark Murray t3000_write(fd, cp, n)
3270f3bdf5dSMark Murray int fd;
3280f3bdf5dSMark Murray char *cp;
3290f3bdf5dSMark Murray int n;
3300f3bdf5dSMark Murray {
3310f3bdf5dSMark Murray #ifdef notdef
3320f3bdf5dSMark Murray 	if (boolean(value(VERBOSE)))
3330f3bdf5dSMark Murray 		write(1, cp, n);
3340f3bdf5dSMark Murray #endif
3350f3bdf5dSMark Murray 	tcdrain(fd);
3360f3bdf5dSMark Murray 	t3000_nap();
3370f3bdf5dSMark Murray 	for ( ; n-- ; cp++) {
3380f3bdf5dSMark Murray 		write(fd, cp, 1);
3390f3bdf5dSMark Murray 		tcdrain(fd);
3400f3bdf5dSMark Murray 		t3000_nap();
3410f3bdf5dSMark Murray 	}
3420f3bdf5dSMark Murray }
3430f3bdf5dSMark Murray 
3440f3bdf5dSMark Murray #ifdef DEBUG
3450f3bdf5dSMark Murray t3000_verbose_read()
3460f3bdf5dSMark Murray {
3470f3bdf5dSMark Murray 	int n = 0;
3480f3bdf5dSMark Murray 	char buf[BUFSIZ];
3490f3bdf5dSMark Murray 
3500f3bdf5dSMark Murray 	if (ioctl(FD, FIONREAD, &n) < 0)
3510f3bdf5dSMark Murray 		return;
3520f3bdf5dSMark Murray 	if (n <= 0)
3530f3bdf5dSMark Murray 		return;
3540f3bdf5dSMark Murray 	if (read(FD, buf, n) != n)
3550f3bdf5dSMark Murray 		return;
3560f3bdf5dSMark Murray 	write(1, buf, n);
3570f3bdf5dSMark Murray }
3580f3bdf5dSMark Murray #endif
3590f3bdf5dSMark Murray 
3600f3bdf5dSMark Murray /* Give the t3000 50 milliseconds between characters */
3610f3bdf5dSMark Murray void
3620f3bdf5dSMark Murray t3000_nap()
3630f3bdf5dSMark Murray {
3640f3bdf5dSMark Murray 	struct timespec ts;
3650f3bdf5dSMark Murray 
3660f3bdf5dSMark Murray 	ts.tv_sec = 0;
3670f3bdf5dSMark Murray 	ts.tv_nsec = 50 * 1000000;
3680f3bdf5dSMark Murray 
3690f3bdf5dSMark Murray 	nanosleep(&ts, NULL);
3700f3bdf5dSMark Murray }
371