<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">Index: src/Makefile.main
===================================================================
RCS file: /cvsroot/etherboot/etherboot/etherboot-5.3/src/Makefile.main,v
retrieving revision 1.29
diff -u -p -r1.29 Makefile.main
--- src/Makefile.main	12 Dec 2004 09:01:04 -0000	1.29
+++ src/Makefile.main	21 Dec 2004 12:03:17 -0000
@@ -103,7 +103,7 @@ MAKEROM=	$(PERL) ./util/makerom.pl
 VERSION_MAJOR=	5
 VERSION_MINOR=	3
 VERSION_PATCH=	11
-EXTRAVERSION=	
+EXTRAVERSION=	-RTnet-0.3
 VERSION=	$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH)$(EXTRAVERSION)
 MM_VERSION=	$(VERSION_MAJOR).$(VERSION_MINOR)
 CFLAGS+=	-DVERSION_MAJOR=$(VERSION_MAJOR) \
@@ -179,6 +179,7 @@ SRCS+=	core/proto_slam.c core/proto_tftm
 SRCS+=	core/isapnp.c
 SRCS+=	core/pcmcia.c core/i82365.c
 SRCS+=	core/pxe_export.c core/dns_resolver.c
+SRCS+=	core/rtnet.c
 
 SRCS+=	$(FILO)/drivers/ide_x.c  
 SRCS+=	$(FILO)/fs/blockdev.c $(FILO)/fs/eltorito.c $(FILO)/fs/fsys_ext2fs.c $(FILO)/fs/fsys_fat.c $(FILO)/fs/fsys_iso9660.c
@@ -201,6 +202,7 @@ BOBJS+=		$(BIN)/pci.o $(BIN)/isa_probe.o
 BOBJS+=		$(BIN)/vsprintf.o $(BIN)/string.o
 BOBJS+=		$(BIN)/pcmcia.o $(BIN)/i82365.o
 BOBJS+=		$(BIN)/pxe_export.o $(BIN)/dns_resolver.o
+BOBJS+=		$(BIN)/rtnet.o
 
 BOBJS+=		$(BIN)/ide_x.o $(BIN)/pci_x.o
 BOBJS+=		$(BIN)/blockdev.o $(BIN)/eltorito.o $(BIN)/fsys_ext2fs.o $(BIN)/fsys_fat.o $(BIN)/fsys_iso9660.o $(BIN)/fsys_reiserfs.o $(BIN)/vfs.o
Index: src/arch/i386/Config
===================================================================
RCS file: /cvsroot/etherboot/etherboot/etherboot-5.3/src/arch/i386/Config,v
retrieving revision 1.8
diff -u -p -r1.8 Config
--- src/arch/i386/Config	27 Nov 2004 00:40:06 -0000	1.8
+++ src/arch/i386/Config	21 Dec 2004 12:03:17 -0000
@@ -80,7 +80,7 @@
 # @/OptionDescription@
 
 # BIOS select don't change unless you know what you are doing
-CFLAGS+=	-DPCBIOS
+CFLAGS+=	-DPCBIOS -DCONFIG_TSC_CURRTICKS
 
 # Compile in k8/hammer support
 #CFLAGS+= -DCONFIG_X86_64
Index: src/arch/i386/core/i386_timer.c
===================================================================
RCS file: /cvsroot/etherboot/etherboot/etherboot-5.3/src/arch/i386/core/i386_timer.c,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 i386_timer.c
--- src/arch/i386/core/i386_timer.c	13 Aug 2003 22:43:15 -0000	1.1.1.1
+++ src/arch/i386/core/i386_timer.c	21 Dec 2004 12:03:17 -0000
@@ -74,19 +74,12 @@ void udelay(unsigned int usecs)
      __asm__ __volatile__ ("rdtsc" : "=A" (val))
 
 
-/* Number of clock ticks to time with the rtc */
-#define LATCH 0xFF
+#define HZ              100
+#define LATCH           ((CLOCK_TICK_RATE + HZ/2) / HZ)
+#define CALIBRATE_LATCH (5 * LATCH)
+#define CALIBRATE_TIME  (5 * 1000020/HZ)
 
