summaryrefslogtreecommitdiff
path: root/libdde_linux26/examples
diff options
context:
space:
mode:
Diffstat (limited to 'libdde_linux26/examples')
-rw-r--r--libdde_linux26/examples/.svn/all-wcprops11
-rw-r--r--libdde_linux26/examples/.svn/entries74
-rw-r--r--libdde_linux26/examples/.svn/format1
-rw-r--r--libdde_linux26/examples/.svn/text-base/Makefile.svn-base13
-rw-r--r--libdde_linux26/examples/Makefile13
-rw-r--r--libdde_linux26/examples/bug_timersleep/.svn/all-wcprops29
-rw-r--r--libdde_linux26/examples/bug_timersleep/.svn/entries164
-rw-r--r--libdde_linux26/examples/bug_timersleep/.svn/format1
-rw-r--r--libdde_linux26/examples/bug_timersleep/.svn/text-base/Makeconf.local.svn-base1
-rw-r--r--libdde_linux26/examples/bug_timersleep/.svn/text-base/Makefile.svn-base25
-rw-r--r--libdde_linux26/examples/bug_timersleep/.svn/text-base/WhatIsThis.svn-base16
-rw-r--r--libdde_linux26/examples/bug_timersleep/.svn/text-base/main.c.svn-base150
-rw-r--r--libdde_linux26/examples/bug_timersleep/Makeconf.local1
-rw-r--r--libdde_linux26/examples/bug_timersleep/Makefile25
-rw-r--r--libdde_linux26/examples/bug_timersleep/WhatIsThis16
-rw-r--r--libdde_linux26/examples/bug_timersleep/main.c150
-rw-r--r--libdde_linux26/examples/dde26_test/.svn/all-wcprops17
-rw-r--r--libdde_linux26/examples/dde26_test/.svn/entries96
-rw-r--r--libdde_linux26/examples/dde26_test/.svn/format1
-rw-r--r--libdde_linux26/examples/dde26_test/.svn/text-base/Makefile.svn-base21
-rw-r--r--libdde_linux26/examples/dde26_test/.svn/text-base/main.c.svn-base502
-rw-r--r--libdde_linux26/examples/dde26_test/Makefile21
-rw-r--r--libdde_linux26/examples/dde26_test/main.c502
-rw-r--r--libdde_linux26/examples/ne2k/.svn/all-wcprops53
-rw-r--r--libdde_linux26/examples/ne2k/.svn/entries300
-rw-r--r--libdde_linux26/examples/ne2k/.svn/format1
-rw-r--r--libdde_linux26/examples/ne2k/.svn/text-base/8390.c.svn-base109
-rw-r--r--libdde_linux26/examples/ne2k/.svn/text-base/8390.h.svn-base231
-rw-r--r--libdde_linux26/examples/ne2k/.svn/text-base/Makefile.svn-base32
-rw-r--r--libdde_linux26/examples/ne2k/.svn/text-base/arping.c.svn-base185
-rw-r--r--libdde_linux26/examples/ne2k/.svn/text-base/arping.h.svn-base15
-rw-r--r--libdde_linux26/examples/ne2k/.svn/text-base/lib8390.c.svn-base1125
-rw-r--r--libdde_linux26/examples/ne2k/.svn/text-base/main.c.svn-base115
-rw-r--r--libdde_linux26/examples/ne2k/.svn/text-base/ne2k-pci.c.svn-base727
-rw-r--r--libdde_linux26/examples/ne2k/8390.c109
-rw-r--r--libdde_linux26/examples/ne2k/8390.h231
-rw-r--r--libdde_linux26/examples/ne2k/Makefile32
-rw-r--r--libdde_linux26/examples/ne2k/arping.c185
-rw-r--r--libdde_linux26/examples/ne2k/arping.h15
-rw-r--r--libdde_linux26/examples/ne2k/lib8390.c1125
-rw-r--r--libdde_linux26/examples/ne2k/main.c115
-rw-r--r--libdde_linux26/examples/ne2k/ne2k-pci.c727
-rw-r--r--libdde_linux26/examples/unittest/.svn/all-wcprops17
-rw-r--r--libdde_linux26/examples/unittest/.svn/entries96
-rw-r--r--libdde_linux26/examples/unittest/.svn/format1
-rw-r--r--libdde_linux26/examples/unittest/.svn/text-base/Makefile.svn-base21
-rw-r--r--libdde_linux26/examples/unittest/.svn/text-base/main.c.svn-base611
-rw-r--r--libdde_linux26/examples/unittest/Makefile21
-rw-r--r--libdde_linux26/examples/unittest/main.c611
49 files changed, 8660 insertions, 0 deletions
diff --git a/libdde_linux26/examples/.svn/all-wcprops b/libdde_linux26/examples/.svn/all-wcprops
new file mode 100644
index 00000000..b30dbfeb
--- /dev/null
+++ b/libdde_linux26/examples/.svn/all-wcprops
@@ -0,0 +1,11 @@
+K 25
+svn:wc:ra_dav:version-url
+V 59
+/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/examples
+END
+Makefile
+K 25
+svn:wc:ra_dav:version-url
+V 68
+/repos/tudos/!svn/ver/443/trunk/l4/pkg/dde/linux26/examples/Makefile
+END
diff --git a/libdde_linux26/examples/.svn/entries b/libdde_linux26/examples/.svn/entries
new file mode 100644
index 00000000..bee27e97
--- /dev/null
+++ b/libdde_linux26/examples/.svn/entries
@@ -0,0 +1,74 @@
+9
+
+dir
+465
+http://svn.tudos.org/repos/tudos/trunk/l4/pkg/dde/linux26/examples
+http://svn.tudos.org/repos/tudos
+
+
+
+2009-05-20T14:32:55.606606Z
+455
+l4check
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+a704ac0b-3a55-4d43-a2a9-7be6f07c34fb
+
+ne2k
+dir
+
+unittest
+dir
+
+dde26_test
+dir
+
+bug_timersleep
+dir
+
+Makefile
+file
+
+
+
+
+2009-11-15T17:17:14.000000Z
+e5078d83828da469a57cbec2f20b2d91
+2009-03-26T03:50:31.959106Z
+443
+l4check
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+209
+
diff --git a/libdde_linux26/examples/.svn/format b/libdde_linux26/examples/.svn/format
new file mode 100644
index 00000000..ec635144
--- /dev/null
+++ b/libdde_linux26/examples/.svn/format
@@ -0,0 +1 @@
+9
diff --git a/libdde_linux26/examples/.svn/text-base/Makefile.svn-base b/libdde_linux26/examples/.svn/text-base/Makefile.svn-base
new file mode 100644
index 00000000..8717a0b5
--- /dev/null
+++ b/libdde_linux26/examples/.svn/text-base/Makefile.svn-base
@@ -0,0 +1,13 @@
+PKGDIR ?= ../..
+L4DIR ?= $(PKGDIR)/../..
+
+include $(L4DIR)/mk/Makeconf
+-include $(PKGDIR_OBJ)/Makeconf
+
+ifeq ($(CONFIG_DDE26),y)
+TARGET = dde26_test ne2k bug_timersleep
+endif
+
+include $(L4DIR)/mk/subdir.mk
+
+
diff --git a/libdde_linux26/examples/Makefile b/libdde_linux26/examples/Makefile
new file mode 100644
index 00000000..8717a0b5
--- /dev/null
+++ b/libdde_linux26/examples/Makefile
@@ -0,0 +1,13 @@
+PKGDIR ?= ../..
+L4DIR ?= $(PKGDIR)/../..
+
+include $(L4DIR)/mk/Makeconf
+-include $(PKGDIR_OBJ)/Makeconf
+
+ifeq ($(CONFIG_DDE26),y)
+TARGET = dde26_test ne2k bug_timersleep
+endif
+
+include $(L4DIR)/mk/subdir.mk
+
+
diff --git a/libdde_linux26/examples/bug_timersleep/.svn/all-wcprops b/libdde_linux26/examples/bug_timersleep/.svn/all-wcprops
new file mode 100644
index 00000000..e0897b47
--- /dev/null
+++ b/libdde_linux26/examples/bug_timersleep/.svn/all-wcprops
@@ -0,0 +1,29 @@
+K 25
+svn:wc:ra_dav:version-url
+V 74
+/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/examples/bug_timersleep
+END
+main.c
+K 25
+svn:wc:ra_dav:version-url
+V 81
+/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/examples/bug_timersleep/main.c
+END
+WhatIsThis
+K 25
+svn:wc:ra_dav:version-url
+V 85
+/repos/tudos/!svn/ver/443/trunk/l4/pkg/dde/linux26/examples/bug_timersleep/WhatIsThis
+END
+Makeconf.local
+K 25
+svn:wc:ra_dav:version-url
+V 89
+/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/examples/bug_timersleep/Makeconf.local
+END
+Makefile
+K 25
+svn:wc:ra_dav:version-url
+V 83
+/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/examples/bug_timersleep/Makefile
+END
diff --git a/libdde_linux26/examples/bug_timersleep/.svn/entries b/libdde_linux26/examples/bug_timersleep/.svn/entries
new file mode 100644
index 00000000..4475ed37
--- /dev/null
+++ b/libdde_linux26/examples/bug_timersleep/.svn/entries
@@ -0,0 +1,164 @@
+9
+
+dir
+465
+http://svn.tudos.org/repos/tudos/trunk/l4/pkg/dde/linux26/examples/bug_timersleep
+http://svn.tudos.org/repos/tudos
+
+
+
+2009-05-20T14:32:55.606606Z
+455
+l4check
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+a704ac0b-3a55-4d43-a2a9-7be6f07c34fb
+
+main.c
+file
+
+
+
+
+2009-11-15T17:17:14.000000Z
+9ef2d314e37201c0d6813c088a9bdf9b
+2009-05-20T14:32:55.606606Z
+455
+l4check
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3348
+
+WhatIsThis
+file
+
+
+
+
+2009-11-15T17:17:14.000000Z
+b3d846298a511fba776c557db5645ad7
+2009-03-26T03:50:31.959106Z
+443
+l4check
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+504
+
+Makeconf.local
+file
+
+
+
+
+2009-11-15T17:17:14.000000Z
+075b1f05a72c4dc89dcd7e4e97e3da21
+2009-05-20T14:32:55.606606Z
+455
+l4check
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+108
+
+Makefile
+file
+
+
+
+
+2009-11-15T17:17:14.000000Z
+896d9d28b3e9e8626a8229ba171f9890
+2009-05-20T14:32:55.606606Z
+455
+l4check
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+585
+
diff --git a/libdde_linux26/examples/bug_timersleep/.svn/format b/libdde_linux26/examples/bug_timersleep/.svn/format
new file mode 100644
index 00000000..ec635144
--- /dev/null
+++ b/libdde_linux26/examples/bug_timersleep/.svn/format
@@ -0,0 +1 @@
+9
diff --git a/libdde_linux26/examples/bug_timersleep/.svn/text-base/Makeconf.local.svn-base b/libdde_linux26/examples/bug_timersleep/.svn/text-base/Makeconf.local.svn-base
new file mode 100644
index 00000000..28ebade5
--- /dev/null
+++ b/libdde_linux26/examples/bug_timersleep/.svn/text-base/Makeconf.local.svn-base
@@ -0,0 +1 @@
+#LIBS += -lferret_client -lferret_producer -lferret_util -lferret_comm -lferret_fpages -lferret_local_names
diff --git a/libdde_linux26/examples/bug_timersleep/.svn/text-base/Makefile.svn-base b/libdde_linux26/examples/bug_timersleep/.svn/text-base/Makefile.svn-base
new file mode 100644
index 00000000..a1f39f00
--- /dev/null
+++ b/libdde_linux26/examples/bug_timersleep/.svn/text-base/Makefile.svn-base
@@ -0,0 +1,25 @@
+PKGDIR ?= ../../..
+L4DIR ?= $(PKGDIR)/../..
+
+SYSTEMS = x86-l4v2
+
+DEFAULT_RELOC = 0x00a00000
+
+-include $(PKGDIR_OBJ)/Makeconf
+
+TARGET = dde26_bug_timersleep
+
+SRC_C = main.c
+
+LIBS += -ldde_linux26.o -lddekit -lio -lomega0 -llist_alloc
+
+PRIVATE_INCDIR = $(PKGDIR_ABS)/linux26/include $(MY_DDE_INCDIR) $(MY_LINUX26_INCDIR) \
+ $(OBJ_BASE)/include/uclibc
+
+LIBCINCDIR = -nostdinc $(I_GCCINCDIR)
+DEFINES = -D__KERNEL__ -DDDE_LINUX $(KBUILD_DEFINES)
+CPPFLAGS += $(KBUILD_CPPFLAGS)
+
+include $(PKGDIR)/linux26/Makeconf
+
+include $(L4DIR)/mk/prog.mk
diff --git a/libdde_linux26/examples/bug_timersleep/.svn/text-base/WhatIsThis.svn-base b/libdde_linux26/examples/bug_timersleep/.svn/text-base/WhatIsThis.svn-base
new file mode 100644
index 00000000..3fb57408
--- /dev/null
+++ b/libdde_linux26/examples/bug_timersleep/.svn/text-base/WhatIsThis.svn-base
@@ -0,0 +1,16 @@
+=== Bug reported by Andre Puschmann ===
+
+main.c contains Linux kernel code that triggers 2 problems:
+
+1) list order violation in the list alloc lib
+2) threads hang after scheduling a very short timer, because
+ the timer thread seems to miss some events
+
+
+Fixes
+=====
+1) correct locking for ddekit's memory allocation functions
+ solves the problem
+2) fixed DDEKit's timer implementation to not use IPC for
+ notifications (because some got lost for atomicity reasons)
+ but use a counting semaphore
diff --git a/libdde_linux26/examples/bug_timersleep/.svn/text-base/main.c.svn-base b/libdde_linux26/examples/bug_timersleep/.svn/text-base/main.c.svn-base
new file mode 100644
index 00000000..a02e6841
--- /dev/null
+++ b/libdde_linux26/examples/bug_timersleep/.svn/text-base/main.c.svn-base
@@ -0,0 +1,150 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/version.h>
+#include <linux/kthread.h>
+
+//BEER for L4
+#include <l4/sys/kdebug.h>
+#include <l4/util/util.h>
+#include <l4/dde/linux26/dde26.h>
+
+#if 0
+#include <l4/ferret/client.h>
+#include <l4/ferret/clock.h>
+#include <l4/ferret/types.h>
+#include <l4/ferret/util.h>
+#include <l4/ferret/sensors/list_producer.h>
+#include <l4/ferret/sensors/list_producer_wrap.h>
+#endif
+
+static int idle_thread(void *);
+int __init init_module(void);
+void __exit cleanup_module(void);
+#if 0
+ferret_list_local_t *sensor;
+#endif
+
+enum Events
+{
+ DDE_INIT = 10,
+ DDE_INITCALLS = 11,
+ INIT_MODULE = 12,
+ START_THREAD = 13,
+ THREAD_INIT = 14,
+ THREAD_SLEEP_START = 15,
+ THREAD_SLEEP_END = 16
+};
+
+atomic_t val = ATOMIC_INIT(0);
+
+static int idle_thread(void *priv_data)
+{
+ int master_thread_counter = 0;
+#if 0
+ ferret_list_post_1t1wc(1, sensor, 42, 1, 0, me,THREAD_INIT);
+#endif
+
+ while (1)
+ {
+ master_thread_counter++;
+ if ((master_thread_counter % 100) == 0)
+ atomic_inc(&val);
+#if 0
+ printk(KERN_INFO "master_thread_counter: %d jiffies: %d\n",
+ master_thread_counter, jiffies);
+#endif
+
+ // do something interesting
+
+ // wait for 10ms assuming HZ=100
+ set_current_state(TASK_INTERRUPTIBLE);
+// ferret_list_post_1t1wc(1, sensor, 42, 1, 0, me,THREAD_SLEEP_START);
+ schedule_timeout(1);
+// ferret_list_post_1t1wc(1, sensor, 42, 1, 0, me,THREAD_SLEEP_END);
+ //msleep(10);
+ }
+}
+
+int __init init_module(void)
+{
+ int i;
+ printk(KERN_INFO "init module\n");
+
+ for (i = 0; i < 10; i++)
+ {
+// ferret_list_post_1t1wc(1, sensor, 42, 1, 0, l4_myself(),START_THREAD);
+ kthread_run(idle_thread, NULL, "IDLE THREAD");
+ udelay(1000);
+ }
+ // no error check
+ return 0;
+}
+
+void __exit cleanup_module(void)
+{
+ printk(KERN_INFO "exit module\n");
+ // kill thread
+}
+
+MODULE_AUTHOR("test");
+MODULE_DESCRIPTION("test");
+MODULE_LICENSE("GPL");
+
+static void *kmalloc_wrap(size_t sz)
+{ return kmalloc(sz,GFP_KERNEL); }
+
+int main(void)
+{
+ int old, v = 12000;
+ printk("Initializing Ferret\n");
+#if 0
+ int ret = ferret_create(42, 1, 0, FERRET_LIST, 0,
+ "64:100000", sensor, &kmalloc_wrap);
+ printk("Created sensor: %d\n", ret);
+
+ ferret_list_post_1t1wc(1, sensor, 42, 1, 0, l4_myself(),DDE_INIT);
+#endif
+ printk("Initializing DDE base system.\n");
+
+#if 0
+ ferret_list_post_1t1wc(1, sensor, 42, 1, 0, l4_myself(),DDE_INITCALLS);
+#endif
+
+#if 0
+ ferret_list_post_1t1wc(1, sensor, 42, 1, 0, l4_myself(),INIT_MODULE);
+#endif
+ init_module();
+
+ while (1)
+ {
+ l4_sleep(3000);
+ old = v;
+ v = atomic_read(&val);
+ printk("%d - %d = %d\n", v, old, v-old);
+ if (v - old == 0)
+ {
+ printk("System halt!? %d\n", v);
+ //enter_kdebug("..");
+#if 0
+ ferret_list_entry_common_t * elc;
+
+ int idx = ferret_list_dequeue(sensor);
+ elc = (ferret_list_entry_common_t *)ferret_list_e4i(sensor->glob, idx);
+ elc->major = FERRET_MONCON_MAJOR;
+ elc->minor = FERRET_MONCON_SERSEND;
+ strncpy(elc->data8, "foobar", 7);
+ ferret_list_commit(sensor, idx);
+ printk("Dumped %d\n", idx);
+ l4_sleep(10000);
+#endif
+ enter_kdebug("");
+ }
+ }
+
+ l4_sleep_forever();
+ return -1;
+}
diff --git a/libdde_linux26/examples/bug_timersleep/Makeconf.local b/libdde_linux26/examples/bug_timersleep/Makeconf.local
new file mode 100644
index 00000000..28ebade5
--- /dev/null
+++ b/libdde_linux26/examples/bug_timersleep/Makeconf.local
@@ -0,0 +1 @@
+#LIBS += -lferret_client -lferret_producer -lferret_util -lferret_comm -lferret_fpages -lferret_local_names
diff --git a/libdde_linux26/examples/bug_timersleep/Makefile b/libdde_linux26/examples/bug_timersleep/Makefile
new file mode 100644
index 00000000..a1f39f00
--- /dev/null
+++ b/libdde_linux26/examples/bug_timersleep/Makefile
@@ -0,0 +1,25 @@
+PKGDIR ?= ../../..
+L4DIR ?= $(PKGDIR)/../..
+
+SYSTEMS = x86-l4v2
+
+DEFAULT_RELOC = 0x00a00000
+
+-include $(PKGDIR_OBJ)/Makeconf
+
+TARGET = dde26_bug_timersleep
+
+SRC_C = main.c
+
+LIBS += -ldde_linux26.o -lddekit -lio -lomega0 -llist_alloc
+
+PRIVATE_INCDIR = $(PKGDIR_ABS)/linux26/include $(MY_DDE_INCDIR) $(MY_LINUX26_INCDIR) \
+ $(OBJ_BASE)/include/uclibc
+
+LIBCINCDIR = -nostdinc $(I_GCCINCDIR)
+DEFINES = -D__KERNEL__ -DDDE_LINUX $(KBUILD_DEFINES)
+CPPFLAGS += $(KBUILD_CPPFLAGS)
+
+include $(PKGDIR)/linux26/Makeconf
+
+include $(L4DIR)/mk/prog.mk
diff --git a/libdde_linux26/examples/bug_timersleep/WhatIsThis b/libdde_linux26/examples/bug_timersleep/WhatIsThis
new file mode 100644
index 00000000..3fb57408
--- /dev/null
+++ b/libdde_linux26/examples/bug_timersleep/WhatIsThis
@@ -0,0 +1,16 @@
+=== Bug reported by Andre Puschmann ===
+
+main.c contains Linux kernel code that triggers 2 problems:
+
+1) list order violation in the list alloc lib
+2) threads hang after scheduling a very short timer, because
+ the timer thread seems to miss some events
+
+
+Fixes
+=====
+1) correct locking for ddekit's memory allocation functions
+ solves the problem
+2) fixed DDEKit's timer implementation to not use IPC for
+ notifications (because some got lost for atomicity reasons)
+ but use a counting semaphore
diff --git a/libdde_linux26/examples/bug_timersleep/main.c b/libdde_linux26/examples/bug_timersleep/main.c
new file mode 100644
index 00000000..a02e6841
--- /dev/null
+++ b/libdde_linux26/examples/bug_timersleep/main.c
@@ -0,0 +1,150 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/version.h>
+#include <linux/kthread.h>
+
+//BEER for L4
+#include <l4/sys/kdebug.h>
+#include <l4/util/util.h>
+#include <l4/dde/linux26/dde26.h>
+
+#if 0
+#include <l4/ferret/client.h>
+#include <l4/ferret/clock.h>
+#include <l4/ferret/types.h>
+#include <l4/ferret/util.h>
+#include <l4/ferret/sensors/list_producer.h>
+#include <l4/ferret/sensors/list_producer_wrap.h>
+#endif
+
+static int idle_thread(void *);
+int __init init_module(void);
+void __exit cleanup_module(void);
+#if 0
+ferret_list_local_t *sensor;
+#endif
+
+enum Events
+{
+ DDE_INIT = 10,
+ DDE_INITCALLS = 11,
+ INIT_MODULE = 12,
+ START_THREAD = 13,
+ THREAD_INIT = 14,
+ THREAD_SLEEP_START = 15,
+ THREAD_SLEEP_END = 16
+};
+
+atomic_t val = ATOMIC_INIT(0);
+
+static int idle_thread(void *priv_data)
+{
+ int master_thread_counter = 0;
+#if 0
+ ferret_list_post_1t1wc(1, sensor, 42, 1, 0, me,THREAD_INIT);
+#endif
+
+ while (1)
+ {
+ master_thread_counter++;
+ if ((master_thread_counter % 100) == 0)
+ atomic_inc(&val);
+#if 0
+ printk(KERN_INFO "master_thread_counter: %d jiffies: %d\n",
+ master_thread_counter, jiffies);
+#endif
+
+ // do something interesting
+
+ // wait for 10ms assuming HZ=100
+ set_current_state(TASK_INTERRUPTIBLE);
+// ferret_list_post_1t1wc(1, sensor, 42, 1, 0, me,THREAD_SLEEP_START);
+ schedule_timeout(1);
+// ferret_list_post_1t1wc(1, sensor, 42, 1, 0, me,THREAD_SLEEP_END);
+ //msleep(10);
+ }
+}
+
+int __init init_module(void)
+{
+ int i;
+ printk(KERN_INFO "init module\n");
+
+ for (i = 0; i < 10; i++)
+ {
+// ferret_list_post_1t1wc(1, sensor, 42, 1, 0, l4_myself(),START_THREAD);
+ kthread_run(idle_thread, NULL, "IDLE THREAD");
+ udelay(1000);
+ }
+ // no error check
+ return 0;
+}
+
+void __exit cleanup_module(void)
+{
+ printk(KERN_INFO "exit module\n");
+ // kill thread
+}
+
+MODULE_AUTHOR("test");
+MODULE_DESCRIPTION("test");
+MODULE_LICENSE("GPL");
+
+static void *kmalloc_wrap(size_t sz)
+{ return kmalloc(sz,GFP_KERNEL); }
+
+int main(void)
+{
+ int old, v = 12000;
+ printk("Initializing Ferret\n");
+#if 0
+ int ret = ferret_create(42, 1, 0, FERRET_LIST, 0,
+ "64:100000", sensor, &kmalloc_wrap);
+ printk("Created sensor: %d\n", ret);
+
+ ferret_list_post_1t1wc(1, sensor, 42, 1, 0, l4_myself(),DDE_INIT);
+#endif
+ printk("Initializing DDE base system.\n");
+
+#if 0
+ ferret_list_post_1t1wc(1, sensor, 42, 1, 0, l4_myself(),DDE_INITCALLS);
+#endif
+
+#if 0
+ ferret_list_post_1t1wc(1, sensor, 42, 1, 0, l4_myself(),INIT_MODULE);
+#endif
+ init_module();
+
+ while (1)
+ {
+ l4_sleep(3000);
+ old = v;
+ v = atomic_read(&val);
+ printk("%d - %d = %d\n", v, old, v-old);
+ if (v - old == 0)
+ {
+ printk("System halt!? %d\n", v);
+ //enter_kdebug("..");
+#if 0
+ ferret_list_entry_common_t * elc;
+
+ int idx = ferret_list_dequeue(sensor);
+ elc = (ferret_list_entry_common_t *)ferret_list_e4i(sensor->glob, idx);
+ elc->major = FERRET_MONCON_MAJOR;
+ elc->minor = FERRET_MONCON_SERSEND;
+ strncpy(elc->data8, "foobar", 7);
+ ferret_list_commit(sensor, idx);
+ printk("Dumped %d\n", idx);
+ l4_sleep(10000);
+#endif
+ enter_kdebug("");
+ }
+ }
+
+ l4_sleep_forever();
+ return -1;
+}
diff --git a/libdde_linux26/examples/dde26_test/.svn/all-wcprops b/libdde_linux26/examples/dde26_test/.svn/all-wcprops
new file mode 100644
index 00000000..6fec0785
--- /dev/null
+++ b/libdde_linux26/examples/dde26_test/.svn/all-wcprops
@@ -0,0 +1,17 @@
+K 25
+svn:wc:ra_dav:version-url
+V 70
+/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/examples/dde26_test
+END
+main.c
+K 25
+svn:wc:ra_dav:version-url
+V 77
+/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/examples/dde26_test/main.c
+END
+Makefile
+K 25
+svn:wc:ra_dav:version-url
+V 79
+/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/examples/dde26_test/Makefile
+END
diff --git a/libdde_linux26/examples/dde26_test/.svn/entries b/libdde_linux26/examples/dde26_test/.svn/entries
new file mode 100644
index 00000000..8a7ab4c5
--- /dev/null
+++ b/libdde_linux26/examples/dde26_test/.svn/entries
@@ -0,0 +1,96 @@
+9
+
+dir
+465
+http://svn.tudos.org/repos/tudos/trunk/l4/pkg/dde/linux26/examples/dde26_test
+http://svn.tudos.org/repos/tudos
+
+
+
+2009-05-20T14:32:55.606606Z
+455
+l4check
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+a704ac0b-3a55-4d43-a2a9-7be6f07c34fb
+
+main.c
+file
+
+
+
+
+2009-11-15T17:17:14.000000Z
+605a540cd2dba4981825383619cfcddd
+2009-05-20T14:32:55.606606Z
+455
+l4check
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+13242
+
+Makefile
+file
+
+
+
+
+2009-11-15T17:17:14.000000Z
+9d1aa1fef27a10b5882bbd2c22cd991c
+2009-05-20T14:32:55.606606Z
+455
+l4check
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+401
+
diff --git a/libdde_linux26/examples/dde26_test/.svn/format b/libdde_linux26/examples/dde26_test/.svn/format
new file mode 100644
index 00000000..ec635144
--- /dev/null
+++ b/libdde_linux26/examples/dde26_test/.svn/format
@@ -0,0 +1 @@
+9
diff --git a/libdde_linux26/examples/dde26_test/.svn/text-base/Makefile.svn-base b/libdde_linux26/examples/dde26_test/.svn/text-base/Makefile.svn-base
new file mode 100644
index 00000000..444a1f2d
--- /dev/null
+++ b/libdde_linux26/examples/dde26_test/.svn/text-base/Makefile.svn-base
@@ -0,0 +1,21 @@
+PKGDIR ?= ../../..
+L4DIR ?= $(PKGDIR)/../..
+
+SYSTEMS = x86-l4v2
+
+DEFAULT_RELOC = 0x00a00000
+
+-include $(PKGDIR_OBJ)/Makeconf
+
+ifeq ($(CONFIG_DDE26_COMMON),y)
+TARGET = dde26_test
+endif
+
+SRC_C = main.c
+
+LIBS += -ldde_linux26.o -lddekit -lio -llist_alloc -lparsecmdline
+
+# DDE configuration
+include $(PKGDIR)/linux26/Makeconf
+
+include $(L4DIR)/mk/prog.mk
diff --git a/libdde_linux26/examples/dde26_test/.svn/text-base/main.c.svn-base b/libdde_linux26/examples/dde26_test/.svn/text-base/main.c.svn-base
new file mode 100644
index 00000000..88d33ba6
--- /dev/null
+++ b/libdde_linux26/examples/dde26_test/.svn/text-base/main.c.svn-base
@@ -0,0 +1,502 @@
+/*
+ * \brief DDE for Linux 2.6 test program
+ * \author Bjoern Doebel <doebel@os.inf.tu-dresden.de>
+ * \author Christian Helmuth <ch12@os.inf.tu-dresden.de>
+ * \date 2007-01-22
+ */
+
+#include <asm/current.h>
+
+#include <linux/kernel.h>
+#include <linux/completion.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+//#include <linux/kthread.h>
+
+#include <l4/dde/dde.h>
+#include <l4/dde/ddekit/initcall.h>
+#include <l4/dde/linux26/dde26.h>
+
+#include <l4/util/parse_cmd.h>
+#include <l4/util/util.h>
+#include <l4/log/l4log.h>
+
+/* We define 4 initcalls and see if these are executed
+ * in the beginning.
+ */
+static __init void foo(void) { printk("foo module_init\n"); }
+static __init void bar(void) { printk("bar device_initcall\n"); }
+static __init void bla(void) { printk("bla arch_initcall\n"); }
+static __init void blub(void) { printk("blub subsys_initcall\n"); }
+module_init(foo);
+device_initcall(bar);
+arch_initcall(bla);
+subsys_initcall(blub);
+
+/***********************************************************************
+ ** Test 1: Check whether the current() macro works. **
+ ***********************************************************************/
+static void current_test(void)
+{
+ struct task_struct *t = NULL;
+
+ printk("Current() test.\n");
+
+ t = current;
+ printk("\tt = %p\n", t);
+}
+
+
+/***********************************************************************
+ ** Test 2: Getting complicated. Test startup of some kernel threads **
+ ** and wait for them to finish using completions. **
+ ***********************************************************************/
+#define NUM_KTHREADS 5
+static struct completion _kthread_completions_[NUM_KTHREADS];
+
+static int kernel_thread_func(void *arg)
+{
+ printk("\t\tKernel thread %d\n", (int)arg);
+ printk("\t\tcurrent = %p\n", current);
+
+ /* do some work */
+ msleep(200);
+
+ complete_and_exit( &_kthread_completions_[(int)arg], 0 );
+ return 0;
+}
+
+
+static void kernel_thread_test(void)
+{
+ int i;
+ printk("Testing kernel_thread()\n");
+ for (i=0; i < NUM_KTHREADS; i++) {
+ int j;
+ printk("\tInitializing completion for kernel thread.%x\n", i+1);
+ init_completion(&_kthread_completions_[i]);
+ printk("\tStarting kthread.%x\n", i+1);
+ j = kernel_thread(kernel_thread_func, (void *)i, 0);
+ printk("\treturn: %d\n", j);
+ }
+
+ for (i=0; i < NUM_KTHREADS; i++) {
+ printk("\tWaiting for kthread.%x to complete.\n", i+1);
+ wait_for_completion(&_kthread_completions_[i]);
+ printk("\tkthread.%x has exited.\n", i+1);
+ }
+}
+
+
+/******************************************************************************
+ ** Test 3: Test kernel wait queues: start a thread incrementing wait_value, **
+ ** and sleep until wait_value is larger than 6 for the first time. **
+ ******************************************************************************/
+static DECLARE_WAIT_QUEUE_HEAD(_wq_head);
+static int wait_value = 0;
+static struct completion wq_completion;
+
+static int inc_func(void *arg)
+{
+ int i = 0;
+
+ printk("\033[33mI am counting up wait_value.\033[0m\n");
+ for (i=0; i<10; i++)
+ {
+ printk("\033[33mwait_value: %d\033[0m\n", ++wait_value);
+ wake_up(&_wq_head);
+ msleep(500);
+ }
+ complete_and_exit(&wq_completion, 0);
+}
+
+
+static void wq_test(void)
+{
+ int pid;
+ printk("\033[32mWait_queue test. I'm waiting vor wait_value to become >6.\033[0m\n");
+
+ init_completion(&wq_completion);
+ pid = kernel_thread(inc_func, 0, 0);
+
+ wait_event(_wq_head, wait_value > 6);
+ printk("\033[32;1mwait_value > 6 occured!\033[0m\n");
+
+ wait_for_completion(&wq_completion);
+ printk("\033[32mtest done.\033[0m\n");
+}
+
+
+/****************************************************************************
+ ** Test 4: Tasklets **
+ ****************************************************************************/
+static void tasklet_func(unsigned long i)
+{
+ printk("TASKLET: %d\n", i);
+}
+
+
+static DECLARE_TASKLET(low0, tasklet_func, 0);
+static DECLARE_TASKLET(low1, tasklet_func, 1);
+static DECLARE_TASKLET(low2, tasklet_func, 2);
+static DECLARE_TASKLET_DISABLED(low3, tasklet_func, 3);
+
+static DECLARE_TASKLET(hi0, tasklet_func, 10);
+static DECLARE_TASKLET(hi1, tasklet_func, 11);
+static DECLARE_TASKLET_DISABLED(hi2, tasklet_func, 12);
+
+
+static void tasklet_test(void)
+{
+ printk("BEGIN TASKLET TEST\n");
+
+ l4dde26_softirq_init();
+
+ printk("sleep 1000 msec\n");
+ msleep(1000);
+
+ printk("Scheduling tasklets 0-2 immediately. 3 is disabled for 2 seconds.\n");
+ tasklet_schedule(&low0);
+
+ tasklet_schedule(&low1);
+ tasklet_schedule(&low2);
+ tasklet_schedule(&low3);
+ msleep(2000);
+ tasklet_enable(&low3);
+
+ msleep(1000);
+
+ printk("Scheduling hi_tasklets 10-12, and tasklets 0-2\n");
+ tasklet_hi_schedule(&hi0);
+ tasklet_hi_schedule(&hi1);
+ tasklet_hi_schedule(&hi2);
+ tasklet_schedule(&low0);
+ tasklet_schedule(&low1);
+ tasklet_schedule(&low2);
+ tasklet_enable(&hi2);
+
+ msleep(1000);
+ printk("Scheduling (disabled) tasklet 3 twice - should only run once after enabling.\n");
+ tasklet_disable(&low3);
+ tasklet_schedule(&low3);
+ tasklet_schedule(&low3);
+ tasklet_enable(&low3);
+
+ msleep(1000);
+
+ printk("END TASKLET TEST\n");
+}
+
+
+/******************************************************************************
+ ** Test 5: Timers **
+ ** **
+ ** Schedule a periodic timer printing "tick" every second. Additionally, **
+ ** schedule timers for 5, 10, 15, 20, and 25 seconds. Timer at 15s will **
+ ** deactivate the 20s timer. **
+ ******************************************************************************/
+
+static struct timer_list _timer;
+static struct timer_list _timer5;
+static struct timer_list _timer10;
+static struct timer_list _timer15;
+static struct timer_list _timer20;
+static struct timer_list _timer25;
+
+static void tick_func(unsigned long d)
+{
+ printk("tick (%ld)\n", jiffies);
+ _timer.expires = jiffies + HZ;
+ add_timer(&_timer);
+}
+
+
+static void timer_func(unsigned long d)
+{
+ printk("timer_func: %lu\n", d);
+
+ if (d == 15) {
+ printk("De-scheduling 20s timer.\n");
+ del_timer(&_timer20);
+ }
+
+ if (timer_pending(&_timer20))
+ printk("timer for 20s still pending.\n");
+ else
+ printk("timer for 20s has been disabled.\n");
+}
+
+
+static void timer_test(void)
+{
+ l4dde26_init_timers();
+
+ printk("BEGIN TIMER TEST\n");
+ printk("jiffies(%p): %ld, HZ(%p): %ld\n", &jiffies, jiffies, &HZ, HZ);
+
+ setup_timer(&_timer, tick_func, 0);
+ _timer.expires = jiffies + HZ;
+ add_timer(&_timer);
+
+ setup_timer(&_timer5, timer_func, 5);
+ _timer5.expires = jiffies + 5*HZ;
+ setup_timer(&_timer10, timer_func, 10);
+ _timer10.expires = jiffies + 10*HZ;
+ setup_timer(&_timer15, timer_func, 15);
+ _timer15.expires = jiffies + 15*HZ;
+ setup_timer(&_timer20, timer_func, 20);
+ _timer20.expires = jiffies + 20*HZ;
+ setup_timer(&_timer25, timer_func, 25);
+ _timer25.expires = jiffies + 25*HZ;
+
+ add_timer(&_timer5);
+ add_timer(&_timer10);
+ add_timer(&_timer15);
+ add_timer(&_timer20);
+ add_timer(&_timer25);
+
+ msleep(30000);
+
+ del_timer(&_timer);
+ printk("END TIMER TEST\n");
+}
+
+
+/******************************
+ ** Test 6: Memory subsystem **
+ ******************************/
+
+static void memory_kmem_cache_test(void)
+{
+ struct kmem_cache *cache0;
+ struct obj0
+ {
+ unsigned foo;
+ unsigned bar;
+ };
+ static struct obj0 *p0[1024];
+
+ struct kmem_cache *cache1;
+ struct obj1
+ {
+ char foo[50];
+ unsigned *bar;
+ };
+ static struct obj1 *p1[256];
+
+ cache0 = kmem_cache_create("obj0", sizeof(*p0[0]), 0, 0, 0);
+ cache1 = kmem_cache_create("obj1", sizeof(*p1[0]), 0, 0, 0);
+ printk("kmem caches: %p %p\n", cache0, cache1);
+
+ unsigned i;
+ for (i = 0; i < 1024; ++i)
+ p0[i] = kmem_cache_alloc(cache0, i);
+
+ for (i = 0; i < 256; ++i)
+ p1[i] = kmem_cache_alloc(cache1, i);
+
+ for (i = 256; i > 0; --i)
+ kmem_cache_free(cache1, p1[i-1]);
+
+ for (i = 1024; i > 0; --i)
+ kmem_cache_free(cache0, p0[i-1]);
+
+ kmem_cache_destroy(cache1);
+ kmem_cache_destroy(cache0);
+ printk("Done testing kmem_cache_alloc() & co.\n");
+}
+
+
+static void memory_page_alloc_test(void)
+{
+ unsigned long p[4];
+ p[0] = __get_free_page(GFP_KERNEL);
+ p[1] = __get_free_pages(GFP_KERNEL, 1);
+ p[2] = __get_free_pages(GFP_KERNEL, 2);
+ p[3] = __get_free_pages(GFP_KERNEL, 3);
+ printk("pages: %p %p %p %p\n", p[0], p[1], p[2], p[3]);
+
+ free_pages(p[0], 0);
+ free_pages(p[1], 1);
+ free_pages(p[2], 2);
+ free_pages(p[3], 3);
+ printk("Freed pages\n");
+}
+
+
+static void memory_kmalloc_test(void)
+{
+ // XXX initialized by dde26_init()!
+// l4dde26_kmalloc_init();
+
+ const unsigned count = 33;
+ char *p[count];
+
+ int i;
+ for (i = 0; i < count; ++i) {
+ p[i] = kmalloc(32 + i*15, GFP_KERNEL);
+ *p[i] = i;
+ printk("p[%d] = %p\n", i, p[i]);
+ }
+
+ for (i = count; i > 0; --i)
+ if (p[i-1]) kfree(p[i-1]);
+
+ for (i = 0; i < count; ++i) {
+ p[i] = kmalloc(3000 + i*20, GFP_KERNEL);
+ *p[i] = i;
+ printk("p[%d] = %p\n", i, p[i]);
+ }
+
+ for (i = count; i > 0; --i)
+ if (p[i-1]) kfree(p[i-1]);
+
+}
+
+
+static void memory_test(void)
+{
+ printk("memory test\n");
+ if (1) memory_kmem_cache_test();
+ if (1) memory_page_alloc_test();
+ if (1) memory_kmalloc_test();
+ printk("End of memory test\n");
+}
+
+
+/****************************************************************************
+ ** Test 7: KThreads **
+ ****************************************************************************/
+void kthread_test(void)
+{
+}
+
+
+/****************************************************************************
+ ** Test 8: Work queues **
+ ****************************************************************************/
+static void work_queue_func(struct work_struct *data);
+static void work_queue_func2(struct work_struct *data);
+static struct workqueue_struct *_wq;
+static DECLARE_WORK(_wobj, work_queue_func);
+static DECLARE_WORK(_wobj2, work_queue_func2);
+static int wq_cnt = 0;
+
+static void work_queue_func(struct work_struct *data)
+{
+ printk("(1) Work queue function... Do some work here...\n");
+ if (++wq_cnt < 5)
+ queue_work(_wq, &_wobj);
+}
+
+
+static void work_queue_func2(struct work_struct *data)
+{
+ printk("(2) Work queue function 2... Do some work here...\n");
+ if (++wq_cnt < 10)
+ schedule_work(&_wobj2);
+}
+
+
+static void work_queue_test(void)
+{
+ int i;
+ printk("BEGIN WQ TEST\n");
+ _wq = create_workqueue("HelloWQ");
+ BUG_ON(_wq == NULL);
+ queue_work(_wq, &_wobj);
+ schedule_work(&_wobj2);
+ printk("END WQ TEST\n");
+}
+
+
+/****************************************************************************
+ ** Test 9: PCI **
+ ****************************************************************************/
+
+void pci_test(void)
+{
+ l4dde26_init_pci();
+}
+
+
+/*************************************************
+ ** Main routine (switch on desired tests here) **
+ *************************************************/
+
+int main(int argc, const char **argv)
+{
+ int test_current = 1;
+ int test_kernel_thread = 1;
+ int test_wait = 1;
+ int test_tasklet = 1;
+ int test_timer = 1;
+ int test_memory = 1;
+ int test_kthread = 1;
+ int test_work = 1;
+ int test_pci = 1;
+
+ msleep(1000);
+
+ if (parse_cmdline(&argc, &argv,
+ 'c', "current", "test current() function",
+ PARSE_CMD_SWITCH, 1, &test_current,
+ 'k', "kernel-thread", "test startup of kernel threads",
+ PARSE_CMD_SWITCH, 1, &test_kernel_thread,
+ 'w', "waitqueue", "test wait queues",
+ PARSE_CMD_SWITCH, 1, &test_wait,
+ 't', "tasklet", "test tasklets",
+ PARSE_CMD_SWITCH, 1, &test_tasklet,
+ 'T', "timer", "test timers",
+ PARSE_CMD_SWITCH, 1, &test_timer,
+ 'm', "memory", "test memory management",
+ PARSE_CMD_SWITCH, 1, &test_memory,
+ 'K', "kthread", "test kthreads",
+ PARSE_CMD_SWITCH, 1, &test_kthread,
+ 'W', "workqueue", "test work queues",
+ PARSE_CMD_SWITCH, 1, &test_work,
+ 'p', "pci", "test PCI stuff",
+ PARSE_CMD_SWITCH, 1, &test_pci,
+ 0, 0))
+ return 1;
+
+ printk("DDEKit test. Carrying out tests:\n");
+ printk("\t* current()\n");
+ printk("\t* kernel_thread()\n");
+ printk("\t* wait queues\n");
+ printk("\t* tasklets\n");
+ printk("\t* timers\n");
+ printk("\t* memory management\n");
+ printk("\t* kthreads\n");
+ printk("\t* work queues\n");
+ printk("\t* PCI subsystem\n");
+
+#if 0
+ printk("l4dde26_init()\n");
+ l4dde26_init();
+ printk("l4dde26_process_init()\n");
+ l4dde26_process_init();
+ printk("l4dde26_do_initcalls()\n");
+ l4dde26_do_initcalls();
+#endif
+
+ printk("Init done. Running tests.\n");
+ if (test_current) current_test();
+ if (test_kernel_thread) kernel_thread_test();
+ if (test_wait) wq_test();
+ if (test_tasklet) tasklet_test();
+ if (test_timer) timer_test();
+ if (test_memory) memory_test();
+ if (1) kthread_test();
+ if (test_work) work_queue_test();
+// if (test_pci) pci_test();
+ printk("Test done.\n");
+
+ l4_sleep_forever();
+
+ return 0;
+}
diff --git a/libdde_linux26/examples/dde26_test/Makefile b/libdde_linux26/examples/dde26_test/Makefile
new file mode 100644
index 00000000..444a1f2d
--- /dev/null
+++ b/libdde_linux26/examples/dde26_test/Makefile
@@ -0,0 +1,21 @@
+PKGDIR ?= ../../..
+L4DIR ?= $(PKGDIR)/../..
+
+SYSTEMS = x86-l4v2
+
+DEFAULT_RELOC = 0x00a00000
+
+-include $(PKGDIR_OBJ)/Makeconf
+
+ifeq ($(CONFIG_DDE26_COMMON),y)
+TARGET = dde26_test
+endif
+
+SRC_C = main.c
+
+LIBS += -ldde_linux26.o -lddekit -lio -llist_alloc -lparsecmdline
+
+# DDE configuration
+include $(PKGDIR)/linux26/Makeconf
+
+include $(L4DIR)/mk/prog.mk
diff --git a/libdde_linux26/examples/dde26_test/main.c b/libdde_linux26/examples/dde26_test/main.c
new file mode 100644
index 00000000..88d33ba6
--- /dev/null
+++ b/libdde_linux26/examples/dde26_test/main.c
@@ -0,0 +1,502 @@
+/*
+ * \brief DDE for Linux 2.6 test program
+ * \author Bjoern Doebel <doebel@os.inf.tu-dresden.de>
+ * \author Christian Helmuth <ch12@os.inf.tu-dresden.de>
+ * \date 2007-01-22
+ */
+
+#include <asm/current.h>
+
+#include <linux/kernel.h>
+#include <linux/completion.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+//#include <linux/kthread.h>
+
+#include <l4/dde/dde.h>
+#include <l4/dde/ddekit/initcall.h>
+#include <l4/dde/linux26/dde26.h>
+
+#include <l4/util/parse_cmd.h>
+#include <l4/util/util.h>
+#include <l4/log/l4log.h>
+
+/* We define 4 initcalls and see if these are executed
+ * in the beginning.
+ */
+static __init void foo(void) { printk("foo module_init\n"); }
+static __init void bar(void) { printk("bar device_initcall\n"); }
+static __init void bla(void) { printk("bla arch_initcall\n"); }
+static __init void blub(void) { printk("blub subsys_initcall\n"); }
+module_init(foo);
+device_initcall(bar);
+arch_initcall(bla);
+subsys_initcall(blub);
+
+/***********************************************************************
+ ** Test 1: Check whether the current() macro works. **
+ ***********************************************************************/
+static void current_test(void)
+{
+ struct task_struct *t = NULL;
+
+ printk("Current() test.\n");
+
+ t = current;
+ printk("\tt = %p\n", t);
+}
+
+
+/***********************************************************************
+ ** Test 2: Getting complicated. Test startup of some kernel threads **
+ ** and wait for them to finish using completions. **
+ ***********************************************************************/
+#define NUM_KTHREADS 5
+static struct completion _kthread_completions_[NUM_KTHREADS];
+
+static int kernel_thread_func(void *arg)
+{
+ printk("\t\tKernel thread %d\n", (int)arg);
+ printk("\t\tcurrent = %p\n", current);
+
+ /* do some work */
+ msleep(200);
+
+ complete_and_exit( &_kthread_completions_[(int)arg], 0 );
+ return 0;
+}
+
+
+static void kernel_thread_test(void)
+{
+ int i;
+ printk("Testing kernel_thread()\n");
+ for (i=0; i < NUM_KTHREADS; i++) {
+ int j;
+ printk("\tInitializing completion for kernel thread.%x\n", i+1);
+ init_completion(&_kthread_completions_[i]);
+ printk("\tStarting kthread.%x\n", i+1);
+ j = kernel_thread(kernel_thread_func, (void *)i, 0);
+ printk("\treturn: %d\n", j);
+ }
+
+ for (i=0; i < NUM_KTHREADS; i++) {
+ printk("\tWaiting for kthread.%x to complete.\n", i+1);
+ wait_for_completion(&_kthread_completions_[i]);
+ printk("\tkthread.%x has exited.\n", i+1);
+ }
+}
+
+
+/******************************************************************************
+ ** Test 3: Test kernel wait queues: start a thread incrementing wait_value, **
+ ** and sleep until wait_value is larger than 6 for the first time. **
+ ******************************************************************************/
+static DECLARE_WAIT_QUEUE_HEAD(_wq_head);
+static int wait_value = 0;
+static struct completion wq_completion;
+
+static int inc_func(void *arg)
+{
+ int i = 0;
+
+ printk("\033[33mI am counting up wait_value.\033[0m\n");
+ for (i=0; i<10; i++)
+ {
+ printk("\033[33mwait_value: %d\033[0m\n", ++wait_value);
+ wake_up(&_wq_head);
+ msleep(500);
+ }
+ complete_and_exit(&wq_completion, 0);
+}
+
+
+static void wq_test(void)
+{
+ int pid;
+ printk("\033[32mWait_queue test. I'm waiting vor wait_value to become >6.\033[0m\n");
+
+ init_completion(&wq_completion);
+ pid = kernel_thread(inc_func, 0, 0);
+
+ wait_event(_wq_head, wait_value > 6);
+ printk("\033[32;1mwait_value > 6 occured!\033[0m\n");
+
+ wait_for_completion(&wq_completion);
+ printk("\033[32mtest done.\033[0m\n");
+}
+
+
+/****************************************************************************
+ ** Test 4: Tasklets **
+ ****************************************************************************/
+static void tasklet_func(unsigned long i)
+{
+ printk("TASKLET: %d\n", i);
+}
+
+
+static DECLARE_TASKLET(low0, tasklet_func, 0);
+static DECLARE_TASKLET(low1, tasklet_func, 1);
+static DECLARE_TASKLET(low2, tasklet_func, 2);
+static DECLARE_TASKLET_DISABLED(low3, tasklet_func, 3);
+
+static DECLARE_TASKLET(hi0, tasklet_func, 10);
+static DECLARE_TASKLET(hi1, tasklet_func, 11);
+static DECLARE_TASKLET_DISABLED(hi2, tasklet_func, 12);
+
+
+static void tasklet_test(void)
+{
+ printk("BEGIN TASKLET TEST\n");
+
+ l4dde26_softirq_init();
+
+ printk("sleep 1000 msec\n");
+ msleep(1000);
+
+ printk("Scheduling tasklets 0-2 immediately. 3 is disabled for 2 seconds.\n");
+ tasklet_schedule(&low0);
+
+ tasklet_schedule(&low1);
+ tasklet_schedule(&low2);
+ tasklet_schedule(&low3);
+ msleep(2000);
+ tasklet_enable(&low3);
+
+ msleep(1000);
+
+ printk("Scheduling hi_tasklets 10-12, and tasklets 0-2\n");
+ tasklet_hi_schedule(&hi0);
+ tasklet_hi_schedule(&hi1);
+ tasklet_hi_schedule(&hi2);
+ tasklet_schedule(&low0);
+ tasklet_schedule(&low1);
+ tasklet_schedule(&low2);
+ tasklet_enable(&hi2);
+
+ msleep(1000);
+ printk("Scheduling (disabled) tasklet 3 twice - should only run once after enabling.\n");
+ tasklet_disable(&low3);
+ tasklet_schedule(&low3);
+ tasklet_schedule(&low3);
+ tasklet_enable(&low3);
+
+ msleep(1000);
+
+ printk("END TASKLET TEST\n");
+}
+
+
+/******************************************************************************
+ ** Test 5: Timers **
+ ** **
+ ** Schedule a periodic timer printing "tick" every second. Additionally, **
+ ** schedule timers for 5, 10, 15, 20, and 25 seconds. Timer at 15s will **
+ ** deactivate the 20s timer. **
+ ******************************************************************************/
+
+static struct timer_list _timer;
+static struct timer_list _timer5;
+static struct timer_list _timer10;
+static struct timer_list _timer15;
+static struct timer_list _timer20;
+static struct timer_list _timer25;
+
+static void tick_func(unsigned long d)
+{
+ printk("tick (%ld)\n", jiffies);
+ _timer.expires = jiffies + HZ;
+ add_timer(&_timer);
+}
+
+
+static void timer_func(unsigned long d)
+{
+ printk("timer_func: %lu\n", d);
+
+ if (d == 15) {
+ printk("De-scheduling 20s timer.\n");
+ del_timer(&_timer20);
+ }
+
+ if (timer_pending(&_timer20))
+ printk("timer for 20s still pending.\n");
+ else
+ printk("timer for 20s has been disabled.\n");
+}
+
+
+static void timer_test(void)
+{
+ l4dde26_init_timers();
+
+ printk("BEGIN TIMER TEST\n");
+ printk("jiffies(%p): %ld, HZ(%p): %ld\n", &jiffies, jiffies, &HZ, HZ);
+
+ setup_timer(&_timer, tick_func, 0);
+ _timer.expires = jiffies + HZ;
+ add_timer(&_timer);
+
+ setup_timer(&_timer5, timer_func, 5);
+ _timer5.expires = jiffies + 5*HZ;
+ setup_timer(&_timer10, timer_func, 10);
+ _timer10.expires = jiffies + 10*HZ;
+ setup_timer(&_timer15, timer_func, 15);
+ _timer15.expires = jiffies + 15*HZ;
+ setup_timer(&_timer20, timer_func, 20);
+ _timer20.expires = jiffies + 20*HZ;
+ setup_timer(&_timer25, timer_func, 25);
+ _timer25.expires = jiffies + 25*HZ;
+
+ add_timer(&_timer5);
+ add_timer(&_timer10);
+ add_timer(&_timer15);
+ add_timer(&_timer20);
+ add_timer(&_timer25);
+
+ msleep(30000);
+
+ del_timer(&_timer);
+ printk("END TIMER TEST\n");
+}
+
+
+/******************************
+ ** Test 6: Memory subsystem **
+ ******************************/
+
+static void memory_kmem_cache_test(void)
+{
+ struct kmem_cache *cache0;
+ struct obj0
+ {
+ unsigned foo;
+ unsigned bar;
+ };
+ static struct obj0 *p0[1024];
+
+ struct kmem_cache *cache1;
+ struct obj1
+ {
+ char foo[50];
+ unsigned *bar;
+ };
+ static struct obj1 *p1[256];
+
+ cache0 = kmem_cache_create("obj0", sizeof(*p0[0]), 0, 0, 0);
+ cache1 = kmem_cache_create("obj1", sizeof(*p1[0]), 0, 0, 0);
+ printk("kmem caches: %p %p\n", cache0, cache1);
+
+ unsigned i;
+ for (i = 0; i < 1024; ++i)
+ p0[i] = kmem_cache_alloc(cache0, i);
+
+ for (i = 0; i < 256; ++i)
+ p1[i] = kmem_cache_alloc(cache1, i);
+
+ for (i = 256; i > 0; --i)
+ kmem_cache_free(cache1, p1[i-1]);
+
+ for (i = 1024; i > 0; --i)
+ kmem_cache_free(cache0, p0[i-1]);
+
+ kmem_cache_destroy(cache1);
+ kmem_cache_destroy(cache0);
+ printk("Done testing kmem_cache_alloc() & co.\n");
+}
+
+
+static void memory_page_alloc_test(void)
+{
+ unsigned long p[4];
+ p[0] = __get_free_page(GFP_KERNEL);
+ p[1] = __get_free_pages(GFP_KERNEL, 1);
+ p[2] = __get_free_pages(GFP_KERNEL, 2);
+ p[3] = __get_free_pages(GFP_KERNEL, 3);
+ printk("pages: %p %p %p %p\n", p[0], p[1], p[2], p[3]);
+
+ free_pages(p[0], 0);
+ free_pages(p[1], 1);
+ free_pages(p[2], 2);
+ free_pages(p[3], 3);
+ printk("Freed pages\n");
+}
+
+
+static void memory_kmalloc_test(void)
+{
+ // XXX initialized by dde26_init()!
+// l4dde26_kmalloc_init();
+
+ const unsigned count = 33;
+ char *p[count];
+
+ int i;
+ for (i = 0; i < count; ++i) {
+ p[i] = kmalloc(32 + i*15, GFP_KERNEL);
+ *p[i] = i;
+ printk("p[%d] = %p\n", i, p[i]);
+ }
+
+ for (i = count; i > 0; --i)
+ if (p[i-1]) kfree(p[i-1]);
+
+ for (i = 0; i < count; ++i) {
+ p[i] = kmalloc(3000 + i*20, GFP_KERNEL);
+ *p[i] = i;
+ printk("p[%d] = %p\n", i, p[i]);
+ }
+
+ for (i = count; i > 0; --i)
+ if (p[i-1]) kfree(p[i-1]);
+
+}
+
+
+static void memory_test(void)
+{
+ printk("memory test\n");
+ if (1) memory_kmem_cache_test();
+ if (1) memory_page_alloc_test();
+ if (1) memory_kmalloc_test();
+ printk("End of memory test\n");
+}
+
+
+/****************************************************************************
+ ** Test 7: KThreads **
+ ****************************************************************************/
+void kthread_test(void)
+{
+}
+
+
+/****************************************************************************
+ ** Test 8: Work queues **
+ ****************************************************************************/
+static void work_queue_func(struct work_struct *data);
+static void work_queue_func2(struct work_struct *data);
+static struct workqueue_struct *_wq;
+static DECLARE_WORK(_wobj, work_queue_func);
+static DECLARE_WORK(_wobj2, work_queue_func2);
+static int wq_cnt = 0;
+
+static void work_queue_func(struct work_struct *data)
+{
+ printk("(1) Work queue function... Do some work here...\n");
+ if (++wq_cnt < 5)
+ queue_work(_wq, &_wobj);
+}
+
+
+static void work_queue_func2(struct work_struct *data)
+{
+ printk("(2) Work queue function 2... Do some work here...\n");
+ if (++wq_cnt < 10)
+ schedule_work(&_wobj2);
+}
+
+
+static void work_queue_test(void)
+{
+ int i;
+ printk("BEGIN WQ TEST\n");
+ _wq = create_workqueue("HelloWQ");
+ BUG_ON(_wq == NULL);
+ queue_work(_wq, &_wobj);
+ schedule_work(&_wobj2);
+ printk("END WQ TEST\n");
+}
+
+
+/****************************************************************************
+ ** Test 9: PCI **
+ ****************************************************************************/
+
+void pci_test(void)
+{
+ l4dde26_init_pci();
+}
+
+
+/*************************************************
+ ** Main routine (switch on desired tests here) **
+ *************************************************/
+
+int main(int argc, const char **argv)
+{
+ int test_current = 1;
+ int test_kernel_thread = 1;
+ int test_wait = 1;
+ int test_tasklet = 1;
+ int test_timer = 1;
+ int test_memory = 1;
+ int test_kthread = 1;
+ int test_work = 1;
+ int test_pci = 1;
+
+ msleep(1000);
+
+ if (parse_cmdline(&argc, &argv,
+ 'c', "current", "test current() function",
+ PARSE_CMD_SWITCH, 1, &test_current,
+ 'k', "kernel-thread", "test startup of kernel threads",
+ PARSE_CMD_SWITCH, 1, &test_kernel_thread,
+ 'w', "waitqueue", "test wait queues",
+ PARSE_CMD_SWITCH, 1, &test_wait,
+ 't', "tasklet", "test tasklets",
+ PARSE_CMD_SWITCH, 1, &test_tasklet,
+ 'T', "timer", "test timers",
+ PARSE_CMD_SWITCH, 1, &test_timer,
+ 'm', "memory", "test memory management",
+ PARSE_CMD_SWITCH, 1, &test_memory,
+ 'K', "kthread", "test kthreads",
+ PARSE_CMD_SWITCH, 1, &test_kthread,
+ 'W', "workqueue", "test work queues",
+ PARSE_CMD_SWITCH, 1, &test_work,
+ 'p', "pci", "test PCI stuff",
+ PARSE_CMD_SWITCH, 1, &test_pci,
+ 0, 0))
+ return 1;
+
+ printk("DDEKit test. Carrying out tests:\n");
+ printk("\t* current()\n");
+ printk("\t* kernel_thread()\n");
+ printk("\t* wait queues\n");
+ printk("\t* tasklets\n");
+ printk("\t* timers\n");
+ printk("\t* memory management\n");
+ printk("\t* kthreads\n");
+ printk("\t* work queues\n");
+ printk("\t* PCI subsystem\n");
+
+#if 0
+ printk("l4dde26_init()\n");
+ l4dde26_init();
+ printk("l4dde26_process_init()\n");
+ l4dde26_process_init();
+ printk("l4dde26_do_initcalls()\n");
+ l4dde26_do_initcalls();
+#endif
+
+ printk("Init done. Running tests.\n");
+ if (test_current) current_test();
+ if (test_kernel_thread) kernel_thread_test();
+ if (test_wait) wq_test();
+ if (test_tasklet) tasklet_test();
+ if (test_timer) timer_test();
+ if (test_memory) memory_test();
+ if (1) kthread_test();
+ if (test_work) work_queue_test();
+// if (test_pci) pci_test();
+ printk("Test done.\n");
+
+ l4_sleep_forever();
+
+ return 0;
+}
diff --git a/libdde_linux26/examples/ne2k/.svn/all-wcprops b/libdde_linux26/examples/ne2k/.svn/all-wcprops
new file mode 100644
index 00000000..ba1cfa01
--- /dev/null
+++ b/libdde_linux26/examples/ne2k/.svn/all-wcprops
@@ -0,0 +1,53 @@
+K 25
+svn:wc:ra_dav:version-url
+V 64
+/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/examples/ne2k
+END
+arping.c
+K 25
+svn:wc:ra_dav:version-url
+V 73
+/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/examples/ne2k/arping.c
+END
+8390.c
+K 25
+svn:wc:ra_dav:version-url
+V 71
+/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/examples/ne2k/8390.c
+END
+main.c
+K 25
+svn:wc:ra_dav:version-url
+V 71
+/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/examples/ne2k/main.c
+END
+arping.h
+K 25
+svn:wc:ra_dav:version-url
+V 73
+/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/examples/ne2k/arping.h
+END
+8390.h
+K 25
+svn:wc:ra_dav:version-url
+V 71
+/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/examples/ne2k/8390.h
+END
+ne2k-pci.c
+K 25
+svn:wc:ra_dav:version-url
+V 75
+/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/examples/ne2k/ne2k-pci.c
+END
+lib8390.c
+K 25
+svn:wc:ra_dav:version-url
+V 74
+/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/examples/ne2k/lib8390.c
+END
+Makefile
+K 25
+svn:wc:ra_dav:version-url
+V 73
+/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/linux26/examples/ne2k/Makefile
+END
diff --git a/libdde_linux26/examples/ne2k/.svn/entries b/libdde_linux26/examples/ne2k/.svn/entries
new file mode 100644
index 00000000..b8581989
--- /dev/null
+++ b/libdde_linux26/examples/ne2k/.svn/entries
@@ -0,0 +1,300 @@
+9
+
+dir
+465
+http://svn.tudos.org/repos/tudos/trunk/l4/pkg/dde/linux26/examples/ne2k
+http://svn.tudos.org/repos/tudos
+
+
+
+2009-05-20T14:32:55.606606Z
+455
+l4check
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+a704ac0b-3a55-4d43-a2a9-7be6f07c34fb
+
+arping.c
+file
+
+
+
+
+2009-11-15T17:17:14.000000Z
+7ecf555fdf42cf807c50307a4d606c1f
+2009-05-20T14:32:55.606606Z
+455
+l4check
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5020
+
+8390.c
+file
+
+
+
+
+2009-11-15T17:17:14.000000Z
+3d38acf72b8158d4ad5177a249629995
+2009-05-20T14:32:55.606606Z
+455
+l4check
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2262
+
+main.c
+file
+
+
+
+
+2009-11-15T17:17:14.000000Z
+dea13f4d4bf665c902dd7374bd71ced5
+2009-05-20T14:32:55.606606Z
+455
+l4check
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2336
+
+arping.h
+file
+
+
+
+
+2009-11-15T17:17:14.000000Z
+0824ab97e55f86b3b57e79e8f2f3a8c2
+2009-05-20T14:32:55.606606Z
+455
+l4check
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+375
+
+8390.h
+file
+
+
+
+
+2009-11-15T17:17:14.000000Z
+7f695007d1e1230448538e76664346c8
+2009-05-20T14:32:55.606606Z
+455
+l4check
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+9629
+
+ne2k-pci.c
+file
+
+
+
+
+2009-11-15T17:17:14.000000Z
+87272d5c5070aef58772ef09202657de
+2009-05-20T14:32:55.606606Z
+455
+l4check
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+21164
+
+lib8390.c
+file
+
+
+
+
+2009-11-15T17:17:14.000000Z
+7de96b11d54826c5dac5c04aee240d79
+2009-05-20T14:32:55.606606Z
+455
+l4check
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+35915
+
+Makefile
+file
+
+
+
+
+2009-11-15T17:17:14.000000Z
+0028681d378a3d65e7efa5fdae1d84be
+2009-05-20T14:32:55.606606Z
+455
+l4check
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+706
+
diff --git a/libdde_linux26/examples/ne2k/.svn/format b/libdde_linux26/examples/ne2k/.svn/format
new file mode 100644
index 00000000..ec635144
--- /dev/null
+++ b/libdde_linux26/examples/ne2k/.svn/format
@@ -0,0 +1 @@
+9
diff --git a/libdde_linux26/examples/ne2k/.svn/text-base/8390.c.svn-base b/libdde_linux26/examples/ne2k/.svn/text-base/8390.c.svn-base
new file mode 100644
index 00000000..ec3e22e6
--- /dev/null
+++ b/libdde_linux26/examples/ne2k/.svn/text-base/8390.c.svn-base
@@ -0,0 +1,109 @@
+/* 8390 core for usual drivers */
+
+static const char version[] =
+ "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+
+#include "lib8390.c"
+
+int ei_open(struct net_device *dev)
+{
+ return __ei_open(dev);
+}
+EXPORT_SYMBOL(ei_open);
+
+int ei_close(struct net_device *dev)
+{
+ return __ei_close(dev);
+}
+EXPORT_SYMBOL(ei_close);
+
+int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ return __ei_start_xmit(skb, dev);
+}
+EXPORT_SYMBOL(ei_start_xmit);
+
+struct net_device_stats *ei_get_stats(struct net_device *dev)
+{
+ return __ei_get_stats(dev);
+}
+EXPORT_SYMBOL(ei_get_stats);
+
+void ei_set_multicast_list(struct net_device *dev)
+{
+ __ei_set_multicast_list(dev);
+}
+EXPORT_SYMBOL(ei_set_multicast_list);
+
+void ei_tx_timeout(struct net_device *dev)
+{
+ __ei_tx_timeout(dev);
+}
+EXPORT_SYMBOL(ei_tx_timeout);
+
+irqreturn_t ei_interrupt(int irq, void *dev_id)
+{
+ return __ei_interrupt(irq, dev_id);
+}
+EXPORT_SYMBOL(ei_interrupt);
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+void ei_poll(struct net_device *dev)
+{
+ __ei_poll(dev);
+}
+EXPORT_SYMBOL(ei_poll);
+#endif
+
+const struct net_device_ops ei_netdev_ops = {
+ .ndo_open = ei_open,
+ .ndo_stop = ei_close,
+ .ndo_start_xmit = ei_start_xmit,
+ .ndo_tx_timeout = ei_tx_timeout,
+ .ndo_get_stats = ei_get_stats,
+ .ndo_set_multicast_list = ei_set_multicast_list,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_change_mtu = eth_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = ei_poll,
+#endif
+};
+EXPORT_SYMBOL(ei_netdev_ops);
+
+struct net_device *__alloc_ei_netdev(int size)
+{
+ struct net_device *dev = ____alloc_ei_netdev(size);
+#ifdef CONFIG_COMPAT_NET_DEV_OPS
+ if (dev) {
+ dev->hard_start_xmit = ei_start_xmit;
+ dev->get_stats = ei_get_stats;
+ dev->set_multicast_list = ei_set_multicast_list;
+ dev->tx_timeout = ei_tx_timeout;
+ }
+#endif
+ return dev;
+}
+EXPORT_SYMBOL(__alloc_ei_netdev);
+
+void NS8390_init(struct net_device *dev, int startp)
+{
+ __NS8390_init(dev, startp);
+}
+EXPORT_SYMBOL(NS8390_init);
+
+#if defined(MODULE)
+
+static int __init ns8390_module_init(void)
+{
+ return 0;
+}
+
+static void __exit ns8390_module_exit(void)
+{
+}
+
+module_init(ns8390_module_init);
+module_exit(ns8390_module_exit);
+#endif /* MODULE */
+MODULE_LICENSE("GPL");
diff --git a/libdde_linux26/examples/ne2k/.svn/text-base/8390.h.svn-base b/libdde_linux26/examples/ne2k/.svn/text-base/8390.h.svn-base
new file mode 100644
index 00000000..3c61d6d2
--- /dev/null
+++ b/libdde_linux26/examples/ne2k/.svn/text-base/8390.h.svn-base
@@ -0,0 +1,231 @@
+/* Generic NS8390 register definitions. */
+/* This file is part of Donald Becker's 8390 drivers, and is distributed
+ under the same license. Auto-loading of 8390.o only in v2.2 - Paul G.
+ Some of these names and comments originated from the Crynwr
+ packet drivers, which are distributed under the GPL. */
+
+#ifndef _8390_h
+#define _8390_h
+
+#include <linux/if_ether.h>
+#include <linux/ioport.h>
+#include <linux/skbuff.h>
+
+#define TX_PAGES 12 /* Two Tx slots */
+
+#define ETHER_ADDR_LEN 6
+
+/* The 8390 specific per-packet-header format. */
+struct e8390_pkt_hdr {
+ unsigned char status; /* status */
+ unsigned char next; /* pointer to next packet. */
+ unsigned short count; /* header + packet length in bytes */
+};
+
+#ifdef notdef
+extern int ei_debug;
+#else
+#define ei_debug 1
+#endif
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+extern void ei_poll(struct net_device *dev);
+extern void eip_poll(struct net_device *dev);
+#endif
+
+
+/* Without I/O delay - non ISA or later chips */
+extern void NS8390_init(struct net_device *dev, int startp);
+extern int ei_open(struct net_device *dev);
+extern int ei_close(struct net_device *dev);
+extern irqreturn_t ei_interrupt(int irq, void *dev_id);
+extern void ei_tx_timeout(struct net_device *dev);
+extern int ei_start_xmit(struct sk_buff *skb, struct net_device *dev);
+extern void ei_set_multicast_list(struct net_device *dev);
+extern struct net_device_stats *ei_get_stats(struct net_device *dev);
+
+extern const struct net_device_ops ei_netdev_ops;
+
+extern struct net_device *__alloc_ei_netdev(int size);
+static inline struct net_device *alloc_ei_netdev(void)
+{
+ return __alloc_ei_netdev(0);
+}
+
+/* With I/O delay form */
+extern void NS8390p_init(struct net_device *dev, int startp);
+extern int eip_open(struct net_device *dev);
+extern int eip_close(struct net_device *dev);
+extern irqreturn_t eip_interrupt(int irq, void *dev_id);
+extern void eip_tx_timeout(struct net_device *dev);
+extern int eip_start_xmit(struct sk_buff *skb, struct net_device *dev);
+extern void eip_set_multicast_list(struct net_device *dev);
+extern struct net_device_stats *eip_get_stats(struct net_device *dev);
+
+extern const struct net_device_ops eip_netdev_ops;
+
+extern struct net_device *__alloc_eip_netdev(int size);
+static inline struct net_device *alloc_eip_netdev(void)
+{
+ return __alloc_eip_netdev(0);
+}
+
+/* You have one of these per-board */
+struct ei_device {
+ const char *name;
+ void (*reset_8390)(struct net_device *);
+ void (*get_8390_hdr)(struct net_device *, struct e8390_pkt_hdr *, int);
+ void (*block_output)(struct net_device *, int, const unsigned char *, int);
+ void (*block_input)(struct net_device *, int, struct sk_buff *, int);
+ unsigned long rmem_start;
+ unsigned long rmem_end;
+ void __iomem *mem;
+ unsigned char mcfilter[8];
+ unsigned open:1;
+ unsigned word16:1; /* We have the 16-bit (vs 8-bit) version of the card. */
+ unsigned bigendian:1; /* 16-bit big endian mode. Do NOT */
+ /* set this on random 8390 clones! */
+ unsigned txing:1; /* Transmit Active */
+ unsigned irqlock:1; /* 8390's intrs disabled when '1'. */
+ unsigned dmaing:1; /* Remote DMA Active */
+ unsigned char tx_start_page, rx_start_page, stop_page;
+ unsigned char current_page; /* Read pointer in buffer */
+ unsigned char interface_num; /* Net port (AUI, 10bT.) to use. */
+ unsigned char txqueue; /* Tx Packet buffer queue length. */
+ short tx1, tx2; /* Packet lengths for ping-pong tx. */
+ short lasttx; /* Alpha version consistency check. */
+ unsigned char reg0; /* Register '0' in a WD8013 */
+ unsigned char reg5; /* Register '5' in a WD8013 */
+ unsigned char saved_irq; /* Original dev->irq value. */
+ u32 *reg_offset; /* Register mapping table */
+ spinlock_t page_lock; /* Page register locks */
+ unsigned long priv; /* Private field to store bus IDs etc. */
+#ifdef AX88796_PLATFORM
+ unsigned char rxcr_base; /* default value for RXCR */
+#endif
+};
+
+/* The maximum number of 8390 interrupt service routines called per IRQ. */
+#define MAX_SERVICE 12
+
+/* The maximum time waited (in jiffies) before assuming a Tx failed. (20ms) */
+#define TX_TIMEOUT (20*HZ/100)
+
+#define ei_status (*(struct ei_device *)netdev_priv(dev))
+
+/* Some generic ethernet register configurations. */
+#define E8390_TX_IRQ_MASK 0xa /* For register EN0_ISR */
+#define E8390_RX_IRQ_MASK 0x5
+
+#ifdef AX88796_PLATFORM
+#define E8390_RXCONFIG (ei_status.rxcr_base | 0x04)
+#define E8390_RXOFF (ei_status.rxcr_base | 0x20)
+#else
+#define E8390_RXCONFIG 0x4 /* EN0_RXCR: broadcasts, no multicast,errors */
+#define E8390_RXOFF 0x20 /* EN0_RXCR: Accept no packets */
+#endif
+
+#define E8390_TXCONFIG 0x00 /* EN0_TXCR: Normal transmit mode */
+#define E8390_TXOFF 0x02 /* EN0_TXCR: Transmitter off */
+
+
+/* Register accessed at EN_CMD, the 8390 base addr. */
+#define E8390_STOP 0x01 /* Stop and reset the chip */
+#define E8390_START 0x02 /* Start the chip, clear reset */
+#define E8390_TRANS 0x04 /* Transmit a frame */
+#define E8390_RREAD 0x08 /* Remote read */
+#define E8390_RWRITE 0x10 /* Remote write */
+#define E8390_NODMA 0x20 /* Remote DMA */
+#define E8390_PAGE0 0x00 /* Select page chip registers */
+#define E8390_PAGE1 0x40 /* using the two high-order bits */
+#define E8390_PAGE2 0x80 /* Page 3 is invalid. */
+
+/*
+ * Only generate indirect loads given a machine that needs them.
+ * - removed AMIGA_PCMCIA from this list, handled as ISA io now
+ * - the _p for generates no delay by default 8390p.c overrides this.
+ */
+
+#ifndef ei_inb
+#define ei_inb(_p) inb(_p)
+#define ei_outb(_v,_p) outb(_v,_p)
+#define ei_inb_p(_p) inb(_p)
+#define ei_outb_p(_v,_p) outb(_v,_p)
+#endif
+
+#ifndef EI_SHIFT
+#define EI_SHIFT(x) (x)
+#endif
+
+#define E8390_CMD EI_SHIFT(0x00) /* The command register (for all pages) */
+/* Page 0 register offsets. */
+#define EN0_CLDALO EI_SHIFT(0x01) /* Low byte of current local dma addr RD */
+#define EN0_STARTPG EI_SHIFT(0x01) /* Starting page of ring bfr WR */
+#define EN0_CLDAHI EI_SHIFT(0x02) /* High byte of current local dma addr RD */
+#define EN0_STOPPG EI_SHIFT(0x02) /* Ending page +1 of ring bfr WR */
+#define EN0_BOUNDARY EI_SHIFT(0x03) /* Boundary page of ring bfr RD WR */
+#define EN0_TSR EI_SHIFT(0x04) /* Transmit status reg RD */
+#define EN0_TPSR EI_SHIFT(0x04) /* Transmit starting page WR */
+#define EN0_NCR EI_SHIFT(0x05) /* Number of collision reg RD */
+#define EN0_TCNTLO EI_SHIFT(0x05) /* Low byte of tx byte count WR */
+#define EN0_FIFO EI_SHIFT(0x06) /* FIFO RD */
+#define EN0_TCNTHI EI_SHIFT(0x06) /* High byte of tx byte count WR */
+#define EN0_ISR EI_SHIFT(0x07) /* Interrupt status reg RD WR */
+#define EN0_CRDALO EI_SHIFT(0x08) /* low byte of current remote dma address RD */
+#define EN0_RSARLO EI_SHIFT(0x08) /* Remote start address reg 0 */
+#define EN0_CRDAHI EI_SHIFT(0x09) /* high byte, current remote dma address RD */
+#define EN0_RSARHI EI_SHIFT(0x09) /* Remote start address reg 1 */
+#define EN0_RCNTLO EI_SHIFT(0x0a) /* Remote byte count reg WR */
+#define EN0_RCNTHI EI_SHIFT(0x0b) /* Remote byte count reg WR */
+#define EN0_RSR EI_SHIFT(0x0c) /* rx status reg RD */
+#define EN0_RXCR EI_SHIFT(0x0c) /* RX configuration reg WR */
+#define EN0_TXCR EI_SHIFT(0x0d) /* TX configuration reg WR */
+#define EN0_COUNTER0 EI_SHIFT(0x0d) /* Rcv alignment error counter RD */
+#define EN0_DCFG EI_SHIFT(0x0e) /* Data configuration reg WR */
+#define EN0_COUNTER1 EI_SHIFT(0x0e) /* Rcv CRC error counter RD */
+#define EN0_IMR EI_SHIFT(0x0f) /* Interrupt mask reg WR */
+#define EN0_COUNTER2 EI_SHIFT(0x0f) /* Rcv missed frame error counter RD */
+
+/* Bits in EN0_ISR - Interrupt status register */
+#define ENISR_RX 0x01 /* Receiver, no error */
+#define ENISR_TX 0x02 /* Transmitter, no error */
+#define ENISR_RX_ERR 0x04 /* Receiver, with error */
+#define ENISR_TX_ERR 0x08 /* Transmitter, with error */
+#define ENISR_OVER 0x10 /* Receiver overwrote the ring */
+#define ENISR_COUNTERS 0x20 /* Counters need emptying */
+#define ENISR_RDC 0x40 /* remote dma complete */
+#define ENISR_RESET 0x80 /* Reset completed */
+#define ENISR_ALL 0x3f /* Interrupts we will enable */
+
+/* Bits in EN0_DCFG - Data config register */
+#define ENDCFG_WTS 0x01 /* word transfer mode selection */
+#define ENDCFG_BOS 0x02 /* byte order selection */
+
+/* Page 1 register offsets. */
+#define EN1_PHYS EI_SHIFT(0x01) /* This board's physical enet addr RD WR */
+#define EN1_PHYS_SHIFT(i) EI_SHIFT(i+1) /* Get and set mac address */
+#define EN1_CURPAG EI_SHIFT(0x07) /* Current memory page RD WR */
+#define EN1_MULT EI_SHIFT(0x08) /* Multicast filter mask array (8 bytes) RD WR */
+#define EN1_MULT_SHIFT(i) EI_SHIFT(8+i) /* Get and set multicast filter */
+
+/* Bits in received packet status byte and EN0_RSR*/
+#define ENRSR_RXOK 0x01 /* Received a good packet */
+#define ENRSR_CRC 0x02 /* CRC error */
+#define ENRSR_FAE 0x04 /* frame alignment error */
+#define ENRSR_FO 0x08 /* FIFO overrun */
+#define ENRSR_MPA 0x10 /* missed pkt */
+#define ENRSR_PHY 0x20 /* physical/multicast address */
+#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */
+#define ENRSR_DEF 0x80 /* deferring */
+
+/* Transmitted packet status, EN0_TSR. */
+#define ENTSR_PTX 0x01 /* Packet transmitted without error */
+#define ENTSR_ND 0x02 /* The transmit wasn't deferred. */
+#define ENTSR_COL 0x04 /* The transmit collided at least once. */
+#define ENTSR_ABT 0x08 /* The transmit collided 16 times, and was deferred. */
+#define ENTSR_CRS 0x10 /* The carrier sense was lost. */
+#define ENTSR_FU 0x20 /* A "FIFO underrun" occurred during transmit. */
+#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */
+#define ENTSR_OWC 0x80 /* There was an out-of-window collision. */
+
+#endif /* _8390_h */
diff --git a/libdde_linux26/examples/ne2k/.svn/text-base/Makefile.svn-base b/libdde_linux26/examples/ne2k/.svn/text-base/Makefile.svn-base
new file mode 100644
index 00000000..2a7b1543
--- /dev/null
+++ b/libdde_linux26/examples/ne2k/.svn/text-base/Makefile.svn-base
@@ -0,0 +1,32 @@
+PKGDIR ?= ../../..
+L4DIR ?= $(PKGDIR)/../..
+
+SYSTEMS = x86-l4v2
+
+DEFAULT_RELOC = 0x00a00000
+
+-include $(PKGDIR_OBJ)/Makeconf
+
+ifeq ($(CONFIG_DDE26_NET),y)
+TARGET = ne2k_dde26
+endif
+
+SRC_C = ne2k-pci.c 8390.c main.c arping.c
+
+LIBS += -ldde_linux26_net -ldde_linux26.o -lddekit -lio -lomega0 -llist_alloc
+
+PRIVATE_INCDIR = $(PKGDIR_ABS)/linux26/include $(MY_DDE_INCDIR) $(MY_LINUX26_INCDIR) \
+ $(OBJ_BASE)/include/uclibc
+
+LIBCINCDIR = -nostdinc $(I_GCCINCDIR)
+DEFINES = -D__KERNEL__ -DDDE_LINUX\
+ $(KBUILD_DEFINES)
+CPPFLAGS += $(KBUILD_CPPFLAGS)
+
+include $(PKGDIR)/linux26/Makeconf
+
+include $(L4DIR)/mk/prog.mk
+
+foo :
+ @echo $(L4INCDIR)
+ @echo $(OBJ_BASE)
diff --git a/libdde_linux26/examples/ne2k/.svn/text-base/arping.c.svn-base b/libdde_linux26/examples/ne2k/.svn/text-base/arping.c.svn-base
new file mode 100644
index 00000000..18876806
--- /dev/null
+++ b/libdde_linux26/examples/ne2k/.svn/text-base/arping.c.svn-base
@@ -0,0 +1,185 @@
+/****************************************************************
+ * (c) 2007 Technische Universitaet Dresden *
+ * This file is part of DROPS, which is distributed under the *
+ * terms of the GNU General Public License 2. Please see the *
+ * COPYING file for details. *
+ ****************************************************************/
+
+#include <l4/log/l4log.h>
+#include <l4/util/util.h>
+#include <l4/util/l4_macros.h>
+#include <l4/sys/ipc.h>
+
+#include <linux/netdevice.h>
+#include <linux/if_ether.h>
+
+#include "arping.h"
+
+#define PROT_ICMP 1
+#define ICMP_REPLY 0
+#define ICMP_REQ 8
+#define ETH_ALEN 6
+
+/* configuration */
+int arping_verbose = 0; // verbose
+
+#define VERBOSE_LOG(fmt, ...) \
+ do { \
+ if (arping_verbose) printk(fmt, ##__VA_ARGS__); \
+ } while (0);
+
+char LOG_tag[9] = "arping";
+l4_ssize_t l4libc_heapsize = 32 * 1024;
+
+static unsigned char broadcast_mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+static int exit_somewhen = 0;
+
+
+struct ethernet_hdr
+{
+ unsigned char dest[6];
+ unsigned char src[6];
+ unsigned char type[2];
+};
+
+
+struct ip_hdr
+{
+ char version_length;
+ char type;
+ l4_int16_t length;
+ l4_int16_t id;
+ l4_int16_t flags_offset;
+ char ttl;
+ char protocol;
+ l4_int16_t checksum;
+ l4_int32_t src_ip;
+ l4_int32_t dest_ip;
+};
+
+
+struct icmp_hdr
+{
+ char type;
+ char code;
+ l4_uint16_t checksum;
+ l4_uint16_t id;
+ l4_uint16_t seq_num;
+};
+
+
+static int handle_icmp_packet(struct sk_buff *skb);
+static int handle_icmp_packet(struct sk_buff *skb)
+{
+ char *data = skb->data;
+ struct ethernet_hdr *eth = NULL;
+ struct ethernet_hdr *e = NULL;
+ struct ip_hdr *ip = NULL;
+ struct ip_hdr *iphdr = NULL;
+ struct icmp_hdr *icmp = NULL;
+ struct icmp_hdr *icmp2 = NULL;
+ int ver, len;
+ struct sk_buff *snd_skb = NULL;
+
+ eth = (struct ethernet_hdr *)data;
+ VERBOSE_LOG("dest mac = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ eth->dest[0], eth->dest[1], eth->dest[2],
+ eth->dest[3], eth->dest[4], eth->dest[5]);
+ VERBOSE_LOG("src mac = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ eth->src[0], eth->src[1], eth->src[2],
+ eth->src[3], eth->src[4], eth->src[5]);
+ VERBOSE_LOG("type field = %02x%02x\n", eth->type[0], eth->type[1]);
+ if (eth->type[0] != 0x08 || eth->type[1] != 0x00) {
+ printk("unknown ethernet packet type!\n");
+ return -1;
+ }
+
+ ip = (struct ip_hdr *)(data + sizeof(struct ethernet_hdr));
+ VERBOSE_LOG("protocol = %02x (2x?)\n", ip->protocol, PROT_ICMP);
+ if (ip->protocol != PROT_ICMP)
+ {
+ printk("Unknown packet type.\n");
+ return -1;
+ }
+
+ VERBOSE_LOG("ICMP packet!\n");
+ ver = ip->version_length >> 4;
+ len = ip->version_length & 0x0F;
+ VERBOSE_LOG("IP version = %d, length = %d\n", ver, len);
+
+ VERBOSE_LOG("src IP: "NIPQUAD_FMT"\n", NIPQUAD(ip->src_ip));
+ VERBOSE_LOG("dest IP: "NIPQUAD_FMT"\n", NIPQUAD(ip->dest_ip));
+
+ icmp = (struct icmp_hdr *)(data + sizeof(struct ethernet_hdr)
+ + sizeof(struct ip_hdr));
+
+ if (icmp->type != ICMP_REQ)
+ {
+ printk("This is no ICMP request.\n");
+ return -1;
+ }
+ VERBOSE_LOG("Hey this is an ICMP request just for me. :)\n");
+ VERBOSE_LOG("ICMP type : %d\n", icmp->type);
+ VERBOSE_LOG("ICMP code : %d\n", icmp->code);
+ VERBOSE_LOG("ICMP seq : %d\n", ntohs(icmp->seq_num));
+
+ snd_skb = alloc_skb(skb->len + skb->dev->hard_header_len, GFP_KERNEL);
+ memcpy(snd_skb->data, skb->data, skb->len);
+
+ e = (struct ethernet_hdr *)snd_skb->data;
+ memcpy(e->src, eth->dest, ETH_ALEN);
+ memcpy(e->dest, eth->src, ETH_ALEN);
+ VERBOSE_LOG("dest mac = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ e->dest[0], e->dest[1], e->dest[2],
+ e->dest[3], e->dest[4], e->dest[5]);
+ VERBOSE_LOG("src mac = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ e->src[0], e->src[1], e->src[2],
+ e->src[3], e->src[4], e->src[5]);
+ e->type[0] = 0x08;
+ e->type[1] = 0x00;
+
+ iphdr = (struct ip_hdr *)(snd_skb->data + sizeof(struct ethernet_hdr));
+ *iphdr = *ip;
+ // also switch src and dest
+ iphdr->src_ip = ip->dest_ip;
+ iphdr->dest_ip = ip->src_ip;
+ VERBOSE_LOG("src IP: "NIPQUAD_FMT"\n", NIPQUAD(iphdr->src_ip));
+ VERBOSE_LOG("dest IP: "NIPQUAD_FMT"\n", NIPQUAD(iphdr->dest_ip));
+
+ icmp2 = (struct icmp_hdr *)(snd_skb->data + sizeof(struct ethernet_hdr)
+ + sizeof(struct ip_hdr));
+ *icmp2 = *icmp;
+ icmp2->type = ICMP_REPLY;
+
+ snd_skb->dev = skb->dev;
+ snd_skb->len = skb->len;
+
+ VERBOSE_LOG("sending reply\n");
+ skb->dev->hard_start_xmit(snd_skb, skb->dev);
+ VERBOSE_LOG("done\n");
+
+ return 0;
+}
+
+ddekit_sem_t *arping_semaphore = NULL;
+struct arping_elem *arping_list = NULL;
+
+int arping(void)
+{
+ arping_semaphore = ddekit_sem_init(0);
+
+ while(1)
+ {
+ ddekit_sem_down(arping_semaphore);
+ struct arping_elem *elem = arping_list;
+ arping_list = arping_list->next;
+
+ /* parse packet */
+ int err = handle_icmp_packet(elem->skb);
+ VERBOSE_LOG("handle_icmp_packet: %d\n", err);
+
+ kfree_skb(elem->skb);
+ kfree(elem);
+ }
+}
+
diff --git a/libdde_linux26/examples/ne2k/.svn/text-base/arping.h.svn-base b/libdde_linux26/examples/ne2k/.svn/text-base/arping.h.svn-base
new file mode 100644
index 00000000..2df7f303
--- /dev/null
+++ b/libdde_linux26/examples/ne2k/.svn/text-base/arping.h.svn-base
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <l4/dde/ddekit/semaphore.h>
+
+struct arping_elem
+{
+ struct arping_elem *next;
+ struct sk_buff *skb;
+};
+
+extern ddekit_sem_t *arping_semaphore;
+extern struct arping_elem *arping_list;
+
+#define mac_fmt "%02X:%02X:%02X:%02X:%02X:%02X"
+#define mac_str(mac) (unsigned char)((mac)[0]), (unsigned char)((mac)[1]),(mac)[2],(mac)[3],(mac)[4],(mac)[5]
diff --git a/libdde_linux26/examples/ne2k/.svn/text-base/lib8390.c.svn-base b/libdde_linux26/examples/ne2k/.svn/text-base/lib8390.c.svn-base
new file mode 100644
index 00000000..789b6cb7
--- /dev/null
+++ b/libdde_linux26/examples/ne2k/.svn/text-base/lib8390.c.svn-base
@@ -0,0 +1,1125 @@
+/* 8390.c: A general NS8390 ethernet driver core for linux. */
+/*
+ Written 1992-94 by Donald Becker.
+
+ Copyright 1993 United States Government as represented by the
+ Director, National Security Agency.
+
+ This software may be used and distributed according to the terms
+ of the GNU General Public License, incorporated herein by reference.
+
+ The author may be reached as becker@scyld.com, or C/O
+ Scyld Computing Corporation
+ 410 Severn Ave., Suite 210
+ Annapolis MD 21403
+
+
+ This is the chip-specific code for many 8390-based ethernet adaptors.
+ This is not a complete driver, it must be combined with board-specific
+ code such as ne.c, wd.c, 3c503.c, etc.
+
+ Seeing how at least eight drivers use this code, (not counting the
+ PCMCIA ones either) it is easy to break some card by what seems like
+ a simple innocent change. Please contact me or Donald if you think
+ you have found something that needs changing. -- PG
+
+
+ Changelog:
+
+ Paul Gortmaker : remove set_bit lock, other cleanups.
+ Paul Gortmaker : add ei_get_8390_hdr() so we can pass skb's to
+ ei_block_input() for eth_io_copy_and_sum().
+ Paul Gortmaker : exchange static int ei_pingpong for a #define,
+ also add better Tx error handling.
+ Paul Gortmaker : rewrite Rx overrun handling as per NS specs.
+ Alexey Kuznetsov : use the 8390's six bit hash multicast filter.
+ Paul Gortmaker : tweak ANK's above multicast changes a bit.
+ Paul Gortmaker : update packet statistics for v2.1.x
+ Alan Cox : support arbitary stupid port mappings on the
+ 68K Macintosh. Support >16bit I/O spaces
+ Paul Gortmaker : add kmod support for auto-loading of the 8390
+ module by all drivers that require it.
+ Alan Cox : Spinlocking work, added 'BUG_83C690'
+ Paul Gortmaker : Separate out Tx timeout code from Tx path.
+ Paul Gortmaker : Remove old unused single Tx buffer code.
+ Hayato Fujiwara : Add m32r support.
+ Paul Gortmaker : use skb_padto() instead of stack scratch area
+
+ Sources:
+ The National Semiconductor LAN Databook, and the 3Com 3c503 databook.
+
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/jiffies.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/bitops.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/in.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/crc32.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+#define NS8390_CORE
+#include "8390.h"
+
+#define BUG_83C690
+
+/* These are the operational function interfaces to board-specific
+ routines.
+ void reset_8390(struct net_device *dev)
+ Resets the board associated with DEV, including a hardware reset of
+ the 8390. This is only called when there is a transmit timeout, and
+ it is always followed by 8390_init().
+ void block_output(struct net_device *dev, int count, const unsigned char *buf,
+ int start_page)
+ Write the COUNT bytes of BUF to the packet buffer at START_PAGE. The
+ "page" value uses the 8390's 256-byte pages.
+ void get_8390_hdr(struct net_device *dev, struct e8390_hdr *hdr, int ring_page)
+ Read the 4 byte, page aligned 8390 header. *If* there is a
+ subsequent read, it will be of the rest of the packet.
+ void block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
+ Read COUNT bytes from the packet buffer into the skb data area. Start
+ reading from RING_OFFSET, the address as the 8390 sees it. This will always
+ follow the read of the 8390 header.
+*/
+#define ei_reset_8390 (ei_local->reset_8390)
+#define ei_block_output (ei_local->block_output)
+#define ei_block_input (ei_local->block_input)
+#define ei_get_8390_hdr (ei_local->get_8390_hdr)
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef ei_debug
+int ei_debug = 1;
+#endif
+
+/* Index to functions. */
+static void ei_tx_intr(struct net_device *dev);
+static void ei_tx_err(struct net_device *dev);
+void ei_tx_timeout(struct net_device *dev);
+static void ei_receive(struct net_device *dev);
+static void ei_rx_overrun(struct net_device *dev);
+
+/* Routines generic to NS8390-based boards. */
+static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
+ int start_page);
+static void do_set_multicast_list(struct net_device *dev);
+static void __NS8390_init(struct net_device *dev, int startp);
+
+/*
+ * SMP and the 8390 setup.
+ *
+ * The 8390 isnt exactly designed to be multithreaded on RX/TX. There is
+ * a page register that controls bank and packet buffer access. We guard
+ * this with ei_local->page_lock. Nobody should assume or set the page other
+ * than zero when the lock is not held. Lock holders must restore page 0
+ * before unlocking. Even pure readers must take the lock to protect in
+ * page 0.
+ *
+ * To make life difficult the chip can also be very slow. We therefore can't
+ * just use spinlocks. For the longer lockups we disable the irq the device
+ * sits on and hold the lock. We must hold the lock because there is a dual
+ * processor case other than interrupts (get stats/set multicast list in
+ * parallel with each other and transmit).
+ *
+ * Note: in theory we can just disable the irq on the card _but_ there is
+ * a latency on SMP irq delivery. So we can easily go "disable irq" "sync irqs"
+ * enter lock, take the queued irq. So we waddle instead of flying.
+ *
+ * Finally by special arrangement for the purpose of being generally
+ * annoying the transmit function is called bh atomic. That places
+ * restrictions on the user context callers as disable_irq won't save
+ * them.
+ *
+ * Additional explanation of problems with locking by Alan Cox:
+ *
+ * "The author (me) didn't use spin_lock_irqsave because the slowness of the
+ * card means that approach caused horrible problems like losing serial data
+ * at 38400 baud on some chips. Remember many 8390 nics on PCI were ISA
+ * chips with FPGA front ends.
+ *
+ * Ok the logic behind the 8390 is very simple:
+ *
+ * Things to know
+ * - IRQ delivery is asynchronous to the PCI bus
+ * - Blocking the local CPU IRQ via spin locks was too slow
+ * - The chip has register windows needing locking work
+ *
+ * So the path was once (I say once as people appear to have changed it
+ * in the mean time and it now looks rather bogus if the changes to use
+ * disable_irq_nosync_irqsave are disabling the local IRQ)
+ *
+ *
+ * Take the page lock
+ * Mask the IRQ on chip
+ * Disable the IRQ (but not mask locally- someone seems to have
+ * broken this with the lock validator stuff)
+ * [This must be _nosync as the page lock may otherwise
+ * deadlock us]
+ * Drop the page lock and turn IRQs back on
+ *
+ * At this point an existing IRQ may still be running but we can't
+ * get a new one
+ *
+ * Take the lock (so we know the IRQ has terminated) but don't mask
+ * the IRQs on the processor
+ * Set irqlock [for debug]
+ *
+ * Transmit (slow as ****)
+ *
+ * re-enable the IRQ
+ *
+ *
+ * We have to use disable_irq because otherwise you will get delayed
+ * interrupts on the APIC bus deadlocking the transmit path.
+ *
+ * Quite hairy but the chip simply wasn't designed for SMP and you can't
+ * even ACK an interrupt without risking corrupting other parallel
+ * activities on the chip." [lkml, 25 Jul 2007]
+ */
+
+
+
+/**
+ * ei_open - Open/initialize the board.
+ * @dev: network device to initialize
+ *
+ * This routine goes all-out, setting everything
+ * up anew at each open, even though many of these registers should only
+ * need to be set once at boot.
+ */
+static int __ei_open(struct net_device *dev)
+{
+ unsigned long flags;
+ struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+
+ if (dev->watchdog_timeo <= 0)
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ /*
+ * Grab the page lock so we own the register set, then call
+ * the init function.
+ */
+
+ spin_lock_irqsave(&ei_local->page_lock, flags);
+ __NS8390_init(dev, 1);
+ /* Set the flag before we drop the lock, That way the IRQ arrives
+ after its set and we get no silly warnings */
+ netif_start_queue(dev);
+ spin_unlock_irqrestore(&ei_local->page_lock, flags);
+ ei_local->irqlock = 0;
+ return 0;
+}
+
+/**
+ * ei_close - shut down network device
+ * @dev: network device to close
+ *
+ * Opposite of ei_open(). Only used when "ifconfig <devname> down" is done.
+ */
+static int __ei_close(struct net_device *dev)
+{
+ struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ unsigned long flags;
+
+ /*
+ * Hold the page lock during close
+ */
+
+ spin_lock_irqsave(&ei_local->page_lock, flags);
+ __NS8390_init(dev, 0);
+ spin_unlock_irqrestore(&ei_local->page_lock, flags);
+ netif_stop_queue(dev);
+ return 0;
+}
+
+/**
+ * ei_tx_timeout - handle transmit time out condition
+ * @dev: network device which has apparently fallen asleep
+ *
+ * Called by kernel when device never acknowledges a transmit has
+ * completed (or failed) - i.e. never posted a Tx related interrupt.
+ */
+
+static void __ei_tx_timeout(struct net_device *dev)
+{
+ unsigned long e8390_base = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ int txsr, isr, tickssofar = jiffies - dev->trans_start;
+ unsigned long flags;
+
+ dev->stats.tx_errors++;
+
+ spin_lock_irqsave(&ei_local->page_lock, flags);
+ txsr = ei_inb(e8390_base+EN0_TSR);
+ isr = ei_inb(e8390_base+EN0_ISR);
+ spin_unlock_irqrestore(&ei_local->page_lock, flags);
+
+ printk(KERN_DEBUG "%s: Tx timed out, %s TSR=%#2x, ISR=%#2x, t=%d.\n",
+ dev->name, (txsr & ENTSR_ABT) ? "excess collisions." :
+ (isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar);
+
+ if (!isr && !dev->stats.tx_packets)
+ {
+ /* The 8390 probably hasn't gotten on the cable yet. */
+ ei_local->interface_num ^= 1; /* Try a different xcvr. */
+ }
+
+ /* Ugly but a reset can be slow, yet must be protected */
+
+ disable_irq_nosync_lockdep(dev->irq);
+ spin_lock(&ei_local->page_lock);
+
+ /* Try to restart the card. Perhaps the user has fixed something. */
+ ei_reset_8390(dev);
+ __NS8390_init(dev, 1);
+
+ spin_unlock(&ei_local->page_lock);
+ enable_irq_lockdep(dev->irq);
+ netif_wake_queue(dev);
+}
+
+/**
+ * ei_start_xmit - begin packet transmission
+ * @skb: packet to be sent
+ * @dev: network device to which packet is sent
+ *
+ * Sends a packet to an 8390 network device.
+ */
+
+static int __ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ unsigned long e8390_base = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ int send_length = skb->len, output_page;
+ unsigned long flags;
+ char buf[ETH_ZLEN];
+ char *data = skb->data;
+
+ if (skb->len < ETH_ZLEN) {
+ memset(buf, 0, ETH_ZLEN); /* more efficient than doing just the needed bits */
+ memcpy(buf, data, skb->len);
+ send_length = ETH_ZLEN;
+ data = buf;
+ }
+
+ /* Mask interrupts from the ethercard.
+ SMP: We have to grab the lock here otherwise the IRQ handler
+ on another CPU can flip window and race the IRQ mask set. We end
+ up trashing the mcast filter not disabling irqs if we don't lock */
+
+ spin_lock_irqsave(&ei_local->page_lock, flags);
+ ei_outb_p(0x00, e8390_base + EN0_IMR);
+ spin_unlock_irqrestore(&ei_local->page_lock, flags);
+
+
+ /*
+ * Slow phase with lock held.
+ */
+
+ disable_irq_nosync_lockdep_irqsave(dev->irq, &flags);
+
+ spin_lock(&ei_local->page_lock);
+
+ ei_local->irqlock = 1;
+
+ /*
+ * We have two Tx slots available for use. Find the first free
+ * slot, and then perform some sanity checks. With two Tx bufs,
+ * you get very close to transmitting back-to-back packets. With
+ * only one Tx buf, the transmitter sits idle while you reload the
+ * card, leaving a substantial gap between each transmitted packet.
+ */
+
+ if (ei_local->tx1 == 0)
+ {
+ output_page = ei_local->tx_start_page;
+ ei_local->tx1 = send_length;
+ if (ei_debug && ei_local->tx2 > 0)
+ printk(KERN_DEBUG "%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",
+ dev->name, ei_local->tx2, ei_local->lasttx, ei_local->txing);
+ }
+ else if (ei_local->tx2 == 0)
+ {
+ output_page = ei_local->tx_start_page + TX_PAGES/2;
+ ei_local->tx2 = send_length;
+ if (ei_debug && ei_local->tx1 > 0)
+ printk(KERN_DEBUG "%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",
+ dev->name, ei_local->tx1, ei_local->lasttx, ei_local->txing);
+ }
+ else
+ { /* We should never get here. */
+ if (ei_debug)
+ printk(KERN_DEBUG "%s: No Tx buffers free! tx1=%d tx2=%d last=%d\n",
+ dev->name, ei_local->tx1, ei_local->tx2, ei_local->lasttx);
+ ei_local->irqlock = 0;
+ netif_stop_queue(dev);
+ ei_outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+ spin_unlock(&ei_local->page_lock);
+ enable_irq_lockdep_irqrestore(dev->irq, &flags);
+ dev->stats.tx_errors++;
+ return 1;
+ }
+
+ /*
+ * Okay, now upload the packet and trigger a send if the transmitter
+ * isn't already sending. If it is busy, the interrupt handler will
+ * trigger the send later, upon receiving a Tx done interrupt.
+ */
+
+ ei_block_output(dev, send_length, data, output_page);
+
+ if (! ei_local->txing)
+ {
+ ei_local->txing = 1;
+ NS8390_trigger_send(dev, send_length, output_page);
+ dev->trans_start = jiffies;
+ if (output_page == ei_local->tx_start_page)
+ {
+ ei_local->tx1 = -1;
+ ei_local->lasttx = -1;
+ }
+ else
+ {
+ ei_local->tx2 = -1;
+ ei_local->lasttx = -2;
+ }
+ }
+ else ei_local->txqueue++;
+
+ if (ei_local->tx1 && ei_local->tx2)
+ netif_stop_queue(dev);
+ else
+ netif_start_queue(dev);
+
+ /* Turn 8390 interrupts back on. */
+ ei_local->irqlock = 0;
+ ei_outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+
+ spin_unlock(&ei_local->page_lock);
+ enable_irq_lockdep_irqrestore(dev->irq, &flags);
+
+ dev_kfree_skb (skb);
+ dev->stats.tx_bytes += send_length;
+
+ return 0;
+}
+
+/**
+ * ei_interrupt - handle the interrupts from an 8390
+ * @irq: interrupt number
+ * @dev_id: a pointer to the net_device
+ *
+ * Handle the ether interface interrupts. We pull packets from
+ * the 8390 via the card specific functions and fire them at the networking
+ * stack. We also handle transmit completions and wake the transmit path if
+ * necessary. We also update the counters and do other housekeeping as
+ * needed.
+ */
+
+static irqreturn_t __ei_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ unsigned long e8390_base = dev->base_addr;
+ int interrupts, nr_serviced = 0;
+ struct ei_device *ei_local = netdev_priv(dev);
+
+ /*
+ * Protect the irq test too.
+ */
+
+ spin_lock(&ei_local->page_lock);
+
+ if (ei_local->irqlock)
+ {
+#if 1 /* This might just be an interrupt for a PCI device sharing this line */
+ /* The "irqlock" check is only for testing. */
+ printk(ei_local->irqlock
+ ? "%s: Interrupted while interrupts are masked! isr=%#2x imr=%#2x.\n"
+ : "%s: Reentering the interrupt handler! isr=%#2x imr=%#2x.\n",
+ dev->name, ei_inb_p(e8390_base + EN0_ISR),
+ ei_inb_p(e8390_base + EN0_IMR));
+#endif
+ spin_unlock(&ei_local->page_lock);
+ return IRQ_NONE;
+ }
+
+ /* Change to page 0 and read the intr status reg. */
+ ei_outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
+ if (ei_debug > 3)
+ printk(KERN_DEBUG "%s: interrupt(isr=%#2.2x).\n", dev->name,
+ ei_inb_p(e8390_base + EN0_ISR));
+
+ /* !!Assumption!! -- we stay in page 0. Don't break this. */
+ while ((interrupts = ei_inb_p(e8390_base + EN0_ISR)) != 0
+ && ++nr_serviced < MAX_SERVICE)
+ {
+ if (!netif_running(dev)) {
+ printk(KERN_WARNING "%s: interrupt from stopped card\n", dev->name);
+ /* rmk - acknowledge the interrupts */
+ ei_outb_p(interrupts, e8390_base + EN0_ISR);
+ interrupts = 0;
+ break;
+ }
+ if (interrupts & ENISR_OVER)
+ ei_rx_overrun(dev);
+ else if (interrupts & (ENISR_RX+ENISR_RX_ERR))
+ {
+ /* Got a good (?) packet. */
+ ei_receive(dev);
+ }
+ /* Push the next to-transmit packet through. */
+ if (interrupts & ENISR_TX)
+ ei_tx_intr(dev);
+ else if (interrupts & ENISR_TX_ERR)
+ ei_tx_err(dev);
+
+ if (interrupts & ENISR_COUNTERS)
+ {
+ dev->stats.rx_frame_errors += ei_inb_p(e8390_base + EN0_COUNTER0);
+ dev->stats.rx_crc_errors += ei_inb_p(e8390_base + EN0_COUNTER1);
+ dev->stats.rx_missed_errors+= ei_inb_p(e8390_base + EN0_COUNTER2);
+ ei_outb_p(ENISR_COUNTERS, e8390_base + EN0_ISR); /* Ack intr. */
+ }
+
+ /* Ignore any RDC interrupts that make it back to here. */
+ if (interrupts & ENISR_RDC)
+ {
+ ei_outb_p(ENISR_RDC, e8390_base + EN0_ISR);
+ }
+
+ ei_outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
+ }
+
+ if (interrupts && ei_debug)
+ {
+ ei_outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
+ if (nr_serviced >= MAX_SERVICE)
+ {
+ /* 0xFF is valid for a card removal */
+ if(interrupts!=0xFF)
+ printk(KERN_WARNING "%s: Too much work at interrupt, status %#2.2x\n",
+ dev->name, interrupts);
+ ei_outb_p(ENISR_ALL, e8390_base + EN0_ISR); /* Ack. most intrs. */
+ } else {
+ printk(KERN_WARNING "%s: unknown interrupt %#2x\n", dev->name, interrupts);
+ ei_outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */
+ }
+ }
+ spin_unlock(&ei_local->page_lock);
+ return IRQ_RETVAL(nr_serviced > 0);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void __ei_poll(struct net_device *dev)
+{
+ disable_irq(dev->irq);
+ __ei_interrupt(dev->irq, dev);
+ enable_irq(dev->irq);
+}
+#endif
+
+/**
+ * ei_tx_err - handle transmitter error
+ * @dev: network device which threw the exception
+ *
+ * A transmitter error has happened. Most likely excess collisions (which
+ * is a fairly normal condition). If the error is one where the Tx will
+ * have been aborted, we try and send another one right away, instead of
+ * letting the failed packet sit and collect dust in the Tx buffer. This
+ * is a much better solution as it avoids kernel based Tx timeouts, and
+ * an unnecessary card reset.
+ *
+ * Called with lock held.
+ */
+
+static void ei_tx_err(struct net_device *dev)
+{
+ unsigned long e8390_base = dev->base_addr;
+ /* ei_local is used on some platforms via the EI_SHIFT macro */
+ struct ei_device *ei_local __maybe_unused = netdev_priv(dev);
+ unsigned char txsr = ei_inb_p(e8390_base+EN0_TSR);
+ unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU);
+
+#ifdef VERBOSE_ERROR_DUMP
+ printk(KERN_DEBUG "%s: transmitter error (%#2x): ", dev->name, txsr);
+ if (txsr & ENTSR_ABT)
+ printk("excess-collisions ");
+ if (txsr & ENTSR_ND)
+ printk("non-deferral ");
+ if (txsr & ENTSR_CRS)
+ printk("lost-carrier ");
+ if (txsr & ENTSR_FU)
+ printk("FIFO-underrun ");
+ if (txsr & ENTSR_CDH)
+ printk("lost-heartbeat ");
+ printk("\n");
+#endif
+
+ ei_outb_p(ENISR_TX_ERR, e8390_base + EN0_ISR); /* Ack intr. */
+
+ if (tx_was_aborted)
+ ei_tx_intr(dev);
+ else
+ {
+ dev->stats.tx_errors++;
+ if (txsr & ENTSR_CRS) dev->stats.tx_carrier_errors++;
+ if (txsr & ENTSR_CDH) dev->stats.tx_heartbeat_errors++;
+ if (txsr & ENTSR_OWC) dev->stats.tx_window_errors++;
+ }
+}
+
+/**
+ * ei_tx_intr - transmit interrupt handler
+ * @dev: network device for which tx intr is handled
+ *
+ * We have finished a transmit: check for errors and then trigger the next
+ * packet to be sent. Called with lock held.
+ */
+
+static void ei_tx_intr(struct net_device *dev)
+{
+ unsigned long e8390_base = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ int status = ei_inb(e8390_base + EN0_TSR);
+
+ ei_outb_p(ENISR_TX, e8390_base + EN0_ISR); /* Ack intr. */
+
+ /*
+ * There are two Tx buffers, see which one finished, and trigger
+ * the send of another one if it exists.
+ */
+ ei_local->txqueue--;
+
+ if (ei_local->tx1 < 0)
+ {
+ if (ei_local->lasttx != 1 && ei_local->lasttx != -1)
+ printk(KERN_ERR "%s: bogus last_tx_buffer %d, tx1=%d.\n",
+ ei_local->name, ei_local->lasttx, ei_local->tx1);
+ ei_local->tx1 = 0;
+ if (ei_local->tx2 > 0)
+ {
+ ei_local->txing = 1;
+ NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6);
+ dev->trans_start = jiffies;
+ ei_local->tx2 = -1,
+ ei_local->lasttx = 2;
+ }
+ else ei_local->lasttx = 20, ei_local->txing = 0;
+ }
+ else if (ei_local->tx2 < 0)
+ {
+ if (ei_local->lasttx != 2 && ei_local->lasttx != -2)
+ printk("%s: bogus last_tx_buffer %d, tx2=%d.\n",
+ ei_local->name, ei_local->lasttx, ei_local->tx2);
+ ei_local->tx2 = 0;
+ if (ei_local->tx1 > 0)
+ {
+ ei_local->txing = 1;
+ NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page);
+ dev->trans_start = jiffies;
+ ei_local->tx1 = -1;
+ ei_local->lasttx = 1;
+ }
+ else
+ ei_local->lasttx = 10, ei_local->txing = 0;
+ }
+// else printk(KERN_WARNING "%s: unexpected TX-done interrupt, lasttx=%d.\n",
+// dev->name, ei_local->lasttx);
+
+ /* Minimize Tx latency: update the statistics after we restart TXing. */
+ if (status & ENTSR_COL)
+ dev->stats.collisions++;
+ if (status & ENTSR_PTX)
+ dev->stats.tx_packets++;
+ else
+ {
+ dev->stats.tx_errors++;
+ if (status & ENTSR_ABT)
+ {
+ dev->stats.tx_aborted_errors++;
+ dev->stats.collisions += 16;
+ }
+ if (status & ENTSR_CRS)
+ dev->stats.tx_carrier_errors++;
+ if (status & ENTSR_FU)
+ dev->stats.tx_fifo_errors++;
+ if (status & ENTSR_CDH)
+ dev->stats.tx_heartbeat_errors++;
+ if (status & ENTSR_OWC)
+ dev->stats.tx_window_errors++;
+ }
+ netif_wake_queue(dev);
+}
+
+/**
+ * ei_receive - receive some packets
+ * @dev: network device with which receive will be run
+ *
+ * We have a good packet(s), get it/them out of the buffers.
+ * Called with lock held.
+ */
+
+static void ei_receive(struct net_device *dev)
+{
+ unsigned long e8390_base = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ unsigned char rxing_page, this_frame, next_frame;
+ unsigned short current_offset;
+ int rx_pkt_count = 0;
+ struct e8390_pkt_hdr rx_frame;
+ int num_rx_pages = ei_local->stop_page-ei_local->rx_start_page;
+
+ while (++rx_pkt_count < 10)
+ {
+ int pkt_len, pkt_stat;
+
+ /* Get the rx page (incoming packet pointer). */
+ ei_outb_p(E8390_NODMA+E8390_PAGE1, e8390_base + E8390_CMD);
+ rxing_page = ei_inb_p(e8390_base + EN1_CURPAG);
+ ei_outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
+
+ /* Remove one frame from the ring. Boundary is always a page behind. */
+ this_frame = ei_inb_p(e8390_base + EN0_BOUNDARY) + 1;
+ if (this_frame >= ei_local->stop_page)
+ this_frame = ei_local->rx_start_page;
+
+ /* Someday we'll omit the previous, iff we never get this message.
+ (There is at least one clone claimed to have a problem.)
+
+ Keep quiet if it looks like a card removal. One problem here
+ is that some clones crash in roughly the same way.
+ */
+ if (ei_debug > 0 && this_frame != ei_local->current_page && (this_frame!=0x0 || rxing_page!=0xFF))
+ printk(KERN_ERR "%s: mismatched read page pointers %2x vs %2x.\n",
+ dev->name, this_frame, ei_local->current_page);
+
+ if (this_frame == rxing_page) /* Read all the frames? */
+ break; /* Done for now */
+
+ current_offset = this_frame << 8;
+ ei_get_8390_hdr(dev, &rx_frame, this_frame);
+
+ pkt_len = rx_frame.count - sizeof(struct e8390_pkt_hdr);
+ pkt_stat = rx_frame.status;
+
+ next_frame = this_frame + 1 + ((pkt_len+4)>>8);
+
+ /* Check for bogosity warned by 3c503 book: the status byte is never
+ written. This happened a lot during testing! This code should be
+ cleaned up someday. */
+ if (rx_frame.next != next_frame
+ && rx_frame.next != next_frame + 1
+ && rx_frame.next != next_frame - num_rx_pages
+ && rx_frame.next != next_frame + 1 - num_rx_pages) {
+ ei_local->current_page = rxing_page;
+ ei_outb(ei_local->current_page-1, e8390_base+EN0_BOUNDARY);
+ dev->stats.rx_errors++;
+ continue;
+ }
+
+ if (pkt_len < 60 || pkt_len > 1518)
+ {
+ if (ei_debug)
+ printk(KERN_DEBUG "%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n",
+ dev->name, rx_frame.count, rx_frame.status,
+ rx_frame.next);
+ dev->stats.rx_errors++;
+ dev->stats.rx_length_errors++;
+ }
+ else if ((pkt_stat & 0x0F) == ENRSR_RXOK)
+ {
+ struct sk_buff *skb;
+
+ skb = dev_alloc_skb(pkt_len+2);
+ if (skb == NULL)
+ {
+ if (ei_debug > 1)
+ printk(KERN_DEBUG "%s: Couldn't allocate a sk_buff of size %d.\n",
+ dev->name, pkt_len);
+ dev->stats.rx_dropped++;
+ break;
+ }
+ else
+ {
+ skb_reserve(skb,2); /* IP headers on 16 byte boundaries */
+ skb_put(skb, pkt_len); /* Make room */
+ ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame));
+ skb->protocol=eth_type_trans(skb,dev);
+ netif_rx(skb);
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
+ if (pkt_stat & ENRSR_PHY)
+ dev->stats.multicast++;
+ }
+ }
+ else
+ {
+ if (ei_debug)
+ printk(KERN_DEBUG "%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n",
+ dev->name, rx_frame.status, rx_frame.next,
+ rx_frame.count);
+ dev->stats.rx_errors++;
+ /* NB: The NIC counts CRC, frame and missed errors. */
+ if (pkt_stat & ENRSR_FO)
+ dev->stats.rx_fifo_errors++;
+ }
+ next_frame = rx_frame.next;
+
+ /* This _should_ never happen: it's here for avoiding bad clones. */
+ if (next_frame >= ei_local->stop_page) {
+ printk("%s: next frame inconsistency, %#2x\n", dev->name,
+ next_frame);
+ next_frame = ei_local->rx_start_page;
+ }
+ ei_local->current_page = next_frame;
+ ei_outb_p(next_frame-1, e8390_base+EN0_BOUNDARY);
+ }
+
+ /* We used to also ack ENISR_OVER here, but that would sometimes mask
+ a real overrun, leaving the 8390 in a stopped state with rec'vr off. */
+ ei_outb_p(ENISR_RX+ENISR_RX_ERR, e8390_base+EN0_ISR);
+ return;
+}
+
+/**
+ * ei_rx_overrun - handle receiver overrun
+ * @dev: network device which threw exception
+ *
+ * We have a receiver overrun: we have to kick the 8390 to get it started
+ * again. Problem is that you have to kick it exactly as NS prescribes in
+ * the updated datasheets, or "the NIC may act in an unpredictable manner."
+ * This includes causing "the NIC to defer indefinitely when it is stopped
+ * on a busy network." Ugh.
+ * Called with lock held. Don't call this with the interrupts off or your
+ * computer will hate you - it takes 10ms or so.
+ */
+
+static void ei_rx_overrun(struct net_device *dev)
+{
+ unsigned long e8390_base = dev->base_addr;
+ unsigned char was_txing, must_resend = 0;
+ /* ei_local is used on some platforms via the EI_SHIFT macro */
+ struct ei_device *ei_local __maybe_unused = netdev_priv(dev);
+
+ /*
+ * Record whether a Tx was in progress and then issue the
+ * stop command.
+ */
+ was_txing = ei_inb_p(e8390_base+E8390_CMD) & E8390_TRANS;
+ ei_outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
+
+ if (ei_debug > 1)
+ printk(KERN_DEBUG "%s: Receiver overrun.\n", dev->name);
+ dev->stats.rx_over_errors++;
+
+ /*
+ * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total.
+ * Early datasheets said to poll the reset bit, but now they say that
+ * it "is not a reliable indicator and subsequently should be ignored."
+ * We wait at least 10ms.
+ */
+
+ mdelay(10);
+
+ /*
+ * Reset RBCR[01] back to zero as per magic incantation.
+ */
+ ei_outb_p(0x00, e8390_base+EN0_RCNTLO);
+ ei_outb_p(0x00, e8390_base+EN0_RCNTHI);
+
+ /*
+ * See if any Tx was interrupted or not. According to NS, this
+ * step is vital, and skipping it will cause no end of havoc.
+ */
+
+ if (was_txing)
+ {
+ unsigned char tx_completed = ei_inb_p(e8390_base+EN0_ISR) & (ENISR_TX+ENISR_TX_ERR);
+ if (!tx_completed)
+ must_resend = 1;
+ }
+
+ /*
+ * Have to enter loopback mode and then restart the NIC before
+ * you are allowed to slurp packets up off the ring.
+ */
+ ei_outb_p(E8390_TXOFF, e8390_base + EN0_TXCR);
+ ei_outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, e8390_base + E8390_CMD);
+
+ /*
+ * Clear the Rx ring of all the debris, and ack the interrupt.
+ */
+ ei_receive(dev);
+ ei_outb_p(ENISR_OVER, e8390_base+EN0_ISR);
+
+ /*
+ * Leave loopback mode, and resend any packet that got stopped.
+ */
+ ei_outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR);
+ if (must_resend)
+ ei_outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START + E8390_TRANS, e8390_base + E8390_CMD);
+}
+
+/*
+ * Collect the stats. This is called unlocked and from several contexts.
+ */
+
+static struct net_device_stats *__ei_get_stats(struct net_device *dev)
+{
+ unsigned long ioaddr = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ unsigned long flags;
+
+ /* If the card is stopped, just return the present stats. */
+ if (!netif_running(dev))
+ return &dev->stats;
+
+ spin_lock_irqsave(&ei_local->page_lock,flags);
+ /* Read the counter registers, assuming we are in page 0. */
+ dev->stats.rx_frame_errors += ei_inb_p(ioaddr + EN0_COUNTER0);
+ dev->stats.rx_crc_errors += ei_inb_p(ioaddr + EN0_COUNTER1);
+ dev->stats.rx_missed_errors+= ei_inb_p(ioaddr + EN0_COUNTER2);
+ spin_unlock_irqrestore(&ei_local->page_lock, flags);
+
+ return &dev->stats;
+}
+
+/*
+ * Form the 64 bit 8390 multicast table from the linked list of addresses
+ * associated with this dev structure.
+ */
+
+static inline void make_mc_bits(u8 *bits, struct net_device *dev)
+{
+ struct dev_mc_list *dmi;
+
+ for (dmi=dev->mc_list; dmi; dmi=dmi->next)
+ {
+ u32 crc;
+ if (dmi->dmi_addrlen != ETH_ALEN)
+ {
+ printk(KERN_INFO "%s: invalid multicast address length given.\n", dev->name);
+ continue;
+ }
+ crc = ether_crc(ETH_ALEN, dmi->dmi_addr);
+ /*
+ * The 8390 uses the 6 most significant bits of the
+ * CRC to index the multicast table.
+ */
+ bits[crc>>29] |= (1<<((crc>>26)&7));
+ }
+}
+
+/**
+ * do_set_multicast_list - set/clear multicast filter
+ * @dev: net device for which multicast filter is adjusted
+ *
+ * Set or clear the multicast filter for this adaptor. May be called
+ * from a BH in 2.1.x. Must be called with lock held.
+ */
+
+static void do_set_multicast_list(struct net_device *dev)
+{
+ unsigned long e8390_base = dev->base_addr;
+ int i;
+ struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev);
+
+ if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI)))
+ {
+ memset(ei_local->mcfilter, 0, 8);
+ if (dev->mc_list)
+ make_mc_bits(ei_local->mcfilter, dev);
+ }
+ else
+ memset(ei_local->mcfilter, 0xFF, 8); /* mcast set to accept-all */
+
+ /*
+ * DP8390 manuals don't specify any magic sequence for altering
+ * the multicast regs on an already running card. To be safe, we
+ * ensure multicast mode is off prior to loading up the new hash
+ * table. If this proves to be not enough, we can always resort
+ * to stopping the NIC, loading the table and then restarting.
+ *
+ * Bug Alert! The MC regs on the SMC 83C690 (SMC Elite and SMC
+ * Elite16) appear to be write-only. The NS 8390 data sheet lists
+ * them as r/w so this is a bug. The SMC 83C790 (SMC Ultra and
+ * Ultra32 EISA) appears to have this bug fixed.
+ */
+
+ if (netif_running(dev))
+ ei_outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
+ ei_outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD);
+ for(i = 0; i < 8; i++)
+ {
+ ei_outb_p(ei_local->mcfilter[i], e8390_base + EN1_MULT_SHIFT(i));
+#ifndef BUG_83C690
+ if(ei_inb_p(e8390_base + EN1_MULT_SHIFT(i))!=ei_local->mcfilter[i])
+ printk(KERN_ERR "Multicast filter read/write mismap %d\n",i);
+#endif
+ }
+ ei_outb_p(E8390_NODMA + E8390_PAGE0, e8390_base + E8390_CMD);
+
+ if(dev->flags&IFF_PROMISC)
+ ei_outb_p(E8390_RXCONFIG | 0x18, e8390_base + EN0_RXCR);
+ else if(dev->flags&IFF_ALLMULTI || dev->mc_list)
+ ei_outb_p(E8390_RXCONFIG | 0x08, e8390_base + EN0_RXCR);
+ else
+ ei_outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
+ }
+
+/*
+ * Called without lock held. This is invoked from user context and may
+ * be parallel to just about everything else. Its also fairly quick and
+ * not called too often. Must protect against both bh and irq users
+ */
+
+static void __ei_set_multicast_list(struct net_device *dev)
+{
+ unsigned long flags;
+ struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev);
+
+ spin_lock_irqsave(&ei_local->page_lock, flags);
+ do_set_multicast_list(dev);
+ spin_unlock_irqrestore(&ei_local->page_lock, flags);
+}
+
+/**
+ * ethdev_setup - init rest of 8390 device struct
+ * @dev: network device structure to init
+ *
+ * Initialize the rest of the 8390 device structure. Do NOT __init
+ * this, as it is used by 8390 based modular drivers too.
+ */
+
+static void ethdev_setup(struct net_device *dev)
+{
+ struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ if (ei_debug > 1)
+ printk(version);
+
+ ether_setup(dev);
+
+ spin_lock_init(&ei_local->page_lock);
+}
+
+/**
+ * alloc_ei_netdev - alloc_etherdev counterpart for 8390
+ * @size: extra bytes to allocate
+ *
+ * Allocate 8390-specific net_device.
+ */
+static struct net_device *____alloc_ei_netdev(int size)
+{
+ return alloc_netdev(sizeof(struct ei_device) + size, "eth%d",
+ ethdev_setup);
+}
+
+
+
+
+/* This page of functions should be 8390 generic */
+/* Follow National Semi's recommendations for initializing the "NIC". */
+
+/**
+ * NS8390_init - initialize 8390 hardware
+ * @dev: network device to initialize
+ * @startp: boolean. non-zero value to initiate chip processing
+ *
+ * Must be called with lock held.
+ */
+
+static void __NS8390_init(struct net_device *dev, int startp)
+{
+ unsigned long e8390_base = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ int i;
+ int endcfg = ei_local->word16
+ ? (0x48 | ENDCFG_WTS | (ei_local->bigendian ? ENDCFG_BOS : 0))
+ : 0x48;
+
+ if(sizeof(struct e8390_pkt_hdr)!=4)
+ panic("8390.c: header struct mispacked\n");
+ /* Follow National Semi's recommendations for initing the DP83902. */
+ ei_outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); /* 0x21 */
+ ei_outb_p(endcfg, e8390_base + EN0_DCFG); /* 0x48 or 0x49 */
+ /* Clear the remote byte count registers. */
+ ei_outb_p(0x00, e8390_base + EN0_RCNTLO);
+ ei_outb_p(0x00, e8390_base + EN0_RCNTHI);
+ /* Set to monitor and loopback mode -- this is vital!. */
+ ei_outb_p(E8390_RXOFF, e8390_base + EN0_RXCR); /* 0x20 */
+ ei_outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */
+ /* Set the transmit page and receive ring. */
+ ei_outb_p(ei_local->tx_start_page, e8390_base + EN0_TPSR);
+ ei_local->tx1 = ei_local->tx2 = 0;
+ ei_outb_p(ei_local->rx_start_page, e8390_base + EN0_STARTPG);
+ ei_outb_p(ei_local->stop_page-1, e8390_base + EN0_BOUNDARY); /* 3c503 says 0x3f,NS0x26*/
+ ei_local->current_page = ei_local->rx_start_page; /* assert boundary+1 */
+ ei_outb_p(ei_local->stop_page, e8390_base + EN0_STOPPG);
+ /* Clear the pending interrupts and mask. */
+ ei_outb_p(0xFF, e8390_base + EN0_ISR);
+ ei_outb_p(0x00, e8390_base + EN0_IMR);
+
+ /* Copy the station address into the DS8390 registers. */
+
+ ei_outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base+E8390_CMD); /* 0x61 */
+ for(i = 0; i < 6; i++)
+ {
+ ei_outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS_SHIFT(i));
+ if (ei_debug > 1 && ei_inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i])
+ printk(KERN_ERR "Hw. address read/write mismap %d\n",i);
+ }
+
+ ei_outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
+ ei_outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
+
+ netif_start_queue(dev);
+ ei_local->tx1 = ei_local->tx2 = 0;
+ ei_local->txing = 0;
+
+ if (startp)
+ {
+ ei_outb_p(0xff, e8390_base + EN0_ISR);
+ ei_outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+ ei_outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base+E8390_CMD);
+ ei_outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */
+ /* 3c503 TechMan says rxconfig only after the NIC is started. */
+ ei_outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on, */
+ do_set_multicast_list(dev); /* (re)load the mcast table */
+ }
+}
+
+/* Trigger a transmit start, assuming the length is valid.
+ Always called with the page lock held */
+
+static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
+ int start_page)
+{
+ unsigned long e8390_base = dev->base_addr;
+ struct ei_device *ei_local __attribute((unused)) = (struct ei_device *) netdev_priv(dev);
+
+ ei_outb_p(E8390_NODMA+E8390_PAGE0, e8390_base+E8390_CMD);
+
+ if (ei_inb_p(e8390_base + E8390_CMD) & E8390_TRANS)
+ {
+ printk(KERN_WARNING "%s: trigger_send() called with the transmitter busy.\n",
+ dev->name);
+ return;
+ }
+ ei_outb_p(length & 0xff, e8390_base + EN0_TCNTLO);
+ ei_outb_p(length >> 8, e8390_base + EN0_TCNTHI);
+ ei_outb_p(start_page, e8390_base + EN0_TPSR);
+ ei_outb_p(E8390_NODMA+E8390_TRANS+E8390_START, e8390_base+E8390_CMD);
+}
diff --git a/libdde_linux26/examples/ne2k/.svn/text-base/main.c.svn-base b/libdde_linux26/examples/ne2k/.svn/text-base/main.c.svn-base
new file mode 100644
index 00000000..8dba2f00
--- /dev/null
+++ b/libdde_linux26/examples/ne2k/.svn/text-base/main.c.svn-base
@@ -0,0 +1,115 @@
+#include <l4/dde/linux26/dde26.h> /* l4dde26_*() */
+#include <l4/dde/linux26/dde26_net.h> /* l4dde26 networking */
+#include <l4/sys/types.h> /* l4_threadid_t */
+#include <l4/sys/ipc.h> /* l4_ipc_*() */
+
+#include <linux/netdevice.h> /* struct sk_buff */
+#include <linux/pci.h> /* pci_unregister_driver() */
+#include <linux/init.h> // initcall()
+#include <linux/delay.h> // msleep()
+
+#include "arping.h"
+
+#include "8390.h" /* that's what we are */
+
+extern int arping_verbose;
+#define VERBOSE_LOG(fmt, ...) \
+ do { \
+ if (arping_verbose) printk(fmt, ##__VA_ARGS__); \
+ } while (0);
+
+extern struct pci_driver ne2k_driver;
+extern int arping(void);
+
+void open_nw_dev(void);
+void open_nw_dev()
+{
+ struct net_device *dev;
+ struct net *net;
+
+ read_lock(&dev_base_lock);
+ for_each_net(net) {
+ for_each_netdev(net, dev) {
+ int err = 0;
+ printk("dev: '%s'\n", dev->name);
+ printk("MAC: "mac_fmt"\n", mac_str(dev->dev_addr));
+
+ err = dev_open(dev);
+ }
+ }
+ read_unlock(&dev_base_lock);
+}
+
+void close_nw_dev(void);
+void close_nw_dev(void)
+{
+ struct net_device *dev;
+ struct net *net;
+
+ read_lock(&dev_base_lock);
+ for_each_net(net) {
+ for_each_netdev(net, dev) {
+ int err = 0;
+
+ err = dev_close(dev);
+ printk("closed %s\n", dev->name);
+ }
+ }
+ read_unlock(&dev_base_lock);
+}
+
+static int net_rx_handle(struct sk_buff *skb)
+{
+ skb_push(skb, skb->dev->hard_header_len);
+
+ struct arping_elem *e = kmalloc(sizeof(struct arping_elem), GFP_KERNEL);
+ e->skb = skb;
+ skb_get(skb);
+ e->next = NULL;
+
+ if (arping_list == NULL)
+ arping_list = e;
+ else {
+ struct arping_elem *f = arping_list;
+ while (f->next)
+ f = f->next;
+ f->next = e;
+ }
+
+ ddekit_sem_up(arping_semaphore);
+
+ kfree_skb(skb);
+
+ VERBOSE_LOG("freed skb, returning from netif_rx\n");
+ return NET_RX_SUCCESS;
+}
+
+//subsys_initcall(l4dde26_init_pci);
+
+int main(int argc, char **argv);
+int main(int argc, char **argv)
+{
+ l4dde26_init();
+ l4dde26_process_init();
+ l4dde26_softirq_init();
+
+ printk("Initializing skb subsystem\n");
+ skb_init();
+
+ l4dde26_do_initcalls();
+ printk("Setting rx callback @ %p\n", net_rx_handle);
+ l4dde26_register_rx_callback(net_rx_handle);
+
+ printk("Opening nw devs.\n");
+ open_nw_dev();
+ printk("dev is up and ready.\n");
+
+ arping();
+
+ close_nw_dev();
+
+ pci_unregister_driver(&ne2k_driver);
+ printk("shut down driver\n");
+
+ return 0;
+}
diff --git a/libdde_linux26/examples/ne2k/.svn/text-base/ne2k-pci.c.svn-base b/libdde_linux26/examples/ne2k/.svn/text-base/ne2k-pci.c.svn-base
new file mode 100644
index 00000000..c9995d36
--- /dev/null
+++ b/libdde_linux26/examples/ne2k/.svn/text-base/ne2k-pci.c.svn-base
@@ -0,0 +1,727 @@
+/* ne2k-pci.c: A NE2000 clone on PCI bus driver for Linux. */
+/*
+ A Linux device driver for PCI NE2000 clones.
+
+ Authors and other copyright holders:
+ 1992-2000 by Donald Becker, NE2000 core and various modifications.
+ 1995-1998 by Paul Gortmaker, core modifications and PCI support.
+ Copyright 1993 assigned to the United States Government as represented
+ by the Director, National Security Agency.
+
+ This software may be used and distributed according to the terms of
+ the GNU General Public License (GPL), incorporated herein by reference.
+ Drivers based on or derived from this code fall under the GPL and must
+ retain the authorship, copyright and license notice. This file is not
+ a complete program and may only be used when the entire operating
+ system is licensed under the GPL.
+
+ The author may be reached as becker@scyld.com, or C/O
+ Scyld Computing Corporation
+ 410 Severn Ave., Suite 210
+ Annapolis MD 21403
+
+ Issues remaining:
+ People are making PCI ne2000 clones! Oh the horror, the horror...
+ Limited full-duplex support.
+*/
+
+#define DRV_NAME "ne2k-pci"
+#define DRV_VERSION "1.03"
+#define DRV_RELDATE "9/22/2003"
+
+
+/* The user-configurable values.
+ These may be modified when a driver module is loaded.*/
+
+static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
+
+#define MAX_UNITS 8 /* More are supported, limit only on options */
+/* Used to pass the full-duplex flag, etc. */
+static int full_duplex[MAX_UNITS];
+static int options[MAX_UNITS];
+
+/* Force a non std. amount of memory. Units are 256 byte pages. */
+/* #define PACKETBUF_MEMSIZE 0x40 */
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include "8390.h"
+
+/* These identify the driver base version and may not be removed. */
+static char version[] __devinitdata =
+KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " D. Becker/P. Gortmaker\n";
+
+#if defined(__powerpc__)
+#define inl_le(addr) le32_to_cpu(inl(addr))
+#define inw_le(addr) le16_to_cpu(inw(addr))
+#endif
+
+#define PFX DRV_NAME ": "
+
+MODULE_AUTHOR("Donald Becker / Paul Gortmaker");
+MODULE_DESCRIPTION("PCI NE2000 clone driver");
+MODULE_LICENSE("GPL");
+
+module_param(debug, int, 0);
+module_param_array(options, int, NULL, 0);
+module_param_array(full_duplex, int, NULL, 0);
+MODULE_PARM_DESC(debug, "debug level (1-2)");
+MODULE_PARM_DESC(options, "Bit 5: full duplex");
+MODULE_PARM_DESC(full_duplex, "full duplex setting(s) (1)");
+
+/* Some defines that people can play with if so inclined. */
+
+/* Use 32 bit data-movement operations instead of 16 bit. */
+#define USE_LONGIO
+
+/* Do we implement the read before write bugfix ? */
+/* #define NE_RW_BUGFIX */
+
+/* Flags. We rename an existing ei_status field to store flags! */
+/* Thus only the low 8 bits are usable for non-init-time flags. */
+#define ne2k_flags reg0
+enum {
+ ONLY_16BIT_IO=8, ONLY_32BIT_IO=4, /* Chip can do only 16/32-bit xfers. */
+ FORCE_FDX=0x20, /* User override. */
+ REALTEK_FDX=0x40, HOLTEK_FDX=0x80,
+ STOP_PG_0x60=0x100,
+};
+
+enum ne2k_pci_chipsets {
+ CH_RealTek_RTL_8029 = 0,
+ CH_Winbond_89C940,
+ CH_Compex_RL2000,
+ CH_KTI_ET32P2,
+ CH_NetVin_NV5000SC,
+ CH_Via_86C926,
+ CH_SureCom_NE34,
+ CH_Winbond_W89C940F,
+ CH_Holtek_HT80232,
+ CH_Holtek_HT80229,
+ CH_Winbond_89C940_8c4a,
+};
+
+
+static struct {
+ char *name;
+ int flags;
+} pci_clone_list[] __devinitdata = {
+ {"RealTek RTL-8029", REALTEK_FDX},
+ {"Winbond 89C940", 0},
+ {"Compex RL2000", 0},
+ {"KTI ET32P2", 0},
+ {"NetVin NV5000SC", 0},
+ {"Via 86C926", ONLY_16BIT_IO},
+ {"SureCom NE34", 0},
+ {"Winbond W89C940F", 0},
+ {"Holtek HT80232", ONLY_16BIT_IO | HOLTEK_FDX},
+ {"Holtek HT80229", ONLY_32BIT_IO | HOLTEK_FDX | STOP_PG_0x60 },
+ {"Winbond W89C940(misprogrammed)", 0},
+ {NULL,}
+};
+
+
+static struct pci_device_id ne2k_pci_tbl[] = {
+ { 0x10ec, 0x8029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RealTek_RTL_8029 },
+ { 0x1050, 0x0940, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_89C940 },
+ { 0x11f6, 0x1401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Compex_RL2000 },
+ { 0x8e2e, 0x3000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_KTI_ET32P2 },
+ { 0x4a14, 0x5000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_NetVin_NV5000SC },
+ { 0x1106, 0x0926, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Via_86C926 },
+ { 0x10bd, 0x0e34, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_SureCom_NE34 },
+ { 0x1050, 0x5a5a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_W89C940F },
+ { 0x12c3, 0x0058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Holtek_HT80232 },
+ { 0x12c3, 0x5598, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Holtek_HT80229 },
+ { 0x8c4a, 0x1980, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_89C940_8c4a },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, ne2k_pci_tbl);
+
+
+/* ---- No user-serviceable parts below ---- */
+
+#define NE_BASE (dev->base_addr)
+#define NE_CMD 0x00
+#define NE_DATAPORT 0x10 /* NatSemi-defined port window offset. */
+#define NE_RESET 0x1f /* Issue a read to reset, a write to clear. */
+#define NE_IO_EXTENT 0x20
+
+#define NESM_START_PG 0x40 /* First page of TX buffer */
+#define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */
+
+
+static int ne2k_pci_open(struct net_device *dev);
+static int ne2k_pci_close(struct net_device *dev);
+
+static void ne2k_pci_reset_8390(struct net_device *dev);
+static void ne2k_pci_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
+ int ring_page);
+static void ne2k_pci_block_input(struct net_device *dev, int count,
+ struct sk_buff *skb, int ring_offset);
+static void ne2k_pci_block_output(struct net_device *dev, const int count,
+ const unsigned char *buf, const int start_page);
+static const struct ethtool_ops ne2k_pci_ethtool_ops;
+
+
+
+/* There is no room in the standard 8390 structure for extra info we need,
+ so we build a meta/outer-wrapper structure.. */
+struct ne2k_pci_card {
+ struct net_device *dev;
+ struct pci_dev *pci_dev;
+};
+
+
+
+/*
+ NEx000-clone boards have a Station Address (SA) PROM (SAPROM) in the packet
+ buffer memory space. By-the-spec NE2000 clones have 0x57,0x57 in bytes
+ 0x0e,0x0f of the SAPROM, while other supposed NE2000 clones must be
+ detected by their SA prefix.
+
+ Reading the SAPROM from a word-wide card with the 8390 set in byte-wide
+ mode results in doubled values, which can be detected and compensated for.
+
+ The probe is also responsible for initializing the card and filling
+ in the 'dev' and 'ei_status' structures.
+*/
+
+static const struct net_device_ops ne2k_netdev_ops = {
+ .ndo_open = ne2k_pci_open,
+ .ndo_stop = ne2k_pci_close,
+ .ndo_start_xmit = ei_start_xmit,
+ .ndo_tx_timeout = ei_tx_timeout,
+ .ndo_get_stats = ei_get_stats,
+ .ndo_set_multicast_list = ei_set_multicast_list,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_change_mtu = eth_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = ei_poll,
+#endif
+};
+
+static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct net_device *dev;
+ int i;
+ unsigned char SA_prom[32];
+ int start_page, stop_page;
+ int irq, reg0, chip_idx = ent->driver_data;
+ static unsigned int fnd_cnt;
+ long ioaddr;
+ int flags = pci_clone_list[chip_idx].flags;
+
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+ static int printed_version;
+ if (!printed_version++)
+ printk(version);
+#endif
+
+ fnd_cnt++;
+
+ i = pci_enable_device (pdev);
+ if (i)
+ return i;
+
+ ioaddr = pci_resource_start (pdev, 0);
+ irq = pdev->irq;
+
+ if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_IO) == 0)) {
+ dev_err(&pdev->dev, "no I/O resource at PCI BAR #0\n");
+ return -ENODEV;
+ }
+
+ if (request_region (ioaddr, NE_IO_EXTENT, DRV_NAME) == NULL) {
+ dev_err(&pdev->dev, "I/O resource 0x%x @ 0x%lx busy\n",
+ NE_IO_EXTENT, ioaddr);
+ return -EBUSY;
+ }
+
+ reg0 = inb(ioaddr);
+ if (reg0 == 0xFF)
+ goto err_out_free_res;
+
+ /* Do a preliminary verification that we have a 8390. */
+ {
+ int regd;
+ outb(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD);
+ regd = inb(ioaddr + 0x0d);
+ outb(0xff, ioaddr + 0x0d);
+ outb(E8390_NODMA+E8390_PAGE0, ioaddr + E8390_CMD);
+ inb(ioaddr + EN0_COUNTER0); /* Clear the counter by reading. */
+ if (inb(ioaddr + EN0_COUNTER0) != 0) {
+ outb(reg0, ioaddr);
+ outb(regd, ioaddr + 0x0d); /* Restore the old values. */
+ goto err_out_free_res;
+ }
+ }
+
+ /* Allocate net_device, dev->priv; fill in 8390 specific dev fields. */
+ dev = alloc_ei_netdev();
+ if (!dev) {
+ dev_err(&pdev->dev, "cannot allocate ethernet device\n");
+ goto err_out_free_res;
+ }
+ dev->netdev_ops = &ne2k_netdev_ops;
+
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ /* Reset card. Who knows what dain-bramaged state it was left in. */
+ {
+ unsigned long reset_start_time = jiffies;
+
+ outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET);
+
+ /* This looks like a horrible timing loop, but it should never take
+ more than a few cycles.
+ */
+ while ((inb(ioaddr + EN0_ISR) & ENISR_RESET) == 0)
+ /* Limit wait: '2' avoids jiffy roll-over. */
+ if (jiffies - reset_start_time > 2) {
+ dev_err(&pdev->dev,
+ "Card failure (no reset ack).\n");
+ goto err_out_free_netdev;
+ }
+
+ outb(0xff, ioaddr + EN0_ISR); /* Ack all intr. */
+ }
+
+ /* Read the 16 bytes of station address PROM.
+ We must first initialize registers, similar to NS8390_init(eifdev, 0).
+ We can't reliably read the SAPROM address without this.
+ (I learned the hard way!). */
+ {
+ struct {unsigned char value, offset; } program_seq[] = {
+ {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
+ {0x49, EN0_DCFG}, /* Set word-wide access. */
+ {0x00, EN0_RCNTLO}, /* Clear the count regs. */
+ {0x00, EN0_RCNTHI},
+ {0x00, EN0_IMR}, /* Mask completion irq. */
+ {0xFF, EN0_ISR},
+ {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */
+ {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */
+ {32, EN0_RCNTLO},
+ {0x00, EN0_RCNTHI},
+ {0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */
+ {0x00, EN0_RSARHI},
+ {E8390_RREAD+E8390_START, E8390_CMD},
+ };
+ for (i = 0; i < ARRAY_SIZE(program_seq); i++)
+ outb(program_seq[i].value, ioaddr + program_seq[i].offset);
+
+ }
+
+ /* Note: all PCI cards have at least 16 bit access, so we don't have
+ to check for 8 bit cards. Most cards permit 32 bit access. */
+ if (flags & ONLY_32BIT_IO) {
+ for (i = 0; i < 4 ; i++)
+ ((u32 *)SA_prom)[i] = le32_to_cpu(inl(ioaddr + NE_DATAPORT));
+ } else
+ for(i = 0; i < 32 /*sizeof(SA_prom)*/; i++)
+ SA_prom[i] = inb(ioaddr + NE_DATAPORT);
+
+ /* We always set the 8390 registers for word mode. */
+ outb(0x49, ioaddr + EN0_DCFG);
+ start_page = NESM_START_PG;
+
+ stop_page = flags & STOP_PG_0x60 ? 0x60 : NESM_STOP_PG;
+
+ /* Set up the rest of the parameters. */
+ dev->irq = irq;
+ dev->base_addr = ioaddr;
+ pci_set_drvdata(pdev, dev);
+
+ ei_status.name = pci_clone_list[chip_idx].name;
+ ei_status.tx_start_page = start_page;
+ ei_status.stop_page = stop_page;
+ ei_status.word16 = 1;
+ ei_status.ne2k_flags = flags;
+ if (fnd_cnt < MAX_UNITS) {
+ if (full_duplex[fnd_cnt] > 0 || (options[fnd_cnt] & FORCE_FDX))
+ ei_status.ne2k_flags |= FORCE_FDX;
+ }
+
+ ei_status.rx_start_page = start_page + TX_PAGES;
+#ifdef PACKETBUF_MEMSIZE
+ /* Allow the packet buffer size to be overridden by know-it-alls. */
+ ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE;
+#endif
+
+ ei_status.reset_8390 = &ne2k_pci_reset_8390;
+ ei_status.block_input = &ne2k_pci_block_input;
+ ei_status.block_output = &ne2k_pci_block_output;
+ ei_status.get_8390_hdr = &ne2k_pci_get_8390_hdr;
+ ei_status.priv = (unsigned long) pdev;
+
+ dev->ethtool_ops = &ne2k_pci_ethtool_ops;
+ NS8390_init(dev, 0);
+
+ i = register_netdev(dev);
+ if (i)
+ goto err_out_free_netdev;
+
+ for(i = 0; i < 6; i++)
+ dev->dev_addr[i] = SA_prom[i];
+ printk("%s: %s found at %#lx, IRQ %d, %pM.\n",
+ dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq,
+ dev->dev_addr);
+
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
+ return 0;
+
+err_out_free_netdev:
+ free_netdev (dev);
+err_out_free_res:
+ release_region (ioaddr, NE_IO_EXTENT);
+ pci_set_drvdata (pdev, NULL);
+ return -ENODEV;
+
+}
+
+/*
+ * Magic incantation sequence for full duplex on the supported cards.
+ */
+static inline int set_realtek_fdx(struct net_device *dev)
+{
+ long ioaddr = dev->base_addr;
+
+ outb(0xC0 + E8390_NODMA, ioaddr + NE_CMD); /* Page 3 */
+ outb(0xC0, ioaddr + 0x01); /* Enable writes to CONFIG3 */
+ outb(0x40, ioaddr + 0x06); /* Enable full duplex */
+ outb(0x00, ioaddr + 0x01); /* Disable writes to CONFIG3 */
+ outb(E8390_PAGE0 + E8390_NODMA, ioaddr + NE_CMD); /* Page 0 */
+ return 0;
+}
+
+static inline int set_holtek_fdx(struct net_device *dev)
+{
+ long ioaddr = dev->base_addr;
+
+ outb(inb(ioaddr + 0x20) | 0x80, ioaddr + 0x20);
+ return 0;
+}
+
+static int ne2k_pci_set_fdx(struct net_device *dev)
+{
+ if (ei_status.ne2k_flags & REALTEK_FDX)
+ return set_realtek_fdx(dev);
+ else if (ei_status.ne2k_flags & HOLTEK_FDX)
+ return set_holtek_fdx(dev);
+
+ return -EOPNOTSUPP;
+}
+
+static int ne2k_pci_open(struct net_device *dev)
+{
+ int ret = request_irq(dev->irq, ei_interrupt, IRQF_SHARED, dev->name, dev);
+ if (ret)
+ return ret;
+
+ if (ei_status.ne2k_flags & FORCE_FDX)
+ ne2k_pci_set_fdx(dev);
+
+ ei_open(dev);
+ return 0;
+}
+
+static int ne2k_pci_close(struct net_device *dev)
+{
+ ei_close(dev);
+ free_irq(dev->irq, dev);
+ return 0;
+}
+
+/* Hard reset the card. This used to pause for the same period that a
+ 8390 reset command required, but that shouldn't be necessary. */
+static void ne2k_pci_reset_8390(struct net_device *dev)
+{
+ unsigned long reset_start_time = jiffies;
+
+ if (debug > 1) printk("%s: Resetting the 8390 t=%ld...",
+ dev->name, jiffies);
+
+ outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);
+
+ ei_status.txing = 0;
+ ei_status.dmaing = 0;
+
+ /* This check _should_not_ be necessary, omit eventually. */
+ while ((inb(NE_BASE+EN0_ISR) & ENISR_RESET) == 0)
+ if (jiffies - reset_start_time > 2) {
+ printk("%s: ne2k_pci_reset_8390() did not complete.\n", dev->name);
+ break;
+ }
+ outb(ENISR_RESET, NE_BASE + EN0_ISR); /* Ack intr. */
+}
+
+/* Grab the 8390 specific header. Similar to the block_input routine, but
+ we don't need to be concerned with ring wrap as the header will be at
+ the start of a page, so we optimize accordingly. */
+
+static void ne2k_pci_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+
+ long nic_base = dev->base_addr;
+
+ /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+ if (ei_status.dmaing) {
+ printk("%s: DMAing conflict in ne2k_pci_get_8390_hdr "
+ "[DMAstat:%d][irqlock:%d].\n",
+ dev->name, ei_status.dmaing, ei_status.irqlock);
+ return;
+ }
+
+ ei_status.dmaing |= 0x01;
+ outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+ outb(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
+ outb(0, nic_base + EN0_RCNTHI);
+ outb(0, nic_base + EN0_RSARLO); /* On page boundary */
+ outb(ring_page, nic_base + EN0_RSARHI);
+ outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+
+ if (ei_status.ne2k_flags & ONLY_16BIT_IO) {
+ insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
+ } else {
+ *(u32*)hdr = le32_to_cpu(inl(NE_BASE + NE_DATAPORT));
+ le16_to_cpus(&hdr->count);
+ }
+
+ outb(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */
+ ei_status.dmaing &= ~0x01;
+}
+
+/* Block input and output, similar to the Crynwr packet driver. If you
+ are porting to a new ethercard, look at the packet driver source for hints.
+ The NEx000 doesn't share the on-board packet memory -- you have to put
+ the packet out through the "remote DMA" dataport using outb. */
+
+static void ne2k_pci_block_input(struct net_device *dev, int count,
+ struct sk_buff *skb, int ring_offset)
+{
+ long nic_base = dev->base_addr;
+ char *buf = skb->data;
+
+ /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+ if (ei_status.dmaing) {
+ printk("%s: DMAing conflict in ne2k_pci_block_input "
+ "[DMAstat:%d][irqlock:%d].\n",
+ dev->name, ei_status.dmaing, ei_status.irqlock);
+ return;
+ }
+ ei_status.dmaing |= 0x01;
+ if (ei_status.ne2k_flags & ONLY_32BIT_IO)
+ count = (count + 3) & 0xFFFC;
+ outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+ outb(count & 0xff, nic_base + EN0_RCNTLO);
+ outb(count >> 8, nic_base + EN0_RCNTHI);
+ outb(ring_offset & 0xff, nic_base + EN0_RSARLO);
+ outb(ring_offset >> 8, nic_base + EN0_RSARHI);
+ outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+
+ if (ei_status.ne2k_flags & ONLY_16BIT_IO) {
+ insw(NE_BASE + NE_DATAPORT,buf,count>>1);
+ if (count & 0x01) {
+ buf[count-1] = inb(NE_BASE + NE_DATAPORT);
+ }
+ } else {
+ insl(NE_BASE + NE_DATAPORT, buf, count>>2);
+ if (count & 3) {
+ buf += count & ~3;
+ if (count & 2) {
+ __le16 *b = (__le16 *)buf;
+
+ *b++ = cpu_to_le16(inw(NE_BASE + NE_DATAPORT));
+ buf = (char *)b;
+ }
+ if (count & 1)
+ *buf = inb(NE_BASE + NE_DATAPORT);
+ }
+ }
+
+ outb(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */
+ ei_status.dmaing &= ~0x01;
+}
+
+static void ne2k_pci_block_output(struct net_device *dev, int count,
+ const unsigned char *buf, const int start_page)
+{
+ long nic_base = NE_BASE;
+ unsigned long dma_start;
+
+ /* On little-endian it's always safe to round the count up for
+ word writes. */
+ if (ei_status.ne2k_flags & ONLY_32BIT_IO)
+ count = (count + 3) & 0xFFFC;
+ else
+ if (count & 0x01)
+ count++;
+
+ /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+ if (ei_status.dmaing) {
+ printk("%s: DMAing conflict in ne2k_pci_block_output."
+ "[DMAstat:%d][irqlock:%d]\n",
+ dev->name, ei_status.dmaing, ei_status.irqlock);
+ return;
+ }
+ ei_status.dmaing |= 0x01;
+ /* We should already be in page 0, but to be safe... */
+ outb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
+
+#ifdef NE8390_RW_BUGFIX
+ /* Handle the read-before-write bug the same way as the
+ Crynwr packet driver -- the NatSemi method doesn't work.
+ Actually this doesn't always work either, but if you have
+ problems with your NEx000 this is better than nothing! */
+ outb(0x42, nic_base + EN0_RCNTLO);
+ outb(0x00, nic_base + EN0_RCNTHI);
+ outb(0x42, nic_base + EN0_RSARLO);
+ outb(0x00, nic_base + EN0_RSARHI);
+ outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+#endif
+ outb(ENISR_RDC, nic_base + EN0_ISR);
+
+ /* Now the normal output. */
+ outb(count & 0xff, nic_base + EN0_RCNTLO);
+ outb(count >> 8, nic_base + EN0_RCNTHI);
+ outb(0x00, nic_base + EN0_RSARLO);
+ outb(start_page, nic_base + EN0_RSARHI);
+ outb(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
+ if (ei_status.ne2k_flags & ONLY_16BIT_IO) {
+ outsw(NE_BASE + NE_DATAPORT, buf, count>>1);
+ } else {
+ outsl(NE_BASE + NE_DATAPORT, buf, count>>2);
+ if (count & 3) {
+ buf += count & ~3;
+ if (count & 2) {
+ __le16 *b = (__le16 *)buf;
+
+ outw(le16_to_cpu(*b++), NE_BASE + NE_DATAPORT);
+ buf = (char *)b;
+ }
+ }
+ }
+
+ dma_start = jiffies;
+
+ while ((inb(nic_base + EN0_ISR) & ENISR_RDC) == 0)
+ if (jiffies - dma_start > 2) { /* Avoid clock roll-over. */
+ printk(KERN_WARNING "%s: timeout waiting for Tx RDC.\n", dev->name);
+ ne2k_pci_reset_8390(dev);
+ NS8390_init(dev,1);
+ break;
+ }
+
+ outb(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */
+ ei_status.dmaing &= ~0x01;
+ return;
+}
+
+static void ne2k_pci_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ struct ei_device *ei = netdev_priv(dev);
+ struct pci_dev *pci_dev = (struct pci_dev *) ei->priv;
+
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ strcpy(info->bus_info, pci_name(pci_dev));
+}
+
+static const struct ethtool_ops ne2k_pci_ethtool_ops = {
+ .get_drvinfo = ne2k_pci_get_drvinfo,
+};
+
+static void __devexit ne2k_pci_remove_one (struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+
+ BUG_ON(!dev);
+ unregister_netdev(dev);
+ release_region(dev->base_addr, NE_IO_EXTENT);
+ free_netdev(dev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+}
+
+#ifdef CONFIG_PM
+static int ne2k_pci_suspend (struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *dev = pci_get_drvdata (pdev);
+
+ netif_device_detach(dev);
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+ return 0;
+}
+
+static int ne2k_pci_resume (struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata (pdev);
+ int rc;
+
+ pci_set_power_state(pdev, 0);
+ pci_restore_state(pdev);
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ NS8390_init(dev, 1);
+ netif_device_attach(dev);
+
+ return 0;
+}
+
+#endif /* CONFIG_PM */
+
+
+struct pci_driver ne2k_driver = {
+ .name = DRV_NAME,
+ .probe = ne2k_pci_init_one,
+ .remove = __devexit_p(ne2k_pci_remove_one),
+ .id_table = ne2k_pci_tbl,
+#ifdef CONFIG_PM
+ .suspend = ne2k_pci_suspend,
+ .resume = ne2k_pci_resume,
+#endif /* CONFIG_PM */
+
+};
+
+
+int __init ne2k_pci_init(void)
+{
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+ printk(version);
+#endif
+ return pci_register_driver(&ne2k_driver);
+}
+
+
+static void __exit ne2k_pci_cleanup(void)
+{
+ pci_unregister_driver (&ne2k_driver);
+}
+
+module_init(ne2k_pci_init);
+module_exit(ne2k_pci_cleanup);
diff --git a/libdde_linux26/examples/ne2k/8390.c b/libdde_linux26/examples/ne2k/8390.c
new file mode 100644
index 00000000..ec3e22e6
--- /dev/null
+++ b/libdde_linux26/examples/ne2k/8390.c
@@ -0,0 +1,109 @@
+/* 8390 core for usual drivers */
+
+static const char version[] =
+ "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+
+#include "lib8390.c"
+
+int ei_open(struct net_device *dev)
+{
+ return __ei_open(dev);
+}
+EXPORT_SYMBOL(ei_open);
+
+int ei_close(struct net_device *dev)
+{
+ return __ei_close(dev);
+}
+EXPORT_SYMBOL(ei_close);
+
+int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ return __ei_start_xmit(skb, dev);
+}
+EXPORT_SYMBOL(ei_start_xmit);
+
+struct net_device_stats *ei_get_stats(struct net_device *dev)
+{
+ return __ei_get_stats(dev);
+}
+EXPORT_SYMBOL(ei_get_stats);
+
+void ei_set_multicast_list(struct net_device *dev)
+{
+ __ei_set_multicast_list(dev);
+}
+EXPORT_SYMBOL(ei_set_multicast_list);
+
+void ei_tx_timeout(struct net_device *dev)
+{
+ __ei_tx_timeout(dev);
+}
+EXPORT_SYMBOL(ei_tx_timeout);
+
+irqreturn_t ei_interrupt(int irq, void *dev_id)
+{
+ return __ei_interrupt(irq, dev_id);
+}
+EXPORT_SYMBOL(ei_interrupt);
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+void ei_poll(struct net_device *dev)
+{
+ __ei_poll(dev);
+}
+EXPORT_SYMBOL(ei_poll);
+#endif
+
+const struct net_device_ops ei_netdev_ops = {
+ .ndo_open = ei_open,
+ .ndo_stop = ei_close,
+ .ndo_start_xmit = ei_start_xmit,
+ .ndo_tx_timeout = ei_tx_timeout,
+ .ndo_get_stats = ei_get_stats,
+ .ndo_set_multicast_list = ei_set_multicast_list,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_change_mtu = eth_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = ei_poll,
+#endif
+};
+EXPORT_SYMBOL(ei_netdev_ops);
+
+struct net_device *__alloc_ei_netdev(int size)
+{
+ struct net_device *dev = ____alloc_ei_netdev(size);
+#ifdef CONFIG_COMPAT_NET_DEV_OPS
+ if (dev) {
+ dev->hard_start_xmit = ei_start_xmit;
+ dev->get_stats = ei_get_stats;
+ dev->set_multicast_list = ei_set_multicast_list;
+ dev->tx_timeout = ei_tx_timeout;
+ }
+#endif
+ return dev;
+}
+EXPORT_SYMBOL(__alloc_ei_netdev);
+
+void NS8390_init(struct net_device *dev, int startp)
+{
+ __NS8390_init(dev, startp);
+}
+EXPORT_SYMBOL(NS8390_init);
+
+#if defined(MODULE)
+
+static int __init ns8390_module_init(void)
+{
+ return 0;
+}
+
+static void __exit ns8390_module_exit(void)
+{
+}
+
+module_init(ns8390_module_init);
+module_exit(ns8390_module_exit);
+#endif /* MODULE */
+MODULE_LICENSE("GPL");
diff --git a/libdde_linux26/examples/ne2k/8390.h b/libdde_linux26/examples/ne2k/8390.h
new file mode 100644
index 00000000..3c61d6d2
--- /dev/null
+++ b/libdde_linux26/examples/ne2k/8390.h
@@ -0,0 +1,231 @@
+/* Generic NS8390 register definitions. */
+/* This file is part of Donald Becker's 8390 drivers, and is distributed
+ under the same license. Auto-loading of 8390.o only in v2.2 - Paul G.
+ Some of these names and comments originated from the Crynwr
+ packet drivers, which are distributed under the GPL. */
+
+#ifndef _8390_h
+#define _8390_h
+
+#include <linux/if_ether.h>
+#include <linux/ioport.h>
+#include <linux/skbuff.h>
+
+#define TX_PAGES 12 /* Two Tx slots */
+
+#define ETHER_ADDR_LEN 6
+
+/* The 8390 specific per-packet-header format. */
+struct e8390_pkt_hdr {
+ unsigned char status; /* status */
+ unsigned char next; /* pointer to next packet. */
+ unsigned short count; /* header + packet length in bytes */
+};
+
+#ifdef notdef
+extern int ei_debug;
+#else
+#define ei_debug 1
+#endif
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+extern void ei_poll(struct net_device *dev);
+extern void eip_poll(struct net_device *dev);
+#endif
+
+
+/* Without I/O delay - non ISA or later chips */
+extern void NS8390_init(struct net_device *dev, int startp);
+extern int ei_open(struct net_device *dev);
+extern int ei_close(struct net_device *dev);
+extern irqreturn_t ei_interrupt(int irq, void *dev_id);
+extern void ei_tx_timeout(struct net_device *dev);
+extern int ei_start_xmit(struct sk_buff *skb, struct net_device *dev);
+extern void ei_set_multicast_list(struct net_device *dev);
+extern struct net_device_stats *ei_get_stats(struct net_device *dev);
+
+extern const struct net_device_ops ei_netdev_ops;
+
+extern struct net_device *__alloc_ei_netdev(int size);
+static inline struct net_device *alloc_ei_netdev(void)
+{
+ return __alloc_ei_netdev(0);
+}
+
+/* With I/O delay form */
+extern void NS8390p_init(struct net_device *dev, int startp);
+extern int eip_open(struct net_device *dev);
+extern int eip_close(struct net_device *dev);
+extern irqreturn_t eip_interrupt(int irq, void *dev_id);
+extern void eip_tx_timeout(struct net_device *dev);
+extern int eip_start_xmit(struct sk_buff *skb, struct net_device *dev);
+extern void eip_set_multicast_list(struct net_device *dev);
+extern struct net_device_stats *eip_get_stats(struct net_device *dev);
+
+extern const struct net_device_ops eip_netdev_ops;
+
+extern struct net_device *__alloc_eip_netdev(int size);
+static inline struct net_device *alloc_eip_netdev(void)
+{
+ return __alloc_eip_netdev(0);
+}
+
+/* You have one of these per-board */
+struct ei_device {
+ const char *name;
+ void (*reset_8390)(struct net_device *);
+ void (*get_8390_hdr)(struct net_device *, struct e8390_pkt_hdr *, int);
+ void (*block_output)(struct net_device *, int, const unsigned char *, int);
+ void (*block_input)(struct net_device *, int, struct sk_buff *, int);
+ unsigned long rmem_start;
+ unsigned long rmem_end;
+ void __iomem *mem;
+ unsigned char mcfilter[8];
+ unsigned open:1;
+ unsigned word16:1; /* We have the 16-bit (vs 8-bit) version of the card. */
+ unsigned bigendian:1; /* 16-bit big endian mode. Do NOT */
+ /* set this on random 8390 clones! */
+ unsigned txing:1; /* Transmit Active */
+ unsigned irqlock:1; /* 8390's intrs disabled when '1'. */
+ unsigned dmaing:1; /* Remote DMA Active */
+ unsigned char tx_start_page, rx_start_page, stop_page;
+ unsigned char current_page; /* Read pointer in buffer */
+ unsigned char interface_num; /* Net port (AUI, 10bT.) to use. */
+ unsigned char txqueue; /* Tx Packet buffer queue length. */
+ short tx1, tx2; /* Packet lengths for ping-pong tx. */
+ short lasttx; /* Alpha version consistency check. */
+ unsigned char reg0; /* Register '0' in a WD8013 */
+ unsigned char reg5; /* Register '5' in a WD8013 */
+ unsigned char saved_irq; /* Original dev->irq value. */
+ u32 *reg_offset; /* Register mapping table */
+ spinlock_t page_lock; /* Page register locks */
+ unsigned long priv; /* Private field to store bus IDs etc. */
+#ifdef AX88796_PLATFORM
+ unsigned char rxcr_base; /* default value for RXCR */
+#endif
+};
+
+/* The maximum number of 8390 interrupt service routines called per IRQ. */
+#define MAX_SERVICE 12
+
+/* The maximum time waited (in jiffies) before assuming a Tx failed. (20ms) */
+#define TX_TIMEOUT (20*HZ/100)
+
+#define ei_status (*(struct ei_device *)netdev_priv(dev))
+
+/* Some generic ethernet register configurations. */
+#define E8390_TX_IRQ_MASK 0xa /* For register EN0_ISR */
+#define E8390_RX_IRQ_MASK 0x5
+
+#ifdef AX88796_PLATFORM
+#define E8390_RXCONFIG (ei_status.rxcr_base | 0x04)
+#define E8390_RXOFF (ei_status.rxcr_base | 0x20)
+#else
+#define E8390_RXCONFIG 0x4 /* EN0_RXCR: broadcasts, no multicast,errors */
+#define E8390_RXOFF 0x20 /* EN0_RXCR: Accept no packets */
+#endif
+
+#define E8390_TXCONFIG 0x00 /* EN0_TXCR: Normal transmit mode */
+#define E8390_TXOFF 0x02 /* EN0_TXCR: Transmitter off */
+
+
+/* Register accessed at EN_CMD, the 8390 base addr. */
+#define E8390_STOP 0x01 /* Stop and reset the chip */
+#define E8390_START 0x02 /* Start the chip, clear reset */
+#define E8390_TRANS 0x04 /* Transmit a frame */
+#define E8390_RREAD 0x08 /* Remote read */
+#define E8390_RWRITE 0x10 /* Remote write */
+#define E8390_NODMA 0x20 /* Remote DMA */
+#define E8390_PAGE0 0x00 /* Select page chip registers */
+#define E8390_PAGE1 0x40 /* using the two high-order bits */
+#define E8390_PAGE2 0x80 /* Page 3 is invalid. */
+
+/*
+ * Only generate indirect loads given a machine that needs them.
+ * - removed AMIGA_PCMCIA from this list, handled as ISA io now
+ * - the _p for generates no delay by default 8390p.c overrides this.
+ */
+
+#ifndef ei_inb
+#define ei_inb(_p) inb(_p)
+#define ei_outb(_v,_p) outb(_v,_p)
+#define ei_inb_p(_p) inb(_p)
+#define ei_outb_p(_v,_p) outb(_v,_p)
+#endif
+
+#ifndef EI_SHIFT
+#define EI_SHIFT(x) (x)
+#endif
+
+#define E8390_CMD EI_SHIFT(0x00) /* The command register (for all pages) */
+/* Page 0 register offsets. */
+#define EN0_CLDALO EI_SHIFT(0x01) /* Low byte of current local dma addr RD */
+#define EN0_STARTPG EI_SHIFT(0x01) /* Starting page of ring bfr WR */
+#define EN0_CLDAHI EI_SHIFT(0x02) /* High byte of current local dma addr RD */
+#define EN0_STOPPG EI_SHIFT(0x02) /* Ending page +1 of ring bfr WR */
+#define EN0_BOUNDARY EI_SHIFT(0x03) /* Boundary page of ring bfr RD WR */
+#define EN0_TSR EI_SHIFT(0x04) /* Transmit status reg RD */
+#define EN0_TPSR EI_SHIFT(0x04) /* Transmit starting page WR */
+#define EN0_NCR EI_SHIFT(0x05) /* Number of collision reg RD */
+#define EN0_TCNTLO EI_SHIFT(0x05) /* Low byte of tx byte count WR */
+#define EN0_FIFO EI_SHIFT(0x06) /* FIFO RD */
+#define EN0_TCNTHI EI_SHIFT(0x06) /* High byte of tx byte count WR */
+#define EN0_ISR EI_SHIFT(0x07) /* Interrupt status reg RD WR */
+#define EN0_CRDALO EI_SHIFT(0x08) /* low byte of current remote dma address RD */
+#define EN0_RSARLO EI_SHIFT(0x08) /* Remote start address reg 0 */
+#define EN0_CRDAHI EI_SHIFT(0x09) /* high byte, current remote dma address RD */
+#define EN0_RSARHI EI_SHIFT(0x09) /* Remote start address reg 1 */
+#define EN0_RCNTLO EI_SHIFT(0x0a) /* Remote byte count reg WR */
+#define EN0_RCNTHI EI_SHIFT(0x0b) /* Remote byte count reg WR */
+#define EN0_RSR EI_SHIFT(0x0c) /* rx status reg RD */
+#define EN0_RXCR EI_SHIFT(0x0c) /* RX configuration reg WR */
+#define EN0_TXCR EI_SHIFT(0x0d) /* TX configuration reg WR */
+#define EN0_COUNTER0 EI_SHIFT(0x0d) /* Rcv alignment error counter RD */
+#define EN0_DCFG EI_SHIFT(0x0e) /* Data configuration reg WR */
+#define EN0_COUNTER1 EI_SHIFT(0x0e) /* Rcv CRC error counter RD */
+#define EN0_IMR EI_SHIFT(0x0f) /* Interrupt mask reg WR */
+#define EN0_COUNTER2 EI_SHIFT(0x0f) /* Rcv missed frame error counter RD */
+
+/* Bits in EN0_ISR - Interrupt status register */
+#define ENISR_RX 0x01 /* Receiver, no error */
+#define ENISR_TX 0x02 /* Transmitter, no error */
+#define ENISR_RX_ERR 0x04 /* Receiver, with error */
+#define ENISR_TX_ERR 0x08 /* Transmitter, with error */
+#define ENISR_OVER 0x10 /* Receiver overwrote the ring */
+#define ENISR_COUNTERS 0x20 /* Counters need emptying */
+#define ENISR_RDC 0x40 /* remote dma complete */
+#define ENISR_RESET 0x80 /* Reset completed */
+#define ENISR_ALL 0x3f /* Interrupts we will enable */
+
+/* Bits in EN0_DCFG - Data config register */
+#define ENDCFG_WTS 0x01 /* word transfer mode selection */
+#define ENDCFG_BOS 0x02 /* byte order selection */
+
+/* Page 1 register offsets. */
+#define EN1_PHYS EI_SHIFT(0x01) /* This board's physical enet addr RD WR */
+#define EN1_PHYS_SHIFT(i) EI_SHIFT(i+1) /* Get and set mac address */
+#define EN1_CURPAG EI_SHIFT(0x07) /* Current memory page RD WR */
+#define EN1_MULT EI_SHIFT(0x08) /* Multicast filter mask array (8 bytes) RD WR */
+#define EN1_MULT_SHIFT(i) EI_SHIFT(8+i) /* Get and set multicast filter */
+
+/* Bits in received packet status byte and EN0_RSR*/
+#define ENRSR_RXOK 0x01 /* Received a good packet */
+#define ENRSR_CRC 0x02 /* CRC error */
+#define ENRSR_FAE 0x04 /* frame alignment error */
+#define ENRSR_FO 0x08 /* FIFO overrun */
+#define ENRSR_MPA 0x10 /* missed pkt */
+#define ENRSR_PHY 0x20 /* physical/multicast address */
+#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */
+#define ENRSR_DEF 0x80 /* deferring */
+
+/* Transmitted packet status, EN0_TSR. */
+#define ENTSR_PTX 0x01 /* Packet transmitted without error */
+#define ENTSR_ND 0x02 /* The transmit wasn't deferred. */
+#define ENTSR_COL 0x04 /* The transmit collided at least once. */
+#define ENTSR_ABT 0x08 /* The transmit collided 16 times, and was deferred. */
+#define ENTSR_CRS 0x10 /* The carrier sense was lost. */
+#define ENTSR_FU 0x20 /* A "FIFO underrun" occurred during transmit. */
+#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */
+#define ENTSR_OWC 0x80 /* There was an out-of-window collision. */
+
+#endif /* _8390_h */
diff --git a/libdde_linux26/examples/ne2k/Makefile b/libdde_linux26/examples/ne2k/Makefile
new file mode 100644
index 00000000..2a7b1543
--- /dev/null
+++ b/libdde_linux26/examples/ne2k/Makefile
@@ -0,0 +1,32 @@
+PKGDIR ?= ../../..
+L4DIR ?= $(PKGDIR)/../..
+
+SYSTEMS = x86-l4v2
+
+DEFAULT_RELOC = 0x00a00000
+
+-include $(PKGDIR_OBJ)/Makeconf
+
+ifeq ($(CONFIG_DDE26_NET),y)
+TARGET = ne2k_dde26
+endif
+
+SRC_C = ne2k-pci.c 8390.c main.c arping.c
+
+LIBS += -ldde_linux26_net -ldde_linux26.o -lddekit -lio -lomega0 -llist_alloc
+
+PRIVATE_INCDIR = $(PKGDIR_ABS)/linux26/include $(MY_DDE_INCDIR) $(MY_LINUX26_INCDIR) \
+ $(OBJ_BASE)/include/uclibc
+
+LIBCINCDIR = -nostdinc $(I_GCCINCDIR)
+DEFINES = -D__KERNEL__ -DDDE_LINUX\
+ $(KBUILD_DEFINES)
+CPPFLAGS += $(KBUILD_CPPFLAGS)
+
+include $(PKGDIR)/linux26/Makeconf
+
+include $(L4DIR)/mk/prog.mk
+
+foo :
+ @echo $(L4INCDIR)
+ @echo $(OBJ_BASE)
diff --git a/libdde_linux26/examples/ne2k/arping.c b/libdde_linux26/examples/ne2k/arping.c
new file mode 100644
index 00000000..18876806
--- /dev/null
+++ b/libdde_linux26/examples/ne2k/arping.c
@@ -0,0 +1,185 @@
+/****************************************************************
+ * (c) 2007 Technische Universitaet Dresden *
+ * This file is part of DROPS, which is distributed under the *
+ * terms of the GNU General Public License 2. Please see the *
+ * COPYING file for details. *
+ ****************************************************************/
+
+#include <l4/log/l4log.h>
+#include <l4/util/util.h>
+#include <l4/util/l4_macros.h>
+#include <l4/sys/ipc.h>
+
+#include <linux/netdevice.h>
+#include <linux/if_ether.h>
+
+#include "arping.h"
+
+#define PROT_ICMP 1
+#define ICMP_REPLY 0
+#define ICMP_REQ 8
+#define ETH_ALEN 6
+
+/* configuration */
+int arping_verbose = 0; // verbose
+
+#define VERBOSE_LOG(fmt, ...) \
+ do { \
+ if (arping_verbose) printk(fmt, ##__VA_ARGS__); \
+ } while (0);
+
+char LOG_tag[9] = "arping";
+l4_ssize_t l4libc_heapsize = 32 * 1024;
+
+static unsigned char broadcast_mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+static int exit_somewhen = 0;
+
+
+struct ethernet_hdr
+{
+ unsigned char dest[6];
+ unsigned char src[6];
+ unsigned char type[2];
+};
+
+
+struct ip_hdr
+{
+ char version_length;
+ char type;
+ l4_int16_t length;
+ l4_int16_t id;
+ l4_int16_t flags_offset;
+ char ttl;
+ char protocol;
+ l4_int16_t checksum;
+ l4_int32_t src_ip;
+ l4_int32_t dest_ip;
+};
+
+
+struct icmp_hdr
+{
+ char type;
+ char code;
+ l4_uint16_t checksum;
+ l4_uint16_t id;
+ l4_uint16_t seq_num;
+};
+
+
+static int handle_icmp_packet(struct sk_buff *skb);
+static int handle_icmp_packet(struct sk_buff *skb)
+{
+ char *data = skb->data;
+ struct ethernet_hdr *eth = NULL;
+ struct ethernet_hdr *e = NULL;
+ struct ip_hdr *ip = NULL;
+ struct ip_hdr *iphdr = NULL;
+ struct icmp_hdr *icmp = NULL;
+ struct icmp_hdr *icmp2 = NULL;
+ int ver, len;
+ struct sk_buff *snd_skb = NULL;
+
+ eth = (struct ethernet_hdr *)data;
+ VERBOSE_LOG("dest mac = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ eth->dest[0], eth->dest[1], eth->dest[2],
+ eth->dest[3], eth->dest[4], eth->dest[5]);
+ VERBOSE_LOG("src mac = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ eth->src[0], eth->src[1], eth->src[2],
+ eth->src[3], eth->src[4], eth->src[5]);
+ VERBOSE_LOG("type field = %02x%02x\n", eth->type[0], eth->type[1]);
+ if (eth->type[0] != 0x08 || eth->type[1] != 0x00) {
+ printk("unknown ethernet packet type!\n");
+ return -1;
+ }
+
+ ip = (struct ip_hdr *)(data + sizeof(struct ethernet_hdr));
+ VERBOSE_LOG("protocol = %02x (2x?)\n", ip->protocol, PROT_ICMP);
+ if (ip->protocol != PROT_ICMP)
+ {
+ printk("Unknown packet type.\n");
+ return -1;
+ }
+
+ VERBOSE_LOG("ICMP packet!\n");
+ ver = ip->version_length >> 4;
+ len = ip->version_length & 0x0F;
+ VERBOSE_LOG("IP version = %d, length = %d\n", ver, len);
+
+ VERBOSE_LOG("src IP: "NIPQUAD_FMT"\n", NIPQUAD(ip->src_ip));
+ VERBOSE_LOG("dest IP: "NIPQUAD_FMT"\n", NIPQUAD(ip->dest_ip));
+
+ icmp = (struct icmp_hdr *)(data + sizeof(struct ethernet_hdr)
+ + sizeof(struct ip_hdr));
+
+ if (icmp->type != ICMP_REQ)
+ {
+ printk("This is no ICMP request.\n");
+ return -1;
+ }
+ VERBOSE_LOG("Hey this is an ICMP request just for me. :)\n");
+ VERBOSE_LOG("ICMP type : %d\n", icmp->type);
+ VERBOSE_LOG("ICMP code : %d\n", icmp->code);
+ VERBOSE_LOG("ICMP seq : %d\n", ntohs(icmp->seq_num));
+
+ snd_skb = alloc_skb(skb->len + skb->dev->hard_header_len, GFP_KERNEL);
+ memcpy(snd_skb->data, skb->data, skb->len);
+
+ e = (struct ethernet_hdr *)snd_skb->data;
+ memcpy(e->src, eth->dest, ETH_ALEN);
+ memcpy(e->dest, eth->src, ETH_ALEN);
+ VERBOSE_LOG("dest mac = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ e->dest[0], e->dest[1], e->dest[2],
+ e->dest[3], e->dest[4], e->dest[5]);
+ VERBOSE_LOG("src mac = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ e->src[0], e->src[1], e->src[2],
+ e->src[3], e->src[4], e->src[5]);
+ e->type[0] = 0x08;
+ e->type[1] = 0x00;
+
+ iphdr = (struct ip_hdr *)(snd_skb->data + sizeof(struct ethernet_hdr));
+ *iphdr = *ip;
+ // also switch src and dest
+ iphdr->src_ip = ip->dest_ip;
+ iphdr->dest_ip = ip->src_ip;
+ VERBOSE_LOG("src IP: "NIPQUAD_FMT"\n", NIPQUAD(iphdr->src_ip));
+ VERBOSE_LOG("dest IP: "NIPQUAD_FMT"\n", NIPQUAD(iphdr->dest_ip));
+
+ icmp2 = (struct icmp_hdr *)(snd_skb->data + sizeof(struct ethernet_hdr)
+ + sizeof(struct ip_hdr));
+ *icmp2 = *icmp;
+ icmp2->type = ICMP_REPLY;
+
+ snd_skb->dev = skb->dev;
+ snd_skb->len = skb->len;
+
+ VERBOSE_LOG("sending reply\n");
+ skb->dev->hard_start_xmit(snd_skb, skb->dev);
+ VERBOSE_LOG("done\n");
+
+ return 0;
+}
+
+ddekit_sem_t *arping_semaphore = NULL;
+struct arping_elem *arping_list = NULL;
+
+int arping(void)
+{
+ arping_semaphore = ddekit_sem_init(0);
+
+ while(1)
+ {
+ ddekit_sem_down(arping_semaphore);
+ struct arping_elem *elem = arping_list;
+ arping_list = arping_list->next;
+
+ /* parse packet */
+ int err = handle_icmp_packet(elem->skb);
+ VERBOSE_LOG("handle_icmp_packet: %d\n", err);
+
+ kfree_skb(elem->skb);
+ kfree(elem);
+ }
+}
+
diff --git a/libdde_linux26/examples/ne2k/arping.h b/libdde_linux26/examples/ne2k/arping.h
new file mode 100644
index 00000000..2df7f303
--- /dev/null
+++ b/libdde_linux26/examples/ne2k/arping.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <l4/dde/ddekit/semaphore.h>
+
+struct arping_elem
+{
+ struct arping_elem *next;
+ struct sk_buff *skb;
+};
+
+extern ddekit_sem_t *arping_semaphore;
+extern struct arping_elem *arping_list;
+
+#define mac_fmt "%02X:%02X:%02X:%02X:%02X:%02X"
+#define mac_str(mac) (unsigned char)((mac)[0]), (unsigned char)((mac)[1]),(mac)[2],(mac)[3],(mac)[4],(mac)[5]
diff --git a/libdde_linux26/examples/ne2k/lib8390.c b/libdde_linux26/examples/ne2k/lib8390.c
new file mode 100644
index 00000000..789b6cb7
--- /dev/null
+++ b/libdde_linux26/examples/ne2k/lib8390.c
@@ -0,0 +1,1125 @@
+/* 8390.c: A general NS8390 ethernet driver core for linux. */
+/*
+ Written 1992-94 by Donald Becker.
+
+ Copyright 1993 United States Government as represented by the
+ Director, National Security Agency.
+
+ This software may be used and distributed according to the terms
+ of the GNU General Public License, incorporated herein by reference.
+
+ The author may be reached as becker@scyld.com, or C/O
+ Scyld Computing Corporation
+ 410 Severn Ave., Suite 210
+ Annapolis MD 21403
+
+
+ This is the chip-specific code for many 8390-based ethernet adaptors.
+ This is not a complete driver, it must be combined with board-specific
+ code such as ne.c, wd.c, 3c503.c, etc.
+
+ Seeing how at least eight drivers use this code, (not counting the
+ PCMCIA ones either) it is easy to break some card by what seems like
+ a simple innocent change. Please contact me or Donald if you think
+ you have found something that needs changing. -- PG
+
+
+ Changelog:
+
+ Paul Gortmaker : remove set_bit lock, other cleanups.
+ Paul Gortmaker : add ei_get_8390_hdr() so we can pass skb's to
+ ei_block_input() for eth_io_copy_and_sum().
+ Paul Gortmaker : exchange static int ei_pingpong for a #define,
+ also add better Tx error handling.
+ Paul Gortmaker : rewrite Rx overrun handling as per NS specs.
+ Alexey Kuznetsov : use the 8390's six bit hash multicast filter.
+ Paul Gortmaker : tweak ANK's above multicast changes a bit.
+ Paul Gortmaker : update packet statistics for v2.1.x
+ Alan Cox : support arbitary stupid port mappings on the
+ 68K Macintosh. Support >16bit I/O spaces
+ Paul Gortmaker : add kmod support for auto-loading of the 8390
+ module by all drivers that require it.
+ Alan Cox : Spinlocking work, added 'BUG_83C690'
+ Paul Gortmaker : Separate out Tx timeout code from Tx path.
+ Paul Gortmaker : Remove old unused single Tx buffer code.
+ Hayato Fujiwara : Add m32r support.
+ Paul Gortmaker : use skb_padto() instead of stack scratch area
+
+ Sources:
+ The National Semiconductor LAN Databook, and the 3Com 3c503 databook.
+
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/jiffies.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/bitops.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/in.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/crc32.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+#define NS8390_CORE
+#include "8390.h"
+
+#define BUG_83C690
+
+/* These are the operational function interfaces to board-specific
+ routines.
+ void reset_8390(struct net_device *dev)
+ Resets the board associated with DEV, including a hardware reset of
+ the 8390. This is only called when there is a transmit timeout, and
+ it is always followed by 8390_init().
+ void block_output(struct net_device *dev, int count, const unsigned char *buf,
+ int start_page)
+ Write the COUNT bytes of BUF to the packet buffer at START_PAGE. The
+ "page" value uses the 8390's 256-byte pages.
+ void get_8390_hdr(struct net_device *dev, struct e8390_hdr *hdr, int ring_page)
+ Read the 4 byte, page aligned 8390 header. *If* there is a
+ subsequent read, it will be of the rest of the packet.
+ void block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
+ Read COUNT bytes from the packet buffer into the skb data area. Start
+ reading from RING_OFFSET, the address as the 8390 sees it. This will always
+ follow the read of the 8390 header.
+*/
+#define ei_reset_8390 (ei_local->reset_8390)
+#define ei_block_output (ei_local->block_output)
+#define ei_block_input (ei_local->block_input)
+#define ei_get_8390_hdr (ei_local->get_8390_hdr)
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef ei_debug
+int ei_debug = 1;
+#endif
+
+/* Index to functions. */
+static void ei_tx_intr(struct net_device *dev);
+static void ei_tx_err(struct net_device *dev);
+void ei_tx_timeout(struct net_device *dev);
+static void ei_receive(struct net_device *dev);
+static void ei_rx_overrun(struct net_device *dev);
+
+/* Routines generic to NS8390-based boards. */
+static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
+ int start_page);
+static void do_set_multicast_list(struct net_device *dev);
+static void __NS8390_init(struct net_device *dev, int startp);
+
+/*
+ * SMP and the 8390 setup.
+ *
+ * The 8390 isnt exactly designed to be multithreaded on RX/TX. There is
+ * a page register that controls bank and packet buffer access. We guard
+ * this with ei_local->page_lock. Nobody should assume or set the page other
+ * than zero when the lock is not held. Lock holders must restore page 0
+ * before unlocking. Even pure readers must take the lock to protect in
+ * page 0.
+ *
+ * To make life difficult the chip can also be very slow. We therefore can't
+ * just use spinlocks. For the longer lockups we disable the irq the device
+ * sits on and hold the lock. We must hold the lock because there is a dual
+ * processor case other than interrupts (get stats/set multicast list in
+ * parallel with each other and transmit).
+ *
+ * Note: in theory we can just disable the irq on the card _but_ there is
+ * a latency on SMP irq delivery. So we can easily go "disable irq" "sync irqs"
+ * enter lock, take the queued irq. So we waddle instead of flying.
+ *
+ * Finally by special arrangement for the purpose of being generally
+ * annoying the transmit function is called bh atomic. That places
+ * restrictions on the user context callers as disable_irq won't save
+ * them.
+ *
+ * Additional explanation of problems with locking by Alan Cox:
+ *
+ * "The author (me) didn't use spin_lock_irqsave because the slowness of the
+ * card means that approach caused horrible problems like losing serial data
+ * at 38400 baud on some chips. Remember many 8390 nics on PCI were ISA
+ * chips with FPGA front ends.
+ *
+ * Ok the logic behind the 8390 is very simple:
+ *
+ * Things to know
+ * - IRQ delivery is asynchronous to the PCI bus
+ * - Blocking the local CPU IRQ via spin locks was too slow
+ * - The chip has register windows needing locking work
+ *
+ * So the path was once (I say once as people appear to have changed it
+ * in the mean time and it now looks rather bogus if the changes to use
+ * disable_irq_nosync_irqsave are disabling the local IRQ)
+ *
+ *
+ * Take the page lock
+ * Mask the IRQ on chip
+ * Disable the IRQ (but not mask locally- someone seems to have
+ * broken this with the lock validator stuff)
+ * [This must be _nosync as the page lock may otherwise
+ * deadlock us]
+ * Drop the page lock and turn IRQs back on
+ *
+ * At this point an existing IRQ may still be running but we can't
+ * get a new one
+ *
+ * Take the lock (so we know the IRQ has terminated) but don't mask
+ * the IRQs on the processor
+ * Set irqlock [for debug]
+ *
+ * Transmit (slow as ****)
+ *
+ * re-enable the IRQ
+ *
+ *
+ * We have to use disable_irq because otherwise you will get delayed
+ * interrupts on the APIC bus deadlocking the transmit path.
+ *
+ * Quite hairy but the chip simply wasn't designed for SMP and you can't
+ * even ACK an interrupt without risking corrupting other parallel
+ * activities on the chip." [lkml, 25 Jul 2007]
+ */
+
+
+
+/**
+ * ei_open - Open/initialize the board.
+ * @dev: network device to initialize
+ *
+ * This routine goes all-out, setting everything
+ * up anew at each open, even though many of these registers should only
+ * need to be set once at boot.
+ */
+static int __ei_open(struct net_device *dev)
+{
+ unsigned long flags;
+ struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+
+ if (dev->watchdog_timeo <= 0)
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ /*
+ * Grab the page lock so we own the register set, then call
+ * the init function.
+ */
+
+ spin_lock_irqsave(&ei_local->page_lock, flags);
+ __NS8390_init(dev, 1);
+ /* Set the flag before we drop the lock, That way the IRQ arrives
+ after its set and we get no silly warnings */
+ netif_start_queue(dev);
+ spin_unlock_irqrestore(&ei_local->page_lock, flags);
+ ei_local->irqlock = 0;
+ return 0;
+}
+
+/**
+ * ei_close - shut down network device
+ * @dev: network device to close
+ *
+ * Opposite of ei_open(). Only used when "ifconfig <devname> down" is done.
+ */
+static int __ei_close(struct net_device *dev)
+{
+ struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ unsigned long flags;
+
+ /*
+ * Hold the page lock during close
+ */
+
+ spin_lock_irqsave(&ei_local->page_lock, flags);
+ __NS8390_init(dev, 0);
+ spin_unlock_irqrestore(&ei_local->page_lock, flags);
+ netif_stop_queue(dev);
+ return 0;
+}
+
+/**
+ * ei_tx_timeout - handle transmit time out condition
+ * @dev: network device which has apparently fallen asleep
+ *
+ * Called by kernel when device never acknowledges a transmit has
+ * completed (or failed) - i.e. never posted a Tx related interrupt.
+ */
+
+static void __ei_tx_timeout(struct net_device *dev)
+{
+ unsigned long e8390_base = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ int txsr, isr, tickssofar = jiffies - dev->trans_start;
+ unsigned long flags;
+
+ dev->stats.tx_errors++;
+
+ spin_lock_irqsave(&ei_local->page_lock, flags);
+ txsr = ei_inb(e8390_base+EN0_TSR);
+ isr = ei_inb(e8390_base+EN0_ISR);
+ spin_unlock_irqrestore(&ei_local->page_lock, flags);
+
+ printk(KERN_DEBUG "%s: Tx timed out, %s TSR=%#2x, ISR=%#2x, t=%d.\n",
+ dev->name, (txsr & ENTSR_ABT) ? "excess collisions." :
+ (isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar);
+
+ if (!isr && !dev->stats.tx_packets)
+ {
+ /* The 8390 probably hasn't gotten on the cable yet. */
+ ei_local->interface_num ^= 1; /* Try a different xcvr. */
+ }
+
+ /* Ugly but a reset can be slow, yet must be protected */
+
+ disable_irq_nosync_lockdep(dev->irq);
+ spin_lock(&ei_local->page_lock);
+
+ /* Try to restart the card. Perhaps the user has fixed something. */
+ ei_reset_8390(dev);
+ __NS8390_init(dev, 1);
+
+ spin_unlock(&ei_local->page_lock);
+ enable_irq_lockdep(dev->irq);
+ netif_wake_queue(dev);
+}
+
+/**
+ * ei_start_xmit - begin packet transmission
+ * @skb: packet to be sent
+ * @dev: network device to which packet is sent
+ *
+ * Sends a packet to an 8390 network device.
+ */
+
+static int __ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ unsigned long e8390_base = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ int send_length = skb->len, output_page;
+ unsigned long flags;
+ char buf[ETH_ZLEN];
+ char *data = skb->data;
+
+ if (skb->len < ETH_ZLEN) {
+ memset(buf, 0, ETH_ZLEN); /* more efficient than doing just the needed bits */
+ memcpy(buf, data, skb->len);
+ send_length = ETH_ZLEN;
+ data = buf;
+ }
+
+ /* Mask interrupts from the ethercard.
+ SMP: We have to grab the lock here otherwise the IRQ handler
+ on another CPU can flip window and race the IRQ mask set. We end
+ up trashing the mcast filter not disabling irqs if we don't lock */
+
+ spin_lock_irqsave(&ei_local->page_lock, flags);
+ ei_outb_p(0x00, e8390_base + EN0_IMR);
+ spin_unlock_irqrestore(&ei_local->page_lock, flags);
+
+
+ /*
+ * Slow phase with lock held.
+ */
+
+ disable_irq_nosync_lockdep_irqsave(dev->irq, &flags);
+
+ spin_lock(&ei_local->page_lock);
+
+ ei_local->irqlock = 1;
+
+ /*
+ * We have two Tx slots available for use. Find the first free
+ * slot, and then perform some sanity checks. With two Tx bufs,
+ * you get very close to transmitting back-to-back packets. With
+ * only one Tx buf, the transmitter sits idle while you reload the
+ * card, leaving a substantial gap between each transmitted packet.
+ */
+
+ if (ei_local->tx1 == 0)
+ {
+ output_page = ei_local->tx_start_page;
+ ei_local->tx1 = send_length;
+ if (ei_debug && ei_local->tx2 > 0)
+ printk(KERN_DEBUG "%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",
+ dev->name, ei_local->tx2, ei_local->lasttx, ei_local->txing);
+ }
+ else if (ei_local->tx2 == 0)
+ {
+ output_page = ei_local->tx_start_page + TX_PAGES/2;
+ ei_local->tx2 = send_length;
+ if (ei_debug && ei_local->tx1 > 0)
+ printk(KERN_DEBUG "%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",
+ dev->name, ei_local->tx1, ei_local->lasttx, ei_local->txing);
+ }
+ else
+ { /* We should never get here. */
+ if (ei_debug)
+ printk(KERN_DEBUG "%s: No Tx buffers free! tx1=%d tx2=%d last=%d\n",
+ dev->name, ei_local->tx1, ei_local->tx2, ei_local->lasttx);
+ ei_local->irqlock = 0;
+ netif_stop_queue(dev);
+ ei_outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+ spin_unlock(&ei_local->page_lock);
+ enable_irq_lockdep_irqrestore(dev->irq, &flags);
+ dev->stats.tx_errors++;
+ return 1;
+ }
+
+ /*
+ * Okay, now upload the packet and trigger a send if the transmitter
+ * isn't already sending. If it is busy, the interrupt handler will
+ * trigger the send later, upon receiving a Tx done interrupt.
+ */
+
+ ei_block_output(dev, send_length, data, output_page);
+
+ if (! ei_local->txing)
+ {
+ ei_local->txing = 1;
+ NS8390_trigger_send(dev, send_length, output_page);
+ dev->trans_start = jiffies;
+ if (output_page == ei_local->tx_start_page)
+ {
+ ei_local->tx1 = -1;
+ ei_local->lasttx = -1;
+ }
+ else
+ {
+ ei_local->tx2 = -1;
+ ei_local->lasttx = -2;
+ }
+ }
+ else ei_local->txqueue++;
+
+ if (ei_local->tx1 && ei_local->tx2)
+ netif_stop_queue(dev);
+ else
+ netif_start_queue(dev);
+
+ /* Turn 8390 interrupts back on. */
+ ei_local->irqlock = 0;
+ ei_outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+
+ spin_unlock(&ei_local->page_lock);
+ enable_irq_lockdep_irqrestore(dev->irq, &flags);
+
+ dev_kfree_skb (skb);
+ dev->stats.tx_bytes += send_length;
+
+ return 0;
+}
+
+/**
+ * ei_interrupt - handle the interrupts from an 8390
+ * @irq: interrupt number
+ * @dev_id: a pointer to the net_device
+ *
+ * Handle the ether interface interrupts. We pull packets from
+ * the 8390 via the card specific functions and fire them at the networking
+ * stack. We also handle transmit completions and wake the transmit path if
+ * necessary. We also update the counters and do other housekeeping as
+ * needed.
+ */
+
+static irqreturn_t __ei_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ unsigned long e8390_base = dev->base_addr;
+ int interrupts, nr_serviced = 0;
+ struct ei_device *ei_local = netdev_priv(dev);
+
+ /*
+ * Protect the irq test too.
+ */
+
+ spin_lock(&ei_local->page_lock);
+
+ if (ei_local->irqlock)
+ {
+#if 1 /* This might just be an interrupt for a PCI device sharing this line */
+ /* The "irqlock" check is only for testing. */
+ printk(ei_local->irqlock
+ ? "%s: Interrupted while interrupts are masked! isr=%#2x imr=%#2x.\n"
+ : "%s: Reentering the interrupt handler! isr=%#2x imr=%#2x.\n",
+ dev->name, ei_inb_p(e8390_base + EN0_ISR),
+ ei_inb_p(e8390_base + EN0_IMR));
+#endif
+ spin_unlock(&ei_local->page_lock);
+ return IRQ_NONE;
+ }
+
+ /* Change to page 0 and read the intr status reg. */
+ ei_outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
+ if (ei_debug > 3)
+ printk(KERN_DEBUG "%s: interrupt(isr=%#2.2x).\n", dev->name,
+ ei_inb_p(e8390_base + EN0_ISR));
+
+ /* !!Assumption!! -- we stay in page 0. Don't break this. */
+ while ((interrupts = ei_inb_p(e8390_base + EN0_ISR)) != 0
+ && ++nr_serviced < MAX_SERVICE)
+ {
+ if (!netif_running(dev)) {
+ printk(KERN_WARNING "%s: interrupt from stopped card\n", dev->name);
+ /* rmk - acknowledge the interrupts */
+ ei_outb_p(interrupts, e8390_base + EN0_ISR);
+ interrupts = 0;
+ break;
+ }
+ if (interrupts & ENISR_OVER)
+ ei_rx_overrun(dev);
+ else if (interrupts & (ENISR_RX+ENISR_RX_ERR))
+ {
+ /* Got a good (?) packet. */
+ ei_receive(dev);
+ }
+ /* Push the next to-transmit packet through. */
+ if (interrupts & ENISR_TX)
+ ei_tx_intr(dev);
+ else if (interrupts & ENISR_TX_ERR)
+ ei_tx_err(dev);
+
+ if (interrupts & ENISR_COUNTERS)
+ {
+ dev->stats.rx_frame_errors += ei_inb_p(e8390_base + EN0_COUNTER0);
+ dev->stats.rx_crc_errors += ei_inb_p(e8390_base + EN0_COUNTER1);
+ dev->stats.rx_missed_errors+= ei_inb_p(e8390_base + EN0_COUNTER2);
+ ei_outb_p(ENISR_COUNTERS, e8390_base + EN0_ISR); /* Ack intr. */
+ }
+
+ /* Ignore any RDC interrupts that make it back to here. */
+ if (interrupts & ENISR_RDC)
+ {
+ ei_outb_p(ENISR_RDC, e8390_base + EN0_ISR);
+ }
+
+ ei_outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
+ }
+
+ if (interrupts && ei_debug)
+ {
+ ei_outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
+ if (nr_serviced >= MAX_SERVICE)
+ {
+ /* 0xFF is valid for a card removal */
+ if(interrupts!=0xFF)
+ printk(KERN_WARNING "%s: Too much work at interrupt, status %#2.2x\n",
+ dev->name, interrupts);
+ ei_outb_p(ENISR_ALL, e8390_base + EN0_ISR); /* Ack. most intrs. */
+ } else {
+ printk(KERN_WARNING "%s: unknown interrupt %#2x\n", dev->name, interrupts);
+ ei_outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */
+ }
+ }
+ spin_unlock(&ei_local->page_lock);
+ return IRQ_RETVAL(nr_serviced > 0);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void __ei_poll(struct net_device *dev)
+{
+ disable_irq(dev->irq);
+ __ei_interrupt(dev->irq, dev);
+ enable_irq(dev->irq);
+}
+#endif
+
+/**
+ * ei_tx_err - handle transmitter error
+ * @dev: network device which threw the exception
+ *
+ * A transmitter error has happened. Most likely excess collisions (which
+ * is a fairly normal condition). If the error is one where the Tx will
+ * have been aborted, we try and send another one right away, instead of
+ * letting the failed packet sit and collect dust in the Tx buffer. This
+ * is a much better solution as it avoids kernel based Tx timeouts, and
+ * an unnecessary card reset.
+ *
+ * Called with lock held.
+ */
+
+static void ei_tx_err(struct net_device *dev)
+{
+ unsigned long e8390_base = dev->base_addr;
+ /* ei_local is used on some platforms via the EI_SHIFT macro */
+ struct ei_device *ei_local __maybe_unused = netdev_priv(dev);
+ unsigned char txsr = ei_inb_p(e8390_base+EN0_TSR);
+ unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU);
+
+#ifdef VERBOSE_ERROR_DUMP
+ printk(KERN_DEBUG "%s: transmitter error (%#2x): ", dev->name, txsr);
+ if (txsr & ENTSR_ABT)
+ printk("excess-collisions ");
+ if (txsr & ENTSR_ND)
+ printk("non-deferral ");
+ if (txsr & ENTSR_CRS)
+ printk("lost-carrier ");
+ if (txsr & ENTSR_FU)
+ printk("FIFO-underrun ");
+ if (txsr & ENTSR_CDH)
+ printk("lost-heartbeat ");
+ printk("\n");
+#endif
+
+ ei_outb_p(ENISR_TX_ERR, e8390_base + EN0_ISR); /* Ack intr. */
+
+ if (tx_was_aborted)
+ ei_tx_intr(dev);
+ else
+ {
+ dev->stats.tx_errors++;
+ if (txsr & ENTSR_CRS) dev->stats.tx_carrier_errors++;
+ if (txsr & ENTSR_CDH) dev->stats.tx_heartbeat_errors++;
+ if (txsr & ENTSR_OWC) dev->stats.tx_window_errors++;
+ }
+}
+
+/**
+ * ei_tx_intr - transmit interrupt handler
+ * @dev: network device for which tx intr is handled
+ *
+ * We have finished a transmit: check for errors and then trigger the next
+ * packet to be sent. Called with lock held.
+ */
+
+static void ei_tx_intr(struct net_device *dev)
+{
+ unsigned long e8390_base = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ int status = ei_inb(e8390_base + EN0_TSR);
+
+ ei_outb_p(ENISR_TX, e8390_base + EN0_ISR); /* Ack intr. */
+
+ /*
+ * There are two Tx buffers, see which one finished, and trigger
+ * the send of another one if it exists.
+ */
+ ei_local->txqueue--;
+
+ if (ei_local->tx1 < 0)
+ {
+ if (ei_local->lasttx != 1 && ei_local->lasttx != -1)
+ printk(KERN_ERR "%s: bogus last_tx_buffer %d, tx1=%d.\n",
+ ei_local->name, ei_local->lasttx, ei_local->tx1);
+ ei_local->tx1 = 0;
+ if (ei_local->tx2 > 0)
+ {
+ ei_local->txing = 1;
+ NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6);
+ dev->trans_start = jiffies;
+ ei_local->tx2 = -1,
+ ei_local->lasttx = 2;
+ }
+ else ei_local->lasttx = 20, ei_local->txing = 0;
+ }
+ else if (ei_local->tx2 < 0)
+ {
+ if (ei_local->lasttx != 2 && ei_local->lasttx != -2)
+ printk("%s: bogus last_tx_buffer %d, tx2=%d.\n",
+ ei_local->name, ei_local->lasttx, ei_local->tx2);
+ ei_local->tx2 = 0;
+ if (ei_local->tx1 > 0)
+ {
+ ei_local->txing = 1;
+ NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page);
+ dev->trans_start = jiffies;
+ ei_local->tx1 = -1;
+ ei_local->lasttx = 1;
+ }
+ else
+ ei_local->lasttx = 10, ei_local->txing = 0;
+ }
+// else printk(KERN_WARNING "%s: unexpected TX-done interrupt, lasttx=%d.\n",
+// dev->name, ei_local->lasttx);
+
+ /* Minimize Tx latency: update the statistics after we restart TXing. */
+ if (status & ENTSR_COL)
+ dev->stats.collisions++;
+ if (status & ENTSR_PTX)
+ dev->stats.tx_packets++;
+ else
+ {
+ dev->stats.tx_errors++;
+ if (status & ENTSR_ABT)
+ {
+ dev->stats.tx_aborted_errors++;
+ dev->stats.collisions += 16;
+ }
+ if (status & ENTSR_CRS)
+ dev->stats.tx_carrier_errors++;
+ if (status & ENTSR_FU)
+ dev->stats.tx_fifo_errors++;
+ if (status & ENTSR_CDH)
+ dev->stats.tx_heartbeat_errors++;
+ if (status & ENTSR_OWC)
+ dev->stats.tx_window_errors++;
+ }
+ netif_wake_queue(dev);
+}
+
+/**
+ * ei_receive - receive some packets
+ * @dev: network device with which receive will be run
+ *
+ * We have a good packet(s), get it/them out of the buffers.
+ * Called with lock held.
+ */
+
+static void ei_receive(struct net_device *dev)
+{
+ unsigned long e8390_base = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ unsigned char rxing_page, this_frame, next_frame;
+ unsigned short current_offset;
+ int rx_pkt_count = 0;
+ struct e8390_pkt_hdr rx_frame;
+ int num_rx_pages = ei_local->stop_page-ei_local->rx_start_page;
+
+ while (++rx_pkt_count < 10)
+ {
+ int pkt_len, pkt_stat;
+
+ /* Get the rx page (incoming packet pointer). */
+ ei_outb_p(E8390_NODMA+E8390_PAGE1, e8390_base + E8390_CMD);
+ rxing_page = ei_inb_p(e8390_base + EN1_CURPAG);
+ ei_outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
+
+ /* Remove one frame from the ring. Boundary is always a page behind. */
+ this_frame = ei_inb_p(e8390_base + EN0_BOUNDARY) + 1;
+ if (this_frame >= ei_local->stop_page)
+ this_frame = ei_local->rx_start_page;
+
+ /* Someday we'll omit the previous, iff we never get this message.
+ (There is at least one clone claimed to have a problem.)
+
+ Keep quiet if it looks like a card removal. One problem here
+ is that some clones crash in roughly the same way.
+ */
+ if (ei_debug > 0 && this_frame != ei_local->current_page && (this_frame!=0x0 || rxing_page!=0xFF))
+ printk(KERN_ERR "%s: mismatched read page pointers %2x vs %2x.\n",
+ dev->name, this_frame, ei_local->current_page);
+
+ if (this_frame == rxing_page) /* Read all the frames? */
+ break; /* Done for now */
+
+ current_offset = this_frame << 8;
+ ei_get_8390_hdr(dev, &rx_frame, this_frame);
+
+ pkt_len = rx_frame.count - sizeof(struct e8390_pkt_hdr);
+ pkt_stat = rx_frame.status;
+
+ next_frame = this_frame + 1 + ((pkt_len+4)>>8);
+
+ /* Check for bogosity warned by 3c503 book: the status byte is never
+ written. This happened a lot during testing! This code should be
+ cleaned up someday. */
+ if (rx_frame.next != next_frame
+ && rx_frame.next != next_frame + 1
+ && rx_frame.next != next_frame - num_rx_pages
+ && rx_frame.next != next_frame + 1 - num_rx_pages) {
+ ei_local->current_page = rxing_page;
+ ei_outb(ei_local->current_page-1, e8390_base+EN0_BOUNDARY);
+ dev->stats.rx_errors++;
+ continue;
+ }
+
+ if (pkt_len < 60 || pkt_len > 1518)
+ {
+ if (ei_debug)
+ printk(KERN_DEBUG "%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n",
+ dev->name, rx_frame.count, rx_frame.status,
+ rx_frame.next);
+ dev->stats.rx_errors++;
+ dev->stats.rx_length_errors++;
+ }
+ else if ((pkt_stat & 0x0F) == ENRSR_RXOK)
+ {
+ struct sk_buff *skb;
+
+ skb = dev_alloc_skb(pkt_len+2);
+ if (skb == NULL)
+ {
+ if (ei_debug > 1)
+ printk(KERN_DEBUG "%s: Couldn't allocate a sk_buff of size %d.\n",
+ dev->name, pkt_len);
+ dev->stats.rx_dropped++;
+ break;
+ }
+ else
+ {
+ skb_reserve(skb,2); /* IP headers on 16 byte boundaries */
+ skb_put(skb, pkt_len); /* Make room */
+ ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame));
+ skb->protocol=eth_type_trans(skb,dev);
+ netif_rx(skb);
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
+ if (pkt_stat & ENRSR_PHY)
+ dev->stats.multicast++;
+ }
+ }
+ else
+ {
+ if (ei_debug)
+ printk(KERN_DEBUG "%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n",
+ dev->name, rx_frame.status, rx_frame.next,
+ rx_frame.count);
+ dev->stats.rx_errors++;
+ /* NB: The NIC counts CRC, frame and missed errors. */
+ if (pkt_stat & ENRSR_FO)
+ dev->stats.rx_fifo_errors++;
+ }
+ next_frame = rx_frame.next;
+
+ /* This _should_ never happen: it's here for avoiding bad clones. */
+ if (next_frame >= ei_local->stop_page) {
+ printk("%s: next frame inconsistency, %#2x\n", dev->name,
+ next_frame);
+ next_frame = ei_local->rx_start_page;
+ }
+ ei_local->current_page = next_frame;
+ ei_outb_p(next_frame-1, e8390_base+EN0_BOUNDARY);
+ }
+
+ /* We used to also ack ENISR_OVER here, but that would sometimes mask
+ a real overrun, leaving the 8390 in a stopped state with rec'vr off. */
+ ei_outb_p(ENISR_RX+ENISR_RX_ERR, e8390_base+EN0_ISR);
+ return;
+}
+
+/**
+ * ei_rx_overrun - handle receiver overrun
+ * @dev: network device which threw exception
+ *
+ * We have a receiver overrun: we have to kick the 8390 to get it started
+ * again. Problem is that you have to kick it exactly as NS prescribes in
+ * the updated datasheets, or "the NIC may act in an unpredictable manner."
+ * This includes causing "the NIC to defer indefinitely when it is stopped
+ * on a busy network." Ugh.
+ * Called with lock held. Don't call this with the interrupts off or your
+ * computer will hate you - it takes 10ms or so.
+ */
+
+static void ei_rx_overrun(struct net_device *dev)
+{
+ unsigned long e8390_base = dev->base_addr;
+ unsigned char was_txing, must_resend = 0;
+ /* ei_local is used on some platforms via the EI_SHIFT macro */
+ struct ei_device *ei_local __maybe_unused = netdev_priv(dev);
+
+ /*
+ * Record whether a Tx was in progress and then issue the
+ * stop command.
+ */
+ was_txing = ei_inb_p(e8390_base+E8390_CMD) & E8390_TRANS;
+ ei_outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
+
+ if (ei_debug > 1)
+ printk(KERN_DEBUG "%s: Receiver overrun.\n", dev->name);
+ dev->stats.rx_over_errors++;
+
+ /*
+ * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total.
+ * Early datasheets said to poll the reset bit, but now they say that
+ * it "is not a reliable indicator and subsequently should be ignored."
+ * We wait at least 10ms.
+ */
+
+ mdelay(10);
+
+ /*
+ * Reset RBCR[01] back to zero as per magic incantation.
+ */
+ ei_outb_p(0x00, e8390_base+EN0_RCNTLO);
+ ei_outb_p(0x00, e8390_base+EN0_RCNTHI);
+
+ /*
+ * See if any Tx was interrupted or not. According to NS, this
+ * step is vital, and skipping it will cause no end of havoc.
+ */
+
+ if (was_txing)
+ {
+ unsigned char tx_completed = ei_inb_p(e8390_base+EN0_ISR) & (ENISR_TX+ENISR_TX_ERR);
+ if (!tx_completed)
+ must_resend = 1;
+ }
+
+ /*
+ * Have to enter loopback mode and then restart the NIC before
+ * you are allowed to slurp packets up off the ring.
+ */
+ ei_outb_p(E8390_TXOFF, e8390_base + EN0_TXCR);
+ ei_outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, e8390_base + E8390_CMD);
+
+ /*
+ * Clear the Rx ring of all the debris, and ack the interrupt.
+ */
+ ei_receive(dev);
+ ei_outb_p(ENISR_OVER, e8390_base+EN0_ISR);
+
+ /*
+ * Leave loopback mode, and resend any packet that got stopped.
+ */
+ ei_outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR);
+ if (must_resend)
+ ei_outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START + E8390_TRANS, e8390_base + E8390_CMD);
+}
+
+/*
+ * Collect the stats. This is called unlocked and from several contexts.
+ */
+
+static struct net_device_stats *__ei_get_stats(struct net_device *dev)
+{
+ unsigned long ioaddr = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ unsigned long flags;
+
+ /* If the card is stopped, just return the present stats. */
+ if (!netif_running(dev))
+ return &dev->stats;
+
+ spin_lock_irqsave(&ei_local->page_lock,flags);
+ /* Read the counter registers, assuming we are in page 0. */
+ dev->stats.rx_frame_errors += ei_inb_p(ioaddr + EN0_COUNTER0);
+ dev->stats.rx_crc_errors += ei_inb_p(ioaddr + EN0_COUNTER1);
+ dev->stats.rx_missed_errors+= ei_inb_p(ioaddr + EN0_COUNTER2);
+ spin_unlock_irqrestore(&ei_local->page_lock, flags);
+
+ return &dev->stats;
+}
+
+/*
+ * Form the 64 bit 8390 multicast table from the linked list of addresses
+ * associated with this dev structure.
+ */
+
+static inline void make_mc_bits(u8 *bits, struct net_device *dev)
+{
+ struct dev_mc_list *dmi;
+
+ for (dmi=dev->mc_list; dmi; dmi=dmi->next)
+ {
+ u32 crc;
+ if (dmi->dmi_addrlen != ETH_ALEN)
+ {
+ printk(KERN_INFO "%s: invalid multicast address length given.\n", dev->name);
+ continue;
+ }
+ crc = ether_crc(ETH_ALEN, dmi->dmi_addr);
+ /*
+ * The 8390 uses the 6 most significant bits of the
+ * CRC to index the multicast table.
+ */
+ bits[crc>>29] |= (1<<((crc>>26)&7));
+ }
+}
+
+/**
+ * do_set_multicast_list - set/clear multicast filter
+ * @dev: net device for which multicast filter is adjusted
+ *
+ * Set or clear the multicast filter for this adaptor. May be called
+ * from a BH in 2.1.x. Must be called with lock held.
+ */
+
+static void do_set_multicast_list(struct net_device *dev)
+{
+ unsigned long e8390_base = dev->base_addr;
+ int i;
+ struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev);
+
+ if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI)))
+ {
+ memset(ei_local->mcfilter, 0, 8);
+ if (dev->mc_list)
+ make_mc_bits(ei_local->mcfilter, dev);
+ }
+ else
+ memset(ei_local->mcfilter, 0xFF, 8); /* mcast set to accept-all */
+
+ /*
+ * DP8390 manuals don't specify any magic sequence for altering
+ * the multicast regs on an already running card. To be safe, we
+ * ensure multicast mode is off prior to loading up the new hash
+ * table. If this proves to be not enough, we can always resort
+ * to stopping the NIC, loading the table and then restarting.
+ *
+ * Bug Alert! The MC regs on the SMC 83C690 (SMC Elite and SMC
+ * Elite16) appear to be write-only. The NS 8390 data sheet lists
+ * them as r/w so this is a bug. The SMC 83C790 (SMC Ultra and
+ * Ultra32 EISA) appears to have this bug fixed.
+ */
+
+ if (netif_running(dev))
+ ei_outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
+ ei_outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD);
+ for(i = 0; i < 8; i++)
+ {
+ ei_outb_p(ei_local->mcfilter[i], e8390_base + EN1_MULT_SHIFT(i));
+#ifndef BUG_83C690
+ if(ei_inb_p(e8390_base + EN1_MULT_SHIFT(i))!=ei_local->mcfilter[i])
+ printk(KERN_ERR "Multicast filter read/write mismap %d\n",i);
+#endif
+ }
+ ei_outb_p(E8390_NODMA + E8390_PAGE0, e8390_base + E8390_CMD);
+
+ if(dev->flags&IFF_PROMISC)
+ ei_outb_p(E8390_RXCONFIG | 0x18, e8390_base + EN0_RXCR);
+ else if(dev->flags&IFF_ALLMULTI || dev->mc_list)
+ ei_outb_p(E8390_RXCONFIG | 0x08, e8390_base + EN0_RXCR);
+ else
+ ei_outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
+ }
+
+/*
+ * Called without lock held. This is invoked from user context and may
+ * be parallel to just about everything else. Its also fairly quick and
+ * not called too often. Must protect against both bh and irq users
+ */
+
+static void __ei_set_multicast_list(struct net_device *dev)
+{
+ unsigned long flags;
+ struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev);
+
+ spin_lock_irqsave(&ei_local->page_lock, flags);
+ do_set_multicast_list(dev);
+ spin_unlock_irqrestore(&ei_local->page_lock, flags);
+}
+
+/**
+ * ethdev_setup - init rest of 8390 device struct
+ * @dev: network device structure to init
+ *
+ * Initialize the rest of the 8390 device structure. Do NOT __init
+ * this, as it is used by 8390 based modular drivers too.
+ */
+
+static void ethdev_setup(struct net_device *dev)
+{
+ struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ if (ei_debug > 1)
+ printk(version);
+
+ ether_setup(dev);
+
+ spin_lock_init(&ei_local->page_lock);
+}
+
+/**
+ * alloc_ei_netdev - alloc_etherdev counterpart for 8390
+ * @size: extra bytes to allocate
+ *
+ * Allocate 8390-specific net_device.
+ */
+static struct net_device *____alloc_ei_netdev(int size)
+{
+ return alloc_netdev(sizeof(struct ei_device) + size, "eth%d",
+ ethdev_setup);
+}
+
+
+
+
+/* This page of functions should be 8390 generic */
+/* Follow National Semi's recommendations for initializing the "NIC". */
+
+/**
+ * NS8390_init - initialize 8390 hardware
+ * @dev: network device to initialize
+ * @startp: boolean. non-zero value to initiate chip processing
+ *
+ * Must be called with lock held.
+ */
+
+static void __NS8390_init(struct net_device *dev, int startp)
+{
+ unsigned long e8390_base = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
+ int i;
+ int endcfg = ei_local->word16
+ ? (0x48 | ENDCFG_WTS | (ei_local->bigendian ? ENDCFG_BOS : 0))
+ : 0x48;
+
+ if(sizeof(struct e8390_pkt_hdr)!=4)
+ panic("8390.c: header struct mispacked\n");
+ /* Follow National Semi's recommendations for initing the DP83902. */
+ ei_outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); /* 0x21 */
+ ei_outb_p(endcfg, e8390_base + EN0_DCFG); /* 0x48 or 0x49 */
+ /* Clear the remote byte count registers. */
+ ei_outb_p(0x00, e8390_base + EN0_RCNTLO);
+ ei_outb_p(0x00, e8390_base + EN0_RCNTHI);
+ /* Set to monitor and loopback mode -- this is vital!. */
+ ei_outb_p(E8390_RXOFF, e8390_base + EN0_RXCR); /* 0x20 */
+ ei_outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */
+ /* Set the transmit page and receive ring. */
+ ei_outb_p(ei_local->tx_start_page, e8390_base + EN0_TPSR);
+ ei_local->tx1 = ei_local->tx2 = 0;
+ ei_outb_p(ei_local->rx_start_page, e8390_base + EN0_STARTPG);
+ ei_outb_p(ei_local->stop_page-1, e8390_base + EN0_BOUNDARY); /* 3c503 says 0x3f,NS0x26*/
+ ei_local->current_page = ei_local->rx_start_page; /* assert boundary+1 */
+ ei_outb_p(ei_local->stop_page, e8390_base + EN0_STOPPG);
+ /* Clear the pending interrupts and mask. */
+ ei_outb_p(0xFF, e8390_base + EN0_ISR);
+ ei_outb_p(0x00, e8390_base + EN0_IMR);
+
+ /* Copy the station address into the DS8390 registers. */
+
+ ei_outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base+E8390_CMD); /* 0x61 */
+ for(i = 0; i < 6; i++)
+ {
+ ei_outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS_SHIFT(i));
+ if (ei_debug > 1 && ei_inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i])
+ printk(KERN_ERR "Hw. address read/write mismap %d\n",i);
+ }
+
+ ei_outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
+ ei_outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
+
+ netif_start_queue(dev);
+ ei_local->tx1 = ei_local->tx2 = 0;
+ ei_local->txing = 0;
+
+ if (startp)
+ {
+ ei_outb_p(0xff, e8390_base + EN0_ISR);
+ ei_outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+ ei_outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base+E8390_CMD);
+ ei_outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */
+ /* 3c503 TechMan says rxconfig only after the NIC is started. */
+ ei_outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on, */
+ do_set_multicast_list(dev); /* (re)load the mcast table */
+ }
+}
+
+/* Trigger a transmit start, assuming the length is valid.
+ Always called with the page lock held */
+
+static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
+ int start_page)
+{
+ unsigned long e8390_base = dev->base_addr;
+ struct ei_device *ei_local __attribute((unused)) = (struct ei_device *) netdev_priv(dev);
+
+ ei_outb_p(E8390_NODMA+E8390_PAGE0, e8390_base+E8390_CMD);
+
+ if (ei_inb_p(e8390_base + E8390_CMD) & E8390_TRANS)
+ {
+ printk(KERN_WARNING "%s: trigger_send() called with the transmitter busy.\n",
+ dev->name);
+ return;
+ }
+ ei_outb_p(length & 0xff, e8390_base + EN0_TCNTLO);
+ ei_outb_p(length >> 8, e8390_base + EN0_TCNTHI);
+ ei_outb_p(start_page, e8390_base + EN0_TPSR);
+ ei_outb_p(E8390_NODMA+E8390_TRANS+E8390_START, e8390_base+E8390_CMD);
+}
diff --git a/libdde_linux26/examples/ne2k/main.c b/libdde_linux26/examples/ne2k/main.c
new file mode 100644
index 00000000..8dba2f00
--- /dev/null
+++ b/libdde_linux26/examples/ne2k/main.c
@@ -0,0 +1,115 @@
+#include <l4/dde/linux26/dde26.h> /* l4dde26_*() */
+#include <l4/dde/linux26/dde26_net.h> /* l4dde26 networking */
+#include <l4/sys/types.h> /* l4_threadid_t */
+#include <l4/sys/ipc.h> /* l4_ipc_*() */
+
+#include <linux/netdevice.h> /* struct sk_buff */
+#include <linux/pci.h> /* pci_unregister_driver() */
+#include <linux/init.h> // initcall()
+#include <linux/delay.h> // msleep()
+
+#include "arping.h"
+
+#include "8390.h" /* that's what we are */
+
+extern int arping_verbose;
+#define VERBOSE_LOG(fmt, ...) \
+ do { \
+ if (arping_verbose) printk(fmt, ##__VA_ARGS__); \
+ } while (0);
+
+extern struct pci_driver ne2k_driver;
+extern int arping(void);
+
+void open_nw_dev(void);
+void open_nw_dev()
+{
+ struct net_device *dev;
+ struct net *net;
+
+ read_lock(&dev_base_lock);
+ for_each_net(net) {
+ for_each_netdev(net, dev) {
+ int err = 0;
+ printk("dev: '%s'\n", dev->name);
+ printk("MAC: "mac_fmt"\n", mac_str(dev->dev_addr));
+
+ err = dev_open(dev);
+ }
+ }
+ read_unlock(&dev_base_lock);
+}
+
+void close_nw_dev(void);
+void close_nw_dev(void)
+{
+ struct net_device *dev;
+ struct net *net;
+
+ read_lock(&dev_base_lock);
+ for_each_net(net) {
+ for_each_netdev(net, dev) {
+ int err = 0;
+
+ err = dev_close(dev);
+ printk("closed %s\n", dev->name);
+ }
+ }
+ read_unlock(&dev_base_lock);
+}
+
+static int net_rx_handle(struct sk_buff *skb)
+{
+ skb_push(skb, skb->dev->hard_header_len);
+
+ struct arping_elem *e = kmalloc(sizeof(struct arping_elem), GFP_KERNEL);
+ e->skb = skb;
+ skb_get(skb);
+ e->next = NULL;
+
+ if (arping_list == NULL)
+ arping_list = e;
+ else {
+ struct arping_elem *f = arping_list;
+ while (f->next)
+ f = f->next;
+ f->next = e;
+ }
+
+ ddekit_sem_up(arping_semaphore);
+
+ kfree_skb(skb);
+
+ VERBOSE_LOG("freed skb, returning from netif_rx\n");
+ return NET_RX_SUCCESS;
+}
+
+//subsys_initcall(l4dde26_init_pci);
+
+int main(int argc, char **argv);
+int main(int argc, char **argv)
+{
+ l4dde26_init();
+ l4dde26_process_init();
+ l4dde26_softirq_init();
+
+ printk("Initializing skb subsystem\n");
+ skb_init();
+
+ l4dde26_do_initcalls();
+ printk("Setting rx callback @ %p\n", net_rx_handle);
+ l4dde26_register_rx_callback(net_rx_handle);
+
+ printk("Opening nw devs.\n");
+ open_nw_dev();
+ printk("dev is up and ready.\n");
+
+ arping();
+
+ close_nw_dev();
+
+ pci_unregister_driver(&ne2k_driver);
+ printk("shut down driver\n");
+
+ return 0;
+}
diff --git a/libdde_linux26/examples/ne2k/ne2k-pci.c b/libdde_linux26/examples/ne2k/ne2k-pci.c
new file mode 100644
index 00000000..c9995d36
--- /dev/null
+++ b/libdde_linux26/examples/ne2k/ne2k-pci.c
@@ -0,0 +1,727 @@
+/* ne2k-pci.c: A NE2000 clone on PCI bus driver for Linux. */
+/*
+ A Linux device driver for PCI NE2000 clones.
+
+ Authors and other copyright holders:
+ 1992-2000 by Donald Becker, NE2000 core and various modifications.
+ 1995-1998 by Paul Gortmaker, core modifications and PCI support.
+ Copyright 1993 assigned to the United States Government as represented
+ by the Director, National Security Agency.
+
+ This software may be used and distributed according to the terms of
+ the GNU General Public License (GPL), incorporated herein by reference.
+ Drivers based on or derived from this code fall under the GPL and must
+ retain the authorship, copyright and license notice. This file is not
+ a complete program and may only be used when the entire operating
+ system is licensed under the GPL.
+
+ The author may be reached as becker@scyld.com, or C/O
+ Scyld Computing Corporation
+ 410 Severn Ave., Suite 210
+ Annapolis MD 21403
+
+ Issues remaining:
+ People are making PCI ne2000 clones! Oh the horror, the horror...
+ Limited full-duplex support.
+*/
+
+#define DRV_NAME "ne2k-pci"
+#define DRV_VERSION "1.03"
+#define DRV_RELDATE "9/22/2003"
+
+
+/* The user-configurable values.
+ These may be modified when a driver module is loaded.*/
+
+static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
+
+#define MAX_UNITS 8 /* More are supported, limit only on options */
+/* Used to pass the full-duplex flag, etc. */
+static int full_duplex[MAX_UNITS];
+static int options[MAX_UNITS];
+
+/* Force a non std. amount of memory. Units are 256 byte pages. */
+/* #define PACKETBUF_MEMSIZE 0x40 */
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include "8390.h"
+
+/* These identify the driver base version and may not be removed. */
+static char version[] __devinitdata =
+KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " D. Becker/P. Gortmaker\n";
+
+#if defined(__powerpc__)
+#define inl_le(addr) le32_to_cpu(inl(addr))
+#define inw_le(addr) le16_to_cpu(inw(addr))
+#endif
+
+#define PFX DRV_NAME ": "
+
+MODULE_AUTHOR("Donald Becker / Paul Gortmaker");
+MODULE_DESCRIPTION("PCI NE2000 clone driver");
+MODULE_LICENSE("GPL");
+
+module_param(debug, int, 0);
+module_param_array(options, int, NULL, 0);
+module_param_array(full_duplex, int, NULL, 0);
+MODULE_PARM_DESC(debug, "debug level (1-2)");
+MODULE_PARM_DESC(options, "Bit 5: full duplex");
+MODULE_PARM_DESC(full_duplex, "full duplex setting(s) (1)");
+
+/* Some defines that people can play with if so inclined. */
+
+/* Use 32 bit data-movement operations instead of 16 bit. */
+#define USE_LONGIO
+
+/* Do we implement the read before write bugfix ? */
+/* #define NE_RW_BUGFIX */
+
+/* Flags. We rename an existing ei_status field to store flags! */
+/* Thus only the low 8 bits are usable for non-init-time flags. */
+#define ne2k_flags reg0
+enum {
+ ONLY_16BIT_IO=8, ONLY_32BIT_IO=4, /* Chip can do only 16/32-bit xfers. */
+ FORCE_FDX=0x20, /* User override. */
+ REALTEK_FDX=0x40, HOLTEK_FDX=0x80,
+ STOP_PG_0x60=0x100,
+};
+
+enum ne2k_pci_chipsets {
+ CH_RealTek_RTL_8029 = 0,
+ CH_Winbond_89C940,
+ CH_Compex_RL2000,
+ CH_KTI_ET32P2,
+ CH_NetVin_NV5000SC,
+ CH_Via_86C926,
+ CH_SureCom_NE34,
+ CH_Winbond_W89C940F,
+ CH_Holtek_HT80232,
+ CH_Holtek_HT80229,
+ CH_Winbond_89C940_8c4a,
+};
+
+
+static struct {
+ char *name;
+ int flags;
+} pci_clone_list[] __devinitdata = {
+ {"RealTek RTL-8029", REALTEK_FDX},
+ {"Winbond 89C940", 0},
+ {"Compex RL2000", 0},
+ {"KTI ET32P2", 0},
+ {"NetVin NV5000SC", 0},
+ {"Via 86C926", ONLY_16BIT_IO},
+ {"SureCom NE34", 0},
+ {"Winbond W89C940F", 0},
+ {"Holtek HT80232", ONLY_16BIT_IO | HOLTEK_FDX},
+ {"Holtek HT80229", ONLY_32BIT_IO | HOLTEK_FDX | STOP_PG_0x60 },
+ {"Winbond W89C940(misprogrammed)", 0},
+ {NULL,}
+};
+
+
+static struct pci_device_id ne2k_pci_tbl[] = {
+ { 0x10ec, 0x8029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_RealTek_RTL_8029 },
+ { 0x1050, 0x0940, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_89C940 },
+ { 0x11f6, 0x1401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Compex_RL2000 },
+ { 0x8e2e, 0x3000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_KTI_ET32P2 },
+ { 0x4a14, 0x5000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_NetVin_NV5000SC },
+ { 0x1106, 0x0926, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Via_86C926 },
+ { 0x10bd, 0x0e34, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_SureCom_NE34 },
+ { 0x1050, 0x5a5a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_W89C940F },
+ { 0x12c3, 0x0058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Holtek_HT80232 },
+ { 0x12c3, 0x5598, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Holtek_HT80229 },
+ { 0x8c4a, 0x1980, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Winbond_89C940_8c4a },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, ne2k_pci_tbl);
+
+
+/* ---- No user-serviceable parts below ---- */
+
+#define NE_BASE (dev->base_addr)
+#define NE_CMD 0x00
+#define NE_DATAPORT 0x10 /* NatSemi-defined port window offset. */
+#define NE_RESET 0x1f /* Issue a read to reset, a write to clear. */
+#define NE_IO_EXTENT 0x20
+
+#define NESM_START_PG 0x40 /* First page of TX buffer */
+#define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */
+
+
+static int ne2k_pci_open(struct net_device *dev);
+static int ne2k_pci_close(struct net_device *dev);
+
+static void ne2k_pci_reset_8390(struct net_device *dev);
+static void ne2k_pci_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
+ int ring_page);
+static void ne2k_pci_block_input(struct net_device *dev, int count,
+ struct sk_buff *skb, int ring_offset);
+static void ne2k_pci_block_output(struct net_device *dev, const int count,
+ const unsigned char *buf, const int start_page);
+static const struct ethtool_ops ne2k_pci_ethtool_ops;
+
+
+
+/* There is no room in the standard 8390 structure for extra info we need,
+ so we build a meta/outer-wrapper structure.. */
+struct ne2k_pci_card {
+ struct net_device *dev;
+ struct pci_dev *pci_dev;
+};
+
+
+
+/*
+ NEx000-clone boards have a Station Address (SA) PROM (SAPROM) in the packet
+ buffer memory space. By-the-spec NE2000 clones have 0x57,0x57 in bytes
+ 0x0e,0x0f of the SAPROM, while other supposed NE2000 clones must be
+ detected by their SA prefix.
+
+ Reading the SAPROM from a word-wide card with the 8390 set in byte-wide
+ mode results in doubled values, which can be detected and compensated for.
+
+ The probe is also responsible for initializing the card and filling
+ in the 'dev' and 'ei_status' structures.
+*/
+
+static const struct net_device_ops ne2k_netdev_ops = {
+ .ndo_open = ne2k_pci_open,
+ .ndo_stop = ne2k_pci_close,
+ .ndo_start_xmit = ei_start_xmit,
+ .ndo_tx_timeout = ei_tx_timeout,
+ .ndo_get_stats = ei_get_stats,
+ .ndo_set_multicast_list = ei_set_multicast_list,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_change_mtu = eth_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = ei_poll,
+#endif
+};
+
+static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct net_device *dev;
+ int i;
+ unsigned char SA_prom[32];
+ int start_page, stop_page;
+ int irq, reg0, chip_idx = ent->driver_data;
+ static unsigned int fnd_cnt;
+ long ioaddr;
+ int flags = pci_clone_list[chip_idx].flags;
+
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+ static int printed_version;
+ if (!printed_version++)
+ printk(version);
+#endif
+
+ fnd_cnt++;
+
+ i = pci_enable_device (pdev);
+ if (i)
+ return i;
+
+ ioaddr = pci_resource_start (pdev, 0);
+ irq = pdev->irq;
+
+ if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_IO) == 0)) {
+ dev_err(&pdev->dev, "no I/O resource at PCI BAR #0\n");
+ return -ENODEV;
+ }
+
+ if (request_region (ioaddr, NE_IO_EXTENT, DRV_NAME) == NULL) {
+ dev_err(&pdev->dev, "I/O resource 0x%x @ 0x%lx busy\n",
+ NE_IO_EXTENT, ioaddr);
+ return -EBUSY;
+ }
+
+ reg0 = inb(ioaddr);
+ if (reg0 == 0xFF)
+ goto err_out_free_res;
+
+ /* Do a preliminary verification that we have a 8390. */
+ {
+ int regd;
+ outb(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD);
+ regd = inb(ioaddr + 0x0d);
+ outb(0xff, ioaddr + 0x0d);
+ outb(E8390_NODMA+E8390_PAGE0, ioaddr + E8390_CMD);
+ inb(ioaddr + EN0_COUNTER0); /* Clear the counter by reading. */
+ if (inb(ioaddr + EN0_COUNTER0) != 0) {
+ outb(reg0, ioaddr);
+ outb(regd, ioaddr + 0x0d); /* Restore the old values. */
+ goto err_out_free_res;
+ }
+ }
+
+ /* Allocate net_device, dev->priv; fill in 8390 specific dev fields. */
+ dev = alloc_ei_netdev();
+ if (!dev) {
+ dev_err(&pdev->dev, "cannot allocate ethernet device\n");
+ goto err_out_free_res;
+ }
+ dev->netdev_ops = &ne2k_netdev_ops;
+
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ /* Reset card. Who knows what dain-bramaged state it was left in. */
+ {
+ unsigned long reset_start_time = jiffies;
+
+ outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET);
+
+ /* This looks like a horrible timing loop, but it should never take
+ more than a few cycles.
+ */
+ while ((inb(ioaddr + EN0_ISR) & ENISR_RESET) == 0)
+ /* Limit wait: '2' avoids jiffy roll-over. */
+ if (jiffies - reset_start_time > 2) {
+ dev_err(&pdev->dev,
+ "Card failure (no reset ack).\n");
+ goto err_out_free_netdev;
+ }
+
+ outb(0xff, ioaddr + EN0_ISR); /* Ack all intr. */
+ }
+
+ /* Read the 16 bytes of station address PROM.
+ We must first initialize registers, similar to NS8390_init(eifdev, 0).
+ We can't reliably read the SAPROM address without this.
+ (I learned the hard way!). */
+ {
+ struct {unsigned char value, offset; } program_seq[] = {
+ {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
+ {0x49, EN0_DCFG}, /* Set word-wide access. */
+ {0x00, EN0_RCNTLO}, /* Clear the count regs. */
+ {0x00, EN0_RCNTHI},
+ {0x00, EN0_IMR}, /* Mask completion irq. */
+ {0xFF, EN0_ISR},
+ {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */
+ {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */
+ {32, EN0_RCNTLO},
+ {0x00, EN0_RCNTHI},
+ {0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */
+ {0x00, EN0_RSARHI},
+ {E8390_RREAD+E8390_START, E8390_CMD},
+ };
+ for (i = 0; i < ARRAY_SIZE(program_seq); i++)
+ outb(program_seq[i].value, ioaddr + program_seq[i].offset);
+
+ }
+
+ /* Note: all PCI cards have at least 16 bit access, so we don't have
+ to check for 8 bit cards. Most cards permit 32 bit access. */
+ if (flags & ONLY_32BIT_IO) {
+ for (i = 0; i < 4 ; i++)
+ ((u32 *)SA_prom)[i] = le32_to_cpu(inl(ioaddr + NE_DATAPORT));
+ } else
+ for(i = 0; i < 32 /*sizeof(SA_prom)*/; i++)
+ SA_prom[i] = inb(ioaddr + NE_DATAPORT);
+
+ /* We always set the 8390 registers for word mode. */
+ outb(0x49, ioaddr + EN0_DCFG);
+ start_page = NESM_START_PG;
+
+ stop_page = flags & STOP_PG_0x60 ? 0x60 : NESM_STOP_PG;
+
+ /* Set up the rest of the parameters. */
+ dev->irq = irq;
+ dev->base_addr = ioaddr;
+ pci_set_drvdata(pdev, dev);
+
+ ei_status.name = pci_clone_list[chip_idx].name;
+ ei_status.tx_start_page = start_page;
+ ei_status.stop_page = stop_page;
+ ei_status.word16 = 1;
+ ei_status.ne2k_flags = flags;
+ if (fnd_cnt < MAX_UNITS) {
+ if (full_duplex[fnd_cnt] > 0 || (options[fnd_cnt] & FORCE_FDX))
+ ei_status.ne2k_flags |= FORCE_FDX;
+ }
+
+ ei_status.rx_start_page = start_page + TX_PAGES;
+#ifdef PACKETBUF_MEMSIZE
+ /* Allow the packet buffer size to be overridden by know-it-alls. */
+ ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE;
+#endif
+
+ ei_status.reset_8390 = &ne2k_pci_reset_8390;
+ ei_status.block_input = &ne2k_pci_block_input;
+ ei_status.block_output = &ne2k_pci_block_output;
+ ei_status.get_8390_hdr = &ne2k_pci_get_8390_hdr;
+ ei_status.priv = (unsigned long) pdev;
+
+ dev->ethtool_ops = &ne2k_pci_ethtool_ops;
+ NS8390_init(dev, 0);
+
+ i = register_netdev(dev);
+ if (i)
+ goto err_out_free_netdev;
+
+ for(i = 0; i < 6; i++)
+ dev->dev_addr[i] = SA_prom[i];
+ printk("%s: %s found at %#lx, IRQ %d, %pM.\n",
+ dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq,
+ dev->dev_addr);
+
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
+ return 0;
+
+err_out_free_netdev:
+ free_netdev (dev);
+err_out_free_res:
+ release_region (ioaddr, NE_IO_EXTENT);
+ pci_set_drvdata (pdev, NULL);
+ return -ENODEV;
+
+}
+
+/*
+ * Magic incantation sequence for full duplex on the supported cards.
+ */
+static inline int set_realtek_fdx(struct net_device *dev)
+{
+ long ioaddr = dev->base_addr;
+
+ outb(0xC0 + E8390_NODMA, ioaddr + NE_CMD); /* Page 3 */
+ outb(0xC0, ioaddr + 0x01); /* Enable writes to CONFIG3 */
+ outb(0x40, ioaddr + 0x06); /* Enable full duplex */
+ outb(0x00, ioaddr + 0x01); /* Disable writes to CONFIG3 */
+ outb(E8390_PAGE0 + E8390_NODMA, ioaddr + NE_CMD); /* Page 0 */
+ return 0;
+}
+
+static inline int set_holtek_fdx(struct net_device *dev)
+{
+ long ioaddr = dev->base_addr;
+
+ outb(inb(ioaddr + 0x20) | 0x80, ioaddr + 0x20);
+ return 0;
+}
+
+static int ne2k_pci_set_fdx(struct net_device *dev)
+{
+ if (ei_status.ne2k_flags & REALTEK_FDX)
+ return set_realtek_fdx(dev);
+ else if (ei_status.ne2k_flags & HOLTEK_FDX)
+ return set_holtek_fdx(dev);
+
+ return -EOPNOTSUPP;
+}
+
+static int ne2k_pci_open(struct net_device *dev)
+{
+ int ret = request_irq(dev->irq, ei_interrupt, IRQF_SHARED, dev->name, dev);
+ if (ret)
+ return ret;
+
+ if (ei_status.ne2k_flags & FORCE_FDX)
+ ne2k_pci_set_fdx(dev);
+
+ ei_open(dev);
+ return 0;
+}
+
+static int ne2k_pci_close(struct net_device *dev)
+{
+ ei_close(dev);
+ free_irq(dev->irq, dev);
+ return 0;
+}
+
+/* Hard reset the card. This used to pause for the same period that a
+ 8390 reset command required, but that shouldn't be necessary. */
+static void ne2k_pci_reset_8390(struct net_device *dev)
+{
+ unsigned long reset_start_time = jiffies;
+
+ if (debug > 1) printk("%s: Resetting the 8390 t=%ld...",
+ dev->name, jiffies);
+
+ outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);
+
+ ei_status.txing = 0;
+ ei_status.dmaing = 0;
+
+ /* This check _should_not_ be necessary, omit eventually. */
+ while ((inb(NE_BASE+EN0_ISR) & ENISR_RESET) == 0)
+ if (jiffies - reset_start_time > 2) {
+ printk("%s: ne2k_pci_reset_8390() did not complete.\n", dev->name);
+ break;
+ }
+ outb(ENISR_RESET, NE_BASE + EN0_ISR); /* Ack intr. */
+}
+
+/* Grab the 8390 specific header. Similar to the block_input routine, but
+ we don't need to be concerned with ring wrap as the header will be at
+ the start of a page, so we optimize accordingly. */
+
+static void ne2k_pci_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+
+ long nic_base = dev->base_addr;
+
+ /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+ if (ei_status.dmaing) {
+ printk("%s: DMAing conflict in ne2k_pci_get_8390_hdr "
+ "[DMAstat:%d][irqlock:%d].\n",
+ dev->name, ei_status.dmaing, ei_status.irqlock);
+ return;
+ }
+
+ ei_status.dmaing |= 0x01;
+ outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+ outb(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
+ outb(0, nic_base + EN0_RCNTHI);
+ outb(0, nic_base + EN0_RSARLO); /* On page boundary */
+ outb(ring_page, nic_base + EN0_RSARHI);
+ outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+
+ if (ei_status.ne2k_flags & ONLY_16BIT_IO) {
+ insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
+ } else {
+ *(u32*)hdr = le32_to_cpu(inl(NE_BASE + NE_DATAPORT));
+ le16_to_cpus(&hdr->count);
+ }
+
+ outb(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */
+ ei_status.dmaing &= ~0x01;
+}
+
+/* Block input and output, similar to the Crynwr packet driver. If you
+ are porting to a new ethercard, look at the packet driver source for hints.
+ The NEx000 doesn't share the on-board packet memory -- you have to put
+ the packet out through the "remote DMA" dataport using outb. */
+
+static void ne2k_pci_block_input(struct net_device *dev, int count,
+ struct sk_buff *skb, int ring_offset)
+{
+ long nic_base = dev->base_addr;
+ char *buf = skb->data;
+
+ /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+ if (ei_status.dmaing) {
+ printk("%s: DMAing conflict in ne2k_pci_block_input "
+ "[DMAstat:%d][irqlock:%d].\n",
+ dev->name, ei_status.dmaing, ei_status.irqlock);
+ return;
+ }
+ ei_status.dmaing |= 0x01;
+ if (ei_status.ne2k_flags & ONLY_32BIT_IO)
+ count = (count + 3) & 0xFFFC;
+ outb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+ outb(count & 0xff, nic_base + EN0_RCNTLO);
+ outb(count >> 8, nic_base + EN0_RCNTHI);
+ outb(ring_offset & 0xff, nic_base + EN0_RSARLO);
+ outb(ring_offset >> 8, nic_base + EN0_RSARHI);
+ outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+
+ if (ei_status.ne2k_flags & ONLY_16BIT_IO) {
+ insw(NE_BASE + NE_DATAPORT,buf,count>>1);
+ if (count & 0x01) {
+ buf[count-1] = inb(NE_BASE + NE_DATAPORT);
+ }
+ } else {
+ insl(NE_BASE + NE_DATAPORT, buf, count>>2);
+ if (count & 3) {
+ buf += count & ~3;
+ if (count & 2) {
+ __le16 *b = (__le16 *)buf;
+
+ *b++ = cpu_to_le16(inw(NE_BASE + NE_DATAPORT));
+ buf = (char *)b;
+ }
+ if (count & 1)
+ *buf = inb(NE_BASE + NE_DATAPORT);
+ }
+ }
+
+ outb(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */
+ ei_status.dmaing &= ~0x01;
+}
+
+static void ne2k_pci_block_output(struct net_device *dev, int count,
+ const unsigned char *buf, const int start_page)
+{
+ long nic_base = NE_BASE;
+ unsigned long dma_start;
+
+ /* On little-endian it's always safe to round the count up for
+ word writes. */
+ if (ei_status.ne2k_flags & ONLY_32BIT_IO)
+ count = (count + 3) & 0xFFFC;
+ else
+ if (count & 0x01)
+ count++;
+
+ /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+ if (ei_status.dmaing) {
+ printk("%s: DMAing conflict in ne2k_pci_block_output."
+ "[DMAstat:%d][irqlock:%d]\n",
+ dev->name, ei_status.dmaing, ei_status.irqlock);
+ return;
+ }
+ ei_status.dmaing |= 0x01;
+ /* We should already be in page 0, but to be safe... */
+ outb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
+
+#ifdef NE8390_RW_BUGFIX
+ /* Handle the read-before-write bug the same way as the
+ Crynwr packet driver -- the NatSemi method doesn't work.
+ Actually this doesn't always work either, but if you have
+ problems with your NEx000 this is better than nothing! */
+ outb(0x42, nic_base + EN0_RCNTLO);
+ outb(0x00, nic_base + EN0_RCNTHI);
+ outb(0x42, nic_base + EN0_RSARLO);
+ outb(0x00, nic_base + EN0_RSARHI);
+ outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+#endif
+ outb(ENISR_RDC, nic_base + EN0_ISR);
+
+ /* Now the normal output. */
+ outb(count & 0xff, nic_base + EN0_RCNTLO);
+ outb(count >> 8, nic_base + EN0_RCNTHI);
+ outb(0x00, nic_base + EN0_RSARLO);
+ outb(start_page, nic_base + EN0_RSARHI);
+ outb(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
+ if (ei_status.ne2k_flags & ONLY_16BIT_IO) {
+ outsw(NE_BASE + NE_DATAPORT, buf, count>>1);
+ } else {
+ outsl(NE_BASE + NE_DATAPORT, buf, count>>2);
+ if (count & 3) {
+ buf += count & ~3;
+ if (count & 2) {
+ __le16 *b = (__le16 *)buf;
+
+ outw(le16_to_cpu(*b++), NE_BASE + NE_DATAPORT);
+ buf = (char *)b;
+ }
+ }
+ }
+
+ dma_start = jiffies;
+
+ while ((inb(nic_base + EN0_ISR) & ENISR_RDC) == 0)
+ if (jiffies - dma_start > 2) { /* Avoid clock roll-over. */
+ printk(KERN_WARNING "%s: timeout waiting for Tx RDC.\n", dev->name);
+ ne2k_pci_reset_8390(dev);
+ NS8390_init(dev,1);
+ break;
+ }
+
+ outb(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */
+ ei_status.dmaing &= ~0x01;
+ return;
+}
+
+static void ne2k_pci_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ struct ei_device *ei = netdev_priv(dev);
+ struct pci_dev *pci_dev = (struct pci_dev *) ei->priv;
+
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ strcpy(info->bus_info, pci_name(pci_dev));
+}
+
+static const struct ethtool_ops ne2k_pci_ethtool_ops = {
+ .get_drvinfo = ne2k_pci_get_drvinfo,
+};
+
+static void __devexit ne2k_pci_remove_one (struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+
+ BUG_ON(!dev);
+ unregister_netdev(dev);
+ release_region(dev->base_addr, NE_IO_EXTENT);
+ free_netdev(dev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+}
+
+#ifdef CONFIG_PM
+static int ne2k_pci_suspend (struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *dev = pci_get_drvdata (pdev);
+
+ netif_device_detach(dev);
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+ return 0;
+}
+
+static int ne2k_pci_resume (struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata (pdev);
+ int rc;
+
+ pci_set_power_state(pdev, 0);
+ pci_restore_state(pdev);
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ NS8390_init(dev, 1);
+ netif_device_attach(dev);
+
+ return 0;
+}
+
+#endif /* CONFIG_PM */
+
+
+struct pci_driver ne2k_driver = {
+ .name = DRV_NAME,
+ .probe = ne2k_pci_init_one,
+ .remove = __devexit_p(ne2k_pci_remove_one),
+ .id_table = ne2k_pci_tbl,
+#ifdef CONFIG_PM
+ .suspend = ne2k_pci_suspend,
+ .resume = ne2k_pci_resume,
+#endif /* CONFIG_PM */
+
+};
+
+
+int __init ne2k_pci_init(void)
+{
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+ printk(version);
+#endif
+ return pci_register_driver(&ne2k_driver);
+}
+
+
+static void __exit ne2k_pci_cleanup(void)
+{
+ pci_unregister_driver (&ne2k_driver);
+}
+
+module_init(ne2k_pci_init);
+module_exit(ne2k_pci_cleanup);
diff --git a/libdde_linux26/examples/unittest/.svn/all-wcprops b/libdde_linux26/examples/unittest/.svn/all-wcprops
new file mode 100644
index 00000000..d074c667
--- /dev/null
+++ b/libdde_linux26/examples/unittest/.svn/all-wcprops
@@ -0,0 +1,17 @@
+K 25
+svn:wc:ra_dav:version-url
+V 68
+/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/linux26/examples/unittest
+END
+main.c
+K 25
+svn:wc:ra_dav:version-url
+V 75
+/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/linux26/examples/unittest/main.c
+END
+Makefile
+K 25
+svn:wc:ra_dav:version-url
+V 77
+/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/linux26/examples/unittest/Makefile
+END
diff --git a/libdde_linux26/examples/unittest/.svn/entries b/libdde_linux26/examples/unittest/.svn/entries
new file mode 100644
index 00000000..b28b8fa2
--- /dev/null
+++ b/libdde_linux26/examples/unittest/.svn/entries
@@ -0,0 +1,96 @@
+9
+
+dir
+465
+http://svn.tudos.org/repos/tudos/trunk/l4/pkg/dde/linux26/examples/unittest
+http://svn.tudos.org/repos/tudos
+
+
+
+2007-09-08T19:44:13.897747Z
+174
+l4check
+
+
+svn:special svn:externals svn:needs-lock
+
+
+
+
+
+
+
+
+
+
+
+a704ac0b-3a55-4d43-a2a9-7be6f07c34fb
+
+main.c
+file
+
+
+
+
+2009-11-15T17:17:14.000000Z
+859924cf0bfc1d9fe646bc55fd063ece
+2007-09-08T19:44:13.897747Z
+174
+l4check
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+14854
+
+Makefile
+file
+
+
+
+
+2009-11-15T17:17:14.000000Z
+0c29d82901ef4377917e235b09237d79
+2007-09-08T19:44:13.897747Z
+174
+l4check
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+416
+
diff --git a/libdde_linux26/examples/unittest/.svn/format b/libdde_linux26/examples/unittest/.svn/format
new file mode 100644
index 00000000..ec635144
--- /dev/null
+++ b/libdde_linux26/examples/unittest/.svn/format
@@ -0,0 +1 @@
+9
diff --git a/libdde_linux26/examples/unittest/.svn/text-base/Makefile.svn-base b/libdde_linux26/examples/unittest/.svn/text-base/Makefile.svn-base
new file mode 100644
index 00000000..1ec4e97d
--- /dev/null
+++ b/libdde_linux26/examples/unittest/.svn/text-base/Makefile.svn-base
@@ -0,0 +1,21 @@
+PKGDIR ?= ../../..
+L4DIR ?= $(PKGDIR)/../..
+
+SYSTEMS = x86-l4v2
+
+DEFAULT_RELOC = 0x00a00000
+
+-include $(PKGDIR_OBJ)/Makeconf
+
+ifeq ($(CONFIG_DDE26_COMMON),y)
+TARGET = dde26_unit_test
+endif
+
+SRC_C = main.c
+
+LIBS += -ldde_linux26 -lddekit -lio -llist_alloc -lparsecmdline -lcunit_dde
+
+# DDE configuration
+include $(PKGDIR)/linux26/Makeconf
+
+include $(L4DIR)/mk/prog.mk
diff --git a/libdde_linux26/examples/unittest/.svn/text-base/main.c.svn-base b/libdde_linux26/examples/unittest/.svn/text-base/main.c.svn-base
new file mode 100644
index 00000000..25e13cc3
--- /dev/null
+++ b/libdde_linux26/examples/unittest/.svn/text-base/main.c.svn-base
@@ -0,0 +1,611 @@
+/*
+ * \brief DDE for Linux 2.6 Unit tests
+ * \author Bjoern Doebel <doebel@os.inf.tu-dresden.de>
+ * \author Christian Helmuth <ch12@os.inf.tu-dresden.de>
+ * \date 2007-05-12
+ */
+
+#include <asm/current.h>
+
+#include <linux/kernel.h>
+#include <linux/completion.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+//#include <linux/kthread.h>
+
+#include <l4/dde/dde.h>
+#include <l4/dde/ddekit/initcall.h>
+#include <l4/dde/linux26/dde26.h>
+
+#include <l4/cunit/CUnit.h>
+#include <l4/cunit/Basic.h>
+#include <l4/util/parse_cmd.h>
+#include <l4/util/util.h>
+#include <l4/log/l4log.h>
+
+/* We define 4 initcalls and see if these are executed
+ * in the beginning and in the right order. Expecations:
+ *
+ * - After running the init calls, _init_count == 4
+ * - {_foo, _bar, _bla, _blub}_count carry numbers from 0 through 3
+ * giving their execution order. These need to be:
+ * - _foo_count == 3
+ * - _bar_count == 2
+ * - _bla_count == 0
+ * - _blub_count == 1
+ */
+static unsigned _init_count = 0;
+static unsigned _foo_count = 0;
+static unsigned _bar_count = 0;
+static unsigned _bla_count = 0;
+static unsigned _blub_count = 0;
+
+/** Test checking whether the initcalls have been executed correctly. */
+static int test_initcalls(void)
+{
+ CU_ASSERT(_init_count == 4);
+ CU_ASSERT(_foo_count == 3);
+ CU_ASSERT(_bar_count == 2);
+ CU_ASSERT(_blub_count == 1);
+ CU_ASSERT(_bla_count == 0);
+ return 0;
+}
+
+
+static void foo(void)
+{
+ _foo_count = _init_count++;
+}
+late_initcall(foo);
+
+static void bar(void)
+{
+ _bar_count = _init_count++;
+}
+device_initcall(bar);
+
+static void bla(void)
+{
+ _bla_count = _init_count++;
+}
+arch_initcall(bla);
+
+static void blub(void)
+{
+ _blub_count = _init_count++;
+}
+subsys_initcall(blub);
+
+/***********************************************************************
+ ** Test 1: Check whether the current() macro works. **
+ ***********************************************************************/
+static int current_test(void)
+{
+ struct task_struct *t = current;
+ CU_ASSERT(t != NULL);
+ return 0;
+}
+
+
+/***********************************************************************
+ ** Test 2: Getting complicated. Test startup of some kernel threads **
+ ** and wait for them to finish using completions. **
+ ***********************************************************************/
+#define NUM_KTHREADS 5
+static struct completion _kthread_completions_[NUM_KTHREADS];
+
+static int kernel_thread_func(void *arg)
+{
+ CU_ASSERT((int)arg >= 0);
+ CU_ASSERT((int)arg < NUM_KTHREADS);
+ CU_ASSERT(current != NULL);
+
+ /* do some work */
+ msleep(200);
+
+ complete_and_exit( &_kthread_completions_[(int)arg], 0 );
+ return 0;
+}
+
+
+static int kernel_thread_test(void)
+{
+ int i;
+
+ for (i=0; i < NUM_KTHREADS; i++) {
+ int j;
+ // initialize completion event
+ init_completion(&_kthread_completions_[i]);
+ // start kernel thread
+ j = kernel_thread(kernel_thread_func, (void *)i, 0);
+ CU_ASSERT(j > 0);
+ }
+
+ for (i=0; i < NUM_KTHREADS; i++) {
+ // await completion
+ wait_for_completion(&_kthread_completions_[i]);
+ }
+ CU_ASSERT(i==NUM_KTHREADS);
+
+ return 0;
+}
+
+
+/******************************************************************************
+ ** Test 3: Test kernel wait queues: start a thread incrementing wait_value, **
+ ** and sleep until wait_value is larger than 6 for the first time. **
+ ******************************************************************************/
+static DECLARE_WAIT_QUEUE_HEAD(_wq_head);
+static unsigned wait_value = 0;
+static struct completion wq_completion;
+
+static int inc_func(void *arg)
+{
+ int i = 0;
+
+ for (i=0; i<10; i++)
+ {
+ ++wait_value;
+ wake_up(&_wq_head);
+ msleep(500);
+ }
+ CU_ASSERT(wait_value == 10);
+ CU_ASSERT(i == 10);
+ complete_and_exit(&wq_completion, 0);
+}
+
+
+static int wq_test(void)
+{
+ int pid;
+
+ init_completion(&wq_completion);
+ // start a thread incrementing wait_value
+ pid = kernel_thread(inc_func, 0, 0);
+ CU_ASSERT(pid > 0);
+
+ // wait until wait_value > 6
+ wait_event(_wq_head, wait_value > 6);
+ CU_ASSERT(wait_value > 6);
+
+ // wait for inc_thread to exit
+ wait_for_completion(&wq_completion);
+ CU_ASSERT(wait_value == 10);
+
+ return 0;
+}
+
+
+/****************************************************************************
+ ** Test 4: Tasklets **
+ ****************************************************************************/
+static unsigned _low_count = 0;
+static unsigned _high_count = 0;
+
+static void tasklet_low_func(unsigned long i)
+{
+ ++_low_count;
+}
+
+static void tasklet_high_func(unsigned long i)
+{
+ ++_high_count;
+}
+
+static DECLARE_TASKLET(low0, tasklet_low_func, 0);
+static DECLARE_TASKLET(low1, tasklet_low_func, 1);
+static DECLARE_TASKLET(low2, tasklet_low_func, 2);
+static DECLARE_TASKLET_DISABLED(low3, tasklet_low_func, 3);
+
+static DECLARE_TASKLET(hi0, tasklet_high_func, 10);
+static DECLARE_TASKLET(hi1, tasklet_high_func, 11);
+static DECLARE_TASKLET_DISABLED(hi2, tasklet_high_func, 12);
+
+
+static int tasklet_test(void)
+{
+ l4dde26_softirq_init();
+
+ // schedule tasklets 0-3, 3 disabled
+ tasklet_schedule(&low0);
+ tasklet_schedule(&low1);
+ tasklet_schedule(&low2);
+ tasklet_schedule(&low3);
+ msleep(500);
+
+ // 0-2 should have executed by now
+ CU_ASSERT(_low_count == 3);
+ tasklet_enable(&low3);
+ msleep(500);
+ // 3 should be ready, too
+ CU_ASSERT(_low_count == 4);
+
+ // schedule hi and low tasklets, hi2 is disabled
+ tasklet_hi_schedule(&hi0);
+ tasklet_hi_schedule(&hi1);
+ tasklet_hi_schedule(&hi2);
+ tasklet_schedule(&low0);
+ tasklet_schedule(&low1);
+ tasklet_schedule(&low2);
+ msleep(500);
+ CU_ASSERT(_high_count == 2);
+ CU_ASSERT(_low_count == 7);
+
+ // enable hi2
+ tasklet_enable(&hi2);
+ // schedule low3 2 times, should only run once
+ tasklet_schedule(&low3);
+ tasklet_schedule(&low3);
+ msleep(500);
+ CU_ASSERT(_high_count == 3);
+ CU_ASSERT(_low_count == 8);
+
+ return 0;
+}
+
+
+#if 0
+/******************************************************************************
+ ** Test 5: Timers **
+ ** **
+ ** Schedule a periodic timer printing "tick" every second. Additionally, **
+ ** schedule timers for 5, 10, 15, 20, and 25 seconds. Timer at 15s will **
+ ** deactivate the 20s timer. **
+ ******************************************************************************/
+
+static struct timer_list _timer;
+static struct timer_list _timer5;
+static struct timer_list _timer10;
+static struct timer_list _timer15;
+static struct timer_list _timer20;
+static struct timer_list _timer25;
+
+static void tick_func(unsigned long d)
+{
+ printk("tick (%ld)\n", jiffies);
+ _timer.expires = jiffies + HZ;
+ add_timer(&_timer);
+}
+
+
+static void timer_func(unsigned long d)
+{
+ printk("timer_func: %lu\n", d);
+
+ if (d == 15) {
+ printk("De-scheduling 20s timer.\n");
+ del_timer(&_timer20);
+ }
+
+ if (timer_pending(&_timer20))
+ printk("timer for 20s still pending.\n");
+ else
+ printk("timer for 20s has been disabled.\n");
+}
+
+
+static void timer_test(void)
+{
+ l4dde26_init_timers();
+
+ printk("BEGIN TIMER TEST\n");
+ printk("jiffies(%p): %ld, HZ(%p): %ld\n", &jiffies, jiffies, &HZ, HZ);
+
+ setup_timer(&_timer, tick_func, 0);
+ _timer.expires = jiffies + HZ;
+ add_timer(&_timer);
+
+ setup_timer(&_timer5, timer_func, 5);
+ _timer5.expires = jiffies + 5*HZ;
+ setup_timer(&_timer10, timer_func, 10);
+ _timer10.expires = jiffies + 10*HZ;
+ setup_timer(&_timer15, timer_func, 15);
+ _timer15.expires = jiffies + 15*HZ;
+ setup_timer(&_timer20, timer_func, 20);
+ _timer20.expires = jiffies + 20*HZ;
+ setup_timer(&_timer25, timer_func, 25);
+ _timer25.expires = jiffies + 25*HZ;
+
+ add_timer(&_timer5);
+ add_timer(&_timer10);
+ add_timer(&_timer15);
+ add_timer(&_timer20);
+ add_timer(&_timer25);
+
+ msleep(30000);
+ printk("END TIMER TEST\n");
+}
+#endif
+
+
+/******************************
+ ** Test 6: Memory subsystem **
+ ******************************/
+
+static void memory_kmem_cache_test(void)
+{
+ struct kmem_cache *cache0 = NULL;
+ struct obj0
+ {
+ unsigned foo;
+ unsigned bar;
+ };
+ static struct obj0 *p0[1024];
+
+ struct kmem_cache *cache1 = NULL;
+ struct obj1
+ {
+ char foo[50];
+ unsigned *bar;
+ };
+ static struct obj1 *p1[256];
+
+ CU_ASSERT(cache0 == NULL);
+ CU_ASSERT(cache1 == NULL);
+
+ cache0 = kmem_cache_create("obj0", sizeof(*p0[0]), 0, 0, 0, 0);
+ cache1 = kmem_cache_create("obj1", sizeof(*p1[0]), 0, 0, 0, 0);
+
+ CU_ASSERT(cache0 != NULL);
+ CU_ASSERT(cache1 != NULL);
+
+ unsigned i;
+ for (i = 0; i < 1024; ++i) {
+ p0[i] = kmem_cache_alloc(cache0, i);
+ CU_ASSERT(p0[i] != NULL);
+ }
+
+ for (i = 0; i < 256; ++i) {
+ p1[i] = kmem_cache_alloc(cache1, i);
+ CU_ASSERT(p1[i] != NULL);
+ }
+
+ for (i = 256; i > 0; --i)
+ kmem_cache_free(cache1, p1[i-1]);
+
+ for (i = 1024; i > 0; --i)
+ kmem_cache_free(cache0, p0[i-1]);
+
+ kmem_cache_destroy(cache1);
+ kmem_cache_destroy(cache0);
+}
+
+
+static void memory_page_alloc_test(void)
+{
+ unsigned long p[4];
+ p[0] = __get_free_page(GFP_KERNEL);
+ p[1] = __get_free_pages(GFP_KERNEL, 1);
+ p[2] = __get_free_pages(GFP_KERNEL, 2);
+ p[3] = __get_free_pages(GFP_KERNEL, 3);
+
+ CU_ASSERT(p[0] != 0);
+ CU_ASSERT(p[1] != 0);
+ CU_ASSERT(p[2] != 0);
+ CU_ASSERT(p[3] != 0);
+
+ free_pages(p[0], 0);
+ free_pages(p[1], 1);
+ free_pages(p[2], 2);
+ free_pages(p[3], 3);
+}
+
+
+static void memory_kmalloc_test(void)
+{
+ l4dde26_kmalloc_init();
+
+ const unsigned count = 33;
+ char *p[count];
+
+ unsigned i;
+ for (i = 0; i < count; ++i) {
+ p[i] = kmalloc(32 + i*15, GFP_KERNEL);
+ CU_ASSERT(p[i] != NULL);
+ *p[i] = i;
+ CU_ASSERT(*p[i] == i);
+ }
+
+ for (i = count; i > 0; --i)
+ if (p[i-1]) kfree(p[i-1]);
+
+ for (i = 0; i < count; ++i) {
+ p[i] = kmalloc(3000 + i*20, GFP_KERNEL);
+ CU_ASSERT(p[i] != NULL);
+ *p[i] = i;
+ CU_ASSERT(*p[i] == i);
+ }
+
+ for (i = count; i > 0; --i)
+ if (p[i-1]) kfree(p[i-1]);
+
+}
+
+
+static int memory_test(void)
+{
+ if (1) memory_kmem_cache_test();
+ if (1) memory_page_alloc_test();
+ if (1) memory_kmalloc_test();
+ return 0;
+}
+
+#if 0
+/****************************************************************************
+ ** Test 7: KThreads **
+ ****************************************************************************/
+void kthread_test(void)
+{
+}
+
+
+/****************************************************************************
+ ** Test 8: Work queues **
+ ****************************************************************************/
+static void work_queue_func(void *data);
+static void work_queue_func2(void *data);
+static struct workqueue_struct *_wq;
+static DECLARE_WORK(_wobj, work_queue_func, NULL);
+static DECLARE_WORK(_wobj2, work_queue_func2, NULL);
+static int wq_cnt = 0;
+
+static void work_queue_func(void *data)
+{
+ printk("Work queue function... Do some work here...\n");
+ if (++wq_cnt < 5)
+ queue_work(_wq, &_wobj);
+}
+
+
+static void work_queue_func2(void *data)
+{
+ printk("Work queue function 2... Do some work here...\n");
+ if (++wq_cnt < 5)
+ schedule_work(&_wobj2);
+}
+
+
+static void work_queue_test(void)
+{
+ int i;
+ printk("BEGIN WQ TEST\n");
+ _wq = create_workqueue("HelloWQ");
+ BUG_ON(_wq == NULL);
+ queue_work(_wq, &_wobj);
+ schedule_work(&_wobj2);
+ printk("END WQ TEST\n");
+}
+
+
+/****************************************************************************
+ ** Test 9: PCI **
+ ****************************************************************************/
+
+void pci_test(void)
+{
+ l4dde26_init_pci();
+}
+
+
+/*************************************************
+ ** Main routine (switch on desired tests here) **
+ *************************************************/
+
+int main(int argc, const char **argv)
+{
+ int test_current = 0;
+ int test_kernel_thread = 0;
+ int test_wait = 0;
+ int test_tasklet = 0;
+ int test_timer = 0;
+ int test_memory = 0;
+ int test_kthread = 0;
+ int test_work = 0;
+ int test_pci = 0;
+
+ if (parse_cmdline(&argc, &argv,
+ 'c', "current", "test current() function",
+ PARSE_CMD_SWITCH, 1, &test_current,
+ 'k', "kernel-thread", "test startup of kernel threads",
+ PARSE_CMD_SWITCH, 1, &test_kernel_thread,
+ 'w', "waitqueue", "test wait queues",
+ PARSE_CMD_SWITCH, 1, &test_wait,
+ 't', "tasklet", "test tasklets",
+ PARSE_CMD_SWITCH, 1, &test_tasklet,
+ 'T', "timer", "test timers",
+ PARSE_CMD_SWITCH, 1, &test_timer,
+ 'm', "memory", "test memory management",
+ PARSE_CMD_SWITCH, 1, &test_memory,
+ 'K', "kthread", "test kthreads",
+ PARSE_CMD_SWITCH, 1, &test_kthread,
+ 'W', "workqueue", "test work queues",
+ PARSE_CMD_SWITCH, 1, &test_work,
+ 'p', "pci", "test PCI stuff",
+ PARSE_CMD_SWITCH, 1, &test_pci,
+ 0, 0))
+ return 1;
+
+ LOG("DDEKit test. Carrying out tests:");
+ LOGd(test_current, "\t* current()");
+ LOGd(test_kernel_thread, "\t* kernel_thread()");
+ LOGd(test_wait, "\t* wait queues");
+ LOGd(test_tasklet, "\t* tasklets");
+ LOGd(test_timer, "\t* timers");
+ LOGd(test_memory, "\t* memory management");
+ LOGd(test_kthread, "\t* kthreads");
+ LOGd(test_work, "\t* work queues");
+ LOGd(test_pci, "\t* PCI subsystem");
+
+ l4dde26_init();
+ l4dde26_process_init();
+ l4dde26_do_initcalls();
+
+ if (test_current) current_test();
+ if (test_kernel_thread) kernel_thread_test();
+ if (test_wait) wq_test();
+ if (test_tasklet) tasklet_test();
+ if (test_timer) timer_test();
+ if (test_memory) memory_test();
+/* if (1) kthread_test(); */
+ if (test_work) work_queue_test();
+ if (test_pci) pci_test();
+
+ return 0;
+}
+#endif
+
+static int dde26_ts_init(void)
+{
+ l4dde26_init();
+ l4dde26_process_init();
+ l4dde26_do_initcalls();
+ return 0;
+}
+
+
+static int dde26_ts_cleanup(void)
+{
+ return 0;
+}
+
+
+int main(int argc, char **argv)
+{
+ CU_pSuite dde_testsuite = NULL;
+
+ int err = CU_initialize_registry();
+ if (err == CUE_SUCCESS)
+ printk("Initialized CUnit registry.\n");
+ else {
+ printk("Could not initialize CUnit registry.\n");
+ return -1;
+ }
+
+ dde_testsuite = CU_add_suite("DDE2.6 test suite", dde26_ts_init, dde26_ts_cleanup);
+ if (dde_testsuite)
+ printk("Added DDE2.6 test suite.\n");
+ else {
+ printk("Could not add DDE2.6 test suite.\n");
+ return -2;
+ }
+
+ CU_ADD_TEST(dde_testsuite, test_initcalls);
+ CU_ADD_TEST(dde_testsuite, current_test);
+ CU_ADD_TEST(dde_testsuite, kernel_thread_test);
+ CU_ADD_TEST(dde_testsuite, wq_test);
+ CU_ADD_TEST(dde_testsuite, tasklet_test);
+ CU_ADD_TEST(dde_testsuite, memory_test);
+
+ CU_basic_set_mode(CU_BRM_VERBOSE);
+ CU_basic_run_tests();
+
+ CU_cleanup_registry();
+
+ l4_sleep_forever();
+
+ return 0;
+}
diff --git a/libdde_linux26/examples/unittest/Makefile b/libdde_linux26/examples/unittest/Makefile
new file mode 100644
index 00000000..1ec4e97d
--- /dev/null
+++ b/libdde_linux26/examples/unittest/Makefile
@@ -0,0 +1,21 @@
+PKGDIR ?= ../../..
+L4DIR ?= $(PKGDIR)/../..
+
+SYSTEMS = x86-l4v2
+
+DEFAULT_RELOC = 0x00a00000
+
+-include $(PKGDIR_OBJ)/Makeconf
+
+ifeq ($(CONFIG_DDE26_COMMON),y)
+TARGET = dde26_unit_test
+endif
+
+SRC_C = main.c
+
+LIBS += -ldde_linux26 -lddekit -lio -llist_alloc -lparsecmdline -lcunit_dde
+
+# DDE configuration
+include $(PKGDIR)/linux26/Makeconf
+
+include $(L4DIR)/mk/prog.mk
diff --git a/libdde_linux26/examples/unittest/main.c b/libdde_linux26/examples/unittest/main.c
new file mode 100644
index 00000000..25e13cc3
--- /dev/null
+++ b/libdde_linux26/examples/unittest/main.c
@@ -0,0 +1,611 @@
+/*
+ * \brief DDE for Linux 2.6 Unit tests
+ * \author Bjoern Doebel <doebel@os.inf.tu-dresden.de>
+ * \author Christian Helmuth <ch12@os.inf.tu-dresden.de>
+ * \date 2007-05-12
+ */
+
+#include <asm/current.h>
+
+#include <linux/kernel.h>
+#include <linux/completion.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+//#include <linux/kthread.h>
+
+#include <l4/dde/dde.h>
+#include <l4/dde/ddekit/initcall.h>
+#include <l4/dde/linux26/dde26.h>
+
+#include <l4/cunit/CUnit.h>
+#include <l4/cunit/Basic.h>
+#include <l4/util/parse_cmd.h>
+#include <l4/util/util.h>
+#include <l4/log/l4log.h>
+
+/* We define 4 initcalls and see if these are executed
+ * in the beginning and in the right order. Expecations:
+ *
+ * - After running the init calls, _init_count == 4
+ * - {_foo, _bar, _bla, _blub}_count carry numbers from 0 through 3
+ * giving their execution order. These need to be:
+ * - _foo_count == 3
+ * - _bar_count == 2
+ * - _bla_count == 0
+ * - _blub_count == 1
+ */
+static unsigned _init_count = 0;
+static unsigned _foo_count = 0;
+static unsigned _bar_count = 0;
+static unsigned _bla_count = 0;
+static unsigned _blub_count = 0;
+
+/** Test checking whether the initcalls have been executed correctly. */
+static int test_initcalls(void)
+{
+ CU_ASSERT(_init_count == 4);
+ CU_ASSERT(_foo_count == 3);
+ CU_ASSERT(_bar_count == 2);
+ CU_ASSERT(_blub_count == 1);
+ CU_ASSERT(_bla_count == 0);
+ return 0;
+}
+
+
+static void foo(void)
+{
+ _foo_count = _init_count++;
+}
+late_initcall(foo);
+
+static void bar(void)
+{
+ _bar_count = _init_count++;
+}
+device_initcall(bar);
+
+static void bla(void)
+{
+ _bla_count = _init_count++;
+}
+arch_initcall(bla);
+
+static void blub(void)
+{
+ _blub_count = _init_count++;
+}
+subsys_initcall(blub);
+
+/***********************************************************************
+ ** Test 1: Check whether the current() macro works. **
+ ***********************************************************************/
+static int current_test(void)
+{
+ struct task_struct *t = current;
+ CU_ASSERT(t != NULL);
+ return 0;
+}
+
+
+/***********************************************************************
+ ** Test 2: Getting complicated. Test startup of some kernel threads **
+ ** and wait for them to finish using completions. **
+ ***********************************************************************/
+#define NUM_KTHREADS 5
+static struct completion _kthread_completions_[NUM_KTHREADS];
+
+static int kernel_thread_func(void *arg)
+{
+ CU_ASSERT((int)arg >= 0);
+ CU_ASSERT((int)arg < NUM_KTHREADS);
+ CU_ASSERT(current != NULL);
+
+ /* do some work */
+ msleep(200);
+
+ complete_and_exit( &_kthread_completions_[(int)arg], 0 );
+ return 0;
+}
+
+
+static int kernel_thread_test(void)
+{
+ int i;
+
+ for (i=0; i < NUM_KTHREADS; i++) {
+ int j;
+ // initialize completion event
+ init_completion(&_kthread_completions_[i]);
+ // start kernel thread
+ j = kernel_thread(kernel_thread_func, (void *)i, 0);
+ CU_ASSERT(j > 0);
+ }
+
+ for (i=0; i < NUM_KTHREADS; i++) {
+ // await completion
+ wait_for_completion(&_kthread_completions_[i]);
+ }
+ CU_ASSERT(i==NUM_KTHREADS);
+
+ return 0;
+}
+
+
+/******************************************************************************
+ ** Test 3: Test kernel wait queues: start a thread incrementing wait_value, **
+ ** and sleep until wait_value is larger than 6 for the first time. **
+ ******************************************************************************/
+static DECLARE_WAIT_QUEUE_HEAD(_wq_head);
+static unsigned wait_value = 0;
+static struct completion wq_completion;
+
+static int inc_func(void *arg)
+{
+ int i = 0;
+
+ for (i=0; i<10; i++)
+ {
+ ++wait_value;
+ wake_up(&_wq_head);
+ msleep(500);
+ }
+ CU_ASSERT(wait_value == 10);
+ CU_ASSERT(i == 10);
+ complete_and_exit(&wq_completion, 0);
+}
+
+
+static int wq_test(void)
+{
+ int pid;
+
+ init_completion(&wq_completion);
+ // start a thread incrementing wait_value
+ pid = kernel_thread(inc_func, 0, 0);
+ CU_ASSERT(pid > 0);
+
+ // wait until wait_value > 6
+ wait_event(_wq_head, wait_value > 6);
+ CU_ASSERT(wait_value > 6);
+
+ // wait for inc_thread to exit
+ wait_for_completion(&wq_completion);
+ CU_ASSERT(wait_value == 10);
+
+ return 0;
+}
+
+
+/****************************************************************************
+ ** Test 4: Tasklets **
+ ****************************************************************************/
+static unsigned _low_count = 0;
+static unsigned _high_count = 0;
+
+static void tasklet_low_func(unsigned long i)
+{
+ ++_low_count;
+}
+
+static void tasklet_high_func(unsigned long i)
+{
+ ++_high_count;
+}
+
+static DECLARE_TASKLET(low0, tasklet_low_func, 0);
+static DECLARE_TASKLET(low1, tasklet_low_func, 1);
+static DECLARE_TASKLET(low2, tasklet_low_func, 2);
+static DECLARE_TASKLET_DISABLED(low3, tasklet_low_func, 3);
+
+static DECLARE_TASKLET(hi0, tasklet_high_func, 10);
+static DECLARE_TASKLET(hi1, tasklet_high_func, 11);
+static DECLARE_TASKLET_DISABLED(hi2, tasklet_high_func, 12);
+
+
+static int tasklet_test(void)
+{
+ l4dde26_softirq_init();
+
+ // schedule tasklets 0-3, 3 disabled
+ tasklet_schedule(&low0);
+ tasklet_schedule(&low1);
+ tasklet_schedule(&low2);
+ tasklet_schedule(&low3);
+ msleep(500);
+
+ // 0-2 should have executed by now
+ CU_ASSERT(_low_count == 3);
+ tasklet_enable(&low3);
+ msleep(500);
+ // 3 should be ready, too
+ CU_ASSERT(_low_count == 4);
+
+ // schedule hi and low tasklets, hi2 is disabled
+ tasklet_hi_schedule(&hi0);
+ tasklet_hi_schedule(&hi1);
+ tasklet_hi_schedule(&hi2);
+ tasklet_schedule(&low0);
+ tasklet_schedule(&low1);
+ tasklet_schedule(&low2);
+ msleep(500);
+ CU_ASSERT(_high_count == 2);
+ CU_ASSERT(_low_count == 7);
+
+ // enable hi2
+ tasklet_enable(&hi2);
+ // schedule low3 2 times, should only run once
+ tasklet_schedule(&low3);
+ tasklet_schedule(&low3);
+ msleep(500);
+ CU_ASSERT(_high_count == 3);
+ CU_ASSERT(_low_count == 8);
+
+ return 0;
+}
+
+
+#if 0
+/******************************************************************************
+ ** Test 5: Timers **
+ ** **
+ ** Schedule a periodic timer printing "tick" every second. Additionally, **
+ ** schedule timers for 5, 10, 15, 20, and 25 seconds. Timer at 15s will **
+ ** deactivate the 20s timer. **
+ ******************************************************************************/
+
+static struct timer_list _timer;
+static struct timer_list _timer5;
+static struct timer_list _timer10;
+static struct timer_list _timer15;
+static struct timer_list _timer20;
+static struct timer_list _timer25;
+
+static void tick_func(unsigned long d)
+{
+ printk("tick (%ld)\n", jiffies);
+ _timer.expires = jiffies + HZ;
+ add_timer(&_timer);
+}
+
+
+static void timer_func(unsigned long d)
+{
+ printk("timer_func: %lu\n", d);
+
+ if (d == 15) {
+ printk("De-scheduling 20s timer.\n");
+ del_timer(&_timer20);
+ }
+
+ if (timer_pending(&_timer20))
+ printk("timer for 20s still pending.\n");
+ else
+ printk("timer for 20s has been disabled.\n");
+}
+
+
+static void timer_test(void)
+{
+ l4dde26_init_timers();
+
+ printk("BEGIN TIMER TEST\n");
+ printk("jiffies(%p): %ld, HZ(%p): %ld\n", &jiffies, jiffies, &HZ, HZ);
+
+ setup_timer(&_timer, tick_func, 0);
+ _timer.expires = jiffies + HZ;
+ add_timer(&_timer);
+
+ setup_timer(&_timer5, timer_func, 5);
+ _timer5.expires = jiffies + 5*HZ;
+ setup_timer(&_timer10, timer_func, 10);
+ _timer10.expires = jiffies + 10*HZ;
+ setup_timer(&_timer15, timer_func, 15);
+ _timer15.expires = jiffies + 15*HZ;
+ setup_timer(&_timer20, timer_func, 20);
+ _timer20.expires = jiffies + 20*HZ;
+ setup_timer(&_timer25, timer_func, 25);
+ _timer25.expires = jiffies + 25*HZ;
+
+ add_timer(&_timer5);
+ add_timer(&_timer10);
+ add_timer(&_timer15);
+ add_timer(&_timer20);
+ add_timer(&_timer25);
+
+ msleep(30000);
+ printk("END TIMER TEST\n");
+}
+#endif
+
+
+/******************************
+ ** Test 6: Memory subsystem **
+ ******************************/
+
+static void memory_kmem_cache_test(void)
+{
+ struct kmem_cache *cache0 = NULL;
+ struct obj0
+ {
+ unsigned foo;
+ unsigned bar;
+ };
+ static struct obj0 *p0[1024];
+
+ struct kmem_cache *cache1 = NULL;
+ struct obj1
+ {
+ char foo[50];
+ unsigned *bar;
+ };
+ static struct obj1 *p1[256];
+
+ CU_ASSERT(cache0 == NULL);
+ CU_ASSERT(cache1 == NULL);
+
+ cache0 = kmem_cache_create("obj0", sizeof(*p0[0]), 0, 0, 0, 0);
+ cache1 = kmem_cache_create("obj1", sizeof(*p1[0]), 0, 0, 0, 0);
+
+ CU_ASSERT(cache0 != NULL);
+ CU_ASSERT(cache1 != NULL);
+
+ unsigned i;
+ for (i = 0; i < 1024; ++i) {
+ p0[i] = kmem_cache_alloc(cache0, i);
+ CU_ASSERT(p0[i] != NULL);
+ }
+
+ for (i = 0; i < 256; ++i) {
+ p1[i] = kmem_cache_alloc(cache1, i);
+ CU_ASSERT(p1[i] != NULL);
+ }
+
+ for (i = 256; i > 0; --i)
+ kmem_cache_free(cache1, p1[i-1]);
+
+ for (i = 1024; i > 0; --i)
+ kmem_cache_free(cache0, p0[i-1]);
+
+ kmem_cache_destroy(cache1);
+ kmem_cache_destroy(cache0);
+}
+
+
+static void memory_page_alloc_test(void)
+{
+ unsigned long p[4];
+ p[0] = __get_free_page(GFP_KERNEL);
+ p[1] = __get_free_pages(GFP_KERNEL, 1);
+ p[2] = __get_free_pages(GFP_KERNEL, 2);
+ p[3] = __get_free_pages(GFP_KERNEL, 3);
+
+ CU_ASSERT(p[0] != 0);
+ CU_ASSERT(p[1] != 0);
+ CU_ASSERT(p[2] != 0);
+ CU_ASSERT(p[3] != 0);
+
+ free_pages(p[0], 0);
+ free_pages(p[1], 1);
+ free_pages(p[2], 2);
+ free_pages(p[3], 3);
+}
+
+
+static void memory_kmalloc_test(void)
+{
+ l4dde26_kmalloc_init();
+
+ const unsigned count = 33;
+ char *p[count];
+
+ unsigned i;
+ for (i = 0; i < count; ++i) {
+ p[i] = kmalloc(32 + i*15, GFP_KERNEL);
+ CU_ASSERT(p[i] != NULL);
+ *p[i] = i;
+ CU_ASSERT(*p[i] == i);
+ }
+
+ for (i = count; i > 0; --i)
+ if (p[i-1]) kfree(p[i-1]);
+
+ for (i = 0; i < count; ++i) {
+ p[i] = kmalloc(3000 + i*20, GFP_KERNEL);
+ CU_ASSERT(p[i] != NULL);
+ *p[i] = i;
+ CU_ASSERT(*p[i] == i);
+ }
+
+ for (i = count; i > 0; --i)
+ if (p[i-1]) kfree(p[i-1]);
+
+}
+
+
+static int memory_test(void)
+{
+ if (1) memory_kmem_cache_test();
+ if (1) memory_page_alloc_test();
+ if (1) memory_kmalloc_test();
+ return 0;
+}
+
+#if 0
+/****************************************************************************
+ ** Test 7: KThreads **
+ ****************************************************************************/
+void kthread_test(void)
+{
+}
+
+
+/****************************************************************************
+ ** Test 8: Work queues **
+ ****************************************************************************/
+static void work_queue_func(void *data);
+static void work_queue_func2(void *data);
+static struct workqueue_struct *_wq;
+static DECLARE_WORK(_wobj, work_queue_func, NULL);
+static DECLARE_WORK(_wobj2, work_queue_func2, NULL);
+static int wq_cnt = 0;
+
+static void work_queue_func(void *data)
+{
+ printk("Work queue function... Do some work here...\n");
+ if (++wq_cnt < 5)
+ queue_work(_wq, &_wobj);
+}
+
+
+static void work_queue_func2(void *data)
+{
+ printk("Work queue function 2... Do some work here...\n");
+ if (++wq_cnt < 5)
+ schedule_work(&_wobj2);
+}
+
+
+static void work_queue_test(void)
+{
+ int i;
+ printk("BEGIN WQ TEST\n");
+ _wq = create_workqueue("HelloWQ");
+ BUG_ON(_wq == NULL);
+ queue_work(_wq, &_wobj);
+ schedule_work(&_wobj2);
+ printk("END WQ TEST\n");
+}
+
+
+/****************************************************************************
+ ** Test 9: PCI **
+ ****************************************************************************/
+
+void pci_test(void)
+{
+ l4dde26_init_pci();
+}
+
+
+/*************************************************
+ ** Main routine (switch on desired tests here) **
+ *************************************************/
+
+int main(int argc, const char **argv)
+{
+ int test_current = 0;
+ int test_kernel_thread = 0;
+ int test_wait = 0;
+ int test_tasklet = 0;
+ int test_timer = 0;
+ int test_memory = 0;
+ int test_kthread = 0;
+ int test_work = 0;
+ int test_pci = 0;
+
+ if (parse_cmdline(&argc, &argv,
+ 'c', "current", "test current() function",
+ PARSE_CMD_SWITCH, 1, &test_current,
+ 'k', "kernel-thread", "test startup of kernel threads",
+ PARSE_CMD_SWITCH, 1, &test_kernel_thread,
+ 'w', "waitqueue", "test wait queues",
+ PARSE_CMD_SWITCH, 1, &test_wait,
+ 't', "tasklet", "test tasklets",
+ PARSE_CMD_SWITCH, 1, &test_tasklet,
+ 'T', "timer", "test timers",
+ PARSE_CMD_SWITCH, 1, &test_timer,
+ 'm', "memory", "test memory management",
+ PARSE_CMD_SWITCH, 1, &test_memory,
+ 'K', "kthread", "test kthreads",
+ PARSE_CMD_SWITCH, 1, &test_kthread,
+ 'W', "workqueue", "test work queues",
+ PARSE_CMD_SWITCH, 1, &test_work,
+ 'p', "pci", "test PCI stuff",
+ PARSE_CMD_SWITCH, 1, &test_pci,
+ 0, 0))
+ return 1;
+
+ LOG("DDEKit test. Carrying out tests:");
+ LOGd(test_current, "\t* current()");
+ LOGd(test_kernel_thread, "\t* kernel_thread()");
+ LOGd(test_wait, "\t* wait queues");
+ LOGd(test_tasklet, "\t* tasklets");
+ LOGd(test_timer, "\t* timers");
+ LOGd(test_memory, "\t* memory management");
+ LOGd(test_kthread, "\t* kthreads");
+ LOGd(test_work, "\t* work queues");
+ LOGd(test_pci, "\t* PCI subsystem");
+
+ l4dde26_init();
+ l4dde26_process_init();
+ l4dde26_do_initcalls();
+
+ if (test_current) current_test();
+ if (test_kernel_thread) kernel_thread_test();
+ if (test_wait) wq_test();
+ if (test_tasklet) tasklet_test();
+ if (test_timer) timer_test();
+ if (test_memory) memory_test();
+/* if (1) kthread_test(); */
+ if (test_work) work_queue_test();
+ if (test_pci) pci_test();
+
+ return 0;
+}
+#endif
+
+static int dde26_ts_init(void)
+{
+ l4dde26_init();
+ l4dde26_process_init();
+ l4dde26_do_initcalls();
+ return 0;
+}
+
+
+static int dde26_ts_cleanup(void)
+{
+ return 0;
+}
+
+
+int main(int argc, char **argv)
+{
+ CU_pSuite dde_testsuite = NULL;
+
+ int err = CU_initialize_registry();
+ if (err == CUE_SUCCESS)
+ printk("Initialized CUnit registry.\n");
+ else {
+ printk("Could not initialize CUnit registry.\n");
+ return -1;
+ }
+
+ dde_testsuite = CU_add_suite("DDE2.6 test suite", dde26_ts_init, dde26_ts_cleanup);
+ if (dde_testsuite)
+ printk("Added DDE2.6 test suite.\n");
+ else {
+ printk("Could not add DDE2.6 test suite.\n");
+ return -2;
+ }
+
+ CU_ADD_TEST(dde_testsuite, test_initcalls);
+ CU_ADD_TEST(dde_testsuite, current_test);
+ CU_ADD_TEST(dde_testsuite, kernel_thread_test);
+ CU_ADD_TEST(dde_testsuite, wq_test);
+ CU_ADD_TEST(dde_testsuite, tasklet_test);
+ CU_ADD_TEST(dde_testsuite, memory_test);
+
+ CU_basic_set_mode(CU_BRM_VERBOSE);
+ CU_basic_run_tests();
+
+ CU_cleanup_registry();
+
+ l4_sleep_forever();
+
+ return 0;
+}