-#define LATCHES_PER_SEC ((CLOCK_TICK_RATE + (LATCH/2))/LATCH)
-#define TICKS_PER_LATCH ((LATCHES_PER_SEC + (TICKS_PER_SEC/2))/TICKS_PER_SEC)
-
-static void sleep_latch(void)
-{
-	__load_timer2(LATCH);
-	while(__timer2_running());
-}
-
-/* ------ Calibrate the TSC ------- 
+/* ------ Calibrate the TSC -------
  * Time how long it takes to excute a loop that runs in known time.
  * And find the convertion needed to get to CLOCK_TICK_RATE
  */
@@ -96,9 +89,12 @@ static unsigned long long calibrate_tsc(
 {
 	unsigned long startlow, starthigh;
 	unsigned long endlow, endhigh;
-	
+
+
+	__load_timer2(CALIBRATE_LATCH);
+
 	rdtsc(startlow,starthigh);
-	sleep_latch();
+	while(__timer2_running());
 	rdtsc(endlow,endhigh);
 
 	/* 64-bit subtract - gcc just messes up with long longs */
@@ -107,12 +103,19 @@ static unsigned long long calibrate_tsc(
 		:"=a" (endlow), "=d" (endhigh)
 		:"g" (startlow), "g" (starthigh),
 		"0" (endlow), "1" (endhigh));
-	
+
 	/* Error: ECPUTOOFAST */
 	if (endhigh)
 		goto bad_ctc;
-	
-	endlow *= TICKS_PER_LATCH;
+
+	/* Error: ECPUTOOSLOW */
+	if (endlow &lt;= CALIBRATE_TIME)
+		goto bad_ctc;
+
+	__asm__("divl %2"
+		:"=a" (endlow), "=d" (endhigh)
+		:"r" (endlow), "0" (0), "1" (CALIBRATE_TIME));
+
 	return endlow;
 
 	/*
@@ -126,12 +129,40 @@ bad_ctc:
 }
 
 static unsigned long clocks_per_tick;
+static unsigned long cyc2ns_scale;
+
+#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
+
+static inline void set_cyc2ns_scale(unsigned long cpu_mhz)
+{
+	cyc2ns_scale = (1000 &lt;&lt; CYC2NS_SCALE_FACTOR)/cpu_mhz;
+}
+
+static inline unsigned long long cycles_2_ns(unsigned long long cyc)
+{
+	return (cyc * cyc2ns_scale) &gt;&gt; CYC2NS_SCALE_FACTOR;
+}
+
 void setup_timers(void)
 {
 	if (!clocks_per_tick) {
-		clocks_per_tick = calibrate_tsc();
-		/* Display the CPU Mhz to easily test if the calibration was bad */
-		printf("CPU %ld Mhz\n", (clocks_per_tick/1000 * TICKS_PER_SEC)/1000);
+		unsigned long cpu_khz;
+		unsigned long tsc_quotient = calibrate_tsc();
+
+		/* report CPU clock rate in Hz.
+		 * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
+		 * clock/second. Our precision is about 100 ppm.
+		 */
+		unsigned long eax=0, edx=1000;
+			__asm__("divl %2"
+			:"=a" (cpu_khz), "=d" (edx)
+			:"r" (tsc_quotient),
+			"0" (eax), "1" (edx));
+		printf("Detected %d.%03d MHz processor.\n", cpu_khz / 1000,
+		       cpu_khz % 1000);
+
+		clocks_per_tick = cpu_khz * ((65536 * 1000) / CLOCK_TICK_RATE);
+		set_cyc2ns_scale(cpu_khz/1000);
 	}
 }
 
@@ -188,4 +219,11 @@ int timer2_running(void)
 	return __timer_running();
 }
 
+unsigned long long get_time(void)
+{
+	unsigned long long now;
+	rdtscll(now);
+	return cycles_2_ns(now);
+}
+
 #endif /* RTC_CURRTICKS */
Index: src/core/main.c
===================================================================
RCS file: /cvsroot/etherboot/etherboot/etherboot-5.3/src/core/main.c,v
retrieving revision 1.17
diff -u -p -r1.17 main.c
--- src/core/main.c	17 Nov 2004 02:24:56 -0000	1.17
+++ src/core/main.c	21 Dec 2004 12:03:18 -0000
@@ -23,6 +23,7 @@ Literature dealing with the network prot
 #include "http.h"
 #include "timer.h"
 #include "cpu.h"
+#include "rtnet.h"
 #include &lt;stdarg.h&gt;
 
 #ifdef CONSOLE_BTEXT
@@ -193,7 +194,7 @@ static struct class_operations {
 	int (*load)(struct dev *dev);
 }
 operations[] = {
-	{ &amp;nic.dev,  eth_probe,  eth_load_configuration,  eth_load  },
+	{ &amp;nic.dev,  rteth_probe,  eth_load_configuration,  eth_load  },
 	{ &amp;disk.dev, disk_probe, disk_load_configuration, disk_load },
 	{ &amp;disk.dev, disk_probe, disk_load_configuration, disk_load },
 };
Index: src/include/big_bswap.h
===================================================================
RCS file: /cvsroot/etherboot/etherboot/etherboot-5.3/src/include/big_bswap.h,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 big_bswap.h
--- src/include/big_bswap.h	10 Aug 2003 09:56:11 -0000	1.1.1.1
+++ src/include/big_bswap.h	21 Dec 2004 12:03:18 -0000
@@ -5,12 +5,16 @@
 #define htonl(x) 	(x)
 #define ntohs(x) 	(x)
 #define htons(x) 	(x)
+#define cpu_to_le64(x)	__bswap_64(x)
 #define cpu_to_le32(x)	__bswap_32(x)
 #define cpu_to_le16(x)	__bswap_16(x)
+#define cpu_to_be64(x)	(x)
 #define cpu_to_be32(x)	(x)
 #define cpu_to_be16(x)	(x)
+#define le64_to_cpu(x)	__bswap_64(x)
 #define le32_to_cpu(x)	__bswap_32(x)
 #define le16_to_cpu(x)	__bswap_16(x)
+#define be64_to_cpu(x)	(x)
 #define be32_to_cpu(x)	(x)
 #define be16_to_cpu(x)	(x)
 
Index: src/include/byteswap.h
===================================================================
RCS file: /cvsroot/etherboot/etherboot/etherboot-5.3/src/include/byteswap.h,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 byteswap.h
--- src/include/byteswap.h	10 Aug 2003 09:56:11 -0000	1.1.1.1
+++ src/include/byteswap.h	21 Dec 2004 12:03:18 -0000
@@ -12,9 +12,35 @@
 #endif
 
 /* Make routines available to all */
+#define swap64(x)	__bswap_64(x)
 #define swap32(x)	__bswap_32(x)
 #define swap16(x)	__bswap_16(x)
+#define bswap_64(x)	__bswap_64(x)
 #define bswap_32(x)	__bswap_32(x)
 #define bswap_16(x)	__bswap_16(x)
-	
+
+#define __bswap_constant_64(x) \
+     ((((x) &amp; 0xff00000000000000ull) &gt;&gt; 56)                                   \
+      | (((x) &amp; 0x00ff000000000000ull) &gt;&gt; 40)                                 \
+      | (((x) &amp; 0x0000ff0000000000ull) &gt;&gt; 24)                                 \
+      | (((x) &amp; 0x000000ff00000000ull) &gt;&gt; 8)                                  \
+      | (((x) &amp; 0x00000000ff000000ull) &lt;&lt; 8)                                  \
+      | (((x) &amp; 0x0000000000ff0000ull) &lt;&lt; 24)                                 \
+      | (((x) &amp; 0x000000000000ff00ull) &lt;&lt; 40)                                 \
+      | (((x) &amp; 0x00000000000000ffull) &lt;&lt; 56))
+
+# define __bswap_64(x) \
+     (__extension__                                                           \
+      ({ union { __extension__ unsigned long long int __ll;                   \
+                 unsigned long int __l[2]; } __w, __r;                        \
+         if (__builtin_constant_p (x))                                        \
+           __r.__ll = __bswap_constant_64 (x);                                \
+         else                                                                 \
+           {                                                                  \
+             __w.__ll = (x);                                                  \
+             __r.__l[0] = __bswap_32 (__w.__l[1]);                            \
+             __r.__l[1] = __bswap_32 (__w.__l[0]);                            \
+           }                                                                  \
+         __r.__ll; }))
+
 #endif /* ETHERBOOT_BYTESWAP_H */
Index: src/include/little_bswap.h
===================================================================
RCS file: /cvsroot/etherboot/etherboot/etherboot-5.3/src/include/little_bswap.h,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 little_bswap.h
--- src/include/little_bswap.h	10 Aug 2003 09:56:14 -0000	1.1.1.1
+++ src/include/little_bswap.h	21 Dec 2004 12:03:18 -0000
@@ -5,12 +5,16 @@
 #define htonl(x) 	__bswap_32(x)
 #define ntohs(x) 	__bswap_16(x)
 #define htons(x) 	__bswap_16(x)
+#define cpu_to_le64(x)	(x)
 #define cpu_to_le32(x)	(x)
 #define cpu_to_le16(x)	(x)
+#define cpu_to_be64(x)	__bswap_64(x)
 #define cpu_to_be32(x)	__bswap_32(x)
 #define cpu_to_be16(x)	__bswap_16(x)
+#define le64_to_cpu(x)	(x)
 #define le32_to_cpu(x)	(x)
 #define le16_to_cpu(x)	(x)
+#define be64_to_cpu(x)	__bswap_64(x)
 #define be32_to_cpu(x)	__bswap_32(x)
 #define be16_to_cpu(x)	__bswap_16(x)
 
Index: src/include/timer.h
===================================================================
RCS file: /cvsroot/etherboot/etherboot/etherboot-5.3/src/include/timer.h,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 timer.h
--- src/include/timer.h	10 Aug 2003 09:56:11 -0000	1.1.1.1
+++ src/include/timer.h	21 Dec 2004 12:03:18 -0000
@@ -58,5 +58,10 @@ extern void ndelay(unsigned int nsecs);
 extern void udelay(unsigned int usecs);
 extern void mdelay(unsigned int msecs);
 
+#if defined(CONFIG_TSC_CURRTICKS)
+extern unsigned long long get_time(void);
+#define delay_until(timeout) \
+	while (get_time() &lt; timeout)
+#endif /* CONFIG_TSC_CURRTICKS */
 
 #endif	/* TIMER_H */
--- /dev/null	2004-04-06 15:27:52.000000000 +0200
+++ src/core/rtnet.c	2004-12-21 13:01:14.270857856 +0100
@@ -0,0 +1,502 @@
+/**************************************************************************
+Etherboot -  Network Bootstrap Program
+
+Elementary RTnet support (see http://rtnet.sf.net for details)
+	o RTmac framing (revision 2.0)
+	o TDMA slave (revision 2.1)
+	o RTcfg client (revision 1.x, stage 1 read-only)
+	o RTcfg stage 1 data encoding of rtnet start script (0.8.0)
+
+Copyright (C) 2004 Jan Kiszka &lt;jan.kiszka@web.de&gt;
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+**************************************************************************/
+#include "etherboot.h"
+#include "rtnet.h"
+#include "nic.h"
+#include "timer.h"
+
+
+#define ETH_RTMAC               0x9021
+#define RTMAC_HLEN              4
+#define RTMAC_VERSION           2
+#define RTMAC_FLAG_TUNNEL       0x01
+
+#define RTMAC_TYPE_TDMA         0x0001
+#define TDMA_FRM_VERSION        0x0201
+#define TDMA_FRM_SYNC           0x0000
+#define TDMA_FRM_REQ_CAL        0x0010
+#define TDMA_FRM_RPL_CAL        0x0011
+#define TDMA_SYNC_LEN           24
+#define TDMA_REQ_CAL_LEN        24
+#define TDMA_RPL_CAL_LEN        28
+#define CALIBRATION_ROUNDS      100
+
+#define ETH_RTCFG               0x9022
+#define RTCFG_ID_STAGE_1_CFG    0
+#define RTCFG_ADDR_MAC          0x00
+#define RTCFG_ADDR_IP           0x01
+#define RTCFG_ADDRSIZE_IP       4
+
+struct rtmac_hdr {
+	uint16_t type;
+	uint8_t  ver;
+	uint8_t  flags;
+} PACKED;
+struct sync_frm {
+	uint16_t version;
+	uint16_t id;
+	uint32_t cycle_no;
+	uint64_t xmit_stamp;
+	uint64_t sched_xmit_stamp;
+} PACKED;
+struct reqcal_frm {
+	uint16_t version;
+	uint16_t id;
+	uint64_t xmit_stamp;
+	uint32_t reply_cycle;
+	uint64_t reply_slot_offset;
+} PACKED;
+struct replycal_frm {
+	uint16_t version;
+	uint16_t id;
+	uint64_t request_xmit_stamp;
+	uint64_t reception_stamp;
+	uint64_t xmit_stamp;
+} PACKED;
+
+static unsigned long            slot_offset;
+static unsigned int             slot_size;
+static unsigned long long       master_packet_delay = 0;
+static unsigned long long       next_slot = 0;
+static unsigned int             last_cycle;
+static unsigned int             slot_phasing = 1;
+static unsigned int             slot_period  = 1;
+static int (*nic_poll)P((struct nic *, int));
+static void (*nic_transmit)P((struct nic *, const char *d,
+                              unsigned int t, unsigned int s, const char *p));
+static char shadow_buf[ETH_FRAME_LEN + ETH_DATA_ALIGN] __aligned;
+
+
+static int get_uint(char **p, char *limit)
+{
+	int result = -1;
+	int new_result;
+
+
+	while ((*p &lt; limit) &amp;&amp; (**p &gt;= '0') &amp;&amp; (**p &lt;= '9')) {
+		if (result == -1)
+			result = 0;
+		new_result = result * 10 + (**p - '0');
+		(*p)++;
+		if (new_result &lt; result)
+			return -1;
+		result = new_result;
+	}
+	return result;
+}
+
+static int get_slot_params(struct nic *nic)
+{
+	const char   broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+	const char   TDMACFG[]   = "$TDMACFG rteth0 slot ";
+	const char   p_param[]   = " -p ";
+	const char   s_param[]   = " -s ";
+	char         *stage1_data;
+	char         *limit;
+	unsigned int len;
+	int          slot;
+	int          new_offset;
+	int          offset[2] = { -1, -1 };
+	int          phasing[2];
+	int          period[2];
+	int          size[2];
+
+
+	printf("Waiting for TDMA configuration...");
+	while (1) {
+		while (!(*nic_poll)(nic, 1))
+			poll_interruptions();
+
+		if ((nic-&gt;packetlen &lt; ETH_HLEN+5) ||
+		    (memcmp(nic-&gt;packet, broadcast, sizeof(broadcast)) == 0) ||
+		    (*((short *)&amp;nic-&gt;packet[12]) != htons(ETH_RTCFG)) ||
+		    (nic-&gt;packet[ETH_HLEN] != RTCFG_ID_STAGE_1_CFG))
+			continue;
+
+		stage1_data = &amp;nic-&gt;packet[ETH_HLEN+5];
+		len         = ETH_HLEN+5;
+		if (nic-&gt;packet[ETH_HLEN+1] == RTCFG_ADDR_IP) {
+			stage1_data += 2*RTCFG_ADDRSIZE_IP;
+			len         += 2*RTCFG_ADDRSIZE_IP;
+		}
+		len += ntohs(*((short *)&amp;nic-&gt;packet[len-2]));
+		if (nic-&gt;packetlen &lt; len)
+			continue;
+
+		limit = nic-&gt;packet + nic-&gt;packetlen;
+		while (stage1_data &lt; limit) {
+			if ((stage1_data+sizeof(TDMACFG)-1 &gt; limit) ||
+			    (memcmp(stage1_data, TDMACFG,
+			            sizeof(TDMACFG)-1) != 0)) {
+				stage1_data++;
+				continue;
+			}
+			stage1_data += sizeof(TDMACFG)-1;
+
+			slot = get_uint(&amp;stage1_data, limit);
+			if ((slot &lt; 0) || (slot &gt; 1) ||
+			    (stage1_data == limit) || (*stage1_data != ' '))
+				continue;
+			stage1_data++;
+
+			new_offset = get_uint(&amp;stage1_data, limit);
+			if (new_offset &lt; 0)
+				continue;
+
+			phasing[slot] = 1;
+			period[slot]  = 1;
+			size[slot]    = ETH_MAX_MTU;
+
+			if ((stage1_data+sizeof(p_param)-1 &lt;= limit) &amp;&amp;
+			    (memcmp(stage1_data, p_param,
+			            sizeof(p_param)-1) == 0)) {
+				stage1_data += sizeof(p_param)-1;
+
+				phasing[slot] = get_uint(&amp;stage1_data, limit);
+				if ((phasing[slot] &lt;= 0) ||
+				    (stage1_data == limit) ||
+				    (*stage1_data != '/'))
+					continue;
+				stage1_data++;
+
+				period[slot] = get_uint(&amp;stage1_data, limit);
+				if (period[slot] &lt;= 0)
+					continue;
+			}
+
+			if ((stage1_data+sizeof(s_param)-1 &lt;= limit) &amp;&amp;
+			    (memcmp(stage1_data, s_param,
+			            sizeof(s_param)-1) == 0)) {
+				stage1_data += sizeof(s_param)-1;
+
+				size[slot] = get_uint(&amp;stage1_data, limit);
+				if (size[slot] == 0)
+					size[slot] = ETH_MAX_MTU;
+			}
+
+			offset[slot] = new_offset;
+		}
+
+		if (offset[1] &gt;= 0)
+			slot = 1;
+		else if (offset[0] &gt;= 0)
+			slot = 0;
+		else
+			continue;
+
+		slot_offset  = offset[slot];
+		slot_phasing = phasing[slot];
+		slot_period  = period[slot];
+		slot_size    = size[slot];
+
+		if ((slot_offset &lt; 100) || (slot_offset &gt; 4000000)) {
+			printf("\nUnsupported slot offset (%d us), "
+			       "fix server settings to 100-4000000 us!\n",
+			       slot_offset);
+			return PROBE_FAILED;
+		}
+
+		printf("\nSlot offset: %d us, Phasing/period: %d/%d, "
+		       "size: %d bytes\n", slot_offset, slot_phasing,
+		       slot_period, slot_size);
+
+		/* convert offset to ns */
+		slot_offset = slot_offset * 1000;
+		/* encode phasing as remainder of cycle / period */
+		slot_phasing--;
+		/* decrease slot size by mandatory RTmac header */
+		slot_size -= RTMAC_HLEN;
+
+		return PROBE_WORKED;
+	}
+}
+
+static int check_tdma_sync(struct nic *nic, unsigned long long recv_stamp)
+{
+	unsigned int       cycle;
+	unsigned long long actual_xmit;
+	unsigned long long sched_xmit;
+	struct rtmac_hdr   *rtmac;
+	struct sync_frm    *sync;
+
+
+	/* check packet length */
+	if (nic-&gt;packetlen &lt; ETH_HLEN+RTMAC_HLEN+TDMA_SYNC_LEN)
+		return 0;
+
+	rtmac = (struct rtmac_hdr *)&amp;nic-&gt;packet[ETH_HLEN];
+
+	/* TDMA frame? */
+	if (rtmac-&gt;type != htons(RTMAC_TYPE_TDMA))
+		return 0;
+
+	sync = (struct sync_frm *)&amp;nic-&gt;packet[ETH_HLEN+RTMAC_HLEN];
+
+	/* Correct TDMA version? Synchronisation frame? */
+	if ((sync-&gt;version != htons(TDMA_FRM_VERSION)) ||
+		(sync-&gt;id != htons(TDMA_FRM_SYNC)))
+		return 0;
+
+	cycle = ntohl(sync-&gt;cycle_no);
+
+	/* Only transmit in assigned phase */
+	if ((cycle % slot_period) != slot_phasing)
+		return 0;
+
+	actual_xmit = be64_to_cpu(sync-&gt;xmit_stamp);
+	sched_xmit  = be64_to_cpu(sync-&gt;sched_xmit_stamp);
+
+	next_slot  = recv_stamp + slot_offset -
+		(actual_xmit - sched_xmit) - master_packet_delay;
+	last_cycle = cycle;
+	return 1;
+}
+
+static void wait_on_slot(struct nic *nic)
+{
+	unsigned long long time_stamp;
+	char               *orig_buf;
+	struct rtmac_hdr   *rtmac;
+
+
+	time_stamp = get_time();
+	if ((next_slot != 0) &amp;&amp; (next_slot &gt; time_stamp) &amp;&amp;
+	    ((next_slot - time_stamp) &lt; 4000000000LL)) {
+		delay_until(next_slot);
+		return;
+	}
+
+	/* use different buffer to avoid overwriting */
+	orig_buf    = nic-&gt;packet;
+	nic-&gt;packet = shadow_buf + ETH_DATA_ALIGN;
+
+	/* clear buffer to get clean time stamps */
+	while ((*nic_poll)(nic, 1));
+
+	while (1) {
+		do {
+			poll_interruptions();
+			time_stamp = get_time();
+		} while (!(*nic_poll)(nic, 1));
+
+		/* check packet length */
+		if (nic-&gt;packetlen &lt; ETH_HLEN+RTMAC_HLEN+TDMA_SYNC_LEN)
+			continue;
+
+		/* RTmac Ethernet frame? */
+		if (*((short *)&amp;nic-&gt;packet[12]) != htons(ETH_RTMAC))
+			continue;
+
+		rtmac = (struct rtmac_hdr *)&amp;nic-&gt;packet[ETH_HLEN];
+
+		/* Correct RTmac version? Non-tunnelled frame? */
+		if ((rtmac-&gt;ver != RTMAC_VERSION) ||
+		    ((rtmac-&gt;flags &amp; RTMAC_FLAG_TUNNEL) != 0))
+			continue;
+
+		if (!check_tdma_sync(nic, time_stamp))
+			continue;
+
+		/* restore buffer */
+		nic-&gt;packet = orig_buf;
+
+		delay_until(next_slot);
+		return;
+	}
+}
+
+static void calibrate_packet_delay(struct nic *nic)
+{
+	int                   round;
+	unsigned long long    time_stamp;
+	unsigned long long    delay;
+	unsigned long long    delay_sum = 0;
+	unsigned long long    min_delay = -1;
+	unsigned long long    max_delay = 0;
+	struct rtmac_hdr      *rtmac;
+	struct replycal_frm   *reply;
+	struct {
+		struct rtmac_hdr  hdr;
+		struct reqcal_frm tdma;
+	} request = {
+		{htons(RTMAC_TYPE_TDMA), RTMAC_VERSION, 0},
+		{htons(TDMA_FRM_VERSION), htons(TDMA_FRM_REQ_CAL), 0, 0,
+		 cpu_to_be64(slot_offset)}
+	};
+
+
+	for (round = CALIBRATION_ROUNDS; round &gt; 0; round--) {
+		wait_on_slot(nic);
+		request.tdma.xmit_stamp  = cpu_to_be64(get_time());
+		request.tdma.reply_cycle = htonl(last_cycle + slot_period);
+		(*nic_transmit)(nic, &amp;nic-&gt;packet[6], ETH_RTMAC,
+		                sizeof(request), (char *)&amp;request);
+
+		while (1) {
+			do {
+				poll_interruptions();
+				time_stamp = get_time();
+			} while (!(*nic_poll)(nic, 1));
+
+			/* check packet length */
+			if (nic-&gt;packetlen &lt; ETH_HLEN+RTMAC_HLEN+
+			                     TDMA_RPL_CAL_LEN)
+				continue;
+
+			/* RTmac Ethernet frame? */
+			if (*((short *)&amp;nic-&gt;packet[12]) != htons(ETH_RTMAC))
+				continue;
+
+			rtmac = (struct rtmac_hdr *)&amp;nic-&gt;packet[ETH_HLEN];
+
+			/* Correct RTmac version? Non-tunnelled frame? TDMA? */
+			if ((rtmac-&gt;ver != RTMAC_VERSION) ||
+			    ((rtmac-&gt;flags &amp; RTMAC_FLAG_TUNNEL) != 0) ||
+			    (rtmac-&gt;type != htons(RTMAC_TYPE_TDMA)))
+				continue;
+
+			reply = (struct replycal_frm *)
+				&amp;nic-&gt;packet[ETH_HLEN+RTMAC_HLEN];
+
+			/* Correct TDMA version? Synchronisation frame? */
+			if ((reply-&gt;version != htons(TDMA_FRM_VERSION)) ||
+			    (reply-&gt;id != htons(TDMA_FRM_RPL_CAL)))
+				continue;
+
+			delay = (time_stamp -
+				be64_to_cpu(reply-&gt;request_xmit_stamp) -
+				(be64_to_cpu(reply-&gt;xmit_stamp) -
+				 be64_to_cpu(reply-&gt;reception_stamp))) / 2;
+			if (delay &lt; min_delay)
+				min_delay = delay;
+			if (delay &gt; max_delay)
+				max_delay = delay;
+			delay_sum += delay;
+			break;
+		}
+	}
+
+	/* assumption: delay_sum fits into unsigned long -
+	               true for microsecond delays */
+	master_packet_delay = (unsigned long)delay_sum / CALIBRATION_ROUNDS;
+	printf("Calibrated master-to-slave packet delay: "
+	       "%ld us (min/max: %ld/%ld us)\n\n",
+	       ((unsigned long)master_packet_delay+500)/1000,
+	       ((unsigned long)min_delay+500)/1000,
+	       ((unsigned long)max_delay+500)/1000);
+}
+
+static int rtnet_poll(struct nic *nic, int retrieve)
+{
+	unsigned long long recv_stamp = 0;
+
+
+	if (!retrieve)
+		return (*nic_poll)(nic, 0);
+
+	if (!(*nic_poll)(nic, 1)) {
+		do {
+			poll_interruptions();
+			recv_stamp = get_time();
+		} while (!(*nic_poll)(nic, 1));
+	}
+
+	/* check packet header length */
+	if (nic-&gt;packetlen &lt; ETH_HLEN + RTMAC_HLEN)
+		return 0;
+
+	/* RTmac Ethernet frame? */
+	if (*((short *)&amp;nic-&gt;packet[12]) != htons(ETH_RTMAC))
+		return 0;
+
+	/* Correct RTmac version? */
+	if (nic-&gt;packet[ETH_HLEN+2] != RTMAC_VERSION)
+		return 0;
+
+	/* Tunnelled frame? */
+	if ((nic-&gt;packet[ETH_HLEN+3] &amp; RTMAC_FLAG_TUNNEL) == 0) {
+		/* no, but check for Sync frame */
+		if (recv_stamp != 0) {
+			check_tdma_sync(nic, recv_stamp);
+		} return 0;
+	}
+
+	/* patch the packet type */
+	*((short *)&amp;nic-&gt;packet[12]) =
+	    *((unsigned short *)&amp;nic-&gt;packet[ETH_HLEN]);
+
+	/* remove the RTmac header */
+	nic-&gt;packetlen -= RTMAC_HLEN;
+	memmove(&amp;nic-&gt;packet[ETH_HLEN], &amp;nic-&gt;packet[ETH_HLEN+RTMAC_HLEN],
+	        nic-&gt;packetlen-ETH_HLEN);
+
+	return 1;
+}
+
+static void rtnet_transmit(struct nic *nic, const char *d, unsigned int t,
+                           unsigned int s, const char *p)
+{
+	char buf[ETH_MAX_MTU];
+
+
+	if (s &gt; slot_size) {
+		printf("Outgoing packet too large - dropping!\n");
+		return;
+	}
+
+	memcpy(&amp;buf[RTMAC_HLEN], p, s);
+	*((unsigned short *)buf) = htons(t);
+	buf[2] = RTMAC_VERSION;
+	buf[3] = RTMAC_FLAG_TUNNEL;
+
+	wait_on_slot(nic);
+	(*nic_transmit)(nic, d, ETH_RTMAC, s+RTMAC_HLEN, buf);
+}
+
+int rteth_probe(struct dev *dev)
+{
+	int        result;
+	struct nic *nic = (struct nic *)dev;
+
+
+	result = eth_probe(dev);
+	if (result == PROBE_FAILED)
+		return result;
+
+	nic_poll      = nic-&gt;poll;
+	nic-&gt;poll     = rtnet_poll;
+	nic_transmit  = nic-&gt;transmit;
+	nic-&gt;transmit = rtnet_transmit;
+
+	result = get_slot_params(nic);
+	if (result == PROBE_FAILED)
+		return result;
+
+	calibrate_packet_delay(nic);
+
+	return PROBE_WORKED;
+}
--- /dev/null	2004-04-06 15:27:52.000000000 +0200
+++ src/include/rtnet.h	2004-12-21 11:04:43.067682288 +0100
@@ -0,0 +1,14 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ */
+
+#ifndef	RTNET_H
+#define RTNET_H
+
+#include "dev.h"
+
+extern int rteth_probe(struct dev *dev);
+#endif	/* RTNET_H */
</pre></body></html>