From be514997d2e59f999fb26c297b7331e445153811 Mon Sep 17 00:00:00 2001 From: okuji Date: Tue, 14 Sep 1999 06:55:57 +0000 Subject: [PATCH] add netboot support. --- ChangeLog | 106 ++++ Makefile.am | 2 +- Makefile.in | 4 +- NEWS | 1 + THANKS | 1 + TODO | 7 +- configure | 299 ++++++++--- configure.in | 92 +++- debian/Makefile.in | 2 + docs/.cvsignore | 2 - docs/Makefile.in | 2 + docs/stamp-vti | 3 + docs/version.texi | 3 + grub/Makefile.in | 2 + netboot/3c509.c | 574 +++++++++++++++++++++ netboot/3c509.h | 389 ++++++++++++++ netboot/3c59x.c | 1172 +++++++++++++++++++++++++++++++++++++++++++ netboot/Makefile.am | 20 + netboot/Makefile.in | 536 ++++++++++++++++++++ netboot/byteorder.h | 77 +++ netboot/compile | 82 +++ netboot/config.c | 225 +++++++++ netboot/config.h | 8 + netboot/cs89x0.c | 699 ++++++++++++++++++++++++++ netboot/cs89x0.h | 465 +++++++++++++++++ netboot/eepro100.c | 800 +++++++++++++++++++++++++++++ netboot/fsys_tftp.c | 227 +++++++++ netboot/if.h | 18 + netboot/io.h | 93 ++++ netboot/ip.c | 645 ++++++++++++++++++++++++ netboot/ip.h | 15 + netboot/lance.c | 426 ++++++++++++++++ netboot/netboot.h | 471 +++++++++++++++++ netboot/netdevice.h | 195 +++++++ netboot/nic.h | 18 + netboot/ns8390.c | 746 +++++++++++++++++++++++++++ netboot/ns8390.h | 251 +++++++++ netboot/pci.c | 261 ++++++++++ netboot/pci.h | 89 ++++ stage1/Makefile.in | 2 + stage1/stage1.S | 2 +- stage1/stage1_lba.S | 2 +- stage2/Makefile.am | 4 + stage2/Makefile.in | 8 +- stage2/asm.S | 31 ++ stage2/char_io.c | 65 +++ stage2/disk_io.c | 31 +- stage2/filesys.h | 12 +- stage2/gunzip.c | 52 +- stage2/shared.h | 5 + stage2/size_test | 2 +- 51 files changed, 9152 insertions(+), 92 deletions(-) create mode 100644 docs/stamp-vti create mode 100644 docs/version.texi create mode 100644 netboot/3c509.c create mode 100644 netboot/3c509.h create mode 100644 netboot/3c59x.c create mode 100644 netboot/Makefile.am create mode 100644 netboot/Makefile.in create mode 100644 netboot/byteorder.h create mode 100644 netboot/compile create mode 100644 netboot/config.c create mode 100644 netboot/config.h create mode 100644 netboot/cs89x0.c create mode 100644 netboot/cs89x0.h create mode 100644 netboot/eepro100.c create mode 100644 netboot/fsys_tftp.c create mode 100644 netboot/if.h create mode 100644 netboot/io.h create mode 100644 netboot/ip.c create mode 100644 netboot/ip.h create mode 100644 netboot/lance.c create mode 100644 netboot/netboot.h create mode 100644 netboot/netdevice.h create mode 100644 netboot/nic.h create mode 100644 netboot/ns8390.c create mode 100644 netboot/ns8390.h create mode 100644 netboot/pci.c create mode 100644 netboot/pci.h diff --git a/ChangeLog b/ChangeLog index 533a450f7..9793b1a76 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,109 @@ +1999-09-14 OKUJI Yoshinori + + * configure.in (--enable-ne): Made the description more clear. + (--enable-nepci): Likewise. + (--enable-wd): Likewise. + (--enable-t503): Likewise. + (--enable-t509): Likewise. + (--enable-3c59x): Likewise. + (--enable-lance): Likewise. + (--enable-cs): Likewise. + (--enable-eepro100): Likewise. + (--enable-wd-default_mem): Renamed to ... + (--enable-wd-default-mem): ... this. + (--enable-cs-scan): Corrected the description. + (NETBOOT_SUPPORT): Defined if NET_CFLAGS is not empty. + * stage2/Makefile.am (stage2_exec_LDADD): Defined only if + NETBOOT_SUPPORT is true. + * netboot/Makefile.am (LIBDRIVERS): New variable. If + NETBOOT_SUPPORT is true, set to libdriver.a, otherwise set to an + empty string. + (noinst_LIBRARIES): Set to LIBDRIVERS. + (DRIVERS): Added 3c509.h, cs89x0.h and ns8390.h. + (libdrivers_a_SOURCES): Added byteorder.h, config.h, if.h, io.h, + ip.h, netboot.h, netdevice.h, nic.h and pic.h. + (libdrivers_a_CFLAGS): Added -fno-builtin and -nostdinc and + removed -O2. + * stage2/char_io.c (grub_sprintf): Added parenthesises to avoid + gcc warnings. + * stage2/gunzip.c (gunzip_test_header): Check if FSYS_TYPE is + TFTP. If so, set IS_TFTP to non-zero, otherwise to zero. And, + use IS_TFTP to check if we have GZIP_CRC instead of the equation + "FILEMAX == 16 * 1024 * 1024". + +1999-09-13 Edmund GRIMLEY EVANS + + The netboot support in the Dresden version of GRUB is integrated. + + * Makefile.am (SUBDIRS): Added netboot. + * configure.in (--enable-tftp): New option. + (--enable-ne): Likewise. + (--enable-nepci): Likewise. + (--enable-wd): Likewise. + (--enable-t503): Likewise. + (--enable-t509): Likewise. + (--enable-3c59x): Likewise. + (--enable-lance): Likewise. + (--enable-cs): Likewise. + (--enable-eepro100): Likewise. + (--enable-ne-scan): Likewise. + (--enable-wd-default_mem): Likewise. + (--enable-cs-scan): Likewise. + (NET_CFLAGS): New variable. + (NET_EXTRAFLAGS): Likewise. + Do AC_OUTPUT for netboot/Makefile as well. + * stage1/stage1.S: Set the number of sectors for Stage 2 to 130. + * stage1/stage1_lba.S: Likewise. + * stage2/Makefile.am (stage2_exec_LDADD): Added + ../netboot/libdrivers.a. + * stage2/asm.S [!STAGE1_5] (currticks): New function. + * stage2/char_io.c [!STAGE1_5] (grub_sprintf): Likewise. + [!STAGE1_5] (grub_memcmp): Likewise. + * stage2/disk_io.c (fsys_table) [FSYS_TFTP]: Added an entry for + tftp. + (sane_partition) [!STAGE1_5]: If CURRENT_DRIVE is a network + drive, return 1. + (real_open_partition) [!STAGE1_5]: Likewise. + (set_device): If DEVICE contains a network drive, set + CURRENT_DRIVE to 0x20. + * stage2/filesys.h [FSYS_TFTP] (FSYS_TFTP_NUM): Defined as 1. + [!FSYS_TFTP] (FSYS_TFTP_NUM): Defined as 0. + (NUM_FSYS): Added FSYS_TFTP_NUM. + * stage2/gunzip.c (gunzip_test_header): If FILEMAX >= 16MB, do + not try to examine the last 8 bytes of the file. This is + required for compressed files by TFTP. + * stage2/shared.h (sprintf): New macro. + (memcmp): Likewise. + (currticks): Declared. + (grub_sprintf): Likewise. + (grub_memcmp): Likewise. + * stage2/size_test: Set the maximum size of Stage 2 to 66560. + * netboot/3c509.c: New file. + * netboot/3c509.h: Likewise. + * netboot/3c59x.c: Likewise. + * netboot/Makefile.am: Likewise. + * netboot/Makefile.in: Likewise. + * netboot/byteorder.h: Likewise. + * netboot/compile: Likewise. + * netboot/config.c: Likewise. + * netboot/config.h: Likewise. + * netboot/cs89x0.c: Likewise. + * netboot/cs89x0.h: Likewise. + * netboot/eepro100.c: Likewise. + * netboot/fsys_tftp.c: Likewise. + * netboot/if.h: Likewise. + * netboot/io.h: Likewise. + * netboot/ip.c: Likewise. + * netboot/ip.h: Likewise. + * netboot/lance.c: Likewise. + * netboot/netboot.h: Likewise. + * netboot/netdevice.h: Likewise. + * netboot/nic.h: Likewise. + * netboot/ns8390.c: Likewise. + * netboot/ns8390.h: Likewise. + * netboot/pci.c: Likewise. + * netboot/pci.h: Likewise. + 1999-09-13 OKUJI Yoshinori * configure.in (--enable-maintainer-mode): Do not use our own diff --git a/Makefile.am b/Makefile.am index 50ac3dfc1..7b3bd44ec 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = stage1 stage2 grub docs debian +SUBDIRS = stage1 netboot stage2 grub docs debian EXTRA_DIST = BUGS # We get $(PACKAGE) and $(VERSION) from debian/changelog. diff --git a/Makefile.in b/Makefile.in index 1ec012d28..d65b503b8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -69,6 +69,8 @@ GRUB_LIBS = @GRUB_LIBS@ LD = @LD@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ +NET_CFLAGS = @NET_CFLAGS@ +NET_EXTRAFLAGS = @NET_EXTRAFLAGS@ OBJCOPY = @OBJCOPY@ PACKAGE = @PACKAGE@ PERL = @PERL@ @@ -81,7 +83,7 @@ host_vendor = @host_vendor@ install_sh = @install_sh@ -SUBDIRS = stage1 stage2 grub docs debian +SUBDIRS = stage1 netboot stage2 grub docs debian EXTRA_DIST = BUGS subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 diff --git a/NEWS b/NEWS index b8659b38c..d656bba82 100644 --- a/NEWS +++ b/NEWS @@ -22,6 +22,7 @@ New in 0.5.93: * The option `--no-floppy' force the grub shell to assume that there is no floppy, and the option `--probe-second-floppy' enables the probe of the second floppy drive. +* Integrated the netboot support in the Dresden version of GRUB. New in 0.5.92 - 1999-07-26: * Bug fixes (i.e. Stage 1.5 can work fine again). diff --git a/THANKS b/THANKS index 421ef6898..69e74d830 100644 --- a/THANKS +++ b/THANKS @@ -11,6 +11,7 @@ Bradford Hovinen Brian Brunswick Bryan Ford Dan J. Walters +Edmund GRIMLEY EVANS Edward Killips Eric Hanchrow Heiko Schroeder diff --git a/TODO b/TODO index 006ac0354..f1dd1f0e7 100644 --- a/TODO +++ b/TODO @@ -7,8 +7,6 @@ type''. We need this for clean Hurd install floppies. Add a real scripting language, possibly retaining backward compatibility so that old config files can be used. -Look at the network booting patches from L4. - Add internationalization support, emulating gettext as much as is feasible. @@ -25,8 +23,13 @@ larger than 16MB can be read. ??? Add command for modifying partition types. +Add OpenBSD support. The recent versions cannot be loaded. + Fix-up FreeBSD, NetBSD (and OpenBSD ?) command-line boot parameters +Add a new installation command, such as `setup', which should be easier +to use and more automatic than the command `install'. + Add keyboard layout configuration support. Clean up and enhance the manuals, especially concept indexes. diff --git a/configure b/configure index d7d401d45..b1a29905b 100644 --- a/configure +++ b/configure @@ -22,8 +22,34 @@ ac_help="$ac_help --disable-ffs disable FFS support in Stage 2" ac_help="$ac_help --disable-minix disable Minix fs support in Stage 2" +ac_help="$ac_help + --enable-tftp enable TFTP support in Stage 2" ac_help="$ac_help --disable-gunzip disable decompression in Stage 2" +ac_help="$ac_help + --enable-ne enable NE1000/2000 network driver in Stage 2" +ac_help="$ac_help + --enable-nepci enable PCI NE2000 network driver in Stage 2" +ac_help="$ac_help + --enable-wd enable WD/SMC network driver in Stage 2" +ac_help="$ac_help + --enable-t503 enable 3C503 network driver in Stage 2" +ac_help="$ac_help + --enable-t509 enable 3C509 network driver in Stage 2" +ac_help="$ac_help + --enable-3c59x enable 3C59x network driver in Stage 2" +ac_help="$ac_help + --enable-lance enable LANCE network driver in Stage 2" +ac_help="$ac_help + --enable-cs enable CS89*0 network driver in Stage 2" +ac_help="$ac_help + --enable-eepro100 enable EtherExpress100 network driver in Stage 2" +ac_help="$ac_help + --enable-ne-scan set the parameter for NE network driver" +ac_help="$ac_help + --enable-wd-default-mem set the parameter for WD network driver" +ac_help="$ac_help + --enable-cs-scan set the parameter for CS network driver" # Initialize some variables set by options. # The variables have the same names as the options, with @@ -569,7 +595,7 @@ ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 -echo "configure:573: checking for a BSD compatible install" >&5 +echo "configure:599: checking for a BSD compatible install" >&5 if test -z "$INSTALL"; then if eval "test \"\${ac_cv_path_install+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -626,7 +652,7 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6 -echo "configure:630: checking whether build environment is sane" >&5 +echo "configure:656: checking whether build environment is sane" >&5 # Just in case sleep 1 echo timestamp > conftestfile @@ -687,7 +713,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:691: checking for $ac_word" >&5 +echo "configure:717: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_AWK+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -717,7 +743,7 @@ test -n "$AWK" && break done echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 -echo "configure:721: checking whether ${MAKE-make} sets \${MAKE}" >&5 +echo "configure:747: checking whether ${MAKE-make} sets \${MAKE}" >&5 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -766,7 +792,7 @@ EOF missing_dir=`cd $ac_aux_dir && pwd` echo $ac_n "checking for working aclocal""... $ac_c" 1>&6 -echo "configure:770: checking for working aclocal" >&5 +echo "configure:796: checking for working aclocal" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -779,7 +805,7 @@ else fi echo $ac_n "checking for working autoconf""... $ac_c" 1>&6 -echo "configure:783: checking for working autoconf" >&5 +echo "configure:809: checking for working autoconf" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -792,7 +818,7 @@ else fi echo $ac_n "checking for working automake""... $ac_c" 1>&6 -echo "configure:796: checking for working automake" >&5 +echo "configure:822: checking for working automake" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -805,7 +831,7 @@ else fi echo $ac_n "checking for working autoheader""... $ac_c" 1>&6 -echo "configure:809: checking for working autoheader" >&5 +echo "configure:835: checking for working autoheader" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -818,7 +844,7 @@ else fi echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6 -echo "configure:822: checking for working makeinfo" >&5 +echo "configure:848: checking for working makeinfo" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -838,7 +864,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:842: checking for $ac_word" >&5 +echo "configure:868: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_AMTAR+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -882,7 +908,7 @@ fi echo $ac_n "checking host system type""... $ac_c" 1>&6 -echo "configure:886: checking host system type" >&5 +echo "configure:912: checking host system type" >&5 if test "x$ac_cv_host" = "x" || (test "x$host" != "xNONE" && test "x$host" != "x$ac_cv_host_alias"); then # Make sure we can run config.sub. @@ -935,7 +961,7 @@ esac # echo $ac_n "checking whether to enable maintainer-specific portions of Makefiles""... $ac_c" 1>&6 -echo "configure:939: checking whether to enable maintainer-specific portions of Makefiles" >&5 +echo "configure:965: checking whether to enable maintainer-specific portions of Makefiles" >&5 # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given. if test "${enable_maintainer_mode+set}" = set; then enableval="$enable_maintainer_mode" @@ -961,7 +987,7 @@ if test "x$enable_maintainer_mode" = xyes; then # Extract the first word of "perl", so it can be a program name with args. set dummy perl; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:965: checking for $ac_word" >&5 +echo "configure:991: checking for $ac_word" >&5 if eval "test \"\${ac_cv_path_PERL+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1009,7 +1035,7 @@ fi echo $ac_n "checking build system type""... $ac_c" 1>&6 -echo "configure:1013: checking build system type" >&5 +echo "configure:1039: checking build system type" >&5 if test "x$ac_cv_build" = "x" || (test "x$build" != "xNONE" && test "x$build" != "x$ac_cv_build_alias"); then # Make sure we can run config.sub. @@ -1056,7 +1082,7 @@ fi # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1060: checking for $ac_word" >&5 +echo "configure:1086: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_CC+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1088,7 +1114,7 @@ fi # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1092: checking for $ac_word" >&5 +echo "configure:1118: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_CC+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1118,7 +1144,7 @@ if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1122: checking for $ac_word" >&5 +echo "configure:1148: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_CC+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1169,7 +1195,7 @@ fi # Extract the first word of "cl", so it can be a program name with args. set dummy cl; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1173: checking for $ac_word" >&5 +echo "configure:1199: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_CC+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1201,7 +1227,7 @@ fi fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $CPPFLAGS $LDFLAGS) works""... $ac_c" 1>&6 -echo "configure:1205: checking whether the C compiler ($CC $CFLAGS $CPPFLAGS $LDFLAGS) works" >&5 +echo "configure:1231: checking whether the C compiler ($CC $CFLAGS $CPPFLAGS $LDFLAGS) works" >&5 ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. @@ -1212,12 +1238,12 @@ cross_compiling=$ac_cv_prog_cc_cross cat > conftest.$ac_ext << EOF -#line 1216 "configure" +#line 1242 "configure" #include "confdefs.h" main(){return(0);} EOF -if { (eval echo configure:1221: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:1247: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then ac_cv_prog_cc_works=yes # If we can't run a trivial program, we are probably using a cross compiler. if (./conftest; exit) 2>/dev/null; then @@ -1243,12 +1269,12 @@ if test $ac_cv_prog_cc_works = no; then { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $CPPFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 -echo "configure:1247: checking whether the C compiler ($CC $CFLAGS $CPPFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "configure:1273: checking whether the C compiler ($CC $CFLAGS $CPPFLAGS $LDFLAGS) is a cross-compiler" >&5 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 cross_compiling=$ac_cv_prog_cc_cross echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 -echo "configure:1252: checking whether we are using GNU C" >&5 +echo "configure:1278: checking whether we are using GNU C" >&5 if eval "test \"\${ac_cv_prog_gcc+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1257,7 +1283,7 @@ else yes; #endif EOF -if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1261: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1287: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no @@ -1276,7 +1302,7 @@ ac_test_CFLAGS="${CFLAGS+set}" ac_save_CFLAGS="$CFLAGS" CFLAGS= echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 -echo "configure:1280: checking whether ${CC-cc} accepts -g" >&5 +echo "configure:1306: checking whether ${CC-cc} accepts -g" >&5 if eval "test \"\${ac_cv_prog_cc_g+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1310,7 +1336,7 @@ fi # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1314: checking for $ac_word" >&5 +echo "configure:1340: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_RANLIB+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1345,7 +1371,7 @@ if test "x$ac_cv_prog_gcc" = xyes; then STAGE1_CFLAGS="-O2" GRUB_CFLAGS="-O2" echo $ac_n "checking whether optimization for size works""... $ac_c" 1>&6 -echo "configure:1349: checking whether optimization for size works" >&5 +echo "configure:1375: checking whether optimization for size works" >&5 if eval "test \"\${size_flag+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1353,14 +1379,14 @@ else saved_CFLAGS=$CFLAGS CFLAGS="-Os -g" cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1390: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* size_flag=yes else @@ -1393,7 +1419,7 @@ CPPFLAGS="$CPPFLAGS -Wall -Wmissing-prototypes -Wunused" # Extract the first word of "${ac_tool_prefix}ld", so it can be a program name with args. set dummy ${ac_tool_prefix}ld; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1397: checking for $ac_word" >&5 +echo "configure:1423: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_LD+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1425,7 +1451,7 @@ fi # Extract the first word of "${ac_tool_prefix}objcopy", so it can be a program name with args. set dummy ${ac_tool_prefix}objcopy; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1429: checking for $ac_word" >&5 +echo "configure:1455: checking for $ac_word" >&5 if eval "test \"\${ac_cv_prog_OBJCOPY+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1458,7 +1484,7 @@ fi # Defined in acinclude.m4. echo $ac_n "checking if C symbols get an underscore after compilation""... $ac_c" 1>&6 -echo "configure:1462: checking if C symbols get an underscore after compilation" >&5 +echo "configure:1488: checking if C symbols get an underscore after compilation" >&5 if eval "test \"\${grub_cv_asm_uscore+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1471,7 +1497,7 @@ func (int *list) } EOF -if { ac_try='${CC-cc} -S conftest.c'; { (eval echo configure:1475: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } && test -s conftest.s; then : +if { ac_try='${CC-cc} -S conftest.c'; { (eval echo configure:1501: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } && test -s conftest.s; then : else { echo "configure: error: ${CC-cc} failed to produce assembly code" 1>&2; exit 1; } fi @@ -1493,7 +1519,7 @@ fi echo "$ac_t""$grub_cv_asm_uscore" 1>&6 echo $ac_n "checking whether ${OBJCOPY} works for absolute addresses""... $ac_c" 1>&6 -echo "configure:1497: checking whether ${OBJCOPY} works for absolute addresses" >&5 +echo "configure:1523: checking whether ${OBJCOPY} works for absolute addresses" >&5 if eval "test \"\${grub_cv_prog_objcopy_absolute+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1505,21 +1531,21 @@ blah (void) } EOF -if { (eval echo configure:1509: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; } && test -s conftest.o; then : +if { (eval echo configure:1535: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; } && test -s conftest.o; then : else { echo "configure: error: ${CC-cc} cannot compile C source code" 1>&2; exit 1; } fi grub_cv_prog_objcopy_absolute=yes for link_addr in 2000 8000 7C00; do - if { ac_try='${LD-ld} -N -Ttext $link_addr conftest.o -o conftest.exec'; { (eval echo configure:1515: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then : + if { ac_try='${LD-ld} -N -Ttext $link_addr conftest.o -o conftest.exec'; { (eval echo configure:1541: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then : else { echo "configure: error: ${LD-ld} cannot link at address $link_addr" 1>&2; exit 1; } fi - if { ac_try='${OBJCOPY-objcopy} -O binary conftest.exec conftest'; { (eval echo configure:1519: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then : + if { ac_try='${OBJCOPY-objcopy} -O binary conftest.exec conftest'; { (eval echo configure:1545: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then : else { echo "configure: error: ${OBJCOPY-objcopy} cannot create binary files" 1>&2; exit 1; } fi - if test ! -f conftest.old || { ac_try='cmp -s conftest.old conftest'; { (eval echo configure:1523: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then + if test ! -f conftest.old || { ac_try='cmp -s conftest.old conftest'; { (eval echo configure:1549: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; }; then mv -f conftest conftest.old else grub_cv_prog_objcopy_absolute=no @@ -1536,7 +1562,7 @@ fi echo $ac_n "checking for .code16 addr32 assembler support""... $ac_c" 1>&6 -echo "configure:1540: checking for .code16 addr32 assembler support" >&5 +echo "configure:1566: checking for .code16 addr32 assembler support" >&5 if eval "test \"\${grub_cv_asm_addr32+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1546,7 +1572,7 @@ l1: addr32 movb %al, l1 EOF -if { ac_try='${CC-cc} -c conftest.s'; { (eval echo configure:1550: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } && test -s conftest.o; then +if { ac_try='${CC-cc} -c conftest.s'; { (eval echo configure:1576: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } && test -s conftest.o; then grub_cv_asm_addr32=yes else grub_cv_asm_addr32=no @@ -1561,7 +1587,7 @@ fi echo $ac_n "checking whether addr32 must be in the same line as the instruction""... $ac_c" 1>&6 -echo "configure:1565: checking whether addr32 must be in the same line as the instruction" >&5 +echo "configure:1591: checking whether addr32 must be in the same line as the instruction" >&5 if eval "test \"\${grub_cv_asm_prefix_requirement+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1570,7 +1596,7 @@ else l1: addr32 movb %al, l1 EOF -if { ac_try='${CC-cc} -c conftest.s'; { (eval echo configure:1574: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } && test -s conftest.o; then +if { ac_try='${CC-cc} -c conftest.s'; { (eval echo configure:1600: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } && test -s conftest.o; then grub_cv_asm_prefix_requirement=yes else grub_cv_asm_prefix_requirement=no @@ -1601,7 +1627,7 @@ fi # Check for curses libraries. echo $ac_n "checking for wgetch in -lncurses""... $ac_c" 1>&6 -echo "configure:1605: checking for wgetch in -lncurses" >&5 +echo "configure:1631: checking for wgetch in -lncurses" >&5 ac_lib_var=`echo ncurses'_'wgetch | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -1609,7 +1635,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lncurses $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:1650: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -1643,7 +1669,7 @@ EOF else echo "$ac_t""no" 1>&6 echo $ac_n "checking for wgetch in -lcurses""... $ac_c" 1>&6 -echo "configure:1647: checking for wgetch in -lcurses" >&5 +echo "configure:1673: checking for wgetch in -lcurses" >&5 ac_lib_var=`echo curses'_'wgetch | sed 'y%./+-:%__p__%'` if eval "test \"\${ac_cv_lib_$ac_lib_var+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -1651,7 +1677,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lcurses $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:1692: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -1692,7 +1718,7 @@ fi # Check for headers. echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 -echo "configure:1696: checking how to run the C preprocessor" >&5 +echo "configure:1722: checking how to run the C preprocessor" >&5 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= @@ -1707,13 +1733,13 @@ else # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1717: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1743: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -1724,13 +1750,13 @@ else rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1734: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1760: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -1741,13 +1767,13 @@ else rm -rf conftest* CPP="${CC-cc} -nologo -E" cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1751: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1777: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -1775,17 +1801,17 @@ for ac_hdr in string.h strings.h ncurses/curses.h ncurses.h curses.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:1779: checking for $ac_hdr" >&5 +echo "configure:1805: checking for $ac_hdr" >&5 if eval "test \"\${ac_cv_header_$ac_safe+set}\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1789: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1815: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -1859,6 +1885,17 @@ if test x"$enable_minix" != xno; then FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_MINIX=1" fi +# Check whether --enable-tftp or --disable-tftp was given. +if test "${enable_tftp+set}" = set; then + enableval="$enable_tftp" + : +fi + + +if test x"$enable_tftp" = xyes; then + FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_TFTP=1" +fi + # Check whether --enable-gunzip or --disable-gunzip was given. if test "${enable_gunzip+set}" = set; then enableval="$enable_gunzip" @@ -1872,6 +1909,144 @@ fi +# Check whether --enable-ne or --disable-ne was given. +if test "${enable_ne+set}" = set; then + enableval="$enable_ne" + : +fi + + +if test x"$enable_ne" = xyes; then + NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NE=1" +fi + +# Check whether --enable-nepci or --disable-nepci was given. +if test "${enable_nepci+set}" = set; then + enableval="$enable_nepci" + : +fi + + +if test x"$enable_nepci" = xyes; then + NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NEPCI=1" +fi + +# Check whether --enable-wd or --disable-wd was given. +if test "${enable_wd+set}" = set; then + enableval="$enable_wd" + : +fi + + +if test x"$enable_wd" = xyes; then + NET_CFLAGS="$NET_CFLAGS -DINCLUDE_WD=1" +fi + +# Check whether --enable-t503 or --disable-t503 was given. +if test "${enable_t503+set}" = set; then + enableval="$enable_t503" + : +fi + + +if test x"$enable_t503" = xyes; then + NET_CFLAGS="$NET_CFLAGS -DINCLUDE_T503=1" +fi + +# Check whether --enable-t509 or --disable-t509 was given. +if test "${enable_t509+set}" = set; then + enableval="$enable_t509" + : +fi + + +if test x"$enable_t509" = xyes; then + NET_CFLAGS="$NET_CFLAGS -DINCLUDE_T509=1" +fi + +# Check whether --enable-3c59x or --disable-3c59x was given. +if test "${enable_3c59x+set}" = set; then + enableval="$enable_3c59x" + : +fi + + +if test x"$enable_3c59x" = xyes; then + NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C59X=1" +fi + +# Check whether --enable-lance or --disable-lance was given. +if test "${enable_lance+set}" = set; then + enableval="$enable_lance" + : +fi + + +if test x"$enable_lance" = xyes; then + NET_CFLAGS="$NET_CFLAGS -DINCLUDE_LANCE=1" +fi + +# Check whether --enable-cs or --disable-cs was given. +if test "${enable_cs+set}" = set; then + enableval="$enable_cs" + : +fi + + +if test x"$enable_cs" = xyes; then + NET_CFLAGS="$NET_CFLAGS -DINCLUDE_CS=1" +fi + +# Check whether --enable-eepro100 or --disable-eepro100 was given. +if test "${enable_eepro100+set}" = set; then + enableval="$enable_eepro100" + : +fi + + +if test x"$enable_eepro100" = xyes; then + NET_CFLAGS="$NET_CFLAGS -DINCLUDE_EEPRO100=1" +fi + + + + +if test ! -z "$NET_CFLAGS"; then + NETBOOT_SUPPORT_TRUE= + NETBOOT_SUPPORT_FALSE='#' +else + NETBOOT_SUPPORT_TRUE='#' + NETBOOT_SUPPORT_FALSE= +fi + + +# Check whether --enable-ne-scan or --disable-ne-scan was given. +if test "${enable_ne_scan+set}" = set; then + enableval="$enable_ne_scan" + NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DNE_SCAN=$enable_ne_scan" +else + NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DNE_SCAN=0x280,0x300,0x320,0x340" +fi + + +# Check whether --enable-wd-default-mem or --disable-wd-default-mem was given. +if test "${enable_wd_default_mem+set}" = set; then + enableval="$enable_wd_default_mem" + NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DWD_DEFAULT_MEM=$enable_wd_default_mem" +else + NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DWD_DEFAULT_MEM=0xCC000" +fi + + +# Check whether --enable-cs-scan or --disable-cs-scan was given. +if test "${enable_cs_scan+set}" = set; then + enableval="$enable_cs_scan" + NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DCS_SCAN=$enable_cs_scan" +fi + + + + # Output. trap '' 1 2 15 @@ -1976,7 +2151,7 @@ ac_given_srcdir=$srcdir ac_given_INSTALL="$INSTALL" trap 'rm -fr `echo "Makefile stage1/Makefile stage2/Makefile docs/Makefile \ - debian/Makefile grub/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 + debian/Makefile grub/Makefile netboot/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then diff --git a/configure.in b/configure.in index e13ea8157..5084811b0 100644 --- a/configure.in +++ b/configure.in @@ -147,6 +147,13 @@ if test x"$enable_minix" != xno; then FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_MINIX=1" fi +AC_ARG_ENABLE(tftp, + [ --enable-tftp enable TFTP support in Stage 2]) + +if test x"$enable_tftp" = xyes; then + FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_TFTP=1" +fi + AC_ARG_ENABLE(gunzip, [ --disable-gunzip disable decompression in Stage 2]) @@ -156,7 +163,90 @@ fi AC_SUBST(FSYS_CFLAGS) +AC_ARG_ENABLE(ne, + [ --enable-ne enable NE1000/2000 network driver in Stage 2]) + +if test x"$enable_ne" = xyes; then + NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NE=1" +fi + +AC_ARG_ENABLE(nepci, + [ --enable-nepci enable PCI NE2000 network driver in Stage 2]) + +if test x"$enable_nepci" = xyes; then + NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NEPCI=1" +fi + +AC_ARG_ENABLE(wd, + [ --enable-wd enable WD/SMC network driver in Stage 2]) + +if test x"$enable_wd" = xyes; then + NET_CFLAGS="$NET_CFLAGS -DINCLUDE_WD=1" +fi + +AC_ARG_ENABLE(t503, + [ --enable-t503 enable 3C503 network driver in Stage 2]) + +if test x"$enable_t503" = xyes; then + NET_CFLAGS="$NET_CFLAGS -DINCLUDE_T503=1" +fi + +AC_ARG_ENABLE(t509, + [ --enable-t509 enable 3C509 network driver in Stage 2]) + +if test x"$enable_t509" = xyes; then + NET_CFLAGS="$NET_CFLAGS -DINCLUDE_T509=1" +fi + +AC_ARG_ENABLE(3c59x, + [ --enable-3c59x enable 3C59x network driver in Stage 2]) + +if test x"$enable_3c59x" = xyes; then + NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C59X=1" +fi + +AC_ARG_ENABLE(lance, + [ --enable-lance enable LANCE network driver in Stage 2]) + +if test x"$enable_lance" = xyes; then + NET_CFLAGS="$NET_CFLAGS -DINCLUDE_LANCE=1" +fi + +AC_ARG_ENABLE(cs, + [ --enable-cs enable CS89*0 network driver in Stage 2]) + +if test x"$enable_cs" = xyes; then + NET_CFLAGS="$NET_CFLAGS -DINCLUDE_CS=1" +fi + +AC_ARG_ENABLE(eepro100, + [ --enable-eepro100 enable EtherExpress100 network driver in Stage 2]) + +if test x"$enable_eepro100" = xyes; then + NET_CFLAGS="$NET_CFLAGS -DINCLUDE_EEPRO100=1" +fi + +AC_SUBST(NET_CFLAGS) +AM_CONDITIONAL(NETBOOT_SUPPORT, test ! -z "$NET_CFLAGS") + + +AC_ARG_ENABLE(ne-scan, + [ --enable-ne-scan set the parameter for NE network driver], +[NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DNE_SCAN=$enable_ne_scan"], +[NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DNE_SCAN=0x280,0x300,0x320,0x340"]) + +AC_ARG_ENABLE(wd-default-mem, + [ --enable-wd-default-mem set the parameter for WD network driver], +[NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DWD_DEFAULT_MEM=$enable_wd_default_mem"], +[NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DWD_DEFAULT_MEM=0xCC000"]) + +AC_ARG_ENABLE(cs-scan, + [ --enable-cs-scan set the parameter for CS network driver], +[NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DCS_SCAN=$enable_cs_scan"]) + +AC_SUBST(NET_EXTRAFLAGS) + # Output. AC_OUTPUT([Makefile stage1/Makefile stage2/Makefile docs/Makefile \ - debian/Makefile grub/Makefile]) + debian/Makefile grub/Makefile netboot/Makefile]) diff --git a/debian/Makefile.in b/debian/Makefile.in index 6fac16a45..20d2f6d5d 100644 --- a/debian/Makefile.in +++ b/debian/Makefile.in @@ -69,6 +69,8 @@ GRUB_LIBS = @GRUB_LIBS@ LD = @LD@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ +NET_CFLAGS = @NET_CFLAGS@ +NET_EXTRAFLAGS = @NET_EXTRAFLAGS@ OBJCOPY = @OBJCOPY@ PACKAGE = @PACKAGE@ PERL = @PERL@ diff --git a/docs/.cvsignore b/docs/.cvsignore index 524b652fc..d2865a246 100644 --- a/docs/.cvsignore +++ b/docs/.cvsignore @@ -1,3 +1 @@ *.info* -version.texi -stamp-vti diff --git a/docs/Makefile.in b/docs/Makefile.in index 40787677f..b338b7057 100644 --- a/docs/Makefile.in +++ b/docs/Makefile.in @@ -69,6 +69,8 @@ GRUB_LIBS = @GRUB_LIBS@ LD = @LD@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ +NET_CFLAGS = @NET_CFLAGS@ +NET_EXTRAFLAGS = @NET_EXTRAFLAGS@ OBJCOPY = @OBJCOPY@ PACKAGE = @PACKAGE@ PERL = @PERL@ diff --git a/docs/stamp-vti b/docs/stamp-vti new file mode 100644 index 000000000..b7e8736a5 --- /dev/null +++ b/docs/stamp-vti @@ -0,0 +1,3 @@ +@set UPDATED 10 September 1999 +@set EDITION 0.5.93 +@set VERSION 0.5.93 diff --git a/docs/version.texi b/docs/version.texi new file mode 100644 index 000000000..b7e8736a5 --- /dev/null +++ b/docs/version.texi @@ -0,0 +1,3 @@ +@set UPDATED 10 September 1999 +@set EDITION 0.5.93 +@set VERSION 0.5.93 diff --git a/grub/Makefile.in b/grub/Makefile.in index 75b3ed45c..30fe92a90 100644 --- a/grub/Makefile.in +++ b/grub/Makefile.in @@ -69,6 +69,8 @@ GRUB_LIBS = @GRUB_LIBS@ LD = @LD@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ +NET_CFLAGS = @NET_CFLAGS@ +NET_EXTRAFLAGS = @NET_EXTRAFLAGS@ OBJCOPY = @OBJCOPY@ PACKAGE = @PACKAGE@ PERL = @PERL@ diff --git a/netboot/3c509.c b/netboot/3c509.c new file mode 100644 index 000000000..8387acad9 --- /dev/null +++ b/netboot/3c509.c @@ -0,0 +1,574 @@ +/************************************************************************** +NETBOOT - BOOTP/TFTP Bootstrap Program + +Author: Martin Renters. + Date: Mar 22 1995 + + This code is based heavily on David Greenman's if_ed.c driver and + Andres Vega Garcia's if_ep.c driver. + + Copyright (C) 1993-1994, David Greenman, Martin Renters. + Copyright (C) 1993-1995, Andres Vega Garcia. + Copyright (C) 1995, Serge Babkin. + This software may be used, modified, copied, distributed, and sold, in + both source and binary form provided that the above copyright and these + terms are retained. Under no circumstances are the authors responsible for + the proper functioning of this software, nor do the authors assume any + responsibility for damages incurred with its use. + +3c509 support added by Serge Babkin (babkin@hq.icb.chel.su) + +$Id$ + +***************************************************************************/ + +#ifdef INCLUDE_T509 + +/* #define EDEBUG */ + +#include "netboot.h" +#include "nic.h" +#include "3c509.h" + +static unsigned char eth_vendor, eth_flags, eth_laar; +static unsigned short eth_nic_base, eth_asic_base; +static char bnc=0, utp=0; /* for 3C509 */ + +static void safetwiddle() +{ + static int count=0; + static int count2=0; + static char tiddles[]="-\\|/"; + putchar(tiddles[(count2++)&0xfff?count&3:(count++)&3]); + putchar('\b'); +} + +/* a surrogate */ + +static void DELAY(int val) +{ + int c; + + for(c=0; cnode_addr[i]); + + outw(BASE + EP_COMMAND, RX_RESET); + outw(BASE + EP_COMMAND, TX_RESET); + + /* Window 1 is operating window */ + GO_WINDOW(1); + for (i = 0; i < 31; i++) + inb(BASE + EP_W1_TX_STATUS); + + /* get rid of stray intr's */ + outw(BASE + EP_COMMAND, ACK_INTR | 0xff); + + outw(BASE + EP_COMMAND, SET_RD_0_MASK | S_5_INTS); + + outw(BASE + EP_COMMAND, SET_INTR_MASK); + + outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | + FIL_BRDCST); + + /* configure BNC */ + if (bnc) { + outw(BASE + EP_COMMAND, START_TRANSCEIVER); + SAFEDELAY(1000); + } + /* configure UTP */ + if (utp) { + GO_WINDOW(4); + outw(BASE + EP_W4_MEDIA_TYPE, ENABLE_UTP); + GO_WINDOW(1); + } + + /* start tranciever and receiver */ + outw(BASE + EP_COMMAND, RX_ENABLE); + outw(BASE + EP_COMMAND, TX_ENABLE); + + /* set early threshold for minimal packet length */ + outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | ETH_MIN_PACKET); + + outw(BASE + EP_COMMAND, SET_TX_START_THRESH | 16); +} + +/************************************************************************** +ETH_TRANSMIT - Transmit a frame +***************************************************************************/ +static char padmap[] = { + 0, 3, 2, 1}; + +static void t509_transmit( +struct nic *nic, +char *d, /* Destination */ +unsigned int t, /* Type */ +unsigned int s, /* size */ +char *p) /* Packet */ +{ + register u_int len; + int pad; + int status; + + if(eth_vendor != VENDOR_3C509) + return; + +#ifdef EDEBUG + printf("{l=%d,t=%x}",s+ETHER_HDR_SIZE,t); +#endif + + /* swap bytes of type */ + t= htons(t); + + len=s+ETHER_HDR_SIZE; /* actual length of packet */ + pad = padmap[len & 3]; + + /* + * The 3c509 automatically pads short packets to minimum ethernet length, + * but we drop packets that are too large. Perhaps we should truncate + * them instead? + */ + if (len + pad > ETH_MAX_PACKET) { + return; + } + + /* drop acknowledgements */ + while(( status=inb(BASE + EP_W1_TX_STATUS) )& TXS_COMPLETE ) { + if(status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) { + outw(BASE + EP_COMMAND, TX_RESET); + outw(BASE + EP_COMMAND, TX_ENABLE); + } + + outb(BASE + EP_W1_TX_STATUS, 0x0); + } + + while (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) { + /* no room in FIFO */ + } + + outw(BASE + EP_W1_TX_PIO_WR_1, len); + outw(BASE + EP_W1_TX_PIO_WR_1, 0x0); /* Second dword meaningless */ + + /* write packet */ + outsw(BASE + EP_W1_TX_PIO_WR_1, d, ETHER_ADDR_SIZE/2); + outsw(BASE + EP_W1_TX_PIO_WR_1, nic->node_addr, ETHER_ADDR_SIZE/2); + outw(BASE + EP_W1_TX_PIO_WR_1, t); + outsw(BASE + EP_W1_TX_PIO_WR_1, p, s / 2); + if (s & 1) + outb(BASE + EP_W1_TX_PIO_WR_1, *(p+s - 1)); + + while (pad--) + outb(BASE + EP_W1_TX_PIO_WR_1, 0); /* Padding */ + + /* timeout after sending */ + DELAY(1000); +} + +/************************************************************************** +ETH_POLL - Wait for a frame +***************************************************************************/ +static int t509_poll(struct nic *nic) +{ + /* common variables */ + unsigned short type = 0; /* used by EDEBUG */ + /* variables for 3C509 */ + short status, cst; + register short rx_fifo; + + if(eth_vendor!=VENDOR_3C509) + return 0; + + cst=inw(BASE + EP_STATUS); + +#ifdef EDEBUG + if(cst & 0x1FFF) + printf("-%x-",cst); +#endif + + if( (cst & S_RX_COMPLETE)==0 ) { + /* acknowledge everything */ + outw(BASE + EP_COMMAND, ACK_INTR| (cst & S_5_INTS)); + outw(BASE + EP_COMMAND, C_INTR_LATCH); + + return 0; + } + + status = inw(BASE + EP_W1_RX_STATUS); +#ifdef EDEBUG + printf("*%x*",status); +#endif + + if (status & ERR_RX) { + outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK); + return 0; + } + + rx_fifo = status & RX_BYTES_MASK; + if (rx_fifo==0) + return 0; + + /* read packet */ +#ifdef EDEBUG + printf("[l=%d",rx_fifo); +#endif + insw(BASE + EP_W1_RX_PIO_RD_1, nic->packet, rx_fifo / 2); + if(rx_fifo & 1) + nic->packet[rx_fifo-1]=inb(BASE + EP_W1_RX_PIO_RD_1); + nic->packetlen=rx_fifo; + + while(1) { + status = inw(BASE + EP_W1_RX_STATUS); +#ifdef EDEBUG + printf("*%x*",status); +#endif + rx_fifo = status & RX_BYTES_MASK; + + if(rx_fifo>0) { + insw(BASE + EP_W1_RX_PIO_RD_1, nic->packet+nic->packetlen, rx_fifo / 2); + if(rx_fifo & 1) + nic->packet[nic->packetlen+rx_fifo-1]=inb(BASE + EP_W1_RX_PIO_RD_1); + nic->packetlen+=rx_fifo; +#ifdef EDEBUG + printf("+%d",rx_fifo); +#endif + } + + if(( status & RX_INCOMPLETE )==0) { +#ifdef EDEBUG + printf("=%d",nic->packetlen); +#endif + break; + } + + DELAY(1000); + } + + /* acknowledge reception of packet */ + outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK); + while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); +#ifdef EDEBUG + type = (nic->packet[12]<<8) | nic->packet[13]; + if(nic->packet[0]+nic->packet[1]+nic->packet[2]+nic->packet[3]+nic->packet[4]+ + nic->packet[5] == 0xFF*ETHER_ADDR_SIZE) + printf(",t=0x%x,b]",type); + else + printf(",t=0x%x]",type); +#endif + return 1; +} + + +/************************************************************************* + 3Com 509 - specific routines +**************************************************************************/ + +static int +eeprom_rdy() +{ + int i; + + for (i = 0; is_eeprom_busy(IS_BASE) && i < MAX_EEPROMBUSY; i++); + if (i >= MAX_EEPROMBUSY) { + /* printf("3c509: eeprom failed to come ready.\r\n"); */ + printf("3c509: eeprom is busy.\r\n"); /* memory in EPROM is tight */ + return (0); + } + return (1); +} + +/* + * get_e: gets a 16 bits word from the EEPROM. we must have set the window + * before + */ +static int +get_e(offset) +int offset; +{ + if (!eeprom_rdy()) + return (0xffff); + outw(IS_BASE + EP_W0_EEPROM_COMMAND, EEPROM_CMD_RD | offset); + if (!eeprom_rdy()) + return (0xffff); + return (inw(IS_BASE + EP_W0_EEPROM_DATA)); +} + +static int +send_ID_sequence(port) +int port; +{ + int cx, al; + + for (al = 0xff, cx = 0; cx < 255; cx++) { + outb(port, al); + al <<= 1; + if (al & 0x100) + al ^= 0xcf; + } + return (1); +} + + +/* + * We get eeprom data from the id_port given an offset into the eeprom. + * Basically; after the ID_sequence is sent to all of the cards; they enter + * the ID_CMD state where they will accept command requests. 0x80-0xbf loads + * the eeprom data. We then read the port 16 times and with every read; the + * cards check for contention (ie: if one card writes a 0 bit and another + * writes a 1 bit then the host sees a 0. At the end of the cycle; each card + * compares the data on the bus; if there is a difference then that card goes + * into ID_WAIT state again). In the meantime; one bit of data is returned in + * the AX register which is conveniently returned to us by inb(). Hence; we + * read 16 times getting one bit of data with each read. + */ +static int +get_eeprom_data(id_port, offset) +int id_port; +int offset; +{ + int i, data = 0; + outb(id_port, 0x80 + offset); + DELAY(1000); + for (i = 0; i < 16; i++) + data = (data << 1) | (inw(id_port) & 1); + return (data); +} + +static void t509_disable(struct nic *nic) +{ +} + +/************************************************************************** +ETH_PROBE - Look for an adapter +***************************************************************************/ +struct nic *t509_probe(struct nic *nic, unsigned short *probe_addrs) +{ + /* common variables */ + int i; + int failcount; + + + /* variables for 3C509 */ + + + for (failcount=0; failcount<4000; failcount++) { + int data, j, io_base, id_port = EP_ID_PORT; + u_short k; + int ep_current_tag = EP_LAST_TAG + 1; + short *p; + + id_port = EP_ID_PORT; + ep_current_tag = EP_LAST_TAG + 1; + eth_vendor = VENDOR_NONE; + + /********************************************************* + Search for 3Com 509 card + ***********************************************************/ + + /* Look for the EISA boards, leave them activated */ + /* search for the first card, ignore all others */ + for(j = 1; j < 16 && eth_vendor==VENDOR_NONE ; j++) { + io_base = (j * EP_EISA_START) | EP_EISA_W0; + if (inw(io_base + EP_W0_MFG_ID) != MFG_ID) + continue; + + /* we must found 0x1f if the board is EISA configurated */ + if ((inw(io_base + EP_W0_ADDRESS_CFG) & 0x1f) != 0x1f) + continue; + + /* Reset and Enable the card */ + outb(io_base + EP_W0_CONFIG_CTRL, W0_P4_CMD_RESET_ADAPTER); + SAFEDELAY(1000); /* we must wait at least 1 ms */ + outb(io_base + EP_W0_CONFIG_CTRL, W0_P4_CMD_ENABLE_ADAPTER); + + /* + * Once activated, all the registers are mapped in the range + * x000 - x00F, where x is the slot number. + */ + eth_nic_base = j * EP_EISA_START; + eth_vendor = VENDOR_3C509; + } + ep_current_tag--; + + /* Look for the ISA boards. Init and leave them actived */ + /* search for the first card, ignore all others */ + outb(id_port, 0xc0); /* Global reset */ + SAFEDELAY(1000); + for (i = 0; i < EP_MAX_BOARDS && eth_vendor==VENDOR_NONE; i++) { + outb(id_port, 0); + outb(id_port, 0); + send_ID_sequence(id_port); + + data = get_eeprom_data(id_port, EEPROM_MFG_ID); + if (data != MFG_ID) + break; + + /* resolve contention using the Ethernet address */ + for (j = 0; j < 3; j++) + data = get_eeprom_data(id_port, j); + + eth_nic_base = + (get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * 0x10 + 0x200; + outb(id_port, ep_current_tag); /* tags board */ + outb(id_port, ACTIVATE_ADAPTER_TO_CONFIG); + eth_vendor = VENDOR_3C509; + ep_current_tag--; + } + + if(eth_vendor != VENDOR_3C509) + goto no3c509; + + /* + * The iobase was found and MFG_ID was 0x6d50. PROD_ID should be + * 0x9[0-f]50 + */ + GO_WINDOW(0); + k = get_e(EEPROM_PROD_ID); + if ((k & 0xf0ff) != (PROD_ID & 0xf0ff)) + goto no3c509; + + if(eth_nic_base >= EP_EISA_START) { + printf("3C5x9 board on EISA at 0x%x - ",eth_nic_base); + } else { + printf("3C5x9 board on ISA at 0x%x - ",eth_nic_base); + } + + /* test for presence of connectors */ + i = inw(IS_BASE + EP_W0_CONFIG_CTRL); + j = inw(IS_BASE + EP_W0_ADDRESS_CFG) >> 14; + + switch(j) { + case 0: + if(i & IS_UTP) { + printf("10baseT\r\n"); + utp=1; + } + else { + printf("10baseT not present\r\n"); + eth_vendor=VENDOR_NONE; + goto no3c509; + } + + break; + case 1: + if(i & IS_AUI) + printf("10base5\r\n"); + else { + printf("10base5 not present\r\n"); + eth_vendor=VENDOR_NONE; + goto no3c509; + } + + break; + case 3: + if(i & IS_BNC) { + printf("10base2\r\n"); + bnc=1; + } + else { + printf("10base2 not present\r\n"); + eth_vendor=VENDOR_NONE; + goto no3c509; + } + + break; + default: + printf("unknown connector\r\n"); + eth_vendor=VENDOR_NONE; + goto no3c509; + } + /* + * Read the station address from the eeprom + */ + p = (u_short *) nic->node_addr; + for (i = 0; i < 3; i++) { + GO_WINDOW(0); + p[i] = htons(get_e(i)); + GO_WINDOW(2); + outw(BASE + EP_W2_ADDR_0 + (i * 2), ntohs(p[i])); + } + + printf("Ethernet address: "); + for(i=0; i<5; i++) { + printf("%b:",nic->node_addr[i]); + } + printf("%b\r\n",nic->node_addr[i]); + + t509_reset(nic); + nic->reset = t509_reset; + nic->poll = t509_poll; + nic->transmit = t509_transmit; + nic->disable = t509_disable; + return nic; +no3c509: + eth_vendor = VENDOR_NONE; + printf("(probe fail)"); + } + return 0; +} + +#endif /* INCLUDE_T509 */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/netboot/3c509.h b/netboot/3c509.h new file mode 100644 index 000000000..2b983b804 --- /dev/null +++ b/netboot/3c509.h @@ -0,0 +1,389 @@ +/* + * Copyright (c) 1993 Herb Peyerl (hpeyerl@novatel.ca) All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. The name + * of the author may not be used to endorse or promote products derived from + * this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * if_epreg.h,v 1.4 1994/11/13 10:12:37 gibbs Exp Modified by: + * + October 2, 1994 + + Modified by: Andres Vega Garcia + + INRIA - Sophia Antipolis, France + e-mail: avega@sophia.inria.fr + finger: avega@pax.inria.fr + + */ + +/* + * Ethernet software status per interface. + */ +/* + * Some global constants + */ + +#define TX_INIT_RATE 16 +#define TX_INIT_MAX_RATE 64 +#define RX_INIT_LATENCY 64 +#define RX_INIT_EARLY_THRESH 64 +#define MIN_RX_EARLY_THRESHF 16 /* not less than ether_header */ +#define MIN_RX_EARLY_THRESHL 4 + +#define EEPROMSIZE 0x40 +#define MAX_EEPROMBUSY 1000 +#define EP_LAST_TAG 0xd7 +#define EP_MAX_BOARDS 16 +#define EP_ID_PORT 0x100 + +/* + * some macros to acces long named fields + */ +#define IS_BASE (eth_nic_base) +#define BASE (eth_nic_base) + +/* + * Commands to read/write EEPROM trough EEPROM command register (Window 0, + * Offset 0xa) + */ +#define EEPROM_CMD_RD 0x0080 /* Read: Address required (5 bits) */ +#define EEPROM_CMD_WR 0x0040 /* Write: Address required (5 bits) */ +#define EEPROM_CMD_ERASE 0x00c0 /* Erase: Address required (5 bits) */ +#define EEPROM_CMD_EWEN 0x0030 /* Erase/Write Enable: No data required */ + +#define EEPROM_BUSY (1<<15) +#define EEPROM_TST_MODE (1<<14) + +/* + * Some short functions, worth to let them be a macro + */ +#define is_eeprom_busy(b) (inw((b)+EP_W0_EEPROM_COMMAND)&EEPROM_BUSY) +#define GO_WINDOW(x) outw(BASE+EP_COMMAND, WINDOW_SELECT|(x)) + +/************************************************************************** + * * + * These define the EEPROM data structure. They are used in the probe + * function to verify the existance of the adapter after having sent + * the ID_Sequence. + * + * There are others but only the ones we use are defined here. + * + **************************************************************************/ + +#define EEPROM_NODE_ADDR_0 0x0 /* Word */ +#define EEPROM_NODE_ADDR_1 0x1 /* Word */ +#define EEPROM_NODE_ADDR_2 0x2 /* Word */ +#define EEPROM_PROD_ID 0x3 /* 0x9[0-f]50 */ +#define EEPROM_MFG_ID 0x7 /* 0x6d50 */ +#define EEPROM_ADDR_CFG 0x8 /* Base addr */ +#define EEPROM_RESOURCE_CFG 0x9 /* IRQ. Bits 12-15 */ + +/************************************************************************** + * * + * These are the registers for the 3Com 3c509 and their bit patterns when * + * applicable. They have been taken out the the "EtherLink III Parallel * + * Tasking EISA and ISA Technical Reference" "Beta Draft 10/30/92" manual * + * from 3com. * + * * + **************************************************************************/ + +#define EP_COMMAND 0x0e /* Write. BASE+0x0e is always a + * command reg. */ +#define EP_STATUS 0x0e /* Read. BASE+0x0e is always status + * reg. */ +#define EP_WINDOW 0x0f /* Read. BASE+0x0f is always window + * reg. */ +/* + * Window 0 registers. Setup. + */ +/* Write */ +#define EP_W0_EEPROM_DATA 0x0c +#define EP_W0_EEPROM_COMMAND 0x0a +#define EP_W0_RESOURCE_CFG 0x08 +#define EP_W0_ADDRESS_CFG 0x06 +#define EP_W0_CONFIG_CTRL 0x04 +/* Read */ +#define EP_W0_PRODUCT_ID 0x02 +#define EP_W0_MFG_ID 0x00 + +/* + * Window 1 registers. Operating Set. + */ +/* Write */ +#define EP_W1_TX_PIO_WR_2 0x02 +#define EP_W1_TX_PIO_WR_1 0x00 +/* Read */ +#define EP_W1_FREE_TX 0x0c +#define EP_W1_TX_STATUS 0x0b /* byte */ +#define EP_W1_TIMER 0x0a /* byte */ +#define EP_W1_RX_STATUS 0x08 +#define EP_W1_RX_PIO_RD_2 0x02 +#define EP_W1_RX_PIO_RD_1 0x00 + +/* + * Window 2 registers. Station Address Setup/Read + */ +/* Read/Write */ +#define EP_W2_ADDR_5 0x05 +#define EP_W2_ADDR_4 0x04 +#define EP_W2_ADDR_3 0x03 +#define EP_W2_ADDR_2 0x02 +#define EP_W2_ADDR_1 0x01 +#define EP_W2_ADDR_0 0x00 + +/* + * Window 3 registers. FIFO Management. + */ +/* Read */ +#define EP_W3_FREE_TX 0x0c +#define EP_W3_FREE_RX 0x0a + +/* + * Window 4 registers. Diagnostics. + */ +/* Read/Write */ +#define EP_W4_MEDIA_TYPE 0x0a +#define EP_W4_CTRLR_STATUS 0x08 +#define EP_W4_NET_DIAG 0x06 +#define EP_W4_FIFO_DIAG 0x04 +#define EP_W4_HOST_DIAG 0x02 +#define EP_W4_TX_DIAG 0x00 + +/* + * Window 5 Registers. Results and Internal status. + */ +/* Read */ +#define EP_W5_READ_0_MASK 0x0c +#define EP_W5_INTR_MASK 0x0a +#define EP_W5_RX_FILTER 0x08 +#define EP_W5_RX_EARLY_THRESH 0x06 +#define EP_W5_TX_AVAIL_THRESH 0x02 +#define EP_W5_TX_START_THRESH 0x00 + +/* + * Window 6 registers. Statistics. + */ +/* Read/Write */ +#define TX_TOTAL_OK 0x0c +#define RX_TOTAL_OK 0x0a +#define TX_DEFERRALS 0x08 +#define RX_FRAMES_OK 0x07 +#define TX_FRAMES_OK 0x06 +#define RX_OVERRUNS 0x05 +#define TX_COLLISIONS 0x04 +#define TX_AFTER_1_COLLISION 0x03 +#define TX_AFTER_X_COLLISIONS 0x02 +#define TX_NO_SQE 0x01 +#define TX_CD_LOST 0x00 + +/**************************************** + * + * Register definitions. + * + ****************************************/ + +/* + * Command register. All windows. + * + * 16 bit register. + * 15-11: 5-bit code for command to be executed. + * 10-0: 11-bit arg if any. For commands with no args; + * this can be set to anything. + */ +#define GLOBAL_RESET (u_short) 0x0000 /* Wait at least 1ms + * after issuing */ +#define WINDOW_SELECT (u_short) (0x1<<11) +#define START_TRANSCEIVER (u_short) (0x2<<11) /* Read ADDR_CFG reg to + * determine whether + * this is needed. If + * so; wait 800 uSec + * before using trans- + * ceiver. */ +#define RX_DISABLE (u_short) (0x3<<11) /* state disabled on + * power-up */ +#define RX_ENABLE (u_short) (0x4<<11) +#define RX_RESET (u_short) (0x5<<11) +#define RX_DISCARD_TOP_PACK (u_short) (0x8<<11) +#define TX_ENABLE (u_short) (0x9<<11) +#define TX_DISABLE (u_short) (0xa<<11) +#define TX_RESET (u_short) (0xb<<11) +#define REQ_INTR (u_short) (0xc<<11) +#define SET_INTR_MASK (u_short) (0xe<<11) +#define SET_RD_0_MASK (u_short) (0xf<<11) +#define SET_RX_FILTER (u_short) (0x10<<11) +#define FIL_INDIVIDUAL (u_short) (0x1) +#define FIL_GROUP (u_short) (0x2) +#define FIL_BRDCST (u_short) (0x4) +#define FIL_ALL (u_short) (0x8) +#define SET_RX_EARLY_THRESH (u_short) (0x11<<11) +#define SET_TX_AVAIL_THRESH (u_short) (0x12<<11) +#define SET_TX_START_THRESH (u_short) (0x13<<11) +#define STATS_ENABLE (u_short) (0x15<<11) +#define STATS_DISABLE (u_short) (0x16<<11) +#define STOP_TRANSCEIVER (u_short) (0x17<<11) +/* + * The following C_* acknowledge the various interrupts. Some of them don't + * do anything. See the manual. + */ +#define ACK_INTR (u_short) (0x6800) +#define C_INTR_LATCH (u_short) (ACK_INTR|0x1) +#define C_CARD_FAILURE (u_short) (ACK_INTR|0x2) +#define C_TX_COMPLETE (u_short) (ACK_INTR|0x4) +#define C_TX_AVAIL (u_short) (ACK_INTR|0x8) +#define C_RX_COMPLETE (u_short) (ACK_INTR|0x10) +#define C_RX_EARLY (u_short) (ACK_INTR|0x20) +#define C_INT_RQD (u_short) (ACK_INTR|0x40) +#define C_UPD_STATS (u_short) (ACK_INTR|0x80) + +/* + * Status register. All windows. + * + * 15-13: Window number(0-7). + * 12: Command_in_progress. + * 11: reserved. + * 10: reserved. + * 9: reserved. + * 8: reserved. + * 7: Update Statistics. + * 6: Interrupt Requested. + * 5: RX Early. + * 4: RX Complete. + * 3: TX Available. + * 2: TX Complete. + * 1: Adapter Failure. + * 0: Interrupt Latch. + */ +#define S_INTR_LATCH (u_short) (0x1) +#define S_CARD_FAILURE (u_short) (0x2) +#define S_TX_COMPLETE (u_short) (0x4) +#define S_TX_AVAIL (u_short) (0x8) +#define S_RX_COMPLETE (u_short) (0x10) +#define S_RX_EARLY (u_short) (0x20) +#define S_INT_RQD (u_short) (0x40) +#define S_UPD_STATS (u_short) (0x80) +#define S_5_INTS (S_CARD_FAILURE|S_TX_COMPLETE|\ + S_TX_AVAIL|S_RX_COMPLETE|S_RX_EARLY) +#define S_COMMAND_IN_PROGRESS (u_short) (0x1000) + +/* + * FIFO Registers. + * RX Status. Window 1/Port 08 + * + * 15: Incomplete or FIFO empty. + * 14: 1: Error in RX Packet 0: Incomplete or no error. + * 13-11: Type of error. + * 1000 = Overrun. + * 1011 = Run Packet Error. + * 1100 = Alignment Error. + * 1101 = CRC Error. + * 1001 = Oversize Packet Error (>1514 bytes) + * 0010 = Dribble Bits. + * (all other error codes, no errors.) + * + * 10-0: RX Bytes (0-1514) + */ +#define ERR_RX_INCOMPLETE (u_short) (0x1<<15) +#define ERR_RX (u_short) (0x1<<14) +#define ERR_RX_OVERRUN (u_short) (0x8<<11) +#define ERR_RX_RUN_PKT (u_short) (0xb<<11) +#define ERR_RX_ALIGN (u_short) (0xc<<11) +#define ERR_RX_CRC (u_short) (0xd<<11) +#define ERR_RX_OVERSIZE (u_short) (0x9<<11) +#define ERR_RX_DRIBBLE (u_short) (0x2<<11) + +/* + * FIFO Registers. + * TX Status. Window 1/Port 0B + * + * Reports the transmit status of a completed transmission. Writing this + * register pops the transmit completion stack. + * + * Window 1/Port 0x0b. + * + * 7: Complete + * 6: Interrupt on successful transmission requested. + * 5: Jabber Error (TP Only, TX Reset required. ) + * 4: Underrun (TX Reset required. ) + * 3: Maximum Collisions. + * 2: TX Status Overflow. + * 1-0: Undefined. + * + */ +#define TXS_COMPLETE 0x80 +#define TXS_SUCCES_INTR_REQ 0x40 +#define TXS_JABBER 0x20 +#define TXS_UNDERRUN 0x10 +#define TXS_MAX_COLLISION 0x8 +#define TXS_STATUS_OVERFLOW 0x4 + +/* + * Configuration control register. + * Window 0/Port 04 + */ +/* Read */ +#define IS_AUI (1<<13) +#define IS_BNC (1<<12) +#define IS_UTP (1<<9) +/* Write */ +#define ENABLE_DRQ_IRQ 0x0001 +#define W0_P4_CMD_RESET_ADAPTER 0x4 +#define W0_P4_CMD_ENABLE_ADAPTER 0x1 +/* + * Media type and status. + * Window 4/Port 0A + */ +#define ENABLE_UTP 0xc0 +#define DISABLE_UTP 0x0 + +/* + * Resource control register + */ + +#define SET_IRQ(i) ( ((i)<<12) | 0xF00) /* set IRQ i */ + +/* + * Receive status register + */ + +#define RX_BYTES_MASK (u_short) (0x07ff) +#define RX_ERROR 0x4000 +#define RX_INCOMPLETE 0x8000 + + +/* + * Misc defines for various things. + */ +#define ACTIVATE_ADAPTER_TO_CONFIG 0xff /* to the id_port */ +#define MFG_ID 0x6d50 /* in EEPROM and W0 ADDR_CONFIG */ +#define PROD_ID 0x9150 + +#define AUI 0x1 +#define BNC 0x2 +#define UTP 0x4 + +#define RX_BYTES_MASK (u_short) (0x07ff) + + /* EISA support */ +#define EP_EISA_START 0x1000 +#define EP_EISA_W0 0x0c80 +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ + diff --git a/netboot/3c59x.c b/netboot/3c59x.c new file mode 100644 index 000000000..d2cd5721a --- /dev/null +++ b/netboot/3c59x.c @@ -0,0 +1,1172 @@ +/* 3c59x.c: A 3Com 3c59x/3c90x "Vortex/Boomerang" ethernet driver for linux. */ +/* + Written 1995 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + This driver is for the 3Com "Vortex" series ethercards. Members of + the series include the 3c590 PCI EtherLink III and 3c595-Tx PCI Fast + EtherLink. + + The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O + Center of Excellence in Space Data and Information Sciences + Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 +*/ + +#ifdef INCLUDE_3c59x + + +#define lx_outb(a,b) outb(b,a) +#define lx_outw(a,b) outw(b,a) +#define lx_outl(a,b) outl(b,a) + + +static int __jiffies__; + +#define jiffies ((__jiffies__+=1000)) + +void cli () +{ + __asm__ __volatile__("cli"); +} +#define HZ 1 + +void memset (char *add, int v, int s) +{ + while (s--) + *add++ = (char )v; +} + +static char *version = "3c59x.c:v0.30-all 12/23/96 becker@cesdis.gsfc.nasa.gov\n"; + +/* "Knobs" that turn on special features. */ +/* Enable the automatic media selection code. */ +#define AUTOMEDIA 1 + +/* Allow the use of bus master transfers instead of programmed-I/O for the + Tx process. Bus master transfers are always disabled by default, but + iff this is set they may be turned on using 'options'. */ + +#define NO_VORTEX_BUS_MASTER + + +#include "netboot.h" +#include "nic.h" +#include "3c509.h" +#include "pci.h" + +#include "if.h" + +#include "netdevice.h" + +struct device card; + +/* "Knobs" for adjusting internal parameters. */ +/* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs). */ +#define VORTEX_DEBUG 2 + +/* Number of times to check to see if the Tx FIFO has space, used in some + limited cases. */ +#define WAIT_TX_AVAIL 200 + +/* Operational parameter that usually are not changed. */ +/* Time in jiffies before concluding Tx hung */ +#define TX_TIMEOUT ((400*HZ)/1000) + +/* The total size is twice that of the original EtherLinkIII series: the + runtime register window, window 1, is now always mapped in. */ +#define VORTEX_TOTAL_SIZE 0x20 + +#ifdef HAVE_DEVLIST +struct netdev_entry tc59x_drv = +{"Vortex", vortex_pci_probe, VORTEX_TOTAL_SIZE, NULL}; +#endif + +#ifdef VORTEX_DEBUG +int vortex_debug = VORTEX_DEBUG; +#else +int vortex_debug = 1; +#endif + +/* Caution! These entries must be consistent, with the EISA ones last. */ +static int product_ids[] = {0x5900, 0x5950, 0x5951, 0x5952, 0x9000, + 0x9001, 0x9050, 0x9051, 0, 0}; +static const char *product_names[] = { + "3c590 Vortex 10Mbps", + "3c595 Vortex 100baseTX", + "3c595 Vortex 100baseT4", + "3c595 Vortex 100base-MII", + "3c900 Boomerang 10baseT", + "3c900 Boomerang 10Mbps/Combo", + "3c905 Boomerang 100baseTx", + "3c905 Boomerang 100baseT4", + "3c592 EISA 10mbps Demon/Vortex", + "3c597 EISA Fast Demon/Vortex", +}; +#define DEMON10_INDEX 8 +#define DEMON100_INDEX 9 + +/* + Theory of Operation + +I. Board Compatibility + +This device driver is designed for the 3Com FastEtherLink, 3Com's PCI to +10/100baseT adapter. It also works with the 3c590, a similar product +with only a 10Mbs interface. + +II. Board-specific settings + +PCI bus devices are configured by the system at boot time, so no jumpers +need to be set on the board. The system BIOS should be set to assign the +PCI INTA signal to an otherwise unused system IRQ line. While it's +physically possible to shared PCI interrupt lines, the 1.2.0 kernel doesn't +support it. + +III. Driver operation + +The 3c59x series use an interface that's very similar to the previous 3c5x9 +series. The primary interface is two programmed-I/O FIFOs, with an +alternate single-contiguous-region bus-master transfer (see next). + +One extension that is advertised in a very large font is that the adapters +are capable of being bus masters. Unfortunately this capability is only for +a single contiguous region making it less useful than the list of transfer +regions available with the DEC Tulip or AMD PCnet. Given the significant +performance impact of taking an extra interrupt for each transfer, using +DMA transfers is a win only with large blocks. + +IIIC. Synchronization +The driver runs as two independent, single-threaded flows of control. One +is the send-packet routine, which enforces single-threaded use by the +dev->tbusy flag. The other thread is the interrupt handler, which is single +threaded by the hardware and other software. + +IV. Notes + +Thanks to Cameron Spitzer and Terry Murphy of 3Com for providing both +3c590 and 3c595 boards. +The name "Vortex" is the internal 3Com project name for the PCI ASIC, and +the EISA version is called "Demon". According to Terry these names come +from rides at the local amusement park. + +The new chips support both ethernet (1.5K) and FDDI (4.5K) packet sizes! +This driver only supports ethernet packets because of the skbuff allocation +limit of 4K. +*/ + +#define TCOM_VENDOR_ID 0x10B7 /* 3Com's manufacturer's ID. */ + +/* Operational definitions. + These are not used by other compilation units and thus are not + exported in a ".h" file. + + First the windows. There are eight register windows, with the command + and status registers available in each. + */ +#define EL3WINDOW(win_num) lx_outw(SelectWindow + (win_num), ioaddr + EL3_CMD) +#define EL3_CMD 0x0e +#define EL3_STATUS 0x0e + +/* The top five bits written to EL3_CMD are a command, the lower + 11 bits are the parameter, if applicable. + Note that 11 parameters bits was fine for ethernet, but the new chip + can handle FDDI length frames (~4500 octets) and now parameters count + 32-bit 'Dwords' rather than octets. */ + +enum vortex_cmd { + TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11, + RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, RxDiscard = 8<<11, + TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11, + FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11, + SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11, + SetTxThreshold = 18<<11, SetTxStart = 19<<11, + StartDMAUp = 20<<11, StartDMADown = (20<<11)+1, StatsEnable = 21<<11, + StatsDisable = 22<<11, StopCoax = 23<<11,}; + +/* The SetRxFilter command accepts the following classes: */ +enum RxFilter { + RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8 }; + +/* Bits in the general status register. */ +enum vortex_status { + IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004, + TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020, + IntReq = 0x0040, StatsFull = 0x0080, DMADone = 1<<8, + DMAInProgress = 1<<11, /* DMA controller is still busy.*/ + CmdInProgress = 1<<12, /* EL3_CMD is still busy.*/ +}; + +/* Register window 1 offsets, the window used in normal operation. + On the Vortex this window is always mapped at offsets 0x10-0x1f. */ +enum Window1 { + TX_FIFO = 0x10, RX_FIFO = 0x10, RxErrors = 0x14, + RxStatus = 0x18, Timer=0x1A, TxStatus = 0x1B, + TxFree = 0x1C, /* Remaining free bytes in Tx buffer. */ +}; +enum Window0 { + Wn0EepromCmd = 10, /* Window 0: EEPROM command register. */ + Wn0EepromData = 12, /* Window 0: EEPROM results register. */ +}; +enum Win0_EEPROM_bits { + EEPROM_Read = 0x80, EEPROM_WRITE = 0x40, EEPROM_ERASE = 0xC0, + EEPROM_EWENB = 0x30, /* Enable erasing/writing for 10 msec. */ + EEPROM_EWDIS = 0x00, /* Disable EWENB before 10 msec timeout. */ +}; +/* EEPROM locations. */ +enum eeprom_offset { + PhysAddr01=0, PhysAddr23=1, PhysAddr45=2, ModelID=3, + EtherLink3ID=7, IFXcvrIO=8, IRQLine=9, + NodeAddr01=10, NodeAddr23=11, NodeAddr45=12, + DriverTune=13, Checksum=15}; + +enum Window3 { /* Window 3: MAC/config bits. */ + Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8, +}; +union wn3_config { + int i; + struct w3_config_fields { + unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2; + int pad8:8; + unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1, autoselect:1; + int pad24:7; + } u; +}; + +enum Window4 { + Wn4_Media = 0x0A, /* Window 4: Various transcvr/media bits. */ +}; +enum Win4_Media_bits { + Media_SQE = 0x0008, /* Enable SQE error counting for AUI. */ + Media_10TP = 0x00C0, /* Enable link beat and jabber for 10baseT. */ + Media_Lnk = 0x0080, /* Enable just link beat for 100TX/100FX. */ + Media_LnkBeat = 0x0800, +}; +enum Window7 { /* Window 7: Bus Master control. */ + Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12, +}; + +struct vortex_private { + char devname[8]; /* "ethN" string, also for kernel debug. */ + const char *product_name; + int options; /* User-settable misc. driver options. */ + int last_rx_packets; /* For media autoselection. */ + unsigned int available_media:8, /* From Wn3_Options */ + media_override:3, /* Passed-in media type. */ + default_media:3, /* Read from the EEPROM. */ + full_duplex:1, bus_master:1, autoselect:1; +}; + +/* The action to take with a media selection timer tick. + Note that we deviate from the 3Com order by checking 10base2 before AUI. + */ +static struct media_table { + char *name; + unsigned int media_bits:16, /* Bits to set in Wn4_Media register. */ + mask:8, /* The transceiver-present bit in Wn3_Config.*/ + next:8; /* The media type to try next. */ + short wait; /* Time before we check media status. */ +} media_tbl[] = { + { "10baseT", Media_10TP,0x08, 3 /* 10baseT->10base2 */, (14*HZ)/10}, + { "10Mbs AUI", Media_SQE, 0x20, 8 /* AUI->default */, (1*HZ)/10}, + { "undefined", 0, 0x80, 0 /* Undefined */, 0}, + { "10base2", 0, 0x10, 1 /* 10base2->AUI. */, (1*HZ)/10}, + { "100baseTX", Media_Lnk, 0x02, 5 /* 100baseTX->100baseFX */, (14*HZ)/10}, + { "100baseFX", Media_Lnk, 0x04, 6 /* 100baseFX->MII */, (14*HZ)/10}, + { "MII", 0, 0x40, 0 /* MII->10baseT */, (14*HZ)/10}, + { "undefined", 0, 0x01, 0 /* Undefined/100baseT4 */, 0}, + { "Default", 0, 0xFF, 0 /* Use default */, 0}, +}; + +static int vortex_scan(struct device *dev); +static int vortex_found_device(struct device *dev, int ioaddr, int irq, + int product_index, int options); +static int vortex_probe1(struct device *dev); +static int vortex_open(struct device *dev); +static void vortex_timer(unsigned long arg); +static int vortex_start_xmit(struct device *dev,char *data, int len); +static int vortex_rx(struct device *dev, char *data, int len); + +static int vortex_close(struct device *dev); +static void update_stats(int addr, struct device *dev); +static struct enet_statistics *vortex_get_stats(struct device *dev); +static void set_rx_mode(struct device *dev); +#ifndef NEW_MULTICAST +static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); +#endif + + +/* Unlike the other PCI cards the 59x cards don't need a large contiguous + memory region, so making the driver a loadable module is feasible. + + Unfortunately maximizing the shared code between the integrated and + module version of the driver results in a complicated set of initialization + procedures. + init_module() -- modules / tc59x_init() -- built-in + The wrappers for vortex_scan() + vortex_scan() The common routine that scans for PCI and EISA cards + vortex_found_device() Allocate a device structure when we find a card. + Different versions exist for modules and built-in. + vortex_probe1() Fill in the device structure -- this is separated + so that the modules code can put it in dev->init. +*/ +/* This driver uses 'options' to pass the media type, full-duplex flag, etc. */ +/* Note: this is the only limit on the number of cards supported!! */ +static int options[8] = { -1, -1, -1, -1, -1, -1, -1, -1,}; +/* Variables to work-around the Compaq PCI BIOS32 problem. */ +static int compaq_ioaddr = 0, compaq_irq = 0, compaq_prod_id = 0; + +int tc59x_probe(struct device *dev) +{ + int cards_found = 0; + + cards_found = vortex_scan(dev); + + if (vortex_debug > 0 && cards_found) + printf(version); + + return cards_found ? 0 : -1; +} + +static int vortex_scan(struct device *dev) +{ + int cards_found = 0; + +#ifndef NO_PCI +/* if (pcibios_present()) { */ + if (1) { + static int pci_index = 0; + static int board_index = 0; + for (; product_ids[board_index]; board_index++, pci_index = 0) { + for (; pci_index < 16; pci_index++) { + unsigned char pci_bus, pci_device_fn, pci_irq_line; + unsigned char pci_latency; + unsigned int pci_ioaddr; + unsigned short pci_command; + + struct pci_device pcidev; + + eth_pci_init (&pcidev, &pci_ioaddr); + /* Remove I/O space marker in bit 0. */ + +#ifdef VORTEX_BUS_MASTER + /* Get and check the bus-master and latency values. + Some PCI BIOSes fail to set the master-enable bit, and + the latency timer must be set to the maximum value to avoid + data corruption that occurs when the timer expires during + a transfer. Yes, it's a bug. */ + pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, &pci_command); + if ( ! (pci_command & PCI_COMMAND_MASTER)) { + printf(" PCI Master Bit has not been set! Setting...\n"); + pci_command |= PCI_COMMAND_MASTER; + pcibios_write_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, pci_command); + } + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_LATENCY_TIMER, &pci_latency); + if (pci_latency != 255) { + printf(" 3Com EtherLink III: Overriding PCI latency" + " timer (CFLT) setting of %d, new value is 255.\n", + pci_latency); + pcibios_write_config_byte(pci_bus, pci_device_fn, + PCI_LATENCY_TIMER, 255); + } +#endif /* VORTEX_BUS_MASTER */ + vortex_found_device(dev, pci_ioaddr, pci_irq_line, board_index, + dev && dev->mem_start ? dev->mem_start + : options[cards_found]); + dev = 0; + cards_found++; + } + } + } +#endif /* NO_PCI */ + + + /* Special code to work-around the Compaq PCI BIOS32 problem. */ + if (compaq_ioaddr) { + vortex_found_device(dev, compaq_ioaddr, compaq_irq, compaq_prod_id, + dev && dev->mem_start ? dev->mem_start : options[cards_found]); + cards_found++; + dev = 0; + } + + return cards_found; +} + +static int vortex_found_device(struct device *dev, int ioaddr, int irq, + int product_index, int options) +{ + struct vortex_private *vp; + static struct vortex_private vps; + + if (dev) { + /*dev->priv = kmalloc(sizeof (struct vortex_private), GFP_KERNEL); */ + dev->priv = &vps; + memset(dev->priv, 0, sizeof (struct vortex_private)); + } +#if 0 + dev = init_etherdev(dev, sizeof(struct vortex_private)); +#endif + dev->base_addr = ioaddr; + dev->irq = irq; + vp = (struct vortex_private *)dev->priv; + vp->product_name = product_names[product_index]; + vp->options = options; + if (options >= 0) { + vp->media_override = ((options & 7) == 2) ? 0 : options & 7; + vp->full_duplex = (options & 8) ? 1 : 0; + vp->bus_master = (options & 16) ? 1 : 0; + } else { + vp->media_override = 7; + vp->full_duplex = 0; + vp->bus_master = 0; + } + + vortex_probe1(dev); + return 0; +} + +static int vortex_probe1(struct device *dev) +{ + int ioaddr = dev->base_addr; + struct vortex_private *vp = (struct vortex_private *)dev->priv; + int i; + + printf("%s: 3Com %s at %#3x,", dev->name, + vp->product_name, ioaddr); + + /* Read the station address from the EEPROM. */ + EL3WINDOW(0); + for (i = 0; i < 3; i++) { + short *phys_addr = (short *)dev->dev_addr; + int timer; + lx_outw(EEPROM_Read + PhysAddr01 + i, ioaddr + Wn0EepromCmd); + /* Pause for at least 162 us. for the read to take place. */ + for (timer = 162*4 + 400; timer >= 0; timer--) { + SLOW_DOWN_IO; + if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0) + break; + } + phys_addr[i] = htons(inw(ioaddr + Wn0EepromData)); + } + for (i = 0; i < 6; i++) + printf("%c%x", i ? ':' : ' ', dev->dev_addr[i]); + printf(", IRQ %d\n", dev->irq); + /* Tell them about an invalid IRQ. */ + if (vortex_debug && (dev->irq <= 0 || dev->irq > 15)) + printf(" *** Warning: this IRQ is unlikely to work!\n"); + + { + char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; + union wn3_config config; + EL3WINDOW(3); + vp->available_media = inw(ioaddr + Wn3_Options); + config.i = inl(ioaddr + Wn3_Config); + if (vortex_debug > 1) + printf(" Internal config register is %4.4x, transceivers %#x.\n", + config.i, inw(ioaddr + Wn3_Options)); + printf(" %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n", + 8 << config.u.ram_size, + config.u.ram_width ? "word" : "byte", + ram_split[config.u.ram_split], + config.u.autoselect ? "autoselect/" : "", + media_tbl[config.u.xcvr].name); + dev->if_port = config.u.xcvr; + vp->default_media = config.u.xcvr; + vp->autoselect = config.u.autoselect; + } + +#if 0 + /* We do a request_region() only to register /proc/ioports info. */ + request_region(ioaddr, VORTEX_TOTAL_SIZE, vp->product_name); +#endif + return 0; +} + + +static int +vortex_open(struct device *dev) +{ + int ioaddr = dev->base_addr; + struct vortex_private *vp = (struct vortex_private *)dev->priv; + union wn3_config config; + int i; + + /* Before initializing select the active media port. */ + EL3WINDOW(3); + if (vp->full_duplex) + lx_outb(0x20, ioaddr + Wn3_MAC_Ctrl); /* Set the full-duplex bit. */ + config.i = inl(ioaddr + Wn3_Config); + + if (vp->media_override != 7) { + if (vortex_debug > 1) + printf("%s: Media override to transceiver %d (%s).\n", + dev->name, vp->media_override, + media_tbl[vp->media_override].name); + dev->if_port = vp->media_override; + } else if (vp->autoselect) { + /* Find first available media type, starting with 100baseTx. */ + dev->if_port = 4; + while (! (vp->available_media & media_tbl[dev->if_port].mask)) + dev->if_port = media_tbl[dev->if_port].next; + + if (vortex_debug > 1) + printf("%s: Initial media type %s.\n", + dev->name, media_tbl[dev->if_port].name); + +#if 0 + vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait); + vp->timer.data = (unsigned long)dev; + vp->timer.function = &vortex_timer; /* timer handler */ + add_timer(&vp->timer); +#endif + } else + dev->if_port = vp->default_media; + + config.u.xcvr = dev->if_port; + lx_outl(config.i, ioaddr + Wn3_Config); + + if (vortex_debug > 1) { + printf("%s: vortex_open() InternalConfig %8.8x.\n", + dev->name, config.i); + } + + lx_outw(TxReset, ioaddr + EL3_CMD); + for (i = 20; i >= 0 ; i--) + if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) + break; + + lx_outw(RxReset, ioaddr + EL3_CMD); + /* Wait a few ticks for the RxReset command to complete. */ + for (i = 20; i >= 0 ; i--) + if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) + break; + + lx_outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD); + +#if 0 +#ifdef SA_SHIRQ /* Use the now-standard shared IRQ implementation. */ + if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ, + vp->product_name, dev)) { + return -EAGAIN; + } +#else +#ifdef USE_SHARED_IRQ /* Use my shared IRQ implementation. */ + i = request_shared_irq(dev->irq, &vortex_interrupt, dev, vp->product_name); + if (i) /* Error */ + return i; +#else + if (dev->irq == 0 || irq2dev_map[dev->irq] != NULL) + return -EAGAIN; + irq2dev_map[dev->irq] = dev; + if (REQUEST_IRQ(dev->irq, &vortex_interrupt, 0, vp->product_name, NULL)) { + irq2dev_map[dev->irq] = NULL; + return -EAGAIN; + } +#endif /* USE_SHARED_IRQ */ +#endif /* SA_SHIRQ */ +#endif + if (vortex_debug > 1) { + EL3WINDOW(4); + printf("%s: vortex_open() irq %d media status %4.4x.\n", + dev->name, dev->irq, inw(ioaddr + Wn4_Media)); + } + + /* Set the station address and mask in window 2 each time opened. */ + EL3WINDOW(2); + for (i = 0; i < 6; i++) + lx_outb(dev->dev_addr[i], ioaddr + i); + for (; i < 12; i+=2) + lx_outw(0, ioaddr + i); + + if (dev->if_port == 3) + /* Start the thinnet transceiver. We should really wait 50ms...*/ + lx_outw(StartCoax, ioaddr + EL3_CMD); + EL3WINDOW(4); + lx_outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) | + media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media); + + /* Switch to the stats window, and clear all stats by reading. */ + lx_outw(StatsDisable, ioaddr + EL3_CMD); + EL3WINDOW(6); + for (i = 0; i < 10; i++) + inb(ioaddr + i); + inw(ioaddr + 10); + inw(ioaddr + 12); + /* New: On the Vortex we must also clear the BadSSD counter. */ + EL3WINDOW(4); + inb(ioaddr + 12); + + /* Switch to register set 7 for normal use. */ + EL3WINDOW(7); + + /* Set reciever mode: presumably accept b-case and phys addr only. */ + set_rx_mode(dev); + lx_outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + lx_outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ + lx_outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ + /* Allow status bits to be seen. */ + lx_outw(SetStatusEnb | 0x1ff, ioaddr + EL3_CMD); + /* Ack all pending events, and set active indicator mask. */ + lx_outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, + ioaddr + EL3_CMD); + lx_outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull + | DMADone, ioaddr + EL3_CMD); + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + + return 0; +} + +static void vortex_timer(unsigned long data) +{ +#ifdef AUTOMEDIA + struct device *dev = (struct device *)data; + struct vortex_private *vp = (struct vortex_private *)dev->priv; + int ioaddr = dev->base_addr; + unsigned long flags; + int ok = 0; + + if (vortex_debug > 1) + printf("%s: Media selection timer tick happened, %s.\n", + dev->name, media_tbl[dev->if_port].name); + + save_flags(flags); cli(); { + int old_window = inw(ioaddr + EL3_CMD) >> 13; + int media_status; + EL3WINDOW(4); + media_status = inw(ioaddr + Wn4_Media); + switch (dev->if_port) { + case 0: case 4: case 5: /* 10baseT, 100baseTX, 100baseFX */ + if (media_status & Media_LnkBeat) { + ok = 1; + if (vortex_debug > 1) + printf("%s: Media %s has link beat, %x.\n", + dev->name, media_tbl[dev->if_port].name, media_status); + } else if (vortex_debug > 1) + printf("%s: Media %s is has no link beat, %x.\n", + dev->name, media_tbl[dev->if_port].name, media_status); + + break; + default: /* Other media types handled by Tx timeouts. */ + if (vortex_debug > 1) + printf("%s: Media %s is has no indication, %x.\n", + dev->name, media_tbl[dev->if_port].name, media_status); + ok = 1; + } + if ( ! ok) { + union wn3_config config; + + do { + dev->if_port = media_tbl[dev->if_port].next; + } while ( ! (vp->available_media & media_tbl[dev->if_port].mask)); + if (dev->if_port == 8) { /* Go back to default. */ + dev->if_port = vp->default_media; + if (vortex_debug > 1) + printf("%s: Media selection failing, using default %s port.\n", + dev->name, media_tbl[dev->if_port].name); + } else { + if (vortex_debug > 1) + printf("%s: Media selection failed, now trying %s port.\n", + dev->name, media_tbl[dev->if_port].name); +#if 0 + vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait); + add_timer(&vp->timer); +#endif + } + lx_outw((media_status & ~(Media_10TP|Media_SQE)) | + media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media); + + EL3WINDOW(3); + config.i = inl(ioaddr + Wn3_Config); + config.u.xcvr = dev->if_port; + lx_outl(config.i, ioaddr + Wn3_Config); + + lx_outw(dev->if_port == 3 ? StartCoax : StopCoax, ioaddr + EL3_CMD); + } + EL3WINDOW(old_window); + } restore_flags(flags); + if (vortex_debug > 1) + printf("%s: Media selection timer finished, %s.\n", + dev->name, media_tbl[dev->if_port].name); + +#endif /* AUTOMEDIA*/ + return; +} + +static int +vortex_start_xmit(struct device *dev, char *data, int len) +{ + struct vortex_private *vp = (struct vortex_private *)dev->priv; + int ioaddr = dev->base_addr; + + /* Part of the following code is inspired by code from Giuseppe Ciaccio, + ciaccio@disi.unige.it. + It works around a ?bug? in the 8K Vortex that only occurs on some + systems: the TxAvailable interrupt seems to be lost. + The ugly work-around is to busy-wait for room available in the Tx + buffer before deciding the transmitter is actually hung. + This busy-wait should never really occur, since the problem is that + there actually *is* room in the Tx FIFO. + + This pointed out an optimization -- we can ignore dev->tbusy if + we actually have room for this packet. + */ + + if (dev->tbusy) { + /* Transmitter timeout, serious problems. */ + int tickssofar = jiffies - dev->trans_start; + int i; + + if (tickssofar < TX_TIMEOUT-2) /* We probably aren't empty. */ + return 1; + /* Wait a while to see if there really is room. */ + for (i = WAIT_TX_AVAIL; i >= 0; i--) + if (inw(ioaddr + TxFree) > len) + break; + if ( i < 0) { + if (tickssofar < TX_TIMEOUT) + return 1; + printf("%s: transmit timed out, tx_status %2.2x status %4.4x.\n", + dev->name, inb(ioaddr + TxStatus), inw(ioaddr + EL3_STATUS)); + /* Issue TX_RESET and TX_START commands. */ + lx_outw(TxReset, ioaddr + EL3_CMD); + for (i = 20; i >= 0 ; i--) + if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) + break; + lx_outw(TxEnable, ioaddr + EL3_CMD); + dev->trans_start = jiffies; + dev->tbusy = 0; +#if 0 + vp->stats.tx_errors++; + vp->stats.tx_dropped++; +#endif + return 0; /* Yes, silently *drop* the packet! */ + } + } + + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. + If this ever occurs the queue layer is doing something evil! */ +#if 0 + if (set_bit(0, (void*)&dev->tbusy) != 0) { + printf("%s: Transmitter access conflict.\n", dev->name); + return 1; + } +#endif + /* Put out the doubleword header... */ + lx_outl(len, ioaddr + TX_FIFO); +#ifdef VORTEX_BUS_MASTER + if (vp->bus_master) { + /* Set the bus-master controller to transfer the packet. */ + lx_outl((int)(data), ioaddr + Wn7_MasterAddr); + lx_outw((len + 3) & ~3, ioaddr + Wn7_MasterLen); +/* vp->tx_skb = skb; */ + lx_outw(StartDMADown, ioaddr + EL3_CMD); + /* dev->tbusy will be cleared at the DMADone interrupt. */ + } else { + /* ... and the packet rounded to a doubleword. */ + outsl(ioaddr + TX_FIFO, data, (len + 3) >> 2); +/* dev_kfree_skb (skb, FREE_WRITE); */ + if (inw(ioaddr + TxFree) > 1536) { + dev->tbusy = 0; + } else + /* Interrupt us when the FIFO has room for max-sized packet. */ + lx_outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); + } +#else + /* ... and the packet rounded to a doubleword. */ + outsl(ioaddr + TX_FIFO, data, (len + 3) >> 2); +/* dev_kfree_skb (skb, FREE_WRITE); */ + if (inw(ioaddr + TxFree) > 1536) { + dev->tbusy = 0; + } else + /* Interrupt us when the FIFO has room for max-sized packet. */ + lx_outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD); +#endif /* bus master */ + + dev->trans_start = jiffies; + + /* Clear the Tx status stack. */ + { + short tx_status; + int i = 4; + + while (--i > 0 && (tx_status = inb(ioaddr + TxStatus)) > 0) { + if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */ + if (vortex_debug > 2) + printf("%s: Tx error, status %2.2x.\n", + dev->name, tx_status); +#if 0 + if (tx_status & 0x04) vp->stats.tx_fifo_errors++; + if (tx_status & 0x38) vp->stats.tx_aborted_errors++; +#endif + if (tx_status & 0x30) { + int j; + lx_outw(TxReset, ioaddr + EL3_CMD); + for (j = 20; j >= 0 ; j--) + if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) + break; + } + lx_outw(TxEnable, ioaddr + EL3_CMD); + } + lx_outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */ + } + } + return 0; +} + +#if 0 + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs) +{ +#ifdef SA_SHIRQ /* Use the now-standard shared IRQ implementation. */ + struct device *dev = dev_id; +#else +#ifdef USE_SHARED_IRQ + struct device *dev = (struct device *)(irq == 0 ? regs : irq2dev_map[irq]); +#else + struct device *dev = (struct device *)(irq2dev_map[irq]); +#endif +#endif + struct vortex_private *lp; + int ioaddr, status; + int latency; + int i = 0; + + if (dev->interrupt) + printf("%s: Re-entering the interrupt handler.\n", dev->name); + dev->interrupt = 1; + + ioaddr = dev->base_addr; + latency = inb(ioaddr + Timer); + lp = (struct vortex_private *)dev->priv; + + status = inw(ioaddr + EL3_STATUS); + + if (vortex_debug > 4) + printf("%s: interrupt, status %4.4x, timer %d.\n", dev->name, + status, latency); + if ((status & 0xE000) != 0xE000) { + static int donedidthis=0; + /* Some interrupt controllers store a bogus interrupt from boot-time. + Ignore a single early interrupt, but don't hang the machine for + other interrupt problems. */ + if (donedidthis++ > 1) { + printf("%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n", + dev->name, status, dev->start); + FREE_IRQ(dev->irq, dev); + } + } + + do { + if (vortex_debug > 5) + printf("%s: In interrupt loop, status %4.4x.\n", + dev->name, status); + if (status & RxComplete) + vortex_rx(dev); + + if (status & TxAvailable) { + if (vortex_debug > 5) + printf(" TX room bit was handled.\n"); + /* There's room in the FIFO for a full-sized packet. */ + lx_outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); + dev->tbusy = 0; + mark_bh(NET_BH); + } +#ifdef VORTEX_BUS_MASTER + if (status & DMADone) { + lx_outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ + dev->tbusy = 0; + /* dev_kfree_skb (lp->tx_skb, FREE_WRITE); Release the transfered buffer */ +/* mark_bh(NET_BH); */ + } +#endif + if (status & (AdapterFailure | RxEarly | StatsFull)) { + /* Handle all uncommon interrupts at once. */ + if (status & RxEarly) { /* Rx early is unused. */ + vortex_rx(dev); + lx_outw(AckIntr | RxEarly, ioaddr + EL3_CMD); + } + if (status & StatsFull) { /* Empty statistics. */ + static int DoneDidThat = 0; + if (vortex_debug > 4) + printf("%s: Updating stats.\n", dev->name); + update_stats(ioaddr, dev); + /* DEBUG HACK: Disable statistics as an interrupt source. */ + /* This occurs when we have the wrong media type! */ + if (DoneDidThat == 0 && + inw(ioaddr + EL3_STATUS) & StatsFull) { + int win, reg; + printf("%s: Updating stats failed, disabling stats as an" + " interrupt source.\n", dev->name); + for (win = 0; win < 8; win++) { + EL3WINDOW(win); + printf("\n Vortex window %d:", win); + for (reg = 0; reg < 16; reg++) + printf(" %2.2x", inb(ioaddr+reg)); + } + EL3WINDOW(7); + lx_outw(SetIntrEnb | 0x18, ioaddr + EL3_CMD); + DoneDidThat++; + } + } + if (status & AdapterFailure) { + /* Adapter failure requires Rx reset and reinit. */ + lx_outw(RxReset, ioaddr + EL3_CMD); + /* Set the Rx filter to the current state. */ + set_rx_mode(dev); + lx_outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */ + lx_outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD); + } + } + + if (++i > 10) { + printf("%s: Infinite loop in interrupt, status %4.4x. " + "Disabling functions (%4.4x).\n", + dev->name, status, SetStatusEnb | ((~status) & 0xFE)); + /* Disable all pending interrupts. */ + lx_outw(SetStatusEnb | ((~status) & 0xFE), ioaddr + EL3_CMD); + lx_outw(AckIntr | 0xFF, ioaddr + EL3_CMD); + break; + } + /* Acknowledge the IRQ. */ + lx_outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); + + } while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete)); + + if (vortex_debug > 4) + printf("%s: exiting interrupt, status %4.4x.\n", dev->name, status); + + dev->interrupt = 0; + return; +} + +#endif + +static int +vortex_rx(struct device *dev, char *data, int len) +{ + struct vortex_private *vp = (struct vortex_private *)dev->priv; + int ioaddr = dev->base_addr; + int i; + short rx_status; + + if (vortex_debug > 5) + printf(" In rx_packet(), status %4.4x, rx_status %4.4x.\n", + inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus)); + while ((rx_status = inw(ioaddr + RxStatus)) > 0) { + if (rx_status & 0x4000) { /* Error, update stats. */ + unsigned char rx_error = inb(ioaddr + RxErrors); + if (vortex_debug > 4) + printf(" Rx error: status %2.2x.\n", rx_error); +#if 0 + vp->stats.rx_errors++; + if (rx_error & 0x01) vp->stats.rx_over_errors++; + if (rx_error & 0x02) vp->stats.rx_length_errors++; + if (rx_error & 0x04) vp->stats.rx_frame_errors++; + if (rx_error & 0x08) vp->stats.rx_crc_errors++; + if (rx_error & 0x10) vp->stats.rx_length_errors++; +#endif + } else { + /* The packet length: up to 4.5K!. */ + short pkt_len = rx_status & 0x1fff; +/* struct sk_buff *skb; */ + +/* skb = DEV_ALLOC_SKB(pkt_len + 5); */ + if (vortex_debug > 4) + printf("Receiving packet size %d status %4.4x.\n", + pkt_len, rx_status); + + if (1) { + insl(ioaddr + RX_FIFO, data, (pkt_len + 3) >> 2); + lx_outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ + + for (i = 200; i >= 0; i--) + if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) + break; + } + +#if 0 + if (skb != NULL) { + skb->dev = dev; +#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE >= 0x10300 + skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ + /* 'skb_put()' points to the start of sk_buff data area. */ + insl(ioaddr + RX_FIFO, skb_put(skb, pkt_len), + (pkt_len + 3) >> 2); + skb->protocol = eth_type_trans(skb, dev); +#else + skb->len = pkt_len; + /* 'skb->data' points to the start of sk_buff data area. */ + insl(ioaddr + RX_FIFO, skb->data, (pkt_len + 3) >> 2); +#endif /* KERNEL_1_3_0 */ + netif_rx(skb); + lx_outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ + /* Wait a limited time to go to next packet. */ + for (i = 200; i >= 0; i--) + if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) + break; + vp->stats.rx_packets++; + continue; + } else if (vortex_debug) + printf("%s: Couldn't allocate a sk_buff of size %d.\n", + dev->name, pkt_len); +#endif + } +#if 0 + vp->stats.rx_dropped++; +#endif + lx_outw(RxDiscard, ioaddr + EL3_CMD); + /* Wait a limited time to skip this packet. */ + for (i = 200; i >= 0; i--) + if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) + break; + } + + return 0; +} + +static int +vortex_close(struct device *dev) +{ + struct vortex_private *vp = (struct vortex_private *)dev->priv; + int ioaddr = dev->base_addr; + + dev->start = 0; + dev->tbusy = 1; + + if (vortex_debug > 1) + printf("%s: vortex_close() status %4.4x, Tx status %2.2x.\n", + dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus)); + +#if 0 + del_timer(&vp->timer); +#endif + /* Turn off statistics ASAP. We update lp->stats below. */ + lx_outw(StatsDisable, ioaddr + EL3_CMD); + + /* Disable the receiver and transmitter. */ + lx_outw(RxDisable, ioaddr + EL3_CMD); + lx_outw(TxDisable, ioaddr + EL3_CMD); + + if (dev->if_port == 3) + /* Turn off thinnet power. Green! */ + lx_outw(StopCoax, ioaddr + EL3_CMD); +#if 0 + +#ifdef SA_SHIRQ + FREE_IRQ(dev->irq, dev); +#else +#ifdef USE_SHARED_IRQ + free_shared_irq(dev->irq, dev); +#else + FREE_IRQ(dev->irq, NULL); + /* Mmmm, we should disable all interrupt sources here. */ + irq2dev_map[dev->irq] = 0; +#endif +#endif + + update_stats(ioaddr, dev); +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + +#endif + return 0; +} + + +/* This new version of set_rx_mode() supports v1.4 kernels. + The Vortex chip has no documented multicast filter, so the only + multicast setting is to receive all multicast frames. At least + the chip has a very clean way to set the mode, unlike many others. */ +static void +set_rx_mode(struct device *dev) +{ + short ioaddr = dev->base_addr; + short new_mode; + + if (dev->flags & IFF_PROMISC) { + if (vortex_debug > 3) + printf("%s: Setting promiscuous mode.\n", dev->name); + new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm; + } else if (/*(dev->mc_list) || */ (dev->flags & IFF_ALLMULTI)) { + new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast; + } else + new_mode = SetRxFilter | RxStation | RxBroadcast; + + lx_outw(new_mode, ioaddr + EL3_CMD); +} + + +/* + * Local variables: + * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c 3c59x.c -o ../../modules/3c59x.o" + * c-indent-level: 4 + * tab-width: 4 + * End: + */ +void VX_reset (struct nic *nic) +{ + printf ("reset"); +} + +int VX_poll (struct nic *nic) +{ +// printf ("Polling %x %d\n", nic->packet, nic->packetlen); +} + +void VX_transmit (struct nic *nic, char *d, + unsigned int t, unsigned int s, char *p) +{ + int i; + + printf ("Transmit type %d, %x %d\n", t, p, s); + printf ("SRCAddr : "); + for (i = 0; i < 6; i++) + printf ("%x:", ((int)nic->node_addr[i]) & 0xff); + printf ("\nDest : "); + for (i = 0; i < 6; i++) + printf ("%x:", ((int)d[i]) & 0xff); + printf ("\n"); + +} + +void VX_disable (struct nic *nic) +{ + printf ("Disable\n"); +} + +struct nic *VX_probe(struct nic *nic, unsigned short *probe_addrs) +{ + + if (probe_addrs) { + card.mem_start = probe_addrs[0]; + vortex_probe1(&card); + + printf ("Probe 3c93 at %x\n", card.mem_start); + nic->priv_data = &card; + nic->reset = VX_reset; + nic->poll = VX_poll; + nic->transmit = VX_transmit; + nic->disable = VX_disable; + return 1; + } + printf ("Failed : No ProbeAddrs\n"); + return 0; +} + +#endif /* INCLUDE_3c59x */ diff --git a/netboot/Makefile.am b/netboot/Makefile.am new file mode 100644 index 000000000..02904628c --- /dev/null +++ b/netboot/Makefile.am @@ -0,0 +1,20 @@ + +# For . +INCLUDES = -I$(top_srcdir)/stage1 + +if NETBOOT_SUPPORT +LIBDRIVERS = libdrivers.a +else +LIBDRIVERS = +endif + +noinst_LIBRARIES = $(LIBDRIVERS) + +DRIVERS = 3c509.c 3c509.h 3c59x.c cs89x0.c cs89x0.h eepro100.c \ + lance.c ns8390.c ns8390.h + +libdrivers_a_SOURCES = byteorder.h config.c config.h fsys_tftp.c \ + if.h io.h ip.c ip.h netboot.h netdevice.h nic.h pci.c pci.h \ + $(DRIVERS) +libdrivers_a_CFLAGS = $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ + -DFSYS_TFTP $(NET_CFLAGS) $(NET_EXTRAFLAGS) diff --git a/netboot/Makefile.in b/netboot/Makefile.in new file mode 100644 index 000000000..904811b76 --- /dev/null +++ b/netboot/Makefile.in @@ -0,0 +1,536 @@ +# Makefile.in generated automatically by automake 1.4a from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_FLAG = +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ +AMTAR = @AMTAR@ +AMTARFLAGS = @AMTARFLAGS@ +AWK = @AWK@ +CC = @CC@ +FSYS_CFLAGS = @FSYS_CFLAGS@ +GRUB_CFLAGS = @GRUB_CFLAGS@ +GRUB_LIBS = @GRUB_LIBS@ +LD = @LD@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +NET_CFLAGS = @NET_CFLAGS@ +NET_EXTRAFLAGS = @NET_EXTRAFLAGS@ +OBJCOPY = @OBJCOPY@ +PACKAGE = @PACKAGE@ +PERL = @PERL@ +RANLIB = @RANLIB@ +STAGE1_CFLAGS = @STAGE1_CFLAGS@ +STAGE2_CFLAGS = @STAGE2_CFLAGS@ +VERSION = @VERSION@ +host_cpu = @host_cpu@ +host_vendor = @host_vendor@ +install_sh = @install_sh@ + +# For . + + +INCLUDES = -I$(top_srcdir)/stage1 +@NETBOOT_SUPPORT_TRUE@LIBDRIVERS = @NETBOOT_SUPPORT_TRUE@libdrivers.a +@NETBOOT_SUPPORT_FALSE@LIBDRIVERS = + +noinst_LIBRARIES = $(LIBDRIVERS) + +DRIVERS = 3c509.c 3c509.h 3c59x.c cs89x0.c cs89x0.h eepro100.c \ + lance.c ns8390.c ns8390.h + + +libdrivers_a_SOURCES = byteorder.h config.c config.h fsys_tftp.c \ + if.h io.h ip.c ip.h netboot.h netdevice.h nic.h pci.c pci.h \ + $(DRIVERS) + +libdrivers_a_CFLAGS = $(STAGE2_CFLAGS) -fno-builtin -nostdinc \ + -DFSYS_TFTP $(NET_CFLAGS) $(NET_EXTRAFLAGS) + +subdir = netboot +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +libdrivers_a_AR = $(AR) cru +libdrivers_a_LIBADD = +am_libdrivers_a_OBJECTS = libdrivers_a-config.o \ +libdrivers_a-fsys_tftp.o libdrivers_a-ip.o libdrivers_a-pci.o \ +libdrivers_a-3c509.o libdrivers_a-3c59x.o libdrivers_a-cs89x0.o \ +libdrivers_a-eepro100.o libdrivers_a-lance.o libdrivers_a-ns8390.o +libdrivers_a_OBJECTS = $(am_libdrivers_a_OBJECTS) +AR = ar +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CFLAGS = @CFLAGS@ +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libdrivers_a_SOURCES) +DIST_COMMON = Makefile.am Makefile.in compile + + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +GZIP_ENV = --best +DEP_FILES = .deps/3c509.P .deps/3c59x.P .deps/config.P .deps/cs89x0.P \ +.deps/eepro100.P .deps/fsys_tftp.P .deps/ip.P .deps/lance.P \ +.deps/ns8390.P .deps/pci.P +SOURCES = $(libdrivers_a_SOURCES) +OBJECTS = $(am_libdrivers_a_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .c .h .o +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu netboot/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstLIBRARIES: + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +distclean-noinstLIBRARIES: + +maintainer-clean-noinstLIBRARIES: + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: +libdrivers_a-config.o: config.c +libdrivers_a-fsys_tftp.o: fsys_tftp.c +libdrivers_a-ip.o: ip.c +libdrivers_a-pci.o: pci.c +libdrivers_a-3c509.o: 3c509.c +libdrivers_a-3c59x.o: 3c59x.c +libdrivers_a-cs89x0.o: cs89x0.c +libdrivers_a-eepro100.o: eepro100.c +libdrivers_a-lance.o: lance.c +libdrivers_a-ns8390.o: ns8390.c + +libdrivers.a: $(libdrivers_a_OBJECTS) $(libdrivers_a_DEPENDENCIES) + -rm -f libdrivers.a + $(libdrivers_a_AR) libdrivers.a $(libdrivers_a_OBJECTS) $(libdrivers_a_LIBADD) + $(RANLIB) libdrivers.a +.c.o: + $(COMPILE) -c $< + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || etags $(ETAGS_ARGS) $$tags $$unique $(LISP) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +distdir: $(DISTFILES) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(top_distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu netboot/Makefile + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + +DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) + +-include $(DEP_FILES) + +mostlyclean-depend: + +clean-depend: + +distclean-depend: + -rm -rf .deps + +maintainer-clean-depend: + +%.o: %.c + @echo '$(COMPILE) -c -o $@ $<'; \ + $(COMPILE) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-cp .deps/$(*D)/$(*F).pp .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm .deps/$(*D)/$(*F).pp + +%.lo: %.c + @echo '$(LTCOMPILE) -c -o $@ $<'; \ + $(LTCOMPILE) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*D)/$(*F).pp > .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm -f .deps/$(*D)/$(*F).pp + +libdrivers_a-config.o: config.c + @echo '$(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-cp .deps/$(*D)/$(*F).pp .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm .deps/$(*D)/$(*F).pp + +libdrivers_a-config.lo: config.c + @echo '$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*D)/$(*F).pp > .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm -f .deps/$(*D)/$(*F).pp + +libdrivers_a-fsys_tftp.o: fsys_tftp.c + @echo '$(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-cp .deps/$(*D)/$(*F).pp .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm .deps/$(*D)/$(*F).pp + +libdrivers_a-fsys_tftp.lo: fsys_tftp.c + @echo '$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*D)/$(*F).pp > .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm -f .deps/$(*D)/$(*F).pp + +libdrivers_a-ip.o: ip.c + @echo '$(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-cp .deps/$(*D)/$(*F).pp .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm .deps/$(*D)/$(*F).pp + +libdrivers_a-ip.lo: ip.c + @echo '$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*D)/$(*F).pp > .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm -f .deps/$(*D)/$(*F).pp + +libdrivers_a-pci.o: pci.c + @echo '$(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-cp .deps/$(*D)/$(*F).pp .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm .deps/$(*D)/$(*F).pp + +libdrivers_a-pci.lo: pci.c + @echo '$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*D)/$(*F).pp > .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm -f .deps/$(*D)/$(*F).pp + +libdrivers_a-3c509.o: 3c509.c + @echo '$(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-cp .deps/$(*D)/$(*F).pp .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm .deps/$(*D)/$(*F).pp + +libdrivers_a-3c509.lo: 3c509.c + @echo '$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*D)/$(*F).pp > .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm -f .deps/$(*D)/$(*F).pp + +libdrivers_a-3c59x.o: 3c59x.c + @echo '$(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-cp .deps/$(*D)/$(*F).pp .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm .deps/$(*D)/$(*F).pp + +libdrivers_a-3c59x.lo: 3c59x.c + @echo '$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*D)/$(*F).pp > .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm -f .deps/$(*D)/$(*F).pp + +libdrivers_a-cs89x0.o: cs89x0.c + @echo '$(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-cp .deps/$(*D)/$(*F).pp .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm .deps/$(*D)/$(*F).pp + +libdrivers_a-cs89x0.lo: cs89x0.c + @echo '$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*D)/$(*F).pp > .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm -f .deps/$(*D)/$(*F).pp + +libdrivers_a-eepro100.o: eepro100.c + @echo '$(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-cp .deps/$(*D)/$(*F).pp .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm .deps/$(*D)/$(*F).pp + +libdrivers_a-eepro100.lo: eepro100.c + @echo '$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*D)/$(*F).pp > .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm -f .deps/$(*D)/$(*F).pp + +libdrivers_a-lance.o: lance.c + @echo '$(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-cp .deps/$(*D)/$(*F).pp .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm .deps/$(*D)/$(*F).pp + +libdrivers_a-lance.lo: lance.c + @echo '$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*D)/$(*F).pp > .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm -f .deps/$(*D)/$(*F).pp + +libdrivers_a-ns8390.o: ns8390.c + @echo '$(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-cp .deps/$(*D)/$(*F).pp .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm .deps/$(*D)/$(*F).pp + +libdrivers_a-ns8390.lo: ns8390.c + @echo '$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*D)/$(*F).pp > .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm -f .deps/$(*D)/$(*F).pp +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile $(LIBRARIES) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \ + mostlyclean-tags mostlyclean-depend mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-noinstLIBRARIES clean-compile clean-tags clean-depend \ + clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-noinstLIBRARIES distclean-compile \ + distclean-tags distclean-depend distclean-generic \ + clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-noinstLIBRARIES \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-depend maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \ +clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir mostlyclean-depend \ +distclean-depend clean-depend maintainer-clean-depend info-am info \ +dvi-am dvi check check-am installcheck-am installcheck install-exec-am \ +install-exec install-data-am install-data install-am install \ +uninstall-am uninstall all-redirect all-am all install-strip \ +installdirs mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/netboot/byteorder.h b/netboot/byteorder.h new file mode 100644 index 000000000..d7d062270 --- /dev/null +++ b/netboot/byteorder.h @@ -0,0 +1,77 @@ +#ifndef _I386_BYTEORDER_H +#define _I386_BYTEORDER_H + +/* + * This file contains parts of Linux's /usr/include/asm/byteorder.h + */ + +#undef ntohl +#undef ntohs +#undef htonl +#undef htons + +extern unsigned long int ntohl(unsigned long int); +extern unsigned short int ntohs(unsigned short int); +extern unsigned long int htonl(unsigned long int); +extern unsigned short int htons(unsigned short int); + +extern __inline__ unsigned long int __ntohl(unsigned long int); +extern __inline__ unsigned short int __ntohs(unsigned short int); +extern __inline__ unsigned long int __constant_ntohl(unsigned long int); +extern __inline__ unsigned short int __constant_ntohs(unsigned short int); + +extern __inline__ unsigned long int +__ntohl(unsigned long int x) +{ + __asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */ + "rorl $16,%0\n\t" /* swap words */ + "xchgb %b0,%h0" /* swap higher bytes */ + :"=q" (x) + : "0" (x)); + return x; +} + +#define __constant_ntohl(x) \ + ((unsigned long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \ + (((unsigned long int)(x) & 0x0000ff00U) << 8) | \ + (((unsigned long int)(x) & 0x00ff0000U) >> 8) | \ + (((unsigned long int)(x) & 0xff000000U) >> 24))) + +extern __inline__ unsigned short int +__ntohs(unsigned short int x) +{ + __asm__("xchgb %b0,%h0" /* swap bytes */ + : "=q" (x) + : "0" (x)); + return x; +} + +#define __constant_ntohs(x) \ + ((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \ + (((unsigned short int)(x) & 0xff00) >> 8))) \ + +#define __htonl(x) __ntohl(x) +#define __htons(x) __ntohs(x) +#define __constant_htonl(x) __constant_ntohl(x) +#define __constant_htons(x) __constant_ntohs(x) + +#ifdef __OPTIMIZE__ +# define ntohl(x) \ +(__builtin_constant_p((long)(x)) ? \ + __constant_ntohl((x)) : \ + __ntohl((x))) +# define ntohs(x) \ +(__builtin_constant_p((short)(x)) ? \ + __constant_ntohs((x)) : \ + __ntohs((x))) +# define htonl(x) \ +(__builtin_constant_p((long)(x)) ? \ + __constant_htonl((x)) : \ + __htonl((x))) +# define htons(x) \ +(__builtin_constant_p((short)(x)) ? \ + __constant_htons((x)) : \ + __htons((x))) +#endif + +#endif diff --git a/netboot/compile b/netboot/compile new file mode 100644 index 000000000..7da75ce41 --- /dev/null +++ b/netboot/compile @@ -0,0 +1,82 @@ +#! /bin/sh + +# Wrapper for compilers which do not understand `-c -o'. + +# Copyright (C) 1999 Free Software Foundation, Inc. +# Written by Tom Tromey . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Usage: +# compile PROGRAM [ARGS]... +# `-o FOO.o' is removed from the args passed to the actual compile. + +prog="$1" +shift + +ofile= +cfile= +args= +while test $# -gt 0; do + case "$1" in + -o) + ofile="$2" + shift + ;; + *.c) + cfile="$1" + args="$args $1" + ;; + *) + args="$args $1" + ;; + esac + shift +done + +test -z "$ofile" && { + echo "compile: no \`-o' option seen" 1>&2 + exit 1 +} + +test -z "$cfile" && { + echo "compile: no \`.c' file seen" 1>&2 + exit 1 +} + +# Name of file we expect compiler to create. +cofile="`echo $cfile | sed -e 's|^.*/||' -e 's/\.c$/.o/'`" + +# Create the lock directory. +lockdir="`echo $ofile | sed -e 's|/|_|g'`" +while true; do + if mkdir $lockdir > /dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir $lockdir; exit 1" 1 2 15 + +# Run the compile. +"$prog" $args +status=$? + +if test -f "$cofile"; then + mv "$cofile" "$ofile" +fi + +rmdir $lockdir +exit $status diff --git a/netboot/config.c b/netboot/config.c new file mode 100644 index 000000000..6b3e237fa --- /dev/null +++ b/netboot/config.c @@ -0,0 +1,225 @@ +#include "netboot.h" +#include "nic.h" + +#include "config.h" + +#undef INCLUDE_PCI +#if defined(INCLUDE_NEPCI) || defined(INCLUDE_EEPRO100) || defined (INCLUDE_3c59x) + /* || others later */ +#if defined(NETBOOT32) /* only for 32 bit machines */ +#define INCLUDE_PCI +/* #include */ +#include "pci.h" +static unsigned short pci_addrs[16]; + +struct pci_device pci_nic_list[] = { +#ifdef INCLUDE_NEPCI + { PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8029, + "Realtek 8029"}, + { PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C940, + "Winbond NE2000-PCI"}, /* "Winbond 89C940" */ + { PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_RL2000, + "Compex ReadyLink 2000"}, + { PCI_VENDOR_ID_KTI, PCI_DEVICE_ID_KTI_ET32P2, + "KTI ET32P2"}, + {PCI_VENDOR_ID_NETVIN, PCI_DEVICE_ID_NETVIN_NV5000SC, + "NetVin NV5000"}, + {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C926, + "VIA 82C926 Amazon"}, + {PCI_VENDOR_ID_SURECOM, PCI_DEVICE_ID_SURECOM_NE34, + "SureCom NE34"}, +#endif +#ifdef INCLUDE_EEPRO100 + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557, + "Intel EtherExpressPro100"}, +#endif +#ifdef INCLUDE_3c59x + {PCI_VENDOR_ID_VORTEX, PCI_DEVICE_ID_VORTEX_3c595, "3c595"}, + +#endif + +/* other PCI NICs go here */ + {0,} +}; +#endif /* NETBOOT32 */ +#endif /* INCLUDE_*PCI */ + +struct dispatch_table +{ + char *nic_name; + struct nic *(*eth_probe)(struct nic *, unsigned short *); + unsigned short *probe_addrs; /* for probe overrides */ +}; + +#ifdef INCLUDE_WD +extern struct nic *wd_probe(struct nic *, unsigned short *); +#endif + +#ifdef INCLUDE_T503 +extern struct nic *t503_probe(struct nic *, unsigned short *); +#endif + +#if defined(INCLUDE_NE) +extern struct nic *ne_probe(struct nic *, unsigned short *); +#endif + +#if defined(INCLUDE_NEPCI) +extern struct nic *nepci_probe(struct nic *, unsigned short *); +#endif + +#ifdef INCLUDE_T509 +extern struct nic *t509_probe(struct nic *, unsigned short *); +#endif + +#ifdef INCLUDE_EEPRO100 +extern struct nic *eepro100_probe(struct nic *, unsigned short *); +#endif + +#ifdef INCLUDE_CS +extern struct nic *cs89x0_probe(struct nic *, unsigned short *); +#endif + +#ifdef INCLUDE_NE2100 +extern struct nic *ne2100_probe(struct nic *, unsigned short *); +#endif + +#ifdef INCLUDE_3c59x +extern struct nic *VX_probe(struct nic *, unsigned short *); +#endif + + +/* + * NIC probing is in order of appearance in this table. + * If for some reason you want to change the order, + * just rearrange the entries (bracketed by the #ifdef/#endif) + */ +static struct dispatch_table NIC[] = +{ +#ifdef INCLUDE_WD + { "WD", wd_probe, 0 }, +#endif +#ifdef INCLUDE_T503 + { "3C503", t503_probe, 0 }, +#endif +#ifdef INCLUDE_NE + { "NE*000", ne_probe, 0 }, +#endif +#ifdef INCLUDE_T509 + { "3C5x9", t509_probe, 0 }, +#endif +#ifdef INCLUDE_EEPRO100 + { "EEPRO100", eepro100_probe, 0 }, +#endif +#ifdef INCLUDE_CS + { "CS89x0", cs89x0_probe, 0 }, +#endif +#ifdef INCLUDE_NE2100 + { "NE2100", ne2100_probe, 0 }, +#endif +#ifdef INCLUDE_NEPCI + { "NE*000/PCI", nepci_probe, pci_addrs }, +#endif + +#ifdef INCLUDE_3c59x + {"VorTex/PCI", VX_probe, pci_addrs}, +#endif + + /* this entry must always be last to mark the end of list */ + { 0, 0, 0 } +}; + +#define NIC_TABLE_SIZE (sizeof(NIC)/sizeof(NIC[0])) + +static int eth_dummy(struct nic *nic) +{ + return (0); +} + +char packet[ETH_MAX_PACKET]; + +struct nic nic = +{ +#ifdef NETBOOT32 + (void (*)(struct nic *))eth_dummy, /* reset */ + eth_dummy, /* poll */ + (void (*)(struct nic *, char *, + unsigned int, unsigned int, + char *))eth_dummy, /* transmit */ + (void (*)(struct nic *))eth_dummy, /* disable */ +#endif +/* bcc has problems with complicated casts */ +#ifdef NETBOOT16 + eth_dummy, + eth_dummy, + eth_dummy, + eth_dummy, +#endif + 1, /* aui */ + arptable[ARP_CLIENT].node, /* node_addr */ + packet, /* packet */ + 0, /* packetlen */ + 0 /* priv_data */ +}; + +#if 0 +void print_config(void) +{ + struct dispatch_table *t; + +#ifdef NETBOOT32 + printf("Etherboot/32 version " VERSION +#ifdef NFS_BOOT + " ESC for menu" +#endif + " for "); +#endif +#ifdef NETBOOT16 + /* you need to edit the version manually because bcc doesn't + do string literal concatenation yet */ + printf("Etherboot/16 version 3.2 for "); +#endif + for (t = NIC; t->nic_name != 0; ++t) + printf("[%s]", t->nic_name); + printf("\r\n"); +} +#endif + +void eth_reset(void) +{ + (*nic.reset)(&nic); +} + +int eth_probe(void) +{ + struct dispatch_table *t; + +#ifdef INCLUDE_PCI + pci_addrs[0] = 0; + eth_pci_init(pci_nic_list, pci_addrs); + pci_addrs[1] = 0; +#endif + printf("Probing..."); + for (t = NIC; t->nic_name != 0; ++t) + { + printf("[%s]", t->nic_name); + if ((*t->eth_probe)(&nic, t->probe_addrs)) + return (1); + } + return (0); +} + +int eth_poll(void) +{ + return ((*nic.poll)(&nic)); +} + +void eth_transmit(char *d, unsigned int t, unsigned int s, char *p) +{ + (*nic.transmit)(&nic, d, t, s, p); + twiddle(); +} + +void eth_disable(void) +{ + (*nic.disable)(&nic); +} diff --git a/netboot/config.h b/netboot/config.h new file mode 100644 index 000000000..eaf284d15 --- /dev/null +++ b/netboot/config.h @@ -0,0 +1,8 @@ +extern struct nic nic; + +extern void print_config(void); +extern void eth_reset(void); +extern int eth_probe(void); +extern int eth_poll(void); +extern void eth_transmit(char *d, unsigned int t, unsigned int s, char *p); +extern void eth_disable(void); diff --git a/netboot/cs89x0.c b/netboot/cs89x0.c new file mode 100644 index 000000000..d467851e3 --- /dev/null +++ b/netboot/cs89x0.c @@ -0,0 +1,699 @@ +/* cs89x0.c: A Crystal Semiconductor CS89[02]0 driver for etherboot. */ +/* + This code is heavily based on the linux driver as written by + Russell Nelson and Donald Becker + and modified by Mike Cruse + . That driver has been released under the + conditions of the GNU Public License, thus this one is probably to + be considered "derived work". Therefore, there are some legal + obstacles in combining this file with etherboot's code, which is + released under a BSD style license. + + So, if you want to actually use this code, you should make sure that + you are aware of the legal implications. I release *my* work into + the PUBLIC DOMAIN which implies that you can use it either under a + BSD style license, or under the conditions of the GPL, or under any + other conditions that you like. N.B. this does not apply to the + parts that originate from other authors. So, you should probably + contact them first and verify if they agree with your intended use. + + If you contacted all of the above authors and they agreed to give + special permission for using this code under the conditions of a BSD + style license, then please do let me know. + + ChangeLog: + + Thu Dec 6 22:40:00 1996 Markus Gutschke + + * disabled all "advanced" features; this should make the code more reliable + + * reorganized the reset function + + * always reset the address port, so that autoprobing will continue working + + * some cosmetic changes + + * 2.5 + + Thu Dec 5 21:00:00 1996 Markus Gutschke + + * tested the code against a CS8900 card + + * lots of minor bug fixes and adjustments + + * this is the first release, that actually works! it still requires some + changes in order to be more tolerant to different environments + + * 4 + + Fri Nov 22 23:00:00 1996 Markus Gutschke + + * read the manuals for the CS89x0 chipsets and took note of all the + changes that will be neccessary in order to adapt Russel Nelson's code + to the requirements of a BOOT-Prom + + * 6 + + Thu Nov 19 22:00:00 1996 Markus Gutschke + + * Synched with Russel Nelson's current code (v1.00) + + * 2 + + Thu Nov 12 18:00:00 1996 Markus Gutschke + + * Cleaned up some of the code and tried to optimize the code size. + + * 1.5 + + Sun Nov 10 16:30:00 1996 Markus Gutschke + + * First experimental release. This code compiles fine, but I + have no way of testing whether it actually works. + + * I did not (yet) bother to make the code 16bit aware, so for + the time being, it will only work for netboot-32. + + * 12 + + */ + +#ifdef INCLUDE_CS + +#include "netboot.h" +#include "nic.h" +#include "cs89x0.h" + +static unsigned short eth_nic_base; +static unsigned long eth_mem_start; +static unsigned short eth_irq; +static unsigned short eth_cs_type; /* one of: CS8900, CS8920, CS8920M */ +static unsigned short eth_auto_neg_cnf; +static unsigned short eth_adapter_cnf; +static unsigned short eth_linectl; +static unsigned char eth_vendor; + +/************************************************************************* + CS89x0 - specific routines +**************************************************************************/ + +static int inline readreg(portno) + int portno; +{ + outw(eth_nic_base + ADD_PORT, portno); + return inw(eth_nic_base + DATA_PORT); +} + +static void inline writereg(portno,value) + int portno; + int value; +{ + outw(eth_nic_base + ADD_PORT, portno); + outw(eth_nic_base + DATA_PORT, value); + return; +} + +/************************************************************************* +EEPROM access +**************************************************************************/ + +static int wait_eeprom_ready() +{ + long tmo = currticks() + 4*18L; + + /* check to see if the EEPROM is ready, a timeout is used - + just in case EEPROM is ready when SI_BUSY in the + PP_SelfST is clear */ + while(readreg(PP_SelfST) & SI_BUSY) { + if (currticks() - tmo >= 0) + return -1; } + return 0; +} + +static int get_eeprom_data(off,len,buffer) + int off; + int len; + unsigned short *buffer; +{ + int i; + +#if defined(EDEBUG) + printf("\r\ncs: EEPROM data from %x for %x:",off,len); +#endif + for (i = 0; i < len; i++) { + if (wait_eeprom_ready() < 0) + return -1; + /* Now send the EEPROM read command and EEPROM location + to read */ + writereg(PP_EECMD, (off + i) | EEPROM_READ_CMD); + if (wait_eeprom_ready() < 0) + return -1; + buffer[i] = readreg(PP_EEData); +#if defined(EDEBUG) + if (!(i%10)) + printf("\r\ncs: "); + printf("%x ", buffer[i]); +#endif + } +#if defined(EDEBUG) + printf("\r\n"); +#endif + + return(0); +} + +static int get_eeprom_chksum(off, len, buffer) + int off; + int len; + unsigned short *buffer; +{ + int i, cksum; + + cksum = 0; + for (i = 0; i < len; i++) + cksum += buffer[i]; + cksum &= 0xffff; + if (cksum == 0) + return 0; + return -1; +} + +/************************************************************************* +Activate all of the available media and probe for network +**************************************************************************/ + +static void clrline() +{ + int i; + + putchar('\r'); + for (i = 79; i--; ) putchar(' '); + printf("\rcs: "); + return; +} + +static void control_dc_dc(on_not_off) + int on_not_off; +{ + unsigned int selfcontrol; + long tmo = currticks() + 18; + + /* control the DC to DC convertor in the SelfControl register. */ + selfcontrol = HCB1_ENBL; /* Enable the HCB1 bit as an output */ + if (((eth_adapter_cnf & A_CNF_DC_DC_POLARITY) != 0) ^ on_not_off) + selfcontrol |= HCB1; + else + selfcontrol &= ~HCB1; + writereg(PP_SelfCTL, selfcontrol); + + /* Wait for the DC/DC converter to power up - 1000ms */ + while (currticks() - tmo < 0); + + return; +} + +static int detect_tp() +{ + long tmo; + + /* Turn on the chip auto detection of 10BT/ AUI */ + + clrline(); printf("attempting %s:","TP"); + + /* If connected to another full duplex capable 10-Base-T card + the link pulses seem to be lost when the auto detect bit in + the LineCTL is set. To overcome this the auto detect bit + will be cleared whilst testing the 10-Base-T interface. + This would not be necessary for the sparrow chip but is + simpler to do it anyway. */ + writereg(PP_LineCTL, eth_linectl &~ AUI_ONLY); + control_dc_dc(0); + + /* Delay for the hardware to work out if the TP cable is + present - 150ms */ + for (tmo = currticks() + 4; currticks() - tmo < 0; ); + + if ((readreg(PP_LineST) & LINK_OK) == 0) + return 0; + + if (eth_cs_type != CS8900) { + + writereg(PP_AutoNegCTL, eth_auto_neg_cnf & AUTO_NEG_MASK); + + if ((eth_auto_neg_cnf & AUTO_NEG_BITS) == AUTO_NEG_ENABLE) { + printf(" negotiating duplex... "); + while (readreg(PP_AutoNegST) & AUTO_NEG_BUSY) { + if (currticks() - tmo > 40*18) { + printf("time out "); + break; + } + } + } + if (readreg(PP_AutoNegST) & FDX_ACTIVE) + printf("using full duplex"); + else + printf("using half duplex"); + } + + return A_CNF_MEDIA_10B_T; +} + +/* send a test packet - return true if carrier bits are ok */ +static int send_test_pkt(struct nic *nic) +{ + static char testpacket[] = { 0,0,0,0,0,0, 0,0,0,0,0,0, + 0, 46, /*A 46 in network order */ + 0, 0, /*DSAP=0 & SSAP=0 fields */ + 0xf3,0 /*Control (Test Req+P bit set)*/ }; + long tmo; + + writereg(PP_LineCTL, readreg(PP_LineCTL) | SERIAL_TX_ON); + + bcopy(nic->node_addr,testpacket,ETHER_ADDR_SIZE); + bcopy(nic->node_addr,testpacket+ETHER_ADDR_SIZE, + ETHER_ADDR_SIZE); + + outw(eth_nic_base + TX_CMD_PORT, TX_AFTER_ALL); + outw(eth_nic_base + TX_LEN_PORT, ETH_MIN_PACKET); + + /* Test to see if the chip has allocated memory for the packet */ + for (tmo = currticks() + 2; + (readreg(PP_BusST) & READY_FOR_TX_NOW) == 0; ) + if (currticks() - tmo >= 0) + return(0); + + /* Write the contents of the packet */ + outsw(eth_nic_base + TX_FRAME_PORT, testpacket, + (ETH_MIN_PACKET+1)>>1); + + printf(" sending test packet "); + /* wait a couple of timer ticks for packet to be received */ + for (tmo = currticks() + 2; currticks() - tmo < 0; ); + + if ((readreg(PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) { + printf("succeeded"); + return 1; + } + printf("failed"); + return 0; +} + + +static int detect_aui(struct nic *nic) +{ + clrline(); printf("attempting %s:","AUI"); + control_dc_dc(0); + + writereg(PP_LineCTL, (eth_linectl & ~AUTO_AUI_10BASET) | AUI_ONLY); + + if (send_test_pkt(nic)) { + return A_CNF_MEDIA_AUI; } + else + return 0; +} + +static int detect_bnc(struct nic *nic) +{ + clrline(); printf("attempting %s:","BNC"); + control_dc_dc(1); + + writereg(PP_LineCTL, (eth_linectl & ~AUTO_AUI_10BASET) | AUI_ONLY); + + if (send_test_pkt(nic)) { + return A_CNF_MEDIA_10B_2; } + else + return 0; +} + +/************************************************************************** +ETH_RESET - Reset adapter +***************************************************************************/ + +void cs89x0_reset(struct nic *nic) +{ + int i; + long reset_tmo; + + if(eth_vendor!=VENDOR_CS89x0) + return; + + writereg(PP_SelfCTL, readreg(PP_SelfCTL) | POWER_ON_RESET); + + /* wait for two ticks; that is 2*55ms */ + for (reset_tmo = currticks() + 2; + reset_tmo > currticks(); ); + + if (eth_cs_type != CS8900) { + /* Hardware problem requires PNP registers to be reconfigured + after a reset */ + if (eth_irq != 0xFFFF) { + outw(eth_nic_base + ADD_PORT, PP_CS8920_ISAINT); + outb(eth_nic_base + DATA_PORT, eth_irq); + outb(eth_nic_base + DATA_PORT + 1, 0); } + + if (eth_mem_start) { + outw(eth_nic_base + ADD_PORT, PP_CS8920_ISAMemB); + outb(eth_nic_base + DATA_PORT, (eth_mem_start >> 8) & 0xff); + outb(eth_nic_base + DATA_PORT + 1, (eth_mem_start >> 24) & 0xff); } } + + /* Wait until the chip is reset */ + for (reset_tmo = currticks() + 2; + (readreg(PP_SelfST) & INIT_DONE) == 0 && + currticks() - reset_tmo < 0; ); + + /* disable interrupts and memory accesses */ + writereg(PP_BusCTL, 0); + + /* set the ethernet address */ + for (i=0; i < ETHER_ADDR_SIZE/2; i++) + writereg(PP_IA+i*2, + nic->node_addr[i*2] | + (nic->node_addr[i*2+1] << 8)); + + /* receive only error free packets addressed to this card */ + writereg(PP_RxCTL, DEF_RX_ACCEPT); + + /* do not generate any interrupts on receive operations */ + writereg(PP_RxCFG, 0); + + /* do not generate any interrupts on transmit operations */ + writereg(PP_TxCFG, 0); + + /* do not generate any interrupts on buffer operations */ + writereg(PP_BufCFG, 0); + + /* reset address port, so that autoprobing will keep working */ + outw(eth_nic_base + ADD_PORT, PP_ChipID); + + return; +} + +/************************************************************************** +ETH_TRANSMIT - Transmit a frame +***************************************************************************/ + +static void cs89x0_transmit( + struct nic *nic, + char *d, /* Destination */ + unsigned int t, /* Type */ + unsigned int s, /* size */ + char *p) /* Packet */ +{ + long tmo; + int sr; + + if(eth_vendor!=VENDOR_CS89x0) + return; + + /* does this size have to be rounded??? please, + somebody have a look in the specs */ + if ((sr = ((s + ETHER_HDR_SIZE + 1)&~1)) < ETH_MIN_PACKET) + sr = ETH_MIN_PACKET; + +retry: + /* initiate a transmit sequence */ + outw(eth_nic_base + TX_CMD_PORT, TX_AFTER_ALL); + outw(eth_nic_base + TX_LEN_PORT, sr); + + /* Test to see if the chip has allocated memory for the packet */ + if ((readreg(PP_BusST) & READY_FOR_TX_NOW) == 0) { + /* Oops... this should not happen! */ + printf("cs: unable to send packet; retrying...\r\n"); + for (tmo = currticks() + 5*18; currticks() - tmo < 0; ); + cs89x0_reset(nic); + goto retry; } + + /* Write the contents of the packet */ + outsw(eth_nic_base + TX_FRAME_PORT, d, ETHER_ADDR_SIZE/2); + outsw(eth_nic_base + TX_FRAME_PORT, nic->node_addr, + ETHER_ADDR_SIZE/2); + outw(eth_nic_base + TX_FRAME_PORT, ((t >> 8)&0xFF)|(t << 8)); + outsw(eth_nic_base + TX_FRAME_PORT, p, (s+1)/2); + for (sr = sr/2 - (s+1)/2 - ETHER_ADDR_SIZE - 1; sr-- > 0; + outw(eth_nic_base + TX_FRAME_PORT, 0)); + + /* wait for transfer to succeed */ + for (tmo = currticks()+5*18; + (s = readreg(PP_TxEvent)&~0x1F) == 0 && currticks() - tmo < 0; + twiddle()); + if ((s & TX_SEND_OK_BITS) != TX_OK) { + printf("\r\ntransmission error 0x%x\r\n", s); + } + + return; +} + +/************************************************************************** +ETH_POLL - Wait for a frame +***************************************************************************/ + +static int cs89x0_poll(struct nic *nic) +{ + int status; + + if(eth_vendor!=VENDOR_CS89x0) + return 0; + + status = readreg(PP_RxEvent); + + if ((status & RX_OK) == 0) + return(0); + + status = inw(eth_nic_base + RX_FRAME_PORT); + nic->packetlen = inw(eth_nic_base + RX_FRAME_PORT); + insw(eth_nic_base + RX_FRAME_PORT, nic->packet, nic->packetlen >> 1); + if (nic->packetlen & 1) + nic->packet[nic->packetlen-1] = inw(eth_nic_base + RX_FRAME_PORT); + return 1; +} + +static void cs89x0_disable(struct nic *nic) +{ +} + +/************************************************************************** +ETH_PROBE - Look for an adapter +***************************************************************************/ + +struct nic *cs89x0_probe(struct nic *nic, unsigned short *probe_addrs) +{ + static const unsigned int netcard_portlist[] = { +#ifdef CS_SCAN + CS_SCAN, +#else /* use "conservative" default values for autoprobing */ + 0x300,0x320,0x340,0x200,0x220,0x240, + 0x260,0x280,0x2a0,0x2c0,0x2e0, + /* if that did not work, then be more aggressive */ + 0x301,0x321,0x341,0x201,0x221,0x241, + 0x261,0x281,0x2a1,0x2c1,0x2e1, +#endif + 0}; + + int i, result = -1; + unsigned rev_type = 0, ioaddr, ioidx, isa_cnf, cs_revision; + unsigned short eeprom_buff[CHKSUM_LEN]; + + + for (eth_vendor = VENDOR_NONE, ioidx = 0; + eth_vendor == VENDOR_NONE && + (ioaddr=netcard_portlist[ioidx++]) != 0;) { + /* if they give us an odd I/O address, then do ONE write to + the address port, to get it back to address zero, where we + expect to find the EISA signature word. */ + if (ioaddr & 1) { + ioaddr &= ~1; + if ((inw(ioaddr + ADD_PORT) & ADD_MASK) != ADD_SIG) + continue; + outw(ioaddr + ADD_PORT, PP_ChipID); + } + + if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG) + continue; + eth_nic_base = ioaddr; + + /* get the chip type */ + rev_type = readreg(PRODUCT_ID_ADD); + eth_cs_type = rev_type &~ REVISON_BITS; + cs_revision = ((rev_type & REVISON_BITS) >> 8) + 'A'; + + printf("\r\ncs: cs89%c0%s rev %c, base 0x%x", + eth_cs_type==CS8900?'0':'2', + eth_cs_type==CS8920M?"M":"", + cs_revision, + eth_nic_base); + + /* First check to see if an EEPROM is attached*/ + if ((readreg(PP_SelfST) & EEPROM_PRESENT) == 0) { + printf("\r\ncs: no EEPROM...\r\n"); + outw(eth_nic_base + ADD_PORT, PP_ChipID); + continue; } + else if (get_eeprom_data(START_EEPROM_DATA,CHKSUM_LEN, + eeprom_buff) < 0) { + printf("\r\ncs: EEPROM read failed...\r\n"); + outw(eth_nic_base + ADD_PORT, PP_ChipID); + continue; } + else if (get_eeprom_chksum(START_EEPROM_DATA,CHKSUM_LEN, + eeprom_buff) < 0) { + printf("\r\ncs: EEPROM checksum bad...\r\n"); + outw(eth_nic_base + ADD_PORT, PP_ChipID); + continue; } + + /* get transmission control word but keep the + autonegotiation bits */ + eth_auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET/2]; + /* Store adapter configuration */ + eth_adapter_cnf = eeprom_buff[ADAPTER_CNF_OFFSET/2]; + /* Store ISA configuration */ + isa_cnf = eeprom_buff[ISA_CNF_OFFSET/2]; + + /* store the initial memory base address */ + eth_mem_start = eeprom_buff[PACKET_PAGE_OFFSET/2] << 8; + + printf("%s%s%s, addr ", + (eth_adapter_cnf & A_CNF_10B_T)?", RJ-45":"", + (eth_adapter_cnf & A_CNF_AUI)?", AUI":"", + (eth_adapter_cnf & A_CNF_10B_2)?", BNC":""); + + /* If this is a CS8900 then no pnp soft */ + if (eth_cs_type != CS8900 && + /* Check if the ISA IRQ has been set */ + (i = readreg(PP_CS8920_ISAINT) & 0xff, + (i != 0 && i < CS8920_NO_INTS))) + eth_irq = i; + else { + i = isa_cnf & INT_NO_MASK; + if (eth_cs_type == CS8900) { + /* the table that follows is dependent + upon how you wired up your cs8900 + in your system. The table is the + same as the cs8900 engineering demo + board. irq_map also depends on the + contents of the table. Also see + write_irq, which is the reverse + mapping of the table below. */ + if (i < 4) i = "\012\013\014\005"[i]; + else printf("\r\ncs: BUG: isa_config is %d\r\n", i); } + eth_irq = i; } + + /* Retrieve and print the ethernet address. */ + for (i=0; inode_addr[i] = + ((unsigned char *)eeprom_buff)[i]), + i < ETHER_ADDR_SIZE-1 ? ":" : "\r\n"); } + + /* Set the LineCTL quintuplet based on adapter + configuration read from EEPROM */ + if ((eth_adapter_cnf & A_CNF_EXTND_10B_2) && + (eth_adapter_cnf & A_CNF_LOW_RX_SQUELCH)) + eth_linectl = LOW_RX_SQUELCH; + else + eth_linectl = 0; + + /* check to make sure that they have the "right" + hardware available */ + switch(eth_adapter_cnf & A_CNF_MEDIA_TYPE) { + case A_CNF_MEDIA_10B_T: result = eth_adapter_cnf & A_CNF_10B_T; + break; + case A_CNF_MEDIA_AUI: result = eth_adapter_cnf & A_CNF_AUI; + break; + case A_CNF_MEDIA_10B_2: result = eth_adapter_cnf & A_CNF_10B_2; + break; + default: result = eth_adapter_cnf & (A_CNF_10B_T | A_CNF_AUI | + A_CNF_10B_2); + } + if (!result) { + printf("cs: EEPROM is configured for unavailable media\r\n"); + error: + writereg(PP_LineCTL, readreg(PP_LineCTL) & + ~(SERIAL_TX_ON | SERIAL_RX_ON)); + outw(eth_nic_base + ADD_PORT, PP_ChipID); + continue; + } + + /* Initialize the card for probing of the attached media */ + eth_vendor = VENDOR_CS89x0; + cs89x0_reset(nic); + eth_vendor = VENDOR_NONE; + + /* set the hardware to the configured choice */ + switch(eth_adapter_cnf & A_CNF_MEDIA_TYPE) { + case A_CNF_MEDIA_10B_T: + result = detect_tp(); + if (!result) { + clrline(); + printf("10Base-T (RJ-45%s", + ") has no cable\r\n"); } + /* check "ignore missing media" bit */ + if (eth_auto_neg_cnf & IMM_BIT) + /* Yes! I don't care if I see a link pulse */ + result = A_CNF_MEDIA_10B_T; + break; + case A_CNF_MEDIA_AUI: + result = detect_aui(nic); + if (!result) { + clrline(); + printf("10Base-5 (AUI%s", + ") has no cable\r\n"); } + /* check "ignore missing media" bit */ + if (eth_auto_neg_cnf & IMM_BIT) + /* Yes! I don't care if I see a carrrier */ + result = A_CNF_MEDIA_AUI; + break; + case A_CNF_MEDIA_10B_2: + result = detect_bnc(nic); + if (!result) { + clrline(); + printf("10Base-2 (BNC%s", + ") has no cable\r\n"); } + /* check "ignore missing media" bit */ + if (eth_auto_neg_cnf & IMM_BIT) + /* Yes! I don't care if I can xmit a packet */ + result = A_CNF_MEDIA_10B_2; + break; + case A_CNF_MEDIA_AUTO: + writereg(PP_LineCTL, eth_linectl | AUTO_AUI_10BASET); + if (eth_adapter_cnf & A_CNF_10B_T) + if ((result = detect_tp()) != 0) + break; + if (eth_adapter_cnf & A_CNF_AUI) + if ((result = detect_aui(nic)) != 0) + break; + if (eth_adapter_cnf & A_CNF_10B_2) + if ((result = detect_bnc(nic)) != 0) + break; + clrline(); printf("no media detected\r\n"); + goto error; + } + clrline(); + switch(result) { + case 0: printf("no network cable attached to configured media\r\n"); + goto error; + case A_CNF_MEDIA_10B_T: printf("using 10Base-T (RJ-45)\r\n"); + break; + case A_CNF_MEDIA_AUI: printf("using 10Base-5 (AUI)\r\n"); + break; + case A_CNF_MEDIA_10B_2: printf("using 10Base-2 (BNC)\r\n"); + break; + } + + /* Turn on both receive and transmit operations */ + writereg(PP_LineCTL, readreg(PP_LineCTL) | SERIAL_RX_ON | + SERIAL_TX_ON); + + eth_vendor = VENDOR_CS89x0; + } + + nic->reset = cs89x0_reset; + nic->poll = cs89x0_poll; + nic->transmit = cs89x0_transmit; + nic->disable = cs89x0_disable; + return nic; +} + +#endif /* INCLUDE_CS */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/netboot/cs89x0.h b/netboot/cs89x0.h new file mode 100644 index 000000000..ec638659a --- /dev/null +++ b/netboot/cs89x0.h @@ -0,0 +1,465 @@ +/* This file has been copied from Russel Nelson's device driver for + Linux. Please look into the header of cs89x0.c for details on the + legal implications! */ + +/* Copyright, 1988-1992, Russell Nelson, Crynwr Software + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, version 1. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define PP_ChipID 0x0000 /* offset 0h -> Corp -ID */ + /* offset 2h -> Model/Product Number */ + /* offset 3h -> Chip Revision Number */ + +#define PP_ISAIOB 0x0020 /* IO base address */ +#define PP_CS8900_ISAINT 0x0022 /* ISA interrupt select */ +#define PP_CS8920_ISAINT 0x0370 /* ISA interrupt select */ +#define PP_CS8900_ISADMA 0x0024 /* ISA Rec DMA channel */ +#define PP_CS8920_ISADMA 0x0374 /* ISA Rec DMA channel */ +#define PP_ISASOF 0x0026 /* ISA DMA offset */ +#define PP_DmaFrameCnt 0x0028 /* ISA DMA Frame count */ +#define PP_DmaByteCnt 0x002A /* ISA DMA Byte count */ +#define PP_CS8900_ISAMemB 0x002C /* Memory base */ +#define PP_CS8920_ISAMemB 0x0348 /* */ + +#define PP_ISABootBase 0x0030 /* Boot Prom base */ +#define PP_ISABootMask 0x0034 /* Boot Prom Mask */ + +/* EEPROM data and command registers */ +#define PP_EECMD 0x0040 /* NVR Interface Command register */ +#define PP_EEData 0x0042 /* NVR Interface Data Register */ +#define PP_DebugReg 0x0044 /* Debug Register */ + +#define PP_RxCFG 0x0102 /* Rx Bus config */ +#define PP_RxCTL 0x0104 /* Receive Control Register */ +#define PP_TxCFG 0x0106 /* Transmit Config Register */ +#define PP_TxCMD 0x0108 /* Transmit Command Register */ +#define PP_BufCFG 0x010A /* Bus configuration Register */ +#define PP_LineCTL 0x0112 /* Line Config Register */ +#define PP_SelfCTL 0x0114 /* Self Command Register */ +#define PP_BusCTL 0x0116 /* ISA bus control Register */ +#define PP_TestCTL 0x0118 /* Test Register */ +#define PP_AutoNegCTL 0x011C /* Auto Negotiation Ctrl */ + +#define PP_ISQ 0x0120 /* Interrupt Status */ +#define PP_RxEvent 0x0124 /* Rx Event Register */ +#define PP_TxEvent 0x0128 /* Tx Event Register */ +#define PP_BufEvent 0x012C /* Bus Event Register */ +#define PP_RxMiss 0x0130 /* Receive Miss Count */ +#define PP_TxCol 0x0132 /* Transmit Collision Count */ +#define PP_LineST 0x0134 /* Line State Register */ +#define PP_SelfST 0x0136 /* Self State register */ +#define PP_BusST 0x0138 /* Bus Status */ +#define PP_TDR 0x013C /* Time Domain Reflectometry */ +#define PP_AutoNegST 0x013E /* Auto Neg Status */ +#define PP_TxCommand 0x0144 /* Tx Command */ +#define PP_TxLength 0x0146 /* Tx Length */ +#define PP_LAF 0x0150 /* Hash Table */ +#define PP_IA 0x0158 /* Physical Address Register */ + +#define PP_RxStatus 0x0400 /* Receive start of frame */ +#define PP_RxLength 0x0402 /* Receive Length of frame */ +#define PP_RxFrame 0x0404 /* Receive frame pointer */ +#define PP_TxFrame 0x0A00 /* Transmit frame pointer */ + +/* Primary I/O Base Address. If no I/O base is supplied by the user, then this */ +/* can be used as the default I/O base to access the PacketPage Area. */ +#define DEFAULTIOBASE 0x0300 +#define FIRST_IO 0x020C /* First I/O port to check */ +#define LAST_IO 0x037C /* Last I/O port to check (+10h) */ +#define ADD_MASK 0x3000 /* Mask it use of the ADD_PORT register */ +#define ADD_SIG 0x3000 /* Expected ID signature */ + +#define CHIP_EISA_ID_SIG 0x630E /* Product ID Code for Crystal Chip (CS8900 spec 4.3) */ + +#ifdef IBMEIPKT +#define EISA_ID_SIG 0x4D24 /* IBM */ +#define PART_NO_SIG 0x1010 /* IBM */ +#define MONGOOSE_BIT 0x0000 /* IBM */ +#else +#define EISA_ID_SIG 0x630E /* PnP Vendor ID (same as chip id for Crystal board) */ +#define PART_NO_SIG 0x4000 /* ID code CS8920 board (PnP Vendor Product code) */ +#define MONGOOSE_BIT 0x2000 /* PART_NO_SIG + MONGOOSE_BUT => ID of mongoose */ +#endif + +#define PRODUCT_ID_ADD 0x0002 /* Address of product ID */ + +/* Mask to find out the types of registers */ +#define REG_TYPE_MASK 0x001F + +/* Eeprom Commands */ +#define ERSE_WR_ENBL 0x00F0 +#define ERSE_WR_DISABLE 0x0000 + +/* Defines Control/Config register quintuplet numbers */ +#define RX_BUF_CFG 0x0003 +#define RX_CONTROL 0x0005 +#define TX_CFG 0x0007 +#define TX_COMMAND 0x0009 +#define BUF_CFG 0x000B +#define LINE_CONTROL 0x0013 +#define SELF_CONTROL 0x0015 +#define BUS_CONTROL 0x0017 +#define TEST_CONTROL 0x0019 + +/* Defines Status/Count registers quintuplet numbers */ +#define RX_EVENT 0x0004 +#define TX_EVENT 0x0008 +#define BUF_EVENT 0x000C +#define RX_MISS_COUNT 0x0010 +#define TX_COL_COUNT 0x0012 +#define LINE_STATUS 0x0014 +#define SELF_STATUS 0x0016 +#define BUS_STATUS 0x0018 +#define TDR 0x001C + +/* PP_RxCFG - Receive Configuration and Interrupt Mask bit definition - Read/write */ +#define SKIP_1 0x0040 +#define RX_STREAM_ENBL 0x0080 +#define RX_OK_ENBL 0x0100 +#define RX_DMA_ONLY 0x0200 +#define AUTO_RX_DMA 0x0400 +#define BUFFER_CRC 0x0800 +#define RX_CRC_ERROR_ENBL 0x1000 +#define RX_RUNT_ENBL 0x2000 +#define RX_EXTRA_DATA_ENBL 0x4000 + +/* PP_RxCTL - Receive Control bit definition - Read/write */ +#define RX_IA_HASH_ACCEPT 0x0040 +#define RX_PROM_ACCEPT 0x0080 +#define RX_OK_ACCEPT 0x0100 +#define RX_MULTCAST_ACCEPT 0x0200 +#define RX_IA_ACCEPT 0x0400 +#define RX_BROADCAST_ACCEPT 0x0800 +#define RX_BAD_CRC_ACCEPT 0x1000 +#define RX_RUNT_ACCEPT 0x2000 +#define RX_EXTRA_DATA_ACCEPT 0x4000 +#define RX_ALL_ACCEPT (RX_PROM_ACCEPT|RX_BAD_CRC_ACCEPT|RX_RUNT_ACCEPT|RX_EXTRA_DATA_ACCEPT) +/* Default receive mode - individually addressed, broadcast, and error free */ +#define DEF_RX_ACCEPT (RX_IA_ACCEPT | RX_BROADCAST_ACCEPT | RX_OK_ACCEPT) + +/* PP_TxCFG - Transmit Configuration Interrupt Mask bit definition - Read/write */ +#define TX_LOST_CRS_ENBL 0x0040 +#define TX_SQE_ERROR_ENBL 0x0080 +#define TX_OK_ENBL 0x0100 +#define TX_LATE_COL_ENBL 0x0200 +#define TX_JBR_ENBL 0x0400 +#define TX_ANY_COL_ENBL 0x0800 +#define TX_16_COL_ENBL 0x8000 + +/* PP_TxCMD - Transmit Command bit definition - Read-only */ +#define TX_START_4_BYTES 0x0000 +#define TX_START_64_BYTES 0x0040 +#define TX_START_128_BYTES 0x0080 +#define TX_START_ALL_BYTES 0x00C0 +#define TX_FORCE 0x0100 +#define TX_ONE_COL 0x0200 +#define TX_TWO_PART_DEFF_DISABLE 0x0400 +#define TX_NO_CRC 0x1000 +#define TX_RUNT 0x2000 + +/* PP_BufCFG - Buffer Configuration Interrupt Mask bit definition - Read/write */ +#define GENERATE_SW_INTERRUPT 0x0040 +#define RX_DMA_ENBL 0x0080 +#define READY_FOR_TX_ENBL 0x0100 +#define TX_UNDERRUN_ENBL 0x0200 +#define RX_MISS_ENBL 0x0400 +#define RX_128_BYTE_ENBL 0x0800 +#define TX_COL_COUNT_OVRFLOW_ENBL 0x1000 +#define RX_MISS_COUNT_OVRFLOW_ENBL 0x2000 +#define RX_DEST_MATCH_ENBL 0x8000 + +/* PP_LineCTL - Line Control bit definition - Read/write */ +#define SERIAL_RX_ON 0x0040 +#define SERIAL_TX_ON 0x0080 +#define AUI_ONLY 0x0100 +#define AUTO_AUI_10BASET 0x0200 +#define MODIFIED_BACKOFF 0x0800 +#define NO_AUTO_POLARITY 0x1000 +#define TWO_PART_DEFDIS 0x2000 +#define LOW_RX_SQUELCH 0x4000 + +/* PP_SelfCTL - Software Self Control bit definition - Read/write */ +#define POWER_ON_RESET 0x0040 +#define SW_STOP 0x0100 +#define SLEEP_ON 0x0200 +#define AUTO_WAKEUP 0x0400 +#define HCB0_ENBL 0x1000 +#define HCB1_ENBL 0x2000 +#define HCB0 0x4000 +#define HCB1 0x8000 + +/* PP_BusCTL - ISA Bus Control bit definition - Read/write */ +#define RESET_RX_DMA 0x0040 +#define MEMORY_ON 0x0400 +#define DMA_BURST_MODE 0x0800 +#define IO_CHANNEL_READY_ON 0x1000 +#define RX_DMA_SIZE_64K 0x2000 +#define ENABLE_IRQ 0x8000 + +/* PP_TestCTL - Test Control bit definition - Read/write */ +#define LINK_OFF 0x0080 +#define ENDEC_LOOPBACK 0x0200 +#define AUI_LOOPBACK 0x0400 +#define BACKOFF_OFF 0x0800 +#define FAST_TEST 0x8000 + +/* PP_RxEvent - Receive Event Bit definition - Read-only */ +#define RX_IA_HASHED 0x0040 +#define RX_DRIBBLE 0x0080 +#define RX_OK 0x0100 +#define RX_HASHED 0x0200 +#define RX_IA 0x0400 +#define RX_BROADCAST 0x0800 +#define RX_CRC_ERROR 0x1000 +#define RX_RUNT 0x2000 +#define RX_EXTRA_DATA 0x4000 + +#define HASH_INDEX_MASK 0x0FC00 + +/* PP_TxEvent - Transmit Event Bit definition - Read-only */ +#define TX_LOST_CRS 0x0040 +#define TX_SQE_ERROR 0x0080 +#define TX_OK 0x0100 +#define TX_LATE_COL 0x0200 +#define TX_JBR 0x0400 +#define TX_16_COL 0x8000 +#define TX_SEND_OK_BITS (TX_OK|TX_LOST_CRS) +#define TX_COL_COUNT_MASK 0x7800 + +/* PP_BufEvent - Buffer Event Bit definition - Read-only */ +#define SW_INTERRUPT 0x0040 +#define RX_DMA 0x0080 +#define READY_FOR_TX 0x0100 +#define TX_UNDERRUN 0x0200 +#define RX_MISS 0x0400 +#define RX_128_BYTE 0x0800 +#define TX_COL_OVRFLW 0x1000 +#define RX_MISS_OVRFLW 0x2000 +#define RX_DEST_MATCH 0x8000 + +/* PP_LineST - Ethernet Line Status bit definition - Read-only */ +#define LINK_OK 0x0080 +#define AUI_ON 0x0100 +#define TENBASET_ON 0x0200 +#define POLARITY_OK 0x1000 +#define CRS_OK 0x4000 + +/* PP_SelfST - Chip Software Status bit definition */ +#define ACTIVE_33V 0x0040 +#define INIT_DONE 0x0080 +#define SI_BUSY 0x0100 +#define EEPROM_PRESENT 0x0200 +#define EEPROM_OK 0x0400 +#define EL_PRESENT 0x0800 +#define EE_SIZE_64 0x1000 + +/* PP_BusST - ISA Bus Status bit definition */ +#define TX_BID_ERROR 0x0080 +#define READY_FOR_TX_NOW 0x0100 + +/* PP_AutoNegCTL - Auto Negotiation Control bit definition */ +#define RE_NEG_NOW 0x0040 +#define ALLOW_FDX 0x0080 +#define AUTO_NEG_ENABLE 0x0100 +#define NLP_ENABLE 0x0200 +#define FORCE_FDX 0x8000 +#define AUTO_NEG_BITS (FORCE_FDX|NLP_ENABLE|AUTO_NEG_ENABLE) +#define AUTO_NEG_MASK (FORCE_FDX|NLP_ENABLE|AUTO_NEG_ENABLE|ALLOW_FDX|RE_NEG_NOW) + +/* PP_AutoNegST - Auto Negotiation Status bit definition */ +#define AUTO_NEG_BUSY 0x0080 +#define FLP_LINK 0x0100 +#define FLP_LINK_GOOD 0x0800 +#define LINK_FAULT 0x1000 +#define HDX_ACTIVE 0x4000 +#define FDX_ACTIVE 0x8000 + +/* The following block defines the ISQ event types */ +#define ISQ_RECEIVER_EVENT 0x04 +#define ISQ_TRANSMITTER_EVENT 0x08 +#define ISQ_BUFFER_EVENT 0x0c +#define ISQ_RX_MISS_EVENT 0x10 +#define ISQ_TX_COL_EVENT 0x12 + +#define ISQ_EVENT_MASK 0x003F /* ISQ mask to find out type of event */ +#define ISQ_HIST 16 /* small history buffer */ +#define AUTOINCREMENT 0x8000 /* Bit mask to set bit-15 for autoincrement */ + +#define TXRXBUFSIZE 0x0600 +#define RXDMABUFSIZE 0x8000 +#define RXDMASIZE 0x4000 +#define TXRX_LENGTH_MASK 0x07FF + +/* rx options bits */ +#define RCV_WITH_RXON 1 /* Set SerRx ON */ +#define RCV_COUNTS 2 /* Use Framecnt1 */ +#define RCV_PONG 4 /* Pong respondent */ +#define RCV_DONG 8 /* Dong operation */ +#define RCV_POLLING 0x10 /* Poll RxEvent */ +#define RCV_ISQ 0x20 /* Use ISQ, int */ +#define RCV_AUTO_DMA 0x100 /* Set AutoRxDMAE */ +#define RCV_DMA 0x200 /* Set RxDMA only */ +#define RCV_DMA_ALL 0x400 /* Copy all DMA'ed */ +#define RCV_FIXED_DATA 0x800 /* Every frame same */ +#define RCV_IO 0x1000 /* Use ISA IO only */ +#define RCV_MEMORY 0x2000 /* Use ISA Memory */ + +#define RAM_SIZE 0x1000 /* The card has 4k bytes or RAM */ +#define PKT_START PP_TxFrame /* Start of packet RAM */ + +#define RX_FRAME_PORT 0x0000 +#define TX_FRAME_PORT RX_FRAME_PORT +#define TX_CMD_PORT 0x0004 +#define TX_NOW 0x0000 /* Tx packet after 5 bytes copied */ +#define TX_AFTER_381 0x0020 /* Tx packet after 381 bytes copied */ +#define TX_AFTER_ALL 0x0060 /* Tx packet after all bytes copied */ +#define TX_LEN_PORT 0x0006 +#define ISQ_PORT 0x0008 +#define ADD_PORT 0x000A +#define DATA_PORT 0x000C + +#define EEPROM_WRITE_EN 0x00F0 +#define EEPROM_WRITE_DIS 0x0000 +#define EEPROM_WRITE_CMD 0x0100 +#define EEPROM_READ_CMD 0x0200 + +/* Receive Header */ +/* Description of header of each packet in receive area of memory */ +#define RBUF_EVENT_LOW 0 /* Low byte of RxEvent - status of received frame */ +#define RBUF_EVENT_HIGH 1 /* High byte of RxEvent - status of received frame */ +#define RBUF_LEN_LOW 2 /* Length of received data - low byte */ +#define RBUF_LEN_HI 3 /* Length of received data - high byte */ +#define RBUF_HEAD_LEN 4 /* Length of this header */ + +#define CHIP_READ 0x1 /* Used to mark state of the repins code (chip or dma) */ +#define DMA_READ 0x2 /* Used to mark state of the repins code (chip or dma) */ + +/* for bios scan */ +/* */ +#ifdef CSDEBUG +/* use these values for debugging bios scan */ +#define BIOS_START_SEG 0x00000 +#define BIOS_OFFSET_INC 0x0010 +#else +#define BIOS_START_SEG 0x0c000 +#define BIOS_OFFSET_INC 0x0200 +#endif + +#define BIOS_LAST_OFFSET 0x0fc00 + +/* Byte offsets into the EEPROM configuration buffer */ +#define ISA_CNF_OFFSET 0x6 +#define TX_CTL_OFFSET (ISA_CNF_OFFSET + 8) /* 8900 eeprom */ +#define AUTO_NEG_CNF_OFFSET (ISA_CNF_OFFSET + 8) /* 8920 eeprom */ + + /* the assumption here is that the bits in the eeprom are generally */ + /* in the same position as those in the autonegctl register. */ + /* Of course the IMM bit is not in that register so it must be */ + /* masked out */ +#define EE_FORCE_FDX 0x8000 +#define EE_NLP_ENABLE 0x0200 +#define EE_AUTO_NEG_ENABLE 0x0100 +#define EE_ALLOW_FDX 0x0080 +#define EE_AUTO_NEG_CNF_MASK (EE_FORCE_FDX|EE_NLP_ENABLE|EE_AUTO_NEG_ENABLE|EE_ALLOW_FDX) + +#define IMM_BIT 0x0040 /* ignore missing media */ + +#define ADAPTER_CNF_OFFSET (AUTO_NEG_CNF_OFFSET + 2) +#define A_CNF_10B_T 0x0001 +#define A_CNF_AUI 0x0002 +#define A_CNF_10B_2 0x0004 +#define A_CNF_MEDIA_TYPE 0x0060 +#define A_CNF_MEDIA_AUTO 0x0000 +#define A_CNF_MEDIA_10B_T 0x0020 +#define A_CNF_MEDIA_AUI 0x0040 +#define A_CNF_MEDIA_10B_2 0x0060 +#define A_CNF_DC_DC_POLARITY 0x0080 +#define A_CNF_NO_AUTO_POLARITY 0x2000 +#define A_CNF_LOW_RX_SQUELCH 0x4000 +#define A_CNF_EXTND_10B_2 0x8000 + +#define PACKET_PAGE_OFFSET 0x8 + +/* Bit definitions for the ISA configuration word from the EEPROM */ +#define INT_NO_MASK 0x000F +#define DMA_NO_MASK 0x0070 +#define ISA_DMA_SIZE 0x0200 +#define ISA_AUTO_RxDMA 0x0400 +#define ISA_RxDMA 0x0800 +#define DMA_BURST 0x1000 +#define STREAM_TRANSFER 0x2000 +#define ANY_ISA_DMA (ISA_AUTO_RxDMA | ISA_RxDMA) + +/* DMA controller registers */ +#define DMA_BASE 0x00 /* DMA controller base */ +#define DMA_BASE_2 0x0C0 /* DMA controller base */ + +#define DMA_STAT 0x0D0 /* DMA controller status register */ +#define DMA_MASK 0x0D4 /* DMA controller mask register */ +#define DMA_MODE 0x0D6 /* DMA controller mode register */ +#define DMA_RESETFF 0x0D8 /* DMA controller first/last flip flop */ + +/* DMA data */ +#define DMA_DISABLE 0x04 /* Disable channel n */ +#define DMA_ENABLE 0x00 /* Enable channel n */ +/* Demand transfers, incr. address, auto init, writes, ch. n */ +#define DMA_RX_MODE 0x14 +/* Demand transfers, incr. address, auto init, reads, ch. n */ +#define DMA_TX_MODE 0x18 + +#define DMA_SIZE (16*1024) /* Size of dma buffer - 16k */ + +#define CS8900 0x0000 +#define CS8920 0x4000 +#define CS8920M 0x6000 +#define REVISON_BITS 0x1F00 +#define EEVER_NUMBER 0x12 +#define CHKSUM_LEN 0x14 +#define CHKSUM_VAL 0x0000 +#define START_EEPROM_DATA 0x001c /* Offset into eeprom for start of data */ +#define IRQ_MAP_EEPROM_DATA 0x0046 /* Offset into eeprom for the IRQ map */ +#define IRQ_MAP_LEN 0x0004 /* No of bytes to read for the IRQ map */ +#define PNP_IRQ_FRMT 0x0022 /* PNP small item IRQ format */ +#define CS8900_IRQ_MAP 0x1c20 /* This IRQ map is fixed */ + +#define CS8920_NO_INTS 0x0F /* Max CS8920 interrupt select # */ + +#define PNP_ADD_PORT 0x0279 +#define PNP_WRITE_PORT 0x0A79 + +#define GET_PNP_ISA_STRUCT 0x40 +#define PNP_ISA_STRUCT_LEN 0x06 +#define PNP_CSN_CNT_OFF 0x01 +#define PNP_RD_PORT_OFF 0x02 +#define PNP_FUNCTION_OK 0x00 +#define PNP_WAKE 0x03 +#define PNP_RSRC_DATA 0x04 +#define PNP_RSRC_READY 0x01 +#define PNP_STATUS 0x05 +#define PNP_ACTIVATE 0x30 +#define PNP_CNF_IO_H 0x60 +#define PNP_CNF_IO_L 0x61 +#define PNP_CNF_INT 0x70 +#define PNP_CNF_DMA 0x74 +#define PNP_CNF_MEM 0x48 + +#define BIT0 1 +#define BIT15 0x8000 + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ + diff --git a/netboot/eepro100.c b/netboot/eepro100.c new file mode 100644 index 000000000..9d358585e --- /dev/null +++ b/netboot/eepro100.c @@ -0,0 +1,800 @@ +/* + * eepro100.c -- This file implements the eepro100 driver for etherboot. + * + * + * Copyright (C) AW Computer Systems. + * written by R.E.Wolff -- R.E.Wolff@BitWizard.nl + * + * + * AW Computer Systems is contributing to the free software community + * by paying for this driver and then putting the result under GPL. + * + * If you need a Linux device driver, please contact BitWizard for a + * quote. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * date version by what + * Written: May 29 1997 V0.10 REW Initial revision. + * changes: May 31 1997 V0.90 REW Works! + * Jun 1 1997 V0.91 REW Cleanup + * Jun 2 1997 V0.92 REW Add some code documentation + * Jul 25 1997 V1.00 REW Tested by AW to work in a PROM + * Cleanup for publication + * + * This is the etherboot-3.1 compatible intel etherexpress Pro/100B + * driver. + * + * It was written from scratch, with Donald Beckers eepro100.c kernel + * driver as a guideline. Mostly the 82557 related definitions and the + * lower level routines have been cut-and-pasted into this source. + * + * The driver was finished before Intel got the NDA out of the closet. + * I still don't have the docs. + * */ + + + +/* Philosophy of this driver. + * + * Probing: + * + * Using a subset of "bios32" and "pci" functions of the linux kernel, + * the pci 82557 chip is detected. + * + * + * Initialization: + * + * + * The chip is then initialized to "know" its ethernet address, and to + * start recieving packets. The Linux driver has a whole transmit and + * recieve ring of buffers. This is neat if you need high performance: + * you can write the buffers asynchronously to the chip reading the + * buffers and transmitting them over the network. Performance is NOT + * an issue here. We can boot a 400k kernel in about two + * seconds. (Theory: 0.4 seconds). Booting a system is going to take + * about half a minute anyway, so getting 10 times closer to the + * theoretical limit is going to make a difference of a few percent. + * + * + * Transmitting and recieving. + * + * We have only one transmit descriptor. It has two buffer descriptors: + * one for the header, and the other for the data. + * We have only one receive buffer. The chip is told to recieve packets, + * and suspend itself once it got one. The recieve (poll) routine simply + * looks at the recieve buffer to see if there is already a packet there. + * if there is, the buffer is copied, and the reciever is restarted. + * + * Caveats: + * + * The etherboot framework moves the code to the 32k segment from + * 0x98000 to 0xa0000. There is just a little room between the end of + * this driver and the 0xa0000 address. If you compile in too many + * features, this will overflow. + * The number under "hex" in the output of size that scrolls by while + * compiling should be less than 8000. Maybe even the stack is up there, + * so that you need even more headroom. + * + * If you run into trouble, the method used to give "pci.c" dynamic + * allocation should be used to allocate the larger variables (like + * the packet buffers) + * */ + +#ifdef INCLUDE_EEPRO100 + + +/* The etherboot authors seem to dislike the argument ordering in + * outb macros that Linux uses. I disklike the confusion that this + * has caused even more.... This file uses the Linux argument ordering. */ +#define LINUX_OUT_MACROS + +#include "netboot.h" +#include "nic.h" +#include +#include + +static int ioaddr; + +typedef unsigned char u8; +typedef signed char s8; +typedef unsigned short u16; +typedef signed short s16; +typedef unsigned int u32; +typedef signed int s32; + + +enum speedo_offsets { + SCBStatus = 0, SCBCmd = 2, /* Rx/Command Unit command and status. */ + SCBPointer = 4, /* General purpose pointer. */ + SCBPort = 8, /* Misc. commands and operands. */ + SCBflash = 12, SCBeeprom = 14, /* EEPROM and flash memory control. */ + SCBCtrlMDI = 16, /* MDI interface control. */ + SCBEarlyRx = 20, /* Early receive byte count. */ +}; + + +static int read_eeprom(int ioaddr, int location); +static void udelay (int val); +void hd (void *where, int n); + + +/***********************************************************************/ +/* I82557 related defines */ +/***********************************************************************/ + +/* Serial EEPROM section. + A "bit" grungy, but we work our way through bit-by-bit :->. */ +/* EEPROM_Ctrl bits. */ +#define EE_SHIFT_CLK 0x01 /* EEPROM shift clock. */ +#define EE_CS 0x02 /* EEPROM chip select. */ +#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */ +#define EE_WRITE_0 0x01 +#define EE_WRITE_1 0x05 +#define EE_DATA_READ 0x08 /* EEPROM chip data out. */ +#define EE_ENB (0x4800 | EE_CS) + + +/* Delay between EEPROM clock transitions. + This is a "nasty" timing loop, but PC compatible machines are defined + to delay an ISA compatible period for the SLOW_DOWN_IO macro. */ +#define eeprom_delay(nanosec) do { int _i = 3; while (--_i > 0) \ + { __SLOW_DOWN_IO; }} while (0) + +/* The EEPROM commands include the alway-set leading bit. */ +#define EE_WRITE_CMD (5 << 6) +#define EE_READ_CMD (6 << 6) +#define EE_ERASE_CMD (7 << 6) + +/* The SCB accepts the following controls for the Tx and Rx units: */ +#define CU_START 0x0010 +#define CU_RESUME 0x0020 +#define CU_STATSADDR 0x0040 +#define CU_SHOWSTATS 0x0050 /* Dump statistics counters. */ +#define CU_CMD_BASE 0x0060 /* Base address to add to add CU commands. */ +#define CU_DUMPSTATS 0x0070 /* Dump then reset stats counters. */ + +#define RX_START 0x0001 +#define RX_RESUME 0x0002 +#define RX_ABORT 0x0004 +#define RX_ADDR_LOAD 0x0006 +#define RX_RESUMENR 0x0007 +#define INT_MASK 0x0100 +#define DRVR_INT 0x0200 /* Driver generated interrupt. */ + +enum phy_chips { NonSuchPhy=0, I82553AB, I82553C, I82503, DP83840, S80C240, + S80C24, PhyUndefined, DP83840A=10, }; + + + +/* Commands that can be put in a command list entry. */ +enum commands { + CmdNOp = 0, + CmdIASetup = 1, + CmdConfigure = 2, + CmdMulticastList = 3, + CmdTx = 4, + CmdTDR = 5, + CmdDump = 6, + CmdDiagnose = 7, + + /* And some extra flags: */ + CmdSuspend = 0x4000, /* Suspend after completion. */ + CmdIntr = 0x2000, /* Interrupt after completion. */ + CmdTxFlex = 0x0008, /* Use "Flexible mode" for CmdTx command. */ +}; + + +/* How to wait for the command unit to accept a command. + Typically this takes 0 ticks. */ +static inline void wait_for_cmd_done(int cmd_ioaddr) +{ + short wait = 100; + do ; + while(inb(cmd_ioaddr) && --wait >= 0); +} + + +/* Elements of the dump_statistics block. This block must be lword aligned. */ +struct speedo_stats { + u32 tx_good_frames; + u32 tx_coll16_errs; + u32 tx_late_colls; + u32 tx_underruns; + u32 tx_lost_carrier; + u32 tx_deferred; + u32 tx_one_colls; + u32 tx_multi_colls; + u32 tx_total_colls; + u32 rx_good_frames; + u32 rx_crc_errs; + u32 rx_align_errs; + u32 rx_resource_errs; + u32 rx_overrun_errs; + u32 rx_colls_errs; + u32 rx_runt_errs; + u32 done_marker; +} lstats; + + +/* A speedo3 TX buffer descriptor with two buffers... */ +struct TxFD { + volatile s16 status; + s16 command; + u32 link; /* void * */ + u32 tx_desc_addr; /* (almost) Always points to the tx_buf_addr element. */ + s32 count; /* # of TBD (=2), Tx start thresh., etc. */ + /* This constitutes two "TBD" entries: hdr and data */ + u32 tx_buf_addr0; /* void *, header of frame to be transmitted. */ + s32 tx_buf_size0; /* Length of Tx hdr. */ + u32 tx_buf_addr1; /* void *, data to be transmitted. */ + s32 tx_buf_size1; /* Length of Tx data. */ +} txfd; + + + +/* The Speedo3 Rx buffer descriptors. */ +struct RxFD { /* Receive frame descriptor. */ + volatile s16 status; + s16 command; + u32 link; /* struct RxFD * */ + u32 rx_buf_addr; /* void * */ + u16 count; + u16 size; + char packet[1518]; +} rxfd; + + + +static int congenb = 0; /* Enable congestion control in the DP83840. */ +static int txfifo = 8; /* Tx FIFO threshold in 4 byte units, 0-15 */ +static int rxfifo = 8; /* Rx FIFO threshold, default 32 bytes. */ +static int txdmacount = 0; /* Tx DMA burst length, 0-127, default 0. */ +static int rxdmacount = 0; /* Rx DMA length, 0 means no preemption. */ + + + +/* I don't understand a byte in this structure. It was copied from the + * Linux kernel initialization for the eepro100. -- REW */ +struct ConfCmd { + s16 status; + s16 command; + u32 link; + unsigned char data[22]; +} confcmd = { + 0, CmdConfigure, + (u32) & txfd, + {22, 0x08, 0, 0, 0, 0x80, 0x32, 0x03, 1, /* 1=Use MII 0=Use AUI */ + 0, 0x2E, 0, 0x60, 0, + 0xf2, 0x48, 0, 0x40, 0xf2, 0x80, /* 0x40=Force full-duplex */ + 0x3f, 0x05, } +}; + + + +#define TIME_OUT 1000000 + +/* The "pci" code needs to allocate a few structures. It wants to + * increment the "kernel memory ends here" pointer to allocate memory. + * I guess that a machine with PCI has more than 2Mb of memory, so + * that is where those things are put. Those structures don't survive + * the "jump to kernel start". + * */ +#define MEM_START 0x200000 /* Memory starts at 2Mb for now.... */ +#define MEM_END 0 + +static unsigned short eeprom [0x40]; + +static void calibrate_delay (void); + + +/***********************************************************************/ +/* Locally used functions */ +/***********************************************************************/ + + +/* Support function: mdio_write + * + * This probably writes to the "physical media interface chip". + * -- REW + */ + + +static int mdio_write(int ioaddr, int phy_id, int location, int value) +{ + int val, boguscnt = 64*4; /* <64 usec. to complete, typ 27 ticks */ + + outl(0x04000000 | (location<<16) | (phy_id<<21) | value, + ioaddr + SCBCtrlMDI); + do { + udelay(16); + + val = inl(ioaddr + SCBCtrlMDI); + if (--boguscnt < 0) { + printf(" mdio_write() timed out with val = %8.8x.\n", val); + } + } while (! (val & 0x10000000)); + return val & 0xffff; +} + + +/* Support function: mdio_read + * + * This probably reads a register in the "physical media interface chip". + * -- REW + */ +static int mdio_read(int ioaddr, int phy_id, int location) +{ + int val, boguscnt = 64*4; /* <64 usec. to complete, typ 27 ticks */ + outl(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI); + do { + udelay(16); + + val = inl(ioaddr + SCBCtrlMDI); + if (--boguscnt < 0) { + printf( " mdio_read() timed out with val = %8.8x.\n", val); + } + } while (! (val & 0x10000000)); + return val & 0xffff; +} + + +/* Support function: read_eeprom + * reads a value from the eeprom at a specified location. + * Arguments: ioaddr: address of the 82557 chip + * location: address of the location to read from the eeprom. + * returns: value read from eeprom at location. + */ +static int read_eeprom(int ioaddr, int location) +{ + int i; + unsigned short retval = 0; + int ee_addr = ioaddr + SCBeeprom; + int read_cmd = location | EE_READ_CMD; + + outw(EE_ENB & ~EE_CS, ee_addr); + outw(EE_ENB, ee_addr); + + /* Shift the read command bits out. */ + for (i = 10; i >= 0; i--) { + short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; + outw(EE_ENB | dataval, ee_addr); + eeprom_delay(100); + outw(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); + eeprom_delay(150); + outw(EE_ENB | dataval, ee_addr); /* Finish EEPROM a clock tick. */ + eeprom_delay(250); + } + outw(EE_ENB, ee_addr); + + for (i = 15; i >= 0; i--) { + outw(EE_ENB | EE_SHIFT_CLK, ee_addr); + eeprom_delay(100); + retval = (retval << 1) | ((inw(ee_addr) & EE_DATA_READ) ? 1 : 0); + outw(EE_ENB, ee_addr); + eeprom_delay(100); + } + + /* Terminate the EEPROM access. */ + outw(EE_ENB & ~EE_CS, ee_addr); + return retval; +} + + +static void inline whereami (char *str) +{ +#if 0 + printf ("%s\r\n", str); + sleep (2); +#endif +} + + + +/***********************************************************************/ +/* Externally visible functions */ +/***********************************************************************/ + + +/* function: eepro100_reset / eth_reset + * resets the card. This is used to allow Linux to probe the card again + * from a "virginal" state.... + * Arguments: none + * + * returns: void. + */ + +static void eepro100_reset(struct nic *nic) +{ + outl(0, ioaddr + SCBPort); +} + + + +/* function: eepro100_transmit / eth_transmit + * This transmits a packet. + * + * Arguments: char d[6]: destination ethernet address. + * unsigned short t: ethernet protocol type. + * unsigned short s: size of the data-part of the packet. + * char *p: the data for the packet. + * returns: void. + */ + +static void eepro100_transmit(struct nic *nic, char *d, unsigned int t, unsigned int s, char *p) +{ + struct eth_hdr { + unsigned char dst_addr[6]; + unsigned char src_addr[6]; + unsigned short type; + } hdr; + unsigned short status; + int to; + int s1, s2; + + status = inw(ioaddr + SCBStatus); + /* Acknowledge all of the current interrupt sources ASAP. */ + outw(status & 0xfc00, ioaddr + SCBStatus); + +#ifdef DEBUG + printf ("transmitting type %x packet (%d bytes). status = %x, cmd=%x\r\n", + t, s, status, inw (ioaddr + SCBCmd)); +#endif + + + memcpy (&hdr.dst_addr, d, 6); + memcpy (&hdr.src_addr, &arptable[ARP_CLIENT].node, 6); + + hdr.type = htons (t); + + txfd.status = 0; + txfd.command = CmdSuspend | CmdTx | CmdTxFlex; + txfd.link = virt_to_bus (&txfd); + txfd.count = 0x02208000; + txfd.tx_desc_addr = (u32)&txfd.tx_buf_addr0; + + txfd.tx_buf_addr0 = virt_to_bus (&hdr); + txfd.tx_buf_size0 = sizeof (hdr); + + txfd.tx_buf_addr1 = virt_to_bus (p); + txfd.tx_buf_size1 = s; + +#ifdef DEBUG + printf ("txfd: \r\n"); + hd (&txfd, sizeof (txfd)); +#endif + + outl(virt_to_bus(&txfd), ioaddr + SCBPointer); + outw(INT_MASK | CU_START, ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr + SCBCmd); + + s1 = inw (ioaddr + SCBStatus); + to = TIME_OUT; + while (!txfd.status && --to) + /* Wait */; + s2 = inw (ioaddr + SCBStatus); + +#ifdef DEBUG + printf ("Tx: Loop executed %d times.\r\n", TIME_OUT-to); + printf ("s1 = %x, s2 = %x.\r\n", s1, s2); +#endif +} + + +/* function: eepro100_poll / eth_poll + * This recieves a packet from the network. + * + * Arguments: none + * + * returns: 1 if a packet was recieved. + * 0 if no pacet was recieved. + * side effects: + * returns the packet in the array nic->packet. + * returns the length of the packet in nic->packetlen. + */ + +static int eepro100_poll(struct nic *nic) +{ + int to; + + to = TIME_OUT; + while (!rxfd.status && --to) + /* Wait */; + + /* Ok. We got a packet. Now restart the reciever.... */ + rxfd.status = 0; + rxfd.command = 0xc000; + outl(virt_to_bus(&rxfd), ioaddr + SCBPointer); + outw(INT_MASK | RX_START, ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr + SCBCmd); + + if (to) { +#ifdef DEBUG + printf ("Got a packet: Len = %d.\r\n", rxfd.count & 0x3fff); +#endif + nic->packetlen = rxfd.count & 0x3fff; + bcopy (rxfd.packet, nic->packet, sizeof (rxfd.packet)); +#ifdef DEBUG + hd (nic->packet, 0x30); +#endif + return 1; + } else + return 0; +} + +static void eepro100_disable(struct nic *nic) +{ +} + +/* exported function: eepro100_probe / eth_probe + * initializes a card + * + * side effects: + * leaves the ioaddress of the 82557 chip in the variable ioaddr. + * leaves the 82557 initialized, and ready to recieve packets. + */ + +struct nic *eepro100_probe(struct nic *nic, unsigned short *probeaddrs) +{ + int pci_index; + u16 sum = 0; + int i, j, to; + unsigned short value; + int options; + int promisc; + + if (probeaddrs == 0 || probeaddrs[0] == 0) + return 0; + + ioaddr = probeaddrs[0] & ~3; /* Mask the bit that says "this is an io addr" */ + + /* Ok. Got one. Read the eeprom. */ + for (j = 0, i = 0; i < 0x40; i++) { + value = read_eeprom(ioaddr, i); + eeprom[i] = value; + sum += value; + } + + printf ("Ethernet addr: "); + for (i=0;i<6;i++) { + arptable[ARP_CLIENT].node[i] = (eeprom[i/2] >> (8*(i&1))) & 0xff; + printf ("%b%c", arptable[ARP_CLIENT].node[i] , i < 5?':':' '); + } + printf ("\r\n"); + + if (sum != 0xBABA) + printf("eepro100: Invalid EEPROM checksum %#4.4x, " + "check settings before activating this device!\r\n", sum); + outl(0, ioaddr + SCBPort); + udelay (10); + + whereami ("Got eeprom."); + + outl(virt_to_bus(&lstats), ioaddr + SCBPointer); + outw(INT_MASK | CU_STATSADDR, ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr + SCBCmd); + + whereami ("set stats addr."); + /* INIT RX stuff. */ + + /* Base = 0 */ + outl(0, ioaddr + SCBPointer); + outw(INT_MASK | RX_ADDR_LOAD, ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr + SCBCmd); + + whereami ("set rx base addr."); + + rxfd.status = 0x0001; + rxfd.command = 0x0000; + rxfd.link = virt_to_bus(&rxfd); + rxfd.rx_buf_addr = (int) &nic->packet; + rxfd.count = 0; + rxfd.size = 1528; + + outl(virt_to_bus(&rxfd), ioaddr + SCBPointer); + outw(INT_MASK | RX_START, ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr + SCBCmd); + + whereami ("started RX process."); + + /* Start the reciever.... */ + rxfd.status = 0; + rxfd.command = 0xc000; + outl(virt_to_bus(&rxfd), ioaddr + SCBPointer); + outw(INT_MASK | RX_START, ioaddr + SCBCmd); + + + /* INIT TX stuff. */ + + /* Base = 0 */ + outl(0, ioaddr + SCBPointer); + outw(INT_MASK | CU_CMD_BASE, ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr + SCBCmd); + + whereami ("set TX base addr."); + + txfd.command = (CmdIASetup); + txfd.status = 0x0000; + txfd.link = virt_to_bus (&confcmd); + + { + char *p = (char *)&txfd.tx_desc_addr; + + for (i=0;i<6;i++) + p[i] = arptable[ARP_CLIENT].node[i]; + } + +#ifdef DEBUG + printf ("Setup_eaddr:\r\n"); + hd (&txfd, 0x20); +#endif + /* options = 0x40; */ /* 10mbps half duplex... */ + options = 0x00; /* Autosense */ + + promisc = 0; + + printf ("eeprom[6] = %x \r\n", eeprom[6]); + if ( ((eeprom[6]>>8) & 0x3f) == DP83840 + || ((eeprom[6]>>8) & 0x3f) == DP83840A) { + int mdi_reg23 = mdio_read(ioaddr, eeprom[6] & 0x1f, 23) | 0x0422; + if (congenb) + mdi_reg23 |= 0x0100; + printf(" DP83840 specific setup, setting register 23 to %x.\r\n", + mdi_reg23); + mdio_write(ioaddr, eeprom[6] & 0x1f, 23, mdi_reg23); + } + whereami ("Done DP8340 special setup."); + if (options != 0) { + mdio_write(ioaddr, eeprom[6] & 0x1f, 0, + ((options & 0x20) ? 0x2000 : 0) | /* 100mbps? */ + ((options & 0x10) ? 0x0100 : 0)); /* Full duplex? */ + whereami ("set mdio_register."); + } + + confcmd.command = CmdSuspend | CmdConfigure; + confcmd.status = 0x0000; + confcmd.link = virt_to_bus (&txfd); + confcmd.data[1] = (txfifo << 4) | rxfifo; + confcmd.data[4] = rxdmacount; + confcmd.data[5] = txdmacount + 0x80; + confcmd.data[15] = promisc ? 0x49: 0x48; + confcmd.data[19] = (options & 0x10) ? 0xC0 : 0x80; + confcmd.data[21] = promisc ? 0x0D: 0x05; + + outl(virt_to_bus(&txfd), ioaddr + SCBPointer); + outw(INT_MASK | CU_START, ioaddr + SCBCmd); + wait_for_cmd_done(ioaddr + SCBCmd); + + whereami ("started TX thingy (config, iasetup)."); + + to = TIME_OUT; + while (!txfd.status && --to) + /* Wait */; + +#ifdef DEBUG + printf ("\r\nLoop executed %d times.\r\n", TIME_OUT-to); +#endif + nic->reset = eepro100_reset; + nic->poll = eepro100_poll; + nic->transmit = eepro100_transmit; + nic->disable = eepro100_disable; + return nic; +} + +static int loops_per_sec; +static int loops_per_usec; + +static void udelay (int val) +{ + int c; + + for(c=0; c>= 1; + loopbit = loops_per_sec; + while ( lps_precision-- && (loopbit >>= 1) ) { + loops_per_sec |= loopbit; + ticks = jiffies; + while (ticks == jiffies); + ticks = jiffies; + __delay(loops_per_sec); + if (jiffies != ticks) /* longer than 1 tick */ + loops_per_sec &= ~loopbit; + } + + /* finally, adjust loops per second in terms of seconds instead of clocks */ + loops_per_sec *= HZ; + /* Round the value and print it */ + printk("ok - %d.%d BogoMIPS\n", + (loops_per_sec+25000)/500000, + ((loops_per_sec+25000)/50000) % 10); + loops_per_usec = loops_per_sec / 1000000; +} +#endif + + +/*********************************************************************/ + +#ifdef DEBUG + +/* Hexdump a number of bytes from memory... */ +void hd (void *where, int n) +{ + int i; + + while (n > 0) { + printf ("%X ", where); + for (i=0;i < ( (n>16)?16:n);i++) + printf (" %b", ((char *)where)[i]); + printf ("\n\r"); + n -= 16; + where += 16; + } +} +#endif + +#endif /* INCLUDE_EEPRO100 */ diff --git a/netboot/fsys_tftp.c b/netboot/fsys_tftp.c new file mode 100644 index 000000000..b5db2a5bb --- /dev/null +++ b/netboot/fsys_tftp.c @@ -0,0 +1,227 @@ +#include "../stage2/filesys.h" + +#include "netboot.h" +#include "config.h" +#include "nic.h" + +#include "ip.h" + +#if 0 + +#define BUFSIZE (20*TFTP_DEFAULTSIZE_PACKET) +static char buf[BUFSIZE]; + +#else + +/* use GRUB's file system buffer */ +#define BUFSIZE (32*1024) +#define buf ((char *)(FSYS_BUF)) + +#endif + +static int buf_read = 0, buf_eof = 0; +static unsigned long buf_fileoff; + +static int retry; +static unsigned short isocket = 2000; +static unsigned short osocket; +static unsigned short len, block, prevblock; +static struct tftp_t *tr; +static struct tftp_t tp; +static int packetsize = TFTP_DEFAULTSIZE_PACKET; + +static int buf_fill(int abort); + +int tftp_mount(void) +{ + if (current_drive != 0x20) /* only mount network drives */ + return 0; + + if (!ip_init()) + return 0; + + return 1; +} + +/* read "size" bytes from file position "filepos" to "addr" */ +int tftp_read(char *addr, int size) +{ + int ret = 0; + + if (filepos < buf_fileoff) + { + printf("tftp_read: can't read from filepos=%d, buf_fileoff=%d\n", + filepos, buf_fileoff); + errnum = ERR_BOOT_FAILURE; + return 0; + } + + while (size > 0) + { + if (filepos < buf_fileoff + buf_read) + { + /* can copy stuff from buffer */ + int tocopy = buf_fileoff + buf_read - filepos; + if (tocopy > size) tocopy = size; + bcopy(buf + (filepos - buf_fileoff), (void*) addr, tocopy); + size -= tocopy; + addr += tocopy; + filepos += tocopy; + ret += tocopy; + + if (buf_eof && (filepos + size >= buf_fileoff + buf_read)) + break; /* end of file */ + + continue; + } + else if ((filepos == buf_fileoff + buf_read) && buf_eof) + break; /* end of file */ + + if (buf_eof) /* filepos beyond end of file */ + { + errnum = ERR_READ; + return 0; + } + + /* move buffer contents forward by 1/2 buffer size */ + bcopy(buf + BUFSIZE/2, buf, BUFSIZE/2); + buf_fileoff += BUFSIZE/2; + buf_read -= BUFSIZE/2; + + if (! buf_fill(0)) /* read more data */ + { + errnum = ERR_READ; + return 0; + } + } + + return ret; +} + +int tftp_dir(char *dirname) +{ + char name[100], *np; + + if (print_possibilities) + { + printf(" TFTP doesn't support listing the directory; Sorry!\n"); + return 1; + } + + /* open the file */ + np = name; + while (dirname && *dirname && !isspace(*dirname)) + *np++ = *dirname++; + *np = 0; + + buf_eof = buf_read = buf_fileoff = 0; + + retry = 0; + block = 0; + prevblock = 0; + packetsize = TFTP_DEFAULTSIZE_PACKET; + + /* send tftp read request */ + tp.opcode = htons(TFTP_RRQ); + len = 30 + sprintf((char *)tp.u.rrq, "%s%coctet%cblksize%c%d", + name, 0, 0, 0, TFTP_MAX_PACKET) + 1; + + if (!udp_transmit(arptable[ARP_SERVER].ipaddr, ++isocket, TFTP, + len, (char *)&tp)) + { + printf("tftp_dir: can't transmit TFTP read request\n"); + errnum = ERR_BOOT_FAILURE; + return (0); + } + if (! buf_fill(0)) + { + printf("tftp_dir: can't read from file\n"); + errnum = ERR_FILE_NOT_FOUND; + return 0; + } + +/* filemax = 234620; */ + filemax = 16L*1024*1024; /* XXX 16MB is max filesize */ + + return 1; +} + +#if 0 +void tftp_close(void) +{ + buf_read = 0; + buf_fill(1); /* abort. */ +} +#endif + +static int buf_fill(int abort) +{ + while (!buf_eof && (buf_read + packetsize <= BUFSIZE)) + { + /* read a packet from the network */ + if (!await_reply(AWAIT_TFTP, isocket, NULL)) + { + if (ip_abort) + return 0; + + if (prevblock == 0 && retry++ < MAX_TFTP_RETRIES) + { /* maybe initial request was lost */ + rfc951_sleep(retry); + if (!udp_transmit(arptable[ARP_SERVER].ipaddr, + ++isocket, TFTP, len, (char *)&tp)) + return (0); + continue; + } + return 0; /* timeout on other blocks */ + } + + /* we got a packet */ + + tr = (struct tftp_t *)&nic.packet[ETHER_HDR_SIZE]; + + if (tr->opcode == ntohs(TFTP_ERROR)) /* error? */ + { + printf("TFTP error %d (%s)\r\n", + ntohs(tr->u.err.errcode), + tr->u.err.errmsg); + return 0; + } + else if (tr->opcode == ntohs(TFTP_OACK)) + { + continue; /* ignore */ + } + else if (tr->opcode == ntohs(TFTP_DATA)) + { + retry = MAX_TFTP_RETRIES; /*no more retries! */ + len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 4; + if (len > packetsize) /* shouldn't happen */ + continue; /* ignore it */ + block = ntohs(tp.u.ack.block = tr->u.data.block); + } + else /* neither TFTP_OACK nor TFTP_DATA */ + return 0; + + tp.opcode = abort ? htons(TFTP_ERROR) : htons(TFTP_ACK); + osocket = ntohs(tr->udp.src); + udp_transmit(arptable[ARP_SERVER].ipaddr, isocket, + osocket, TFTP_MIN_PACKET, (char *)&tp); /* ack */ + + if (abort) + { + buf_eof = 1; + break; + } + + if (block <= prevblock) /* retransmission or OACK */ + continue; /* don't process */ + prevblock = block; + + bcopy(tr->u.data.download, buf + buf_read, len); + buf_read += len; + + if (len < packetsize) /* End of data */ + buf_eof = 1; + } + + return 1; +} diff --git a/netboot/if.h b/netboot/if.h new file mode 100644 index 000000000..46877e6d2 --- /dev/null +++ b/netboot/if.h @@ -0,0 +1,18 @@ + +/* Standard interface flags. */ +#define IFF_UP 0x1 /* interface is up */ +#define IFF_BROADCAST 0x2 /* broadcast address valid */ +#define IFF_DEBUG 0x4 /* turn on debugging */ +#define IFF_LOOPBACK 0x8 /* is a loopback net */ +#define IFF_POINTOPOINT 0x10 /* interface is has p-p link */ +#define IFF_NOTRAILERS 0x20 /* avoid use of trailers */ +#define IFF_RUNNING 0x40 /* resources allocated */ +#define IFF_NOARP 0x80 /* no ARP protocol */ +#define IFF_PROMISC 0x100 /* receive all packets */ +/* Not supported */ +#define IFF_ALLMULTI 0x200 /* receive all multicast packets*/ + +#define IFF_MASTER 0x400 /* master of a load balancer */ +#define IFF_SLAVE 0x800 /* slave of a load balancer */ + +#define IFF_MULTICAST 0x1000 /* Supports multicast */ diff --git a/netboot/io.h b/netboot/io.h new file mode 100644 index 000000000..5e01163f5 --- /dev/null +++ b/netboot/io.h @@ -0,0 +1,93 @@ +#ifndef _ASM_IO_H +#define _ASM_IO_H + +/* + * This file contains parts of Linux's /usr/include/asm/io.h, but + * with the argument order reversed for outb, outb_p, outw, outw_p. + */ + +#define SLOW_DOWN_IO __asm__ __volatile__("outb %al,$0x80") + +#define __OUT1(s,x) \ +extern inline void __out##s(unsigned x value, unsigned short port); \ +extern inline void __out##s(unsigned x value, unsigned short port) { + +#define __OUT2(s,s1,s2) \ +__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" + +#define __OUT(s,s1,x) \ +__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); } \ +__OUT1(s##c,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); } \ +__OUT1(s##_p,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); SLOW_DOWN_IO; } \ +__OUT1(s##c_p,x) __OUT2(s,s1,"") : : "a" (value), "id" (port)); SLOW_DOWN_IO; } + +#define __IN1(s) \ +extern inline RETURN_TYPE __in##s(unsigned short port); \ +extern inline RETURN_TYPE __in##s(unsigned short port) { RETURN_TYPE _v; + +#define __IN2(s,s1,s2) \ +__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" + +#define __IN(s,s1,i...) \ +__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); return _v; } \ +__IN1(s##c) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); return _v; } \ +__IN1(s##_p) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); SLOW_DOWN_IO; return _v; } \ +__IN1(s##c_p) __IN2(s,s1,"") : "=a" (_v) : "id" (port) ,##i ); SLOW_DOWN_IO; return _v; } + +#define RETURN_TYPE unsigned char +/* __IN(b,"b","0" (0)) */ +__IN(b,"") +#undef RETURN_TYPE +#define RETURN_TYPE unsigned short +/* __IN(w,"w","0" (0)) */ +__IN(w,"") +#undef RETURN_TYPE +#define RETURN_TYPE unsigned int +__IN(l,"") +#undef RETURN_TYPE + +__OUT(b,"b",char) +__OUT(w,"w",short) +__OUT(l,,int) + +#define outb(port,val) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __outbc((val),(port)) : \ + __outb((val),(port))) + +#define inb(port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __inbc(port) : \ + __inb(port)) + +#define outb_p(port,val) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __outbc_p((val),(port)) : \ + __outb_p((val),(port))) + +#define inb_p(port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __inbc_p(port) : \ + __inb_p(port)) + +#define outw(port,val) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __outwc((val),(port)) : \ + __outw((val),(port))) + +#define inw(port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __inwc(port) : \ + __inw(port)) + +#define outw_p(port,val) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __outwc_p((val),(port)) : \ + __outw_p((val),(port))) + +#define inw_p(port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __inwc_p(port) : \ + __inw_p(port)) + +#endif diff --git a/netboot/ip.c b/netboot/ip.c new file mode 100644 index 000000000..fc27caf05 --- /dev/null +++ b/netboot/ip.c @@ -0,0 +1,645 @@ +#include "netboot.h" +#include "config.h" +#include "nic.h" + +#include "ip.h" + + +struct arptable_t arptable[MAX_ARP]; +int _pending_key; + +static unsigned long netmask; +static char rfc1533_cookie[5] = { RFC1533_COOKIE, RFC1533_END }; +static char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + +static char *kernel; +static char kernel_buf[128]; +static struct bootpd_t bootp_data; +static int vendorext_isvalid; +static unsigned char vendorext_magic[] = {0xE4,0x45,0x74,0x68}; /* äEth */ +static unsigned char *end_of_rfc1533 = NULL; + +int ip_abort = 0; + +static int bootp(void); +static void default_netmask(void); +static void convert_ipaddr(register char *d, register char *s); +static int decode_rfc1533(register unsigned char *p, int block, int len, + int eof); + + +int ip_init(void) +{ + static int bootp_completed = 0, + probe_completed = 0; + + if (!probe_completed && !eth_probe()) + { + printf("No ethernet adapter found\n"); + return 0; + } + probe_completed = 1; + +#if 1 + if ((!bootp_completed || + !arptable[ARP_CLIENT].ipaddr || !arptable[ARP_SERVER].ipaddr)) + { +#endif + if (!bootp()) + { + printf("No BOOTP server found\n"); + return 0; + } + + printf("My IP 0x%x, Server IP 0x%x, GW IP 0x%x\n", + arptable[ARP_CLIENT].ipaddr, + arptable[ARP_SERVER].ipaddr, + arptable[ARP_GATEWAY].ipaddr); +#ifdef CONFIG_FILE_EXT + { + char *ext = &config_file; + + /* seek to end of config file name */ + while(*ext) + ext++; + + sprintf(ext, ".%d", arptable[ARP_CLIENT].ipaddr & 0xff); + } +#endif +#if 1 + } + bootp_completed = 1; +#endif + + return 1; +} + +/************************************************************************** +UDP_TRANSMIT - Send a UDP datagram +**************************************************************************/ +int udp_transmit(destip, srcsock, destsock, len, buf) + unsigned long destip; + unsigned int srcsock, destsock; + int len; + char *buf; +{ + struct iphdr *ip; + struct udphdr *udp; + struct arprequest arpreq; + int arpentry, i; + int retry; + + ip = (struct iphdr *)buf; + udp = (struct udphdr *)(buf + sizeof(struct iphdr)); + ip->verhdrlen = 0x45; + ip->service = 0; + ip->len = htons(len); + ip->ident = 0; + ip->frags = 0; + ip->ttl = 60; + ip->protocol = IP_UDP; + ip->chksum = 0; + convert_ipaddr(ip->src, (char *)&arptable[ARP_CLIENT].ipaddr); + convert_ipaddr(ip->dest, (char *)&destip); + ip->chksum = ipchksum((unsigned short *)buf, sizeof(struct iphdr)); + udp->src = htons(srcsock); + udp->dest = htons(destsock); + udp->len = htons(len - sizeof(struct iphdr)); + udp->chksum = 0; + if (destip == IP_BROADCAST) { + eth_transmit(broadcast, IP, len, buf); + } else { + long h_netmask = ntohl(netmask); + /* Check to see if we need gateway */ + if (((destip & h_netmask) != + (arptable[ARP_CLIENT].ipaddr & h_netmask)) && + arptable[ARP_GATEWAY].ipaddr) + destip = arptable[ARP_GATEWAY].ipaddr; + for(arpentry = 0; arpentry currticks()) { +#if 0 + if (iskey() && (getchar() == ESC)) longjmp(jmp_bootmenu,1); +#else + if (iskey() && (getchar() == ESC)) + { + ip_abort = 1; + return 0; + } +#endif + if (eth_poll()) + { /* We have something! */ + /* Check for ARP - No IP hdr */ + if ((nic.packetlen >= ETHER_HDR_SIZE + + sizeof(struct arprequest)) && + (((nic.packet[12] << 8) | nic.packet[13]) == ARP)) + { + unsigned long target_ip; + + arpreply = (struct arprequest *) + &nic.packet[ETHER_HDR_SIZE]; + + if (arpreply->opcode == ntohs(ARP_REQUEST) + && (convert_ipaddr(&target_ip, + &arpreply->tipaddr), + arptable[ARP_CLIENT].ipaddr == target_ip)) + { + /* request for our ether address -- send a reply */ + + unsigned long my_ip_net + = *(unsigned long*)(arpreply->tipaddr); + + bcopy(arpreply->shwaddr, arpreply->thwaddr, 10); + bcopy(arptable[ARP_CLIENT].node, + arpreply->shwaddr, ETHER_ADDR_SIZE); + *(unsigned long*)(arpreply->sipaddr) = my_ip_net; + arpreply->opcode = htons(ARP_REPLY); + eth_transmit(arpreply->thwaddr, ARP, + sizeof(struct arprequest), + (char *) arpreply); + + continue; + } + + else if (type == AWAIT_ARP && + (arpreply->opcode == ntohs(ARP_REPLY)) && + !bcmp(arpreply->sipaddr, ptr, 4)) { + bcopy(arpreply->shwaddr, + arptable[ival].node, + ETHER_ADDR_SIZE); + return(1); + } + continue; + } + + /* Anything else has IP header */ + if ((nic.packetlen < protohdrlen) || + (((nic.packet[12] << 8) | nic.packet[13]) != IP)) continue; + ip = (struct iphdr *)&nic.packet[ETHER_HDR_SIZE]; + if ((ip->verhdrlen != 0x45) || + ipchksum((unsigned short *)ip, sizeof(struct iphdr)) || + (ip->protocol != IP_UDP)) continue; + udp = (struct udphdr *)&nic.packet[ETHER_HDR_SIZE + + sizeof(struct iphdr)]; + + /* BOOTP ? */ + bootpreply = (struct bootp_t *)&nic.packet[ETHER_HDR_SIZE]; + if ((type == AWAIT_BOOTP) && + (nic.packetlen >= (ETHER_HDR_SIZE + + sizeof(struct bootp_t))) && + (ntohs(udp->dest) == BOOTP_CLIENT) && + (bootpreply->bp_op == BOOTP_REPLY)) { + convert_ipaddr((char *)&arptable[ARP_CLIENT].ipaddr, + bootpreply->bp_yiaddr); + default_netmask(); + convert_ipaddr((char *)&arptable[ARP_SERVER].ipaddr, + bootpreply->bp_siaddr); + bzero(arptable[ARP_SERVER].node, + ETHER_ADDR_SIZE); /* Kill arp */ + convert_ipaddr((char *)&arptable[ARP_GATEWAY].ipaddr, + bootpreply->bp_giaddr); + bzero(arptable[ARP_GATEWAY].node, + ETHER_ADDR_SIZE); /* Kill arp */ + if (bootpreply->bp_file[0]) { + bcopy(bootpreply->bp_file, + kernel_buf, 128); + kernel = kernel_buf; + } + bcopy((char *)bootpreply, + (char *)&bootp_data, + sizeof(struct bootp_t)); + decode_rfc1533(bootp_data.bootp_reply.bp_vend, + 0, BOOTP_VENDOR_LEN, 1); + return(1); + } + + /* TFTP ? */ + if ((type == AWAIT_TFTP) && + (ntohs(udp->dest) == ival)) return(1); + + /* RPC */ + rpc = (struct rpc_t *)&nic.packet[ETHER_HDR_SIZE]; +#ifdef NFS_BOOT + if ((type == AWAIT_RPC) && + (ntohs(udp->dest) == RPC_SOCKET) && + (ntohl(rpc->u.reply.id) == ival) && + (ntohl(rpc->u.reply.type) == MSG_REPLY)) { + rpc_id++; + return(1); + } +#endif /* NFS_BOOT */ + } + } + return(0); +} + +/************************************************************************** +IPCHKSUM - Checksum IP Header +**************************************************************************/ +unsigned short ipchksum(ip, len) + register unsigned short *ip; + register int len; +{ + unsigned long sum = 0; + len >>= 1; + while (len--) { + sum += *(ip++); + if (sum > 0xFFFF) + sum -= 0xFFFF; + } + return((~sum) & 0x0000FFFF); +} + +/************************************************************************** +TFTP - Download extended BOOTP data, configuration file or kernel image +**************************************************************************/ +int tftp(name,fnc) + char *name; + int (*fnc)(unsigned char *, int, int, int); +{ + int retry = 0; + static unsigned short isocket = 2000; + unsigned short osocket; + unsigned short len, block = 0, prevblock = 0; + struct tftp_t *tr; + struct tftp_t tp; + int rc; + int packetsize = TFTP_DEFAULTSIZE_PACKET; + + tp.opcode = htons(TFTP_RRQ); + len = 30 + sprintf((char *)tp.u.rrq, "%s%coctet%cblksize%c%d", + name, 0, 0, 0, TFTP_MAX_PACKET) + 1; + if (!udp_transmit(arptable[ARP_SERVER].ipaddr, ++isocket, TFTP, + len, (char *)&tp)) + return (0); + for (;;) + { + if (!await_reply(AWAIT_TFTP, isocket, NULL)) + { + if (ip_abort) + return 0; + if (prevblock == 0 && retry++ < MAX_TFTP_RETRIES) + { /* maybe initial request was lost */ + rfc951_sleep(retry); + if (!udp_transmit(arptable[ARP_SERVER].ipaddr, + ++isocket, TFTP, len, (char *)&tp)) + return (0); + continue; + } + break; /* timeout on other blocks */ + } + tr = (struct tftp_t *)&nic.packet[ETHER_HDR_SIZE]; + if (tr->opcode == ntohs(TFTP_ERROR)) + { + printf("TFTP error %d (%s)\r\n", + ntohs(tr->u.err.errcode), + tr->u.err.errmsg); + break; + } + + if (tr->opcode == ntohs(TFTP_OACK)) { +#if 0 + char *p = tr->u.oack.data, *e; + + retry = MAX_TFTP_RETRIES;/*no more retries! */ + if (prevblock) /* shouldn't happen */ + continue; /* ignore it */ + len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 2; + if (len > TFTP_MAX_PACKET) + goto noak; + e = p + len; + while (*p != '\000' && p < e) { + if (!strcasecmp("blksize", p)) { + p += 8; + if ((packetsize = getdec(&p)) < + TFTP_DEFAULTSIZE_PACKET) + goto noak; + while (p < e && *p) p++; + if (p < e) + p++; + } + else { + noak: + tp.opcode = htons(TFTP_ERROR); + tp.u.err.errcode = 8; + len = 30 + sprintf((char *)tp.u.err.errmsg, + "RFC1782 error")+ 1; + udp_transmit(arptable[ARP_SERVER]. + ipaddr, isocket, + ntohs(tr->udp.src), + len, (char *)&tp); + return (0); + } + } + if (p > e) + goto noak; + block = tp.u.ack.block = 0; /* this ensures, that */ + /* the packet does not get */ + /* processed as data! */ +#else + continue; +#endif + } + else if (tr->opcode == ntohs(TFTP_DATA)) { + retry = MAX_TFTP_RETRIES;/*no more retries! */ + len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 4; + if (len > packetsize) /* shouldn't happen */ + continue; /* ignore it */ + block = ntohs(tp.u.ack.block = tr->u.data.block); } + else /* neither TFTP_OACK nor TFTP_DATA */ + break; + + tp.opcode = htons(TFTP_ACK); + osocket = ntohs(tr->udp.src); + udp_transmit(arptable[ARP_SERVER].ipaddr, isocket, + osocket, TFTP_MIN_PACKET, (char *)&tp); /* ack */ + if (block <= prevblock) /* retransmission or OACK */ + continue; /* don't process */ + prevblock = block; + if ((rc = fnc(tr->u.data.download, + block, len, len < packetsize)) >= 0) + return(rc); + if (len < packetsize) /* End of data */ + return (1); + } + return (0); +} + +/************************************************************************** +CONVERT_IPADDR - Convert IP address from net to machine order +**************************************************************************/ +static void convert_ipaddr(d, s) + register char *d,*s; +{ + d[3] = s[0]; + d[2] = s[1]; + d[1] = s[2]; + d[0] = s[3]; +} + +/************************************************************************** +RFC951_SLEEP - sleep for expotentially longer times +**************************************************************************/ +void rfc951_sleep(exp) + int exp; +{ + static long seed = 0; + long q,z,tmo; + + if (!seed) /* Initialize linear congruential generator */ + seed = currticks() + *(long *)&arptable[ARP_CLIENT].node + + ((short *)arptable[ARP_CLIENT].node)[2]; + /* simplified version of the LCG given in Bruce Scheier's + "Applied Cryptography" */ + q = seed/53668; + if ((seed = 40014*(seed-53668*q) - 12211*q) < 0) seed += 2147483563l; + /* compute mask */ + for (tmo = 63; tmo <= 60*18 && --exp > 0; tmo = 2*tmo+1); + /* sleep */ + printf("\r\n"); + for (tmo = (tmo&seed)+currticks(); currticks() < tmo; ) +/* if (iskey() && (getchar() == ESC)) longjmp(jmp_bootmenu,1) */ ; + eth_reset(); + return; +} + +/************************************************************************** +TWIDDLE +**************************************************************************/ +void twiddle() +{ + static unsigned long lastticks = 0; + static int count=0; + static char tiddles[]="-\\|/"; + unsigned long ticks; + if ((ticks = currticks()) < lastticks) + return; + lastticks = ticks+1; + putchar(tiddles[(count++)&3]); + putchar('\b'); +} + +/************************************************************************** +BOOTP - Get my IP address and load information +**************************************************************************/ +static int bootp() +{ + int retry; + struct bootp_t bp; + unsigned long starttime; +#ifdef T509HACK + int flag; + + flag = 1; +#endif + bzero(&bp, sizeof(struct bootp_t)); + bp.bp_op = BOOTP_REQUEST; + bp.bp_htype = 1; + bp.bp_hlen = ETHER_ADDR_SIZE; + bp.bp_xid = starttime = currticks(); + bcopy(arptable[ARP_CLIENT].node, bp.bp_hwaddr, ETHER_ADDR_SIZE); + bcopy(rfc1533_cookie, bp.bp_vend, 5); /* request RFC-style options */ + + for (retry = 0; retry < MAX_BOOTP_RETRIES; ) { + udp_transmit(IP_BROADCAST, 0, BOOTP_SERVER, + sizeof(struct bootp_t), (char *)&bp); +#ifdef T509HACK + if (flag) { + flag--; + } else { + if (await_reply(AWAIT_BOOTP, 0, NULL)) + return(1); + if (ip_abort) /* hohmuth */ + return 0; + rfc951_sleep(++retry); + + } +#else + if (await_reply(AWAIT_BOOTP, 0, NULL)) + return(1); + if (ip_abort) /* hohmuth */ + return 0; + rfc951_sleep(++retry); +#endif + bp.bp_secs = htons((currticks()-starttime)/20); + } + return(0); +} + +/************************************************************************** +DEFAULT_NETMASK - Set a default netmask for IP address +**************************************************************************/ +static void default_netmask() +{ + int net = arptable[ARP_CLIENT].ipaddr >> 24; + if (net <= 127) + netmask = htonl(0xff000000); + else if (net < 192) + netmask = htonl(0xffff0000); + else + netmask = htonl(0xffffff00); +} + +/************************************************************************** +DECODE_RFC1533 - Decodes RFC1533 header +**************************************************************************/ +static int decode_rfc1533(p, block, len, eof) + register unsigned char *p; + int block, len, eof; +{ + static unsigned char *extdata = NULL, *extend = NULL; + unsigned char *extpath = NULL; + unsigned char *end, *q; + + if (block == 0) { +#ifdef IMAGE_MENU + bzero(imagelist, sizeof(imagelist)); + menudefault = useimagemenu = 0; + menutmo = -1; +#endif +#ifdef MOTD + bzero(motd, sizeof(motd)); +#endif + end_of_rfc1533 = NULL; + vendorext_isvalid = 0; + if (bcmp(p, rfc1533_cookie, 4)) + return(0); /* no RFC 1533 header found */ + p += 4; + end = p + len; } + else { + if (block == 1) { + if (bcmp(p, rfc1533_cookie, 4)) + return(0); /* no RFC 1533 header found */ + p += 4; + len -= 4; } + if (extend + len <= (unsigned char *)(&bootp_data+1)) { + bcopy(p, extend, len); + extend += len; + } else { + printf("Overflow in vendor data buffer! Aborting...\r\n"); + *extdata = RFC1533_END; + return(0); + } + p = extdata; end = extend; + } + if (eof) { + while(p < end) { + unsigned char c = *p; + if (c == RFC1533_PAD) {p++; continue;} + else if (c == RFC1533_END) { + end_of_rfc1533 = end = p; continue; } + else if (c == RFC1533_NETMASK) {bcopy(p+2,&netmask,4);} +#ifdef NFS_BOOT + else if (c == RFC1533_HOSTNAME) { + if (TAG_LEN(p) < (MNAMELEN&~3)-1) { + bcopy(p+2,&nfsdiskless.my_hostnam,TAG_LEN(p)); + nfsdiskless.my_hostnam[TAG_LEN(p)] = '\000'; + hostnamelen = (TAG_LEN(p)+3)&~3; + } + } +#endif + else if (c == RFC1533_GATEWAY) { + /* This is a little simplistic, but it will + usually be sufficient; look into the gate- + way list, only if there has been no BOOTP + gateway. Take only the first entry */ + if (TAG_LEN(p) >= 4 && + arptable[ARP_GATEWAY].ipaddr == 0) + convert_ipaddr((char *)&arptable[ARP_GATEWAY].ipaddr, + p+2); + } + else if (c == RFC1533_EXTENSIONPATH) + extpath = p; + else if (c == RFC1533_VENDOR_MAGIC && + TAG_LEN(p) >= 6 && + !bcmp(p+2,vendorext_magic,4) && + p[6] == RFC1533_VENDOR_MAJOR) + vendorext_isvalid++; +#ifdef IMAGE_MENU + else if (c == RFC1533_VENDOR_MNUOPTS) { + parse_menuopts(p+2, TAG_LEN(p)); + } + else if (c >= RFC1533_VENDOR_IMG && + c= RFC1533_VENDOR_MOTD && + c < RFC1533_VENDOR_MOTD + + RFC1533_VENDOR_NUMOFMOTD) + motd[c - RFC1533_VENDOR_MOTD] = p; +#endif + else { + /* printf("Unknown RFC1533-tag "); + for(q=p;qHRQ, DACK<-HLDA only */ + +/* enable/disable a specific DMA channel */ +static void enable_dma(unsigned int dmanr) +{ + if (dmanr <= 3) + outb_p(DMA1_MASK_REG, dmanr); + else + outb_p(DMA2_MASK_REG, dmanr & 3); +} + +static void disable_dma(unsigned int dmanr) +{ + if (dmanr <= 3) + outb_p(DMA1_MASK_REG, dmanr | 4); + else + outb_p(DMA2_MASK_REG, (dmanr & 3) | 4); +} + +/* set mode (above) for a specific DMA channel */ +static void set_dma_mode(unsigned int dmanr, char mode) +{ + if (dmanr <= 3) + outb_p(DMA1_MODE_REG, mode | dmanr); + else + outb_p(DMA2_MODE_REG, mode | (dmanr&3)); +} + +/************************************************************************** +RESET - Reset adapter +***************************************************************************/ +static void lance_reset(struct nic *nic) +{ + int i; + Address l; + + /* Reset the LANCE */ + (void)inw(ioaddr+LANCE_RESET); + /* Un-Reset the LANCE, needed only for the NE2100 */ + if (chip_table[chip_version].flags & LANCE_MUST_UNRESET) + outw(ioaddr+LANCE_RESET, 0); + if (chip_table[chip_version].flags & LANCE_ENABLE_AUTOSELECT) + { + /* This is 79C960 specific; Turn on auto-select of media + (AUI, BNC). */ + outw(ioaddr+LANCE_ADDR, 0x2); + outw(ioaddr+LANCE_BUS_IF, 0x2); + } + /* Re-initialise the LANCE, and start it when done. */ + /* Set station address */ + for (i = 0; i < ETHER_ADDR_SIZE; ++i) + lp->init_block.phys_addr[i] = nic->node_addr[i]; + /* Preset the receive ring header */ + lp->rx_ring.buf_length = -ETH_MAX_PACKET; + /* OWN */ + lp->rx_ring.u.base = virt_to_bus(lp->rbuf) & 0xffffff; + /* we set the top byte as the very last thing */ + lp->rx_ring.u.addr[3] = 0x80; + lp->init_block.mode = 0x0; /* enable Rx and Tx */ + l = (Address)virt_to_bus(&lp->init_block); + outw(ioaddr+LANCE_ADDR, 0x1); + (void)inw(ioaddr+LANCE_ADDR); + outw(ioaddr+LANCE_DATA, (short)l); + outw(ioaddr+LANCE_ADDR, 0x2); + (void)inw(ioaddr+LANCE_ADDR); + outw(ioaddr+LANCE_DATA, (short)(l >> 16)); + outw(ioaddr+LANCE_ADDR, 0x4); + (void)inw(ioaddr+LANCE_ADDR); + outw(ioaddr+LANCE_DATA, 0x915); + outw(ioaddr+LANCE_ADDR, 0x0); + (void)inw(ioaddr+LANCE_ADDR); + outw(ioaddr+LANCE_DATA, 0x4); /* stop */ + outw(ioaddr+LANCE_DATA, 0x1); /* init */ + for (i = 100; i > 0; --i) + if (inw(ioaddr+LANCE_DATA) & 0x100) + break; + /* Apparently clearing the InitDone bit here triggers a bug + in the '974. (Mark Stockton) */ + outw(ioaddr+LANCE_DATA, 0x2); /* start */ +} + +/************************************************************************** +POLL - Wait for a frame +***************************************************************************/ +static int lance_poll(struct nic *nic) +{ + int status; + + status = lp->rx_ring.u.base >> 24; + if (status & 0x80) + return (0); +#ifdef DEBUG + printf("LANCE packet received rx_ring.u.base %X mcnt %x csr0 %x\r\n", + lp->rx_ring.u.base, lp->rx_ring.msg_length, + inw(ioaddr+LANCE_DATA)); +#endif + if (status == 0x3) + bcopy(lp->rbuf, nic->packet, nic->packetlen = lp->rx_ring.msg_length); + /* Andrew Boyd of QNX reports that some revs of the 79C765 + clear the buffer length */ + lp->rx_ring.buf_length = -ETH_MAX_PACKET; + lp->rx_ring.u.addr[3] |= 0x80; /* prime for next receive */ + outw(ioaddr+LANCE_ADDR, 0x0); + (void)inw(ioaddr+LANCE_ADDR); + outw(ioaddr+LANCE_DATA, 0x500); /* clear receive + InitDone */ + return (status == 0x3); +} + +/************************************************************************** +TRANSMIT - Transmit a frame +***************************************************************************/ +static void lance_transmit( + struct nic *nic, + char *d, /* Destination */ + unsigned int t, /* Type */ + unsigned int s, /* size */ + char *p) /* Packet */ +{ + unsigned long time; + + /* copy the packet to ring buffer */ + bcopy(d, lp->tbuf, ETHER_ADDR_SIZE); /* dst */ + bcopy(nic->node_addr, &lp->tbuf[ETHER_ADDR_SIZE], ETHER_ADDR_SIZE); /* src */ + lp->tbuf[ETHER_ADDR_SIZE+ETHER_ADDR_SIZE] = t >> 8; /* type */ + lp->tbuf[ETHER_ADDR_SIZE+ETHER_ADDR_SIZE+1] = t; /* type */ + bcopy(p, &lp->tbuf[ETHER_HDR_SIZE], s); + s += ETHER_HDR_SIZE; + if (chip_table[chip_version].flags & LANCE_MUST_PAD) + while (s < ETH_MIN_PACKET) /* pad to min length */ + lp->tbuf[s++] = 0; + lp->tx_ring.buf_length = -s; + lp->tx_ring.misc = 0x0; + /* OWN, STP, ENP */ + lp->tx_ring.u.base = virt_to_bus(lp->tbuf) & 0xffffff; + /* we set the top byte as the very last thing */ + lp->tx_ring.u.addr[3] = 0x83; + /* Trigger an immediate send poll */ + outw(ioaddr+LANCE_ADDR, 0x0); + outw(ioaddr+LANCE_DATA, 0x48); + /* wait for transmit complete */ + time = currticks() + 18; /* wait one second */ + while (currticks() < time && (lp->tx_ring.u.base & 0x80000000) != 0) + ; + if ((lp->tx_ring.u.base & 0x80000000) != 0) + printf("LANCE timed out on transmit\r\n"); + (void)inw(ioaddr+LANCE_ADDR); + outw(ioaddr+LANCE_DATA, 0x200); /* clear transmit + InitDone */ +#ifdef DEBUG + printf("tx_ring.u.base %X tx_ring.buf_length %x tx_ring.misc %x csr0 %x\r\n", + lp->tx_ring.u.base, lp->tx_ring.buf_length, lp->tx_ring.misc, + inw(ioaddr+LANCE_DATA)); +#endif +} + +static void lance_disable(struct nic *nic) +{ + disable_dma(dma); +} + +static int lance_probe1(struct nic *nic) +{ + int reset_val, lance_version, i; + Address l; + short dma_channels; + static char dmas[] = { 5, 6, 7, 3 }; + + reset_val = inw(ioaddr+LANCE_RESET); + outw(ioaddr+LANCE_ADDR, 0x0); /* Switch to window 0 */ + if (inw(ioaddr+LANCE_DATA) != 0x4) + return (-1); + outw(ioaddr+LANCE_ADDR, 88); /* Get the version of the chip */ + if (inw(ioaddr+LANCE_ADDR) != 88) + lance_version = 0; + else + { + chip_version = inw(ioaddr+LANCE_DATA); + outw(ioaddr+LANCE_ADDR, 89); + chip_version |= inw(ioaddr+LANCE_DATA) << 16; + if ((chip_version & 0xfff) != 0x3) + return (-1); + chip_version = (chip_version >> 12) & 0xffff; + for (lance_version = 1; chip_table[lance_version].id_number != 0; ++lance_version) + if (chip_table[lance_version].id_number == chip_version) + break; + } + /* make sure data structure is 8-byte aligned */ + l = ((Address)lance + 7) & ~7; + lp = (struct lance_interface *)l; + lp->init_block.mode = 0x3; /* disable Rx and Tx */ + lp->init_block.filter[0] = lp->init_block.filter[1] = 0x0; + /* top bits are zero, we have only one buffer each for Rx and Tx */ + lp->init_block.rx_ring = virt_to_bus(&lp->rx_ring) & 0xffffff; + lp->init_block.tx_ring = virt_to_bus(&lp->tx_ring) & 0xffffff; + l = virt_to_bus(&lp->init_block); + outw(ioaddr+LANCE_ADDR, 0x1); + (void)inw(ioaddr+LANCE_ADDR); + outw(ioaddr+LANCE_DATA, (unsigned short)l); + outw(ioaddr+LANCE_ADDR, 0x2); + (void)inw(ioaddr+LANCE_ADDR); + outw(ioaddr+LANCE_DATA, (unsigned short)(l >> 16)); + outw(ioaddr+LANCE_ADDR, 0x4); + (void)inw(ioaddr+LANCE_ADDR); + outw(ioaddr+LANCE_DATA, 0x915); + outw(ioaddr+LANCE_ADDR, 0x0); + (void)inw(ioaddr+LANCE_ADDR); + /* now probe for DMA channel */ + dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0xf) | + (inb(DMA2_STAT_REG) & 0xf0); + /* need to fix when PCI provides DMA info */ + for (i = 0; i < (sizeof(dmas)/sizeof(dmas[0])); ++i) + { + int j; + + dma = dmas[i]; + /* Don't enable a permanently busy DMA channel, + or the machine will hang */ + if (dma_channels & (1 << dma)) + continue; + outw(ioaddr+LANCE_DATA, 0x7f04); /* clear memory error bits */ + set_dma_mode(dma, DMA_MODE_CASCADE); + enable_dma(dma); + outw(ioaddr+LANCE_DATA, 0x1); /* init */ + for (j = 100; j > 0; --j) + if (inw(ioaddr+LANCE_DATA) & 0x900) + break; + if (inw(ioaddr+LANCE_DATA) & 0x100) + break; + else + disable_dma(dma); + } + if (i >= (sizeof(dmas)/sizeof(dmas[0]))) + dma = 0; + printf("\r\n%s base 0x%x, DMA %d, addr ", + chip_table[lance_version].name, ioaddr, dma); + /* Get station address */ + for (i = 0; i < ETHER_ADDR_SIZE; ++i) + { + printf("%b", nic->node_addr[i] = inb(ioaddr+i)); + if (i < ETHER_ADDR_SIZE -1) + printf(":"); + } + printf("\r\n"); + return (lance_version); +} + +/************************************************************************** +PROBE - Look for an adapter, this routine's visible to the outside +***************************************************************************/ +struct nic *lance_probe(struct nic *nic, unsigned short *probe_addrs) +{ + unsigned short *p; + static unsigned short io_addrs[] = { 0x300, 0x320, 0x340, 0x360, 0 }; + + /* if probe_addrs is 0, then routine can use a hardwired default */ + if (probe_addrs == 0) + probe_addrs = io_addrs; + for (p = probe_addrs; (ioaddr = *p) != 0; ++p) + { + char offset15, offset14 = inb(ioaddr + 14); + + if ((offset14 == 0x52 || offset14 == 0x57) && + ((offset15 = inb(ioaddr + 15)) == 0x57 || offset15 == 0x44)) + if (lance_probe1(nic) >= 0) + break; + } + /* if board found */ + if (ioaddr != 0) + { + /* point to NIC specific routines */ + lance_reset(nic); + nic->reset = lance_reset; + nic->poll = lance_poll; + nic->transmit = lance_transmit; + nic->disable = lance_disable; + return nic; + } + /* else */ + { + return 0; + } +} + +#endif /* INCLUDE_NE2100 */ diff --git a/netboot/netboot.h b/netboot/netboot.h new file mode 100644 index 000000000..fa77cd727 --- /dev/null +++ b/netboot/netboot.h @@ -0,0 +1,471 @@ +/************************************************************************** +NETBOOT - BOOTP/TFTP Bootstrap Program + +Author: Martin Renters + Date: Dec/93 + +**************************************************************************/ + +#define NETBOOT32 + +#include "../stage2/shared.h" + +#include "byteorder.h" +#include "io.h" + +typedef unsigned long Address; + +extern int _pending_key; +extern inline int getchar(void); +extern inline int getchar(void) { + int foo; + + if (_pending_key == -1) + return getkey(); + foo = _pending_key; + _pending_key = -1; + return foo; +} +extern inline int iskey(void); +extern inline int iskey(void) { + return _pending_key != -1 ? 1 : ((_pending_key = checkkey()) != -1); +} + +#if 0 /*Edmund*/ +#define bcmp __builtin_memcmp +#define memcpy(d,s,sz) bcopy((s),(d),(sz)) +#else +#define bcopy(src, dest, n) memcpy(dest, src, n) +#define bzero(s, n) memset(s, 0, n) +#define bcmp(s1, s2, n) memcmp(s1, s2, n) +#endif + +/* ANSI prototyping macro */ +#ifdef __STDC__ +#define P(x) x +#else +#define P(x) () + + + +#endif + +#define ESC 0x1B + +#ifndef DEFAULT_BOOTFILE +#define DEFAULT_BOOTFILE "/kernel" +#endif + +#ifndef MAX_TFTP_RETRIES +#define MAX_TFTP_RETRIES 20 +#endif + +#ifndef MAX_BOOTP_RETRIES +#define MAX_BOOTP_RETRIES 20 +#endif + +#ifndef MAX_BOOTP_EXTLEN +#define MAX_BOOTP_EXTLEN 1024 +#endif + +#ifndef MAX_ARP_RETRIES +#define MAX_ARP_RETRIES 20 +#endif + +#ifndef MAX_RPC_RETRIES +#define MAX_RPC_RETRIES 20 +#endif + +#ifndef TIMEOUT /* Inter-packet retry in ticks 18/sec */ +#define TIMEOUT 180 +#endif + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define TRUE 1 +#define FALSE 0 + +#define ETHER_ADDR_SIZE 6 /* Size of Ethernet address */ +#define ETHER_HDR_SIZE 14 /* Size of ethernet header */ +#define ETH_MIN_PACKET 64 +#define ETH_MAX_PACKET 1518 + +#define VENDOR_NONE 0 +#define VENDOR_WD 1 +#define VENDOR_NOVELL 2 +#define VENDOR_3COM 3 +#define VENDOR_3C509 4 +#define VENDOR_CS89x0 5 + +#define FLAG_PIO 0x01 +#define FLAG_16BIT 0x02 +#define FLAG_790 0x04 + +#define ARP_CLIENT 0 +#define ARP_SERVER 1 +#define ARP_GATEWAY 2 +#define ARP_ROOTSERVER 3 +#define ARP_SWAPSERVER 4 +#define MAX_ARP ARP_SWAPSERVER+1 + +#define IP 0x0800 +#define ARP 0x0806 + +#define BOOTP_SERVER 67 +#define BOOTP_CLIENT 68 +#define TFTP 69 +#define SUNRPC 111 + +#define RPC_SOCKET 620 /* Arbitrary */ + +#define IP_UDP 17 +#define IP_BROADCAST 0xFFFFFFFF + +#define ARP_REQUEST 1 +#define ARP_REPLY 2 + +#define BOOTP_REQUEST 1 +#define BOOTP_REPLY 2 + +#define TAG_LEN(p) (*((p)+1)) +#define RFC1533_COOKIE 99, 130, 83, 99 +#define RFC1533_PAD 0 +#define RFC1533_NETMASK 1 +#define RFC1533_TIMEOFFSET 2 +#define RFC1533_GATEWAY 3 +#define RFC1533_TIMESERVER 4 +#define RFC1533_IEN116NS 5 +#define RFC1533_DNS 6 +#define RFC1533_LOGSERVER 7 +#define RFC1533_COOKIESERVER 8 +#define RFC1533_LPRSERVER 9 +#define RFC1533_IMPRESSSERVER 10 +#define RFC1533_RESOURCESERVER 11 +#define RFC1533_HOSTNAME 12 +#define RFC1533_BOOTFILESIZE 13 +#define RFC1533_MERITDUMPFILE 14 +#define RFC1533_DOMAINNAME 15 +#define RFC1533_SWAPSERVER 16 +#define RFC1533_ROOTPATH 17 +#define RFC1533_EXTENSIONPATH 18 +#define RFC1533_IPFORWARDING 19 +#define RFC1533_IPSOURCEROUTING 20 +#define RFC1533_IPPOLICYFILTER 21 +#define RFC1533_IPMAXREASSEMBLY 22 +#define RFC1533_IPTTL 23 +#define RFC1533_IPMTU 24 +#define RFC1533_IPMTUPLATEAU 25 +#define RFC1533_INTMTU 26 +#define RFC1533_INTLOCALSUBNETS 27 +#define RFC1533_INTBROADCAST 28 +#define RFC1533_INTICMPDISCOVER 29 +#define RFC1533_INTICMPRESPOND 30 +#define RFC1533_INTROUTEDISCOVER 31 +#define RFC1533_INTROUTESOLICIT 32 +#define RFC1533_INTSTATICROUTES 33 +#define RFC1533_LLTRAILERENCAP 34 +#define RFC1533_LLARPCACHETMO 35 +#define RFC1533_LLETHERNETENCAP 36 +#define RFC1533_TCPTTL 37 +#define RFC1533_TCPKEEPALIVETMO 38 +#define RFC1533_TCPKEEPALIVEGB 39 +#define RFC1533_NISDOMAIN 40 +#define RFC1533_NISSERVER 41 +#define RFC1533_NTPSERVER 42 +#define RFC1533_VENDOR 43 +#define RFC1533_NBNS 44 +#define RFC1533_NBDD 45 +#define RFC1533_NBNT 46 +#define RFC1533_NBSCOPE 47 +#define RFC1533_XFS 48 +#define RFC1533_XDM 49 + +#define RFC1533_VENDOR_MAJOR 0 +#define RFC1533_VENDOR_MINOR 0 + +#define RFC1533_VENDOR_MAGIC 128 +#define RFC1533_VENDOR_ADDPARM 129 +#define RFC1533_VENDOR_MNUOPTS 160 +#define RFC1533_VENDOR_SELECTION 176 +#define RFC1533_VENDOR_MOTD 184 +#define RFC1533_VENDOR_NUMOFMOTD 8 +#define RFC1533_VENDOR_IMG 192 +#define RFC1533_VENDOR_NUMOFIMG 16 + +#define RFC1533_END 255 +#define BOOTP_VENDOR_LEN 64 + +#define TFTP_DEFAULTSIZE_PACKET 512 +#define TFTP_MAX_PACKET 1432 /* 512 */ + +#define TFTP_RRQ 1 +#define TFTP_WRQ 2 +#define TFTP_DATA 3 +#define TFTP_ACK 4 +#define TFTP_ERROR 5 +#define TFTP_OACK 6 + +#define TFTP_CODE_EOF 1 +#define TFTP_CODE_MORE 2 +#define TFTP_CODE_ERROR 3 +#define TFTP_CODE_BOOT 4 +#define TFTP_CODE_CFG 5 + +#define PROG_PORTMAP 100000 +#define PROG_NFS 100003 +#define PROG_MOUNT 100005 + +#define MSG_CALL 0 +#define MSG_REPLY 1 + +#define PORTMAP_LOOKUP 3 + +#define MOUNT_ADDENTRY 1 +#define MOUNT_UMNTALL 4 +#define NFS_LOOKUP 4 +#define NFS_READ 6 + +#define NFS_READ_SIZE 1024 + + +#define AWAIT_ARP 0 +#define AWAIT_BOOTP 1 +#define AWAIT_TFTP 2 +#define AWAIT_RPC 3 + +struct arptable_t { + unsigned long ipaddr; + unsigned char node[6]; +}; + +struct arprequest { + unsigned short hwtype; + unsigned short protocol; + char hwlen; + char protolen; + unsigned short opcode; + char shwaddr[6]; + char sipaddr[4]; + char thwaddr[6]; + char tipaddr[4]; +}; + +struct iphdr { + char verhdrlen; + char service; + unsigned short len; + unsigned short ident; + unsigned short frags; + char ttl; + char protocol; + unsigned short chksum; + char src[4]; + char dest[4]; +}; + +struct udphdr { + unsigned short src; + unsigned short dest; + unsigned short len; + unsigned short chksum; +}; + +struct bootp_t { + struct iphdr ip; + struct udphdr udp; + char bp_op; + char bp_htype; + char bp_hlen; + char bp_hops; + unsigned long bp_xid; + unsigned short bp_secs; + unsigned short unused; + char bp_ciaddr[4]; + char bp_yiaddr[4]; + char bp_siaddr[4]; + char bp_giaddr[4]; + char bp_hwaddr[16]; + char bp_sname[64]; + char bp_file[128]; + char bp_vend[BOOTP_VENDOR_LEN]; +}; + +struct bootpd_t { + struct bootp_t bootp_reply; + unsigned char bootp_extension[MAX_BOOTP_EXTLEN]; +}; + + +struct tftp_t { + struct iphdr ip; + struct udphdr udp; + unsigned short opcode; + union { + char rrq[TFTP_DEFAULTSIZE_PACKET]; + struct { + unsigned short block; + char download[TFTP_MAX_PACKET]; + } data; + struct { + unsigned short block; + } ack; + struct { + unsigned short errcode; + char errmsg[TFTP_DEFAULTSIZE_PACKET]; + } err; + struct { + char data[TFTP_DEFAULTSIZE_PACKET+2]; + } oack; + } u; +}; + +struct rpc_t { + struct iphdr ip; + struct udphdr udp; + union { + char data[1400]; + struct { + long id; + long type; + long rstatus; + long verifier; + long v2; + long astatus; + long data[1]; + } reply; + } u; +}; + +#define TFTP_MIN_PACKET (sizeof(struct iphdr) + sizeof(struct udphdr) + 4) + +/*************************************************************************** +RPC Functions +***************************************************************************/ +#define PUTLONG(val) {\ + register int lval = val; \ + *(rpcptr++) = ((lval) >> 24); \ + *(rpcptr++) = ((lval) >> 16); \ + *(rpcptr++) = ((lval) >> 8); \ + *(rpcptr++) = (lval); \ + rpclen+=4; } + +#if 0 /* XXX */ + +/*************************************************************************** +External prototypes +***************************************************************************/ +/* main.c */ +extern void load P((void)); +extern int load_linux P((int root_mount_port,int swap_mount_port, + int root_nfs_port,char *kernel_handle)); +extern int linux_tftp P((unsigned int block,unsigned char *data,int len)); +extern int tftpkernel P((unsigned char *, int, int, int)); +extern int tftp P((char *name, int (*)(unsigned char *, int, int, int))); +extern int bootp P((void)); +extern int udp_transmit P((unsigned long destip, unsigned int srcsock, + unsigned int destsock, int len, char *buf)); +extern int await_reply P((int type, int ival, char *ptr)); +extern void default_netmask P((void)); +extern int decode_rfc1533 P((unsigned char *, int, int, int)); +extern unsigned short ipchksum P((unsigned short *, int len)); +extern void convert_ipaddr P((char *, char *)); +extern void rfc951_sleep P((int)); + +/* bootmenu.c */ +extern int execute P((char *string)); +extern void bootmenu P((void)); +extern void show_motd P((void)); +extern void parse_menuopts P((char *,int)); +extern int getoptvalue P((char **, int *, int *)); +extern void selectImage P((char **, char *, struct arptable_t *)); + +/* linuxloader.c */ +extern char *linux_add_cmdline P((char *string)); + +/* rpc.c */ +extern int rpclookup P((int addr, int prog, int ver)); +extern int nfs_mount P((int server, int port, char *path, char *fh)); +extern int nfs_umountall P((int server, int port)); +extern int nfs_lookup P((int server, int port, char *fh, char *path, char *file_fh)); +extern int nfs_read P((int server, int port, char *fh, int offset, int len, char *buffer)); +extern void rpc_err P((struct rpc_t *rpc)); +extern void nfs_err P((int err)); + +/* misc.c */ +#if 0 /*Edmund*/ +extern void bcopy P((void *src, void *dst, int cnt)); +extern void bzero P((void *dst, int cnt)); +extern int bcmp P((void *src, void *dst, int cnt)); +#endif +extern int strcasecmp P((char *a, char *b)); +extern char *substr P((char *a, char *b)); +extern int getdec P((char **)); +extern void twiddle P((void)); +extern void printf(); /* old style to avoid varargs */ +extern char *sprintf(); +extern int setip P((char *p, unsigned long *i)); +extern void gateA20 P((void)); + +/* start*.S */ +extern int getchar P((void)); +extern void putchar P((int)); +extern int iskey P((void)); +extern int getshift P((void)); +extern unsigned short memsize P((void)); +extern void disk_init P((void)); +extern short disk_read P((int drv,int c,int h,int s,char *buf)); +extern void start_linux P((void)); +extern void xstart P((unsigned long, unsigned long, unsigned long)); +extern long currticks P((void)); +extern int setjmp P((void *jmpbuf)); +extern void longjmp P((void *jmpbuf, int where)); +extern void exit P((int status)); + +/* ansiesc.c */ +extern void ansi_reset P((void)); +extern void enable_cursor P((int)); + +/* md5.c */ +extern void md5_put P((unsigned int ch)); +extern void md5_done P((unsigned char *buf)); + +/* floppy.c */ +extern int bootdisk P((int dev,int part)); + +#endif + +/*************************************************************************** +External variables +***************************************************************************/ +/* main.c */ +extern char *kernel; +extern char kernel_buf[]; +extern struct nfs_diskless nfsdiskless; +extern int hostnamelen; +extern unsigned long netmask; +extern int jmp_bootmenu[10]; +extern char kernel_buf[128]; +extern struct bootpd_t bootp_data; +extern struct arptable_t arptable[MAX_ARP]; +extern char *imagelist[RFC1533_VENDOR_NUMOFIMG]; +extern char *motd[RFC1533_VENDOR_NUMOFMOTD]; +extern int menutmo,menudefault; +extern unsigned char *end_of_rfc1533; + +/* bootmenu.c */ + +/* linuxloader.c */ + +/* rpc.c */ +extern int rpc_id; + +/* created by linker */ +extern char _edata[], _end[]; + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/netboot/netdevice.h b/netboot/netdevice.h new file mode 100644 index 000000000..ebe5e5ca5 --- /dev/null +++ b/netboot/netdevice.h @@ -0,0 +1,195 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the Interfaces handler. + * + * Version: @(#)dev.h 1.0.10 08/12/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * Corey Minyard + * Donald J. Becker, + * Alan Cox, + * Bjorn Ekwall. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Moved to /usr/include/linux for NET3 + */ +/* for future expansion when we will have different priorities. */ +#define DEV_NUMBUFFS 3 +#define MAX_ADDR_LEN 7 +#ifndef CONFIG_AX25 +#ifndef CONFIG_TR +#ifndef CONFIG_NET_IPIP +#define MAX_HEADER 32 /* We really need about 18 worst case .. so 32 is aligned */ +#else +#define MAX_HEADER 80 /* We need to allow for having tunnel headers */ +#endif /* IPIP */ +#else +#define MAX_HEADER 48 /* Token Ring header needs 40 bytes ... 48 is aligned */ +#endif /* TR */ +#else +#define MAX_HEADER 96 /* AX.25 + NetROM */ +#endif /* AX25 */ + +#define IS_MYADDR 1 /* address is (one of) our own */ +#define IS_LOOPBACK 2 /* address is for LOOPBACK */ +#define IS_BROADCAST 3 /* address is a valid broadcast */ +#define IS_INVBCAST 4 /* Wrong netmask bcast not for us (unused)*/ +#define IS_MULTICAST 5 /* Multicast IP address */ + +/* + * The DEVICE structure. + * Actually, this whole structure is a big mistake. It mixes I/O + * data with strictly "high-level" data, and it has to know about + * almost every data structure used in the INET module. + */ +struct device +{ + + /* + * This is the first field of the "visible" part of this structure + * (i.e. as seen by users in the "Space.c" file). It is the name + * the interface. + */ + char *name; + + /* I/O specific fields - FIXME: Merge these and struct ifmap into one */ + unsigned long rmem_end; /* shmem "recv" end */ + unsigned long rmem_start; /* shmem "recv" start */ + unsigned long mem_end; /* shared mem end */ + unsigned long mem_start; /* shared mem start */ + unsigned long base_addr; /* device I/O address */ + unsigned char irq; /* device IRQ number */ + + /* Low-level status flags. */ + volatile unsigned char start, /* start an operation */ + interrupt; /* interrupt arrived */ + unsigned long tbusy; /* transmitter busy must be long for bitops */ + + struct device *next; + + /* The device initialization function. Called only once. */ + int (*init)(struct device *dev); + + /* Some hardware also needs these fields, but they are not part of the + usual set specified in Space.c. */ + unsigned char if_port; /* Selectable AUI, TP,..*/ + unsigned char dma; /* DMA channel */ + +/* struct enet_statistics* (*get_stats)(struct device *dev); */ + + /* + * This marks the end of the "visible" part of the structure. All + * fields hereafter are internal to the system, and may change at + * will (read: may be cleaned up at will). + */ + + /* These may be needed for future network-power-down code. */ + unsigned long trans_start; /* Time (in jiffies) of last Tx */ + unsigned long last_rx; /* Time of last Rx */ + + unsigned short flags; /* interface flags (a la BSD) */ + unsigned short family; /* address family ID (AF_INET) */ + unsigned short metric; /* routing metric (not used) */ + unsigned short mtu; /* interface MTU value */ + unsigned short type; /* interface hardware type */ + unsigned short hard_header_len; /* hardware hdr length */ + void *priv; /* pointer to private data */ + + /* Interface address info. */ + unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */ + unsigned char pad; /* make dev_addr aligned to 8 bytes */ + unsigned char dev_addr[MAX_ADDR_LEN]; /* hw address */ + unsigned char addr_len; /* hardware address length */ + unsigned long pa_addr; /* protocol address */ + unsigned long pa_brdaddr; /* protocol broadcast addr */ + unsigned long pa_dstaddr; /* protocol P-P other side addr */ + unsigned long pa_mask; /* protocol netmask */ + unsigned short pa_alen; /* protocol address length */ + +#if 0 + struct dev_mc_list *mc_list; /* Multicast mac addresses */ +#endif + int mc_count; /* Number of installed mcasts */ + +#if 0 + struct ip_mc_list *ip_mc_list; /* IP multicast filter chain */ +#endif + unsigned int tx_queue_len; /* Max frames per queue allowed */ + + /* For load balancing driver pair support */ + + unsigned long pkt_queue; /* Packets queued */ +#if 0 + struct device *slave; /* Slave device */ + + struct net_alias_info *alias_info; /* main dev alias info */ + struct net_alias *my_alias; /* alias devs */ + /* Pointer to the interface buffers. */ + struct sk_buff_head buffs[DEV_NUMBUFFS]; +#endif + + int (*change_mtu)(struct device *dev, int new_mtu); +}; + +#if 0 +struct packet_type { + unsigned short type; /* This is really htons(ether_type). */ + struct device * dev; + int (*func) (struct sk_buff *, struct device *, + struct packet_type *); + void *data; + struct packet_type *next; +}; + + +/* Used by dev_rint */ +#define IN_SKBUFF 1 + +extern int dev_lockct; + +/* + * These two don't currently need to be interrupt-safe + * but they may do soon. Do it properly anyway. + */ + +extern __inline__ void dev_lock_list(void) +{ + unsigned long flags; + save_flags(flags); + cli(); + dev_lockct++; + restore_flags(flags); +} + +extern __inline__ void dev_unlock_list(void) +{ + unsigned long flags; + save_flags(flags); + cli(); + dev_lockct--; + restore_flags(flags); +} + +/* + * This almost never occurs, isn't in performance critical paths + * and we can thus be relaxed about it + */ + +extern __inline__ void dev_lock_wait(void) +{ + while(dev_lockct) + schedule(); +} + + + + +#endif /* _LINUX_DEV_H */ diff --git a/netboot/nic.h b/netboot/nic.h new file mode 100644 index 000000000..0e09d1098 --- /dev/null +++ b/netboot/nic.h @@ -0,0 +1,18 @@ +/* + * Structure returned from eth_probe and passed to other driver + * functions. + */ + +struct nic +{ + void (*reset)P((struct nic *)); + int (*poll)P((struct nic *)); + void (*transmit)P((struct nic *, char *d, + unsigned int t, unsigned int s, char *p)); + void (*disable)P((struct nic *)); + char aui; + char *node_addr; + char *packet; + int packetlen; + void *priv_data; /* driver can hang private data here */ +}; diff --git a/netboot/ns8390.c b/netboot/ns8390.c new file mode 100644 index 000000000..9c19730c8 --- /dev/null +++ b/netboot/ns8390.c @@ -0,0 +1,746 @@ + +/************************************************************************** +NETBOOT - BOOTP/TFTP Bootstrap Program + +Author: Martin Renters + Date: May/94 + + This code is based heavily on David Greenman's if_ed.c driver + + Copyright (C) 1993-1994, David Greenman, Martin Renters. + This software may be used, modified, copied, distributed, and sold, in + both source and binary form provided that the above copyright and these + terms are retained. Under no circumstances are the authors responsible for + the proper functioning of this software, nor do the authors assume any + responsibility for damages incurred with its use. + +3c503 support added by Bill Paul (wpaul@ctr.columbia.edu) on 11/15/94 +SMC8416 support added by Bill Paul (wpaul@ctr.columbia.edu) on 12/25/94 + +**************************************************************************/ + +#if defined(INCLUDE_NE) || defined(INCLUDE_NEPCI) || defined(INCLUDE_WD) || defined(INCLUDE_T503) + +#include "netboot.h" +#include "nic.h" +#include "ns8390.h" + +static unsigned char eth_vendor, eth_flags, eth_laar; +static unsigned short eth_nic_base, eth_asic_base; +static unsigned char eth_memsize, eth_rx_start, eth_tx_start; +static Address eth_bmem, eth_rmem; + +#if defined(INCLUDE_WD) +#define eth_probe wd_probe +#else +#if defined(INCLUDE_T503) +#define eth_probe t503_probe +#else +#if defined(INCLUDE_NE) +#define eth_probe ne_probe +#else +#if defined(INCLUDE_NEPCI) +#define eth_probe nepci_probe +#else +Error you must define one of the above +#endif +#endif +#endif +#endif + + + +static void net_bcopy (char *s, char *d, int l) +{ + while (l--) + *d++ = *s++; +} + + +#if defined(INCLUDE_NE) || defined(INCLUDE_NEPCI) +/************************************************************************** +ETH_PIO_READ - Read a frame via Programmed I/O +**************************************************************************/ +static void eth_pio_read(src, dst, cnt) + unsigned int src; + unsigned char *dst; + unsigned int cnt; +{ + if (eth_flags & FLAG_16BIT) { ++cnt; cnt &= ~1; } + outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_RD2 | + D8390_COMMAND_STA); + outb(eth_nic_base + D8390_P0_RBCR0, cnt); + outb(eth_nic_base + D8390_P0_RBCR1, cnt>>8); + outb(eth_nic_base + D8390_P0_RSAR0, src); + outb(eth_nic_base + D8390_P0_RSAR1, src>>8); + outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_RD0 | + D8390_COMMAND_STA); + if (eth_flags & FLAG_16BIT) { + cnt >>= 1; /* number of words */ + while (cnt--) { + *((unsigned short *)dst) = inw(eth_asic_base + NE_DATA); + dst += 2; + } + } + else { + while (cnt--) + *(dst++) = inb(eth_asic_base + NE_DATA); + } +} + +/************************************************************************** +ETH_PIO_WRITE - Write a frame via Programmed I/O +**************************************************************************/ +static void eth_pio_write(src, dst, cnt) + unsigned char *src; + unsigned int dst; + unsigned int cnt; +{ + if (eth_flags & FLAG_16BIT) { ++cnt; cnt &= ~1; } + outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_RD2 | + D8390_COMMAND_STA); + outb(eth_nic_base + D8390_P0_ISR, D8390_ISR_RDC); + outb(eth_nic_base + D8390_P0_RBCR0, cnt); + outb(eth_nic_base + D8390_P0_RBCR1, cnt>>8); + outb(eth_nic_base + D8390_P0_RSAR0, dst); + outb(eth_nic_base + D8390_P0_RSAR1, dst>>8); + outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_RD1 | + D8390_COMMAND_STA); + if (eth_flags & FLAG_16BIT) { + cnt >>= 1; /* number of words */ + while (cnt--) { + outw_p(eth_asic_base + NE_DATA, *((unsigned short *)src)); + src += 2; + } + } + else { + while (cnt--) + outb_p(eth_asic_base + NE_DATA, *(src++)); + } + while((inb_p(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC) + != D8390_ISR_RDC); +} +#else +/************************************************************************** +ETH_PIO_READ - Dummy routine when NE2000 not compiled in +**************************************************************************/ +static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt) {} +#endif + +/************************************************************************** +ETH_RESET - Reset adapter +**************************************************************************/ +static void eth_reset(struct nic *nic) +{ + int i; + if (eth_flags & FLAG_790) + outb(eth_nic_base+D8390_P0_COMMAND, + D8390_COMMAND_PS0 | D8390_COMMAND_STP); + else + outb(eth_nic_base+D8390_P0_COMMAND, + D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | + D8390_COMMAND_STP); + if (eth_flags & FLAG_16BIT) + outb(eth_nic_base+D8390_P0_DCR, 0x49); + else + outb(eth_nic_base+D8390_P0_DCR, 0x48); + outb(eth_nic_base+D8390_P0_RBCR0, 0); + outb(eth_nic_base+D8390_P0_RBCR1, 0); + outb(eth_nic_base+D8390_P0_RCR, 0x20); /* monitor mode */ + outb(eth_nic_base+D8390_P0_TCR, 2); + outb(eth_nic_base+D8390_P0_TPSR, eth_tx_start); + outb(eth_nic_base+D8390_P0_PSTART, eth_rx_start); + if (eth_flags & FLAG_790) outb(eth_nic_base + 0x09, 0); + outb(eth_nic_base+D8390_P0_PSTOP, eth_memsize); + outb(eth_nic_base+D8390_P0_BOUND, eth_memsize - 1); + outb(eth_nic_base+D8390_P0_ISR, 0xFF); + outb(eth_nic_base+D8390_P0_IMR, 0); + if (eth_flags & FLAG_790) + outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS1 | + D8390_COMMAND_STP); + else + outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS1 | + D8390_COMMAND_RD2 | D8390_COMMAND_STP); + for (i=0; inode_addr[i]); + for (i=0; iaui) + outb(eth_asic_base + _3COM_CR, 0); + else + outb(eth_asic_base + _3COM_CR, _3COM_CR_XSEL); + } +#endif +} + +/************************************************************************** +ETH_TRANSMIT - Transmit a frame +**************************************************************************/ +static void eth_transmit( + struct nic *nic, + char *d, /* Destination */ + unsigned int t, /* Type */ + unsigned int s, /* size */ + char *p) /* Packet */ +{ + int c; /* used in NETBOOT16 */ + + +#ifdef INCLUDE_T503 + if (eth_vendor == VENDOR_3COM) { +#ifdef NETBOOT32 + net_bcopy(d, (void *)eth_bmem, ETHER_ADDR_SIZE); /* dst */ + net_bcopy(nic->node_addr, (void *)eth_bmem+ETHER_ADDR_SIZE, ETHER_ADDR_SIZE); /* src */ + *((char *)eth_bmem+12) = t>>8; /* type */ + *((char *)eth_bmem+13) = t; + net_bcopy(p, (void *)eth_bmem+ETHER_HDR_SIZE, s); + s += ETHER_HDR_SIZE; + while (s < ETH_MIN_PACKET) *((char *)eth_bmem+(s++)) = 0; +#endif +#ifdef NETBOOT16 + bcopyf(d, eth_bmem, ETHER_ADDR_SIZE); + bcopyf(nic->node_addr, eth_bmem+ETHER_ADDR_SIZE, ETHER_ADDR_SIZE); + c = t >> 8; + bcopyf(&c, eth_bmem+12, 1); + c = t; + bcopyf(&c, eth_bmem+13, 1); + bcopyf(p, (Address)(eth_bmem+ETHER_HDR_SIZE), s); + s += ETHER_HDR_SIZE; + if (s < ETH_MIN_PACKET) + bzerof(eth_bmem+s, ETH_MIN_PACKET-s), s = ETH_MIN_PACKET; +#endif + } +#endif +#ifdef INCLUDE_WD + if (eth_vendor == VENDOR_WD) { /* Memory interface */ + if (eth_flags & FLAG_16BIT) { + outb(eth_asic_base + WD_LAAR, eth_laar | WD_LAAR_M16EN); + inb(0x84); + } + if (eth_flags & FLAG_790) { + outb(eth_asic_base + WD_MSR, WD_MSR_MENB); + inb(0x84); + } + inb(0x84); +#ifdef NETBOOT32 + net_bcopy(d, (void *)eth_bmem, ETHER_ADDR_SIZE); /* dst */ + + net_bcopy(nic->node_addr, (void *)eth_bmem+ETHER_ADDR_SIZE, ETHER_ADDR_SIZE); /* src */ + *((char *)eth_bmem+12) = t>>8; /* type */ + *((char *)eth_bmem+13) = t; + net_bcopy(p, (void *)eth_bmem+ETHER_HDR_SIZE, s); + s += ETHER_HDR_SIZE; + while (s < ETH_MIN_PACKET) *((char *)eth_bmem+(s++)) = 0; +#endif +#ifdef NETBOOT16 + bcopyf(d, eth_bmem, ETHER_ADDR_SIZE); + bcopyf(nic->node_addr, eth_bmem+ETHER_ADDR_SIZE, ETHER_ADDR_SIZE); + c = t >> 8; + /* bcc generates worse code without (const+const) below */ + bcopyf(&c, eth_bmem+(ETHER_ADDR_SIZE+ETHER_ADDR_SIZE), 1); + c = t; + bcopyf(&c, eth_bmem+(ETHER_ADDR_SIZE+ETHER_ADDR_SIZE+1), 1); + bcopyf(p, (Address)(eth_bmem+ETHER_HDR_SIZE), s); + s += ETHER_HDR_SIZE; + if (s < ETH_MIN_PACKET) + bzerof(eth_bmem+s, ETH_MIN_PACKET-s), s = ETH_MIN_PACKET; +#endif + if (eth_flags & FLAG_790) { + outb(eth_asic_base + WD_MSR, 0); + inb(0x84); + } + if (eth_flags & FLAG_16BIT) { + outb(eth_asic_base + WD_LAAR, eth_laar & ~WD_LAAR_M16EN); + inb(0x84); + } + } +#endif +#if defined(INCLUDE_NE) || defined(INCLUDE_NEPCI) + if (eth_vendor == VENDOR_NOVELL) { /* Programmed I/O */ + unsigned short type; + type = (t >> 8) | (t << 8); + eth_pio_write(d, eth_tx_start<<8, ETHER_ADDR_SIZE); + eth_pio_write(nic->node_addr, (eth_tx_start<<8)+ETHER_ADDR_SIZE, ETHER_ADDR_SIZE); + /* bcc generates worse code without (const+const) below */ + eth_pio_write((unsigned char *)&type, (eth_tx_start<<8)+(ETHER_ADDR_SIZE+ETHER_ADDR_SIZE), 2); + eth_pio_write(p, (eth_tx_start<<8)+ETHER_HDR_SIZE, s); + s += ETHER_HDR_SIZE; + if (s < ETH_MIN_PACKET) s = ETH_MIN_PACKET; + } +#endif + if (eth_flags & FLAG_790) + outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 | + D8390_COMMAND_STA); + else + outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 | + D8390_COMMAND_RD2 | D8390_COMMAND_STA); + outb(eth_nic_base+D8390_P0_TPSR, eth_tx_start); + outb(eth_nic_base+D8390_P0_TBCR0, s); + outb(eth_nic_base+D8390_P0_TBCR1, s>>8); + if (eth_flags & FLAG_790) + outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 | + D8390_COMMAND_TXP | D8390_COMMAND_STA); + else + outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 | + D8390_COMMAND_TXP | D8390_COMMAND_RD2 | + D8390_COMMAND_STA); +} + +/************************************************************************** +ETH_POLL - Wait for a frame +**************************************************************************/ +static int eth_poll(struct nic *nic) +{ + int ret = 0; + unsigned char rstat, curr, next; + unsigned short len, frag; + unsigned short pktoff; + unsigned char *p; + struct ringbuffer pkthdr; + rstat = inb(eth_nic_base+D8390_P0_RSR); + if (rstat & D8390_RSTAT_OVER) { + eth_reset(nic); + return(0); + } + if (!(rstat & D8390_RSTAT_PRX)) return(0); + next = inb(eth_nic_base+D8390_P0_BOUND)+1; + if (next >= eth_memsize) next = eth_rx_start; + outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS1); + curr = inb(eth_nic_base+D8390_P1_CURR); + outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0); + if (curr >= eth_memsize) curr=eth_rx_start; + if (curr == next) return(0); + if (eth_vendor == VENDOR_WD) { + if (eth_flags & FLAG_16BIT) { + outb(eth_asic_base + WD_LAAR, eth_laar | WD_LAAR_M16EN); + inb(0x84); + } + if (eth_flags & FLAG_790) { + outb(eth_asic_base + WD_MSR, WD_MSR_MENB); + inb(0x84); + } + inb(0x84); + } + pktoff = next << 8; + if (eth_flags & FLAG_PIO) + eth_pio_read(pktoff, (char *)&pkthdr, 4); + else +#ifdef NETBOOT32 + net_bcopy((void *)eth_rmem + pktoff, &pkthdr, 4); +#endif +#ifdef NETBOOT16 + fnet_bcopy(eth_rmem + pktoff, &pkthdr, 4); +#endif + pktoff += sizeof(pkthdr); + len = pkthdr.len - 4; /* sub CRC */ + if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || pkthdr.len < ETH_MIN_PACKET || pkthdr.len > ETH_MAX_PACKET) { + printf("B"); + return (0); + } + else { + p = nic->packet; + nic->packetlen = len; /* available to caller */ + frag = (eth_memsize << 8) - pktoff; + if (len > frag) { /* We have a wrap-around */ + /* read first part */ + if (eth_flags & FLAG_PIO) + eth_pio_read(pktoff, p, frag); + else +#ifdef NETBOOT32 + net_bcopy((void *)eth_rmem + pktoff, p, frag); +#endif +#ifdef NETBOOT16 + fnet_bcopy(eth_rmem + pktoff, p, frag); +#endif + pktoff = eth_rx_start << 8; + p += frag; + len -= frag; + } + /* read second part */ + if (eth_flags & FLAG_PIO) + eth_pio_read(pktoff, p, len); + else +#ifdef NETBOOT32 + net_bcopy((void *)eth_rmem + pktoff, p, len); +#endif +#ifdef NETBOOT16 + fnet_bcopy(eth_rmem + pktoff, p, len); +#endif + ret = 1; + } + if (eth_vendor == VENDOR_WD) { + if (eth_flags & FLAG_790) { + outb(eth_asic_base + WD_MSR, 0); + inb(0x84); + } + if (eth_flags & FLAG_16BIT) { + outb(eth_asic_base + WD_LAAR, eth_laar & + ~WD_LAAR_M16EN); + inb(0x84); + } + inb(0x84); + } + next = pkthdr.next; /* frame number of next packet */ + if (next == eth_rx_start) + next = eth_memsize; + outb(eth_nic_base+D8390_P0_BOUND, next-1); + return(ret); +} + +/************************************************************************** +ETH_DISABLE - Turn off adapter +**************************************************************************/ +static void eth_disable(struct nic *nic) +{ +} + +/************************************************************************** +ETH_PROBE - Look for an adapter +**************************************************************************/ +struct nic *eth_probe(struct nic *nic, unsigned short *probe_addrs) +{ + int i; + struct wd_board *brd; + unsigned short chksum; + unsigned char c; +#if defined(INCLUDE_WD) && defined(NETBOOT16) + unsigned char bmem13, bmem11; +#endif + + eth_vendor = VENDOR_NONE; + +#ifdef INCLUDE_WD + /****************************************************************** + Search for WD/SMC cards + ******************************************************************/ + for (eth_asic_base = WD_LOW_BASE; eth_asic_base <= WD_HIGH_BASE; + eth_asic_base += 0x20) { + chksum = 0; + for (i=8; i<16; i++) + chksum += inb(i+eth_asic_base); + if ((chksum & 0x00FF) == 0x00FF) + break; + } + if (eth_asic_base <= WD_HIGH_BASE) { /* We've found a board */ + eth_vendor = VENDOR_WD; + eth_nic_base = eth_asic_base + WD_NIC_ADDR; + c = inb(eth_asic_base+WD_BID); /* Get board id */ + for (brd = wd_boards; brd->name; brd++) + if (brd->id == c) break; + if (!brd->name) { + printf("\r\nUnknown Ethernet type %x\r\n", c); + return(0); /* Unknown type */ + } + eth_flags = brd->flags; + eth_memsize = brd->memsize; + eth_tx_start = 0; + eth_rx_start = D8390_TXBUF_SIZE; + if ((c == TYPE_WD8013EP) && + (inb(eth_asic_base + WD_ICR) & WD_ICR_16BIT)) { + eth_flags = FLAG_16BIT; + eth_memsize = MEM_16384; + } + if ((c & WD_SOFTCONFIG) && (!(eth_flags & FLAG_790))) { +#ifdef NETBOOT32 + eth_bmem = (0x80000 | + ((inb(eth_asic_base + WD_MSR) & 0x3F) << 13)); +#endif +#ifdef NETBOOT16 + eth_bmem = inb(eth_asic_base + WD_MSR) & 0x3F; + eth_bmem <<= 13; + eth_bmem |= 0x80000; +#endif + } else + eth_bmem = WD_DEFAULT_MEM; +#ifdef NETBOOT16 + /* cast is to force evaluation in long precision */ + bmem13 = (Address)eth_bmem >> 13; + bmem11 = (Address)eth_bmem >> 11; +#endif +#ifdef NETBOOT32 + if (brd->id == TYPE_SMC8216T || brd->id == TYPE_SMC8216C) { + *((unsigned int *)(eth_bmem + 8192)) = (unsigned int)0; + if (*((unsigned int *)(eth_bmem + 8192))) { + brd += 2; + eth_memsize = brd->memsize; + } + } +#endif +#ifdef NETBOOT16 + if (brd->id == TYPE_SMC8216T || brd->id == TYPE_SMC8216C) { + i = 0; + bcopyf(&i, eth_bmem + 8192, sizeof(i)); + if (!fbsame(eth_bmem + 8192, 0, sizeof(i))) { + brd += 2; + eth_memsize = brd->memsize; + } + } +#endif + outb(eth_asic_base + WD_MSR, 0x80); /* Reset */ + printf("\r\n%s base 0x%x, memory 0x%x, addr ", + brd->name, eth_asic_base, eth_bmem); + for (i=0; inode_addr[i] = + inb(i+eth_asic_base+WD_LAR)) & 0xff)); + if (i < ETHER_ADDR_SIZE-1) printf (":"); + } + if (eth_flags & FLAG_790) { + outb(eth_asic_base+WD_MSR, WD_MSR_MENB); + outb(eth_asic_base+0x04, (inb(eth_asic_base+0x04) | + 0x80)); +#ifdef NETBOOT32 + outb(eth_asic_base+0x0B, + (((unsigned)eth_bmem >> 13) & 0x0F) | + (((unsigned)eth_bmem >> 11) & 0x40) | + (inb(eth_asic_base+0x0B) & 0xB0)); +#endif +#ifdef NETBOOT16 + outb(eth_asic_base+0x0B, + (bmem13 & 0x0F) | + (bmem11 & 0x40) | + (inb(eth_asic_base+0x0B) & 0xB0)); +#endif + outb(eth_asic_base+0x04, (inb(eth_asic_base+0x04) & + ~0x80)); + } else { +#ifdef NETBOOT32 + outb(eth_asic_base+WD_MSR, + (((unsigned)eth_bmem >> 13) & 0x3F) | 0x40); +#endif +#ifdef NETBOOT16 + outb(eth_asic_base+WD_MSR, + (bmem13 & 0x3F) | 0x40); +#endif + } + if (eth_flags & FLAG_16BIT) { + if (eth_flags & FLAG_790) { + eth_laar = inb(eth_asic_base + WD_LAAR); + outb(eth_asic_base + WD_LAAR, WD_LAAR_M16EN); + inb(0x84); + } else { + outb(eth_asic_base + WD_LAAR, (eth_laar = + WD_LAAR_M16EN | WD_LAAR_L16EN | 1)); + } + } + printf("\r\n"); + + } +#endif +#ifdef INCLUDE_T503 + /****************************************************************** + Search for 3Com 3c503 if no WD/SMC cards + ******************************************************************/ + if (eth_vendor == VENDOR_NONE) { + int idx; + static unsigned short base[] = { + 0x300, 0x310, 0x330, 0x350, + 0x250, 0x280, 0x2A0, 0x2E0, 0 }; + /* this must parallel the table above */ + static unsigned char bcfr[] = { + _3COM_BCFR_300, _3COM_BCFR_310, + _3COM_BCFR_330, _3COM_BCFR_350, + _3COM_BCFR_250, _3COM_BCFR_280, + _3COM_BCFR_2A0, _3COM_BCFR_2E0, 0 }; + + /* Loop through possible addresses checking each one */ + + for (idx = 0; (eth_nic_base = base[idx]) != 0; ++idx) { + + eth_asic_base = eth_nic_base + _3COM_ASIC_OFFSET; +/* + * Note that we use the same settings for both 8 and 16 bit cards: + * both have an 8K bank of memory at page 1 while only the 16 bit + * cards have a bank at page 0. + */ + eth_memsize = MEM_16384; + eth_tx_start = 32; + eth_rx_start = 32 + D8390_TXBUF_SIZE; + + /* Check our base address */ + + if (inb(eth_asic_base + _3COM_BCFR) != bcfr[idx]) + continue; /* nope */ + + /* Now get the shared memory address */ + + switch (inb(eth_asic_base + _3COM_PCFR)) { + case _3COM_PCFR_DC000: + eth_bmem = 0xdc000; + break; + case _3COM_PCFR_D8000: + eth_bmem = 0xd8000; + break; + case _3COM_PCFR_CC000: + eth_bmem = 0xcc000; + break; + case _3COM_PCFR_C8000: + eth_bmem = 0xc8000; + break; + default: + continue; /* nope */ + } + break; + } + + if (base[idx] == 0) /* not found */ + return (0); + eth_vendor = VENDOR_3COM; + + + /* Need this to make eth_poll() happy. */ + + eth_rmem = eth_bmem - 0x2000; + + /* Reset NIC and ASIC */ + + outb (eth_asic_base + _3COM_CR , _3COM_CR_RST | _3COM_CR_XSEL); + outb (eth_asic_base + _3COM_CR , _3COM_CR_XSEL); + + /* Get our ethernet address */ + + outb(eth_asic_base + _3COM_CR, _3COM_CR_EALO | _3COM_CR_XSEL); + printf("\r\n3Com 3c503 base 0x%x, memory 0x%X addr ", + eth_nic_base, eth_bmem); + for (i=0; inode_addr[i] = + inb(eth_nic_base+i))); + if (i < ETHER_ADDR_SIZE-1) printf (":"); + } + outb(eth_asic_base + _3COM_CR, _3COM_CR_XSEL); + /* + * Initialize GA configuration register. Set bank and enable shared + * mem. We always use bank 1. + */ + outb(eth_asic_base + _3COM_GACFR, _3COM_GACFR_RSEL | + _3COM_GACFR_MBS0); + + outb(eth_asic_base + _3COM_VPTR2, 0xff); + outb(eth_asic_base + _3COM_VPTR1, 0xff); + outb(eth_asic_base + _3COM_VPTR0, 0x00); + /* + * Clear memory and verify that it worked (we use only 8K) + */ +#ifdef NETBOOT32 + bzero((char *)eth_bmem, 0x2000); + for(i = 0; i < 0x2000; ++i) + if (*(((char *)eth_bmem)+i)) { + printf ("Failed to clear 3c503 shared mem.\r\n"); + return (0); + } +#endif +#ifdef NETBOOT16 + bzerof(eth_bmem, 0x2000); + if (!fbsame(eth_bmem, 0, 0x2000)) { + printf ("Failed to clear 3c503 shared mem.\r\n"); + return (0); + } +#endif + /* + * Initialize GA page/start/stop registers. + */ + outb(eth_asic_base + _3COM_PSTR, eth_tx_start); + outb(eth_asic_base + _3COM_PSPR, eth_memsize); + + printf ("\r\n"); + + } +#endif +#if defined(INCLUDE_NE) || defined(INCLUDE_NEPCI) + /****************************************************************** + Search for NE1000/2000 if no WD/SMC or 3com cards + ******************************************************************/ + if (eth_vendor == VENDOR_NONE) { + char romdata[16], testbuf[32]; + int idx; + static char test[] = "NE1000/2000 memory"; +#ifndef NE_SCAN +#define NE_SCAN 0 +#endif + static unsigned short base[] = {NE_SCAN, 0}; + /* if no addresses supplied, fall back on defaults */ + if (probe_addrs == 0 || probe_addrs[0] == 0) + probe_addrs = base; + eth_bmem = 0; /* No shared memory */ + for (idx = 0; (eth_nic_base = probe_addrs[idx]) != 0; ++idx) { + eth_flags = FLAG_PIO; + eth_asic_base = eth_nic_base + NE_ASIC_OFFSET; + eth_memsize = MEM_16384; + eth_tx_start = 32; + eth_rx_start = 32 + D8390_TXBUF_SIZE; + c = inb(eth_asic_base + NE_RESET); + outb(eth_asic_base + NE_RESET, c); + inb(0x84); + outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_STP | + D8390_COMMAND_RD2); + outb(eth_nic_base + D8390_P0_RCR, D8390_RCR_MON); + outb(eth_nic_base + D8390_P0_DCR, D8390_DCR_FT1 | D8390_DCR_LS); + outb(eth_nic_base + D8390_P0_PSTART, MEM_8192); + outb(eth_nic_base + D8390_P0_PSTOP, MEM_16384); + eth_pio_write(test, 8192, sizeof(test)); + eth_pio_read(8192, testbuf, sizeof(test)); + if (!bcmp(test, testbuf, sizeof(test))) + break; + eth_flags |= FLAG_16BIT; + eth_memsize = MEM_32768; + eth_tx_start = 64; + eth_rx_start = 64 + D8390_TXBUF_SIZE; + outb(eth_nic_base + D8390_P0_DCR, D8390_DCR_WTS | + D8390_DCR_FT1 | D8390_DCR_LS); + outb(eth_nic_base + D8390_P0_PSTART, MEM_16384); + outb(eth_nic_base + D8390_P0_PSTOP, MEM_32768); + eth_pio_write(test, 16384, sizeof(test)); + eth_pio_read(16384, testbuf, sizeof(test)); + if (!bcmp(testbuf, test, sizeof(test))) + break; + } + if (eth_nic_base == 0) + return (0); + if (eth_nic_base > ISA_MAX_ADDR) /* PCI probably */ + eth_flags |= FLAG_16BIT; + eth_vendor = VENDOR_NOVELL; + eth_pio_read(0, romdata, 16); + printf("\r\nNE*000 base 0x%x, addr ", eth_nic_base); + for (i=0; inode_addr[i] = romdata[i + + ((eth_flags & FLAG_16BIT) ? i : 0)])); + if (i < ETHER_ADDR_SIZE-1) printf (":"); + } + printf("\r\n"); + } +#endif + if (eth_vendor == VENDOR_NONE) return(0); + + if (eth_vendor != VENDOR_3COM) eth_rmem = eth_bmem; + eth_reset(nic); + nic->reset = eth_reset; + nic->poll = eth_poll; + nic->transmit = eth_transmit; + nic->disable = eth_disable; + return(nic); +} + +#endif + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/netboot/ns8390.h b/netboot/ns8390.h new file mode 100644 index 000000000..8e70eb01b --- /dev/null +++ b/netboot/ns8390.h @@ -0,0 +1,251 @@ +/************************************************************************** +NETBOOT - BOOTP/TFTP Bootstrap Program + +Author: Martin Renters + Date: Jun/94 + +**************************************************************************/ + +#define MEM_8192 32 +#define MEM_16384 64 +#define MEM_32768 128 + +#define ISA_MAX_ADDR 0x400 + +/************************************************************************** +Western Digital/SMC Board Definitions +**************************************************************************/ +#define WD_LOW_BASE 0x200 +#define WD_HIGH_BASE 0x3e0 +#ifndef WD_DEFAULT_MEM +#define WD_DEFAULT_MEM 0xD0000 +#endif +#define WD_NIC_ADDR 0x10 + +/************************************************************************** +Western Digital/SMC ASIC Addresses +**************************************************************************/ +#define WD_MSR 0x00 +#define WD_ICR 0x01 +#define WD_IAR 0x02 +#define WD_BIO 0x03 +#define WD_IRR 0x04 +#define WD_LAAR 0x05 +#define WD_IJR 0x06 +#define WD_GP2 0x07 +#define WD_LAR 0x08 +#define WD_BID 0x0E + +#define WD_ICR_16BIT 0x01 + +#define WD_MSR_MENB 0x40 + +#define WD_LAAR_L16EN 0x40 +#define WD_LAAR_M16EN 0x80 + +#define WD_SOFTCONFIG 0x20 + +/************************************************************************** +Western Digital/SMC Board Types +**************************************************************************/ +#define TYPE_WD8003S 0x02 +#define TYPE_WD8003E 0x03 +#define TYPE_WD8013EBT 0x05 +#define TYPE_WD8003W 0x24 +#define TYPE_WD8003EB 0x25 +#define TYPE_WD8013W 0x26 +#define TYPE_WD8013EP 0x27 +#define TYPE_WD8013WC 0x28 +#define TYPE_WD8013EPC 0x29 +#define TYPE_SMC8216T 0x2a +#define TYPE_SMC8216C 0x2b +#define TYPE_SMC8416T 0x00 /* Bogus entries: the 8416 generates the */ +#define TYPE_SMC8416C 0x00 /* the same codes as the 8216. */ +#define TYPE_SMC8013EBP 0x2c + +#ifdef INCLUDE_WD +struct wd_board { + char *name; + char id; + char flags; + char memsize; +} wd_boards[] = { + {"WD8003S", TYPE_WD8003S, 0, MEM_8192}, + {"WD8003E", TYPE_WD8003E, 0, MEM_8192}, + {"WD8013EBT", TYPE_WD8013EBT, FLAG_16BIT, MEM_16384}, + {"WD8003W", TYPE_WD8003W, 0, MEM_8192}, + {"WD8003EB", TYPE_WD8003EB, 0, MEM_8192}, + {"WD8013W", TYPE_WD8013W, FLAG_16BIT, MEM_16384}, + {"WD8003EP/WD8013EP", + TYPE_WD8013EP, 0, MEM_8192}, + {"WD8013WC", TYPE_WD8013WC, FLAG_16BIT, MEM_16384}, + {"WD8013EPC", TYPE_WD8013EPC, FLAG_16BIT, MEM_16384}, + {"SMC8216T", TYPE_SMC8216T, FLAG_16BIT | FLAG_790, MEM_16384}, + {"SMC8216C", TYPE_SMC8216C, FLAG_16BIT | FLAG_790, MEM_16384}, + {"SMC8416T", TYPE_SMC8416T, FLAG_16BIT | FLAG_790, MEM_8192}, + {"SMC8416C/BT", TYPE_SMC8416C, FLAG_16BIT | FLAG_790, MEM_8192}, + {"SMC8013EBP", TYPE_SMC8013EBP,FLAG_16BIT, MEM_16384}, + {NULL, 0, 0} +}; +#endif +/************************************************************************** +3com 3c503 definitions +**************************************************************************/ + +#ifndef _3COM_BASE +#define _3COM_BASE 0x300 +#endif + +#define _3COM_TX_PAGE_OFFSET_8BIT 0x20 +#define _3COM_TX_PAGE_OFFSET_16BIT 0x0 +#define _3COM_RX_PAGE_OFFSET_16BIT 0x20 + +#define _3COM_ASIC_OFFSET 0x400 +#define _3COM_NIC_OFFSET 0x0 + +#define _3COM_PSTR 0 +#define _3COM_PSPR 1 + +#define _3COM_BCFR 3 +#define _3COM_BCFR_2E0 0x01 +#define _3COM_BCFR_2A0 0x02 +#define _3COM_BCFR_280 0x04 +#define _3COM_BCFR_250 0x08 +#define _3COM_BCFR_350 0x10 +#define _3COM_BCFR_330 0x20 +#define _3COM_BCFR_310 0x40 +#define _3COM_BCFR_300 0x80 +#define _3COM_PCFR 4 +#define _3COM_PCFR_C8000 0x10 +#define _3COM_PCFR_CC000 0x20 +#define _3COM_PCFR_D8000 0x40 +#define _3COM_PCFR_DC000 0x80 +#define _3COM_CR 6 +#define _3COM_CR_RST 0x01 /* Reset GA and NIC */ +#define _3COM_CR_XSEL 0x02 /* Transceiver select. BNC=1(def) AUI=0 */ +#define _3COM_CR_EALO 0x04 /* window EA PROM 0-15 to I/O base */ +#define _3COM_CR_EAHI 0x08 /* window EA PROM 16-31 to I/O base */ +#define _3COM_CR_SHARE 0x10 /* select interrupt sharing option */ +#define _3COM_CR_DBSEL 0x20 /* Double buffer select */ +#define _3COM_CR_DDIR 0x40 /* DMA direction select */ +#define _3COM_CR_START 0x80 /* Start DMA controller */ +#define _3COM_GACFR 5 +#define _3COM_GACFR_MBS0 0x01 +#define _3COM_GACFR_MBS1 0x02 +#define _3COM_GACFR_MBS2 0x04 +#define _3COM_GACFR_RSEL 0x08 /* enable shared memory */ +#define _3COM_GACFR_TEST 0x10 /* for GA testing */ +#define _3COM_GACFR_OWS 0x20 /* select 0WS access to GA */ +#define _3COM_GACFR_TCM 0x40 /* Mask DMA interrupts */ +#define _3COM_GACFR_NIM 0x80 /* Mask NIC interrupts */ +#define _3COM_STREG 7 +#define _3COM_STREG_REV 0x07 /* GA revision */ +#define _3COM_STREG_DIP 0x08 /* DMA in progress */ +#define _3COM_STREG_DTC 0x10 /* DMA terminal count */ +#define _3COM_STREG_OFLW 0x20 /* Overflow */ +#define _3COM_STREG_UFLW 0x40 /* Underflow */ +#define _3COM_STREG_DPRDY 0x80 /* Data port ready */ +#define _3COM_IDCFR 8 +#define _3COM_IDCFR_DRQ0 0x01 /* DMA request 1 select */ +#define _3COM_IDCFR_DRQ1 0x02 /* DMA request 2 select */ +#define _3COM_IDCFR_DRQ2 0x04 /* DMA request 3 select */ +#define _3COM_IDCFR_UNUSED 0x08 /* not used */ +#define _3COM_IDCFR_IRQ2 0x10 /* Interrupt request 2 select */ +#define _3COM_IDCFR_IRQ3 0x20 /* Interrupt request 3 select */ +#define _3COM_IDCFR_IRQ4 0x40 /* Interrupt request 4 select */ +#define _3COM_IDCFR_IRQ5 0x80 /* Interrupt request 5 select */ +#define _3COM_IRQ2 2 +#define _3COM_IRQ3 3 +#define _3COM_IRQ4 4 +#define _3COM_IRQ5 5 +#define _3COM_DAMSB 9 +#define _3COM_DALSB 0x0a +#define _3COM_VPTR2 0x0b +#define _3COM_VPTR1 0x0c +#define _3COM_VPTR0 0x0d +#define _3COM_RFMSB 0x0e +#define _3COM_RFLSB 0x0f + +/************************************************************************** +NE1000/2000 definitions +**************************************************************************/ +#define NE_ASIC_OFFSET 0x10 +#define NE_RESET 0x0F /* Used to reset card */ +#define NE_DATA 0x00 /* Used to read/write NIC mem */ + +/************************************************************************** +8390 Register Definitions +**************************************************************************/ +#define D8390_P0_COMMAND 0x00 +#define D8390_P0_PSTART 0x01 +#define D8390_P0_PSTOP 0x02 +#define D8390_P0_BOUND 0x03 +#define D8390_P0_TSR 0x04 +#define D8390_P0_TPSR 0x04 +#define D8390_P0_TBCR0 0x05 +#define D8390_P0_TBCR1 0x06 +#define D8390_P0_ISR 0x07 +#define D8390_P0_RSAR0 0x08 +#define D8390_P0_RSAR1 0x09 +#define D8390_P0_RBCR0 0x0A +#define D8390_P0_RBCR1 0x0B +#define D8390_P0_RSR 0x0C +#define D8390_P0_RCR 0x0C +#define D8390_P0_TCR 0x0D +#define D8390_P0_DCR 0x0E +#define D8390_P0_IMR 0x0F +#define D8390_P1_COMMAND 0x00 +#define D8390_P1_PAR0 0x01 +#define D8390_P1_PAR1 0x02 +#define D8390_P1_PAR2 0x03 +#define D8390_P1_PAR3 0x04 +#define D8390_P1_PAR4 0x05 +#define D8390_P1_PAR5 0x06 +#define D8390_P1_CURR 0x07 +#define D8390_P1_MAR0 0x08 + +#define D8390_COMMAND_PS0 0x0 /* Page 0 select */ +#define D8390_COMMAND_PS1 0x40 /* Page 1 select */ +#define D8390_COMMAND_PS2 0x80 /* Page 2 select */ +#define D8390_COMMAND_RD2 0x20 /* Remote DMA control */ +#define D8390_COMMAND_RD1 0x10 +#define D8390_COMMAND_RD0 0x08 +#define D8390_COMMAND_TXP 0x04 /* transmit packet */ +#define D8390_COMMAND_STA 0x02 /* start */ +#define D8390_COMMAND_STP 0x01 /* stop */ + +#define D8390_RCR_MON 0x20 /* monitor mode */ + +#define D8390_DCR_FT1 0x40 +#define D8390_DCR_LS 0x08 /* Loopback select */ +#define D8390_DCR_WTS 0x01 /* Word transfer select */ + +#define D8390_ISR_PRX 0x01 /* successful recv */ +#define D8390_ISR_PTX 0x02 /* successful xmit */ +#define D8390_ISR_RXE 0x04 /* receive error */ +#define D8390_ISR_TXE 0x08 /* transmit error */ +#define D8390_ISR_OVW 0x10 /* Overflow */ +#define D8390_ISR_CNT 0x20 /* Counter overflow */ +#define D8390_ISR_RDC 0x40 /* Remote DMA complete */ +#define D8390_ISR_RST 0x80 /* reset */ + +#define D8390_RSTAT_PRX 0x01 /* successful recv */ +#define D8390_RSTAT_CRC 0x02 /* CRC error */ +#define D8390_RSTAT_FAE 0x04 /* Frame alignment error */ +#define D8390_RSTAT_OVER 0x08 /* overflow */ + +#define D8390_TXBUF_SIZE 6 +#define D8390_RXBUF_END 32 +#define D8390_PAGE_SIZE 256 + +struct ringbuffer { + unsigned char status; + unsigned char next; + unsigned short len; +}; +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ + diff --git a/netboot/pci.c b/netboot/pci.c new file mode 100644 index 000000000..17e5722cd --- /dev/null +++ b/netboot/pci.c @@ -0,0 +1,261 @@ +/* +** Support for NE2000 PCI clones added David Monro June 1997 +** Generalised to other NICs by Ken Yap July 1997 +** +** Most of this is taken from: +** +** /usr/src/linux/drivers/pci/pci.c +** /usr/src/linux/include/linux/pci.h +** /usr/src/linux/arch/i386/bios32.c +** /usr/src/linux/include/linux/bios32.h +** /usr/src/linux/drivers/net/ne.c +** +** Limitations: only finds devices on bus 0 (I figure that anybody with +** a multi-pcibus machine will have something better than an ne2000) +*/ + +#include "netboot.h" +#include "pci.h" + +#define DEBUG 1 + +static unsigned int pci_ioaddr = 0; + +static unsigned long bios32_entry = 0; +static struct { + unsigned long address; + unsigned short segment; +} bios32_indirect = { 0, KERN_CODE_SEG }; + +static long pcibios_entry = 0; +static struct { + unsigned long address; + unsigned short segment; +} pci_indirect = { 0, KERN_CODE_SEG }; + +static unsigned long bios32_service(unsigned long service) +{ + unsigned char return_code; /* %al */ + unsigned long address; /* %ebx */ + unsigned long length; /* %ecx */ + unsigned long entry; /* %edx */ + unsigned long flags; + + save_flags(flags); + __asm__("lcall (%%edi)" + : "=a" (return_code), + "=b" (address), + "=c" (length), + "=d" (entry) + : "0" (service), + "1" (0), + "D" (&bios32_indirect)); + restore_flags(flags); + + switch (return_code) { + case 0: + return address + entry; + case 0x80: /* Not present */ + printf("bios32_service(%d) : not present\r\n", service); + return 0; + default: /* Shouldn't happen */ + printf("bios32_service(%d) : returned 0x%x, mail drew@colorado.edu\r\n", + service, return_code); + return 0; + } +} + +static int pcibios_read_config_byte(unsigned char bus, + unsigned char device_fn, unsigned char where, unsigned char *value) +{ + unsigned long ret; + unsigned long bx = (bus << 8) | device_fn; + unsigned long flags; + + save_flags(flags); + __asm__("lcall (%%esi)\n\t" + "jc 1f\n\t" + "xor %%ah, %%ah\n" + "1:" + : "=c" (*value), + "=a" (ret) + : "1" (PCIBIOS_READ_CONFIG_BYTE), + "b" (bx), + "D" ((long) where), + "S" (&pci_indirect)); + restore_flags(flags); + return (int) (ret & 0xff00) >> 8; +} + +static int pcibios_read_config_dword (unsigned char bus, + unsigned char device_fn, unsigned char where, unsigned int *value) +{ + unsigned long ret; + unsigned long bx = (bus << 8) | device_fn; + unsigned long flags; + + save_flags(flags); + __asm__("lcall (%%esi)\n\t" + "jc 1f\n\t" + "xor %%ah, %%ah\n" + "1:" + : "=c" (*value), + "=a" (ret) + : "1" (PCIBIOS_READ_CONFIG_DWORD), + "b" (bx), + "D" ((long) where), + "S" (&pci_indirect)); + restore_flags(flags); + return (int) (ret & 0xff00) >> 8; +} + +static void check_pcibios(void) +{ + unsigned long signature; + unsigned char present_status; + unsigned char major_revision; + unsigned char minor_revision; + unsigned long flags; + int pack; + + if ((pcibios_entry = bios32_service(PCI_SERVICE))) { + pci_indirect.address = pcibios_entry; + + save_flags(flags); + __asm__("lcall (%%edi)\n\t" + "jc 1f\n\t" + "xor %%ah, %%ah\n" + "1:\tshl $8, %%eax\n\t" + "movw %%bx, %%ax" + : "=d" (signature), + "=a" (pack) + : "1" (PCIBIOS_PCI_BIOS_PRESENT), + "D" (&pci_indirect) + : "bx", "cx"); + restore_flags(flags); + + present_status = (pack >> 16) & 0xff; + major_revision = (pack >> 8) & 0xff; + minor_revision = pack & 0xff; + if (present_status || (signature != PCI_SIGNATURE)) { + printf("ERROR: BIOS32 says PCI BIOS, but no PCI " + "BIOS????\r\n"); + pcibios_entry = 0; + } +#if DEBUG + if (pcibios_entry) { + printf ("pcibios_init : PCI BIOS revision %b.%b" + " entry at 0x%X\r\n", major_revision, + minor_revision, pcibios_entry); + } +#endif + } +} + +static void pcibios_init(void) +{ + union bios32 *check; + unsigned char sum; + int i, length; + + /* + * Follow the standard procedure for locating the BIOS32 Service + * directory by scanning the permissible address range from + * 0xe0000 through 0xfffff for a valid BIOS32 structure. + * + */ + + for (check = (union bios32 *) 0xe0000; check <= (union bios32 *) 0xffff0; ++check) { + if (check->fields.signature != BIOS32_SIGNATURE) + continue; + length = check->fields.length * 16; + if (!length) + continue; + sum = 0; + for (i = 0; i < length ; ++i) + sum += check->chars[i]; + if (sum != 0) + continue; + if (check->fields.revision != 0) { + printf("pcibios_init : unsupported revision %d at 0x%X, mail drew@colorado.edu\r\n", + check->fields.revision, check); + continue; + } +#if DEBUG + printf("pcibios_init : BIOS32 Service Directory " + "structure at 0x%X\r\n", check); +#endif + if (!bios32_entry) { + if (check->fields.entry >= 0x100000) { + printf("pcibios_init: entry in high " + "memory, giving up\r\n"); + return; + } else { + bios32_entry = check->fields.entry; +#if DEBUG + printf("pcibios_init : BIOS32 Service Directory" + " entry at 0x%X\r\n", bios32_entry); +#endif + bios32_indirect.address = bios32_entry; + } + } + } + if (bios32_entry) + check_pcibios(); +} + +static void scan_bus(struct pci_device *pcidev) +{ + unsigned int devfn, l; + unsigned char hdr_type = 0; + unsigned short vendor, device; + int i; + + for (devfn = 0; devfn < 0xff; ++devfn) { + if (PCI_FUNC(devfn) == 0) { + pcibios_read_config_byte(0, devfn, + PCI_HEADER_TYPE, &hdr_type); + } else if (!(hdr_type & 0x80)) { + /* not a multi-function device */ + continue; + } + + pcibios_read_config_dword(0, devfn, + PCI_VENDOR_ID, &l); + /* some broken boards return 0 if a slot is empty: */ + if (l == 0xffffffff || l == 0x00000000) { + hdr_type = 0; + continue; + } + vendor = l & 0xffff; + device = (l >> 16) & 0xffff; +#if DEBUG + printf("bus 0, function %x, vendor %x, device %x\r\n", + devfn, vendor, device); +#endif + for (i = 0; pcidev[i].vendor != 0; i++) { + if (vendor == pcidev[i].vendor + && device == pcidev[i].dev_id) { + pcibios_read_config_dword(0, devfn, + PCI_BASE_ADDRESS_0, &pci_ioaddr); + /* Strip the I/O address out of the + * returned value */ + pci_ioaddr &= PCI_BASE_ADDRESS_IO_MASK; + printf("Found %s at 0x%x\r\n", + pcidev[i].name, pci_ioaddr); + } + } + } +} + +void eth_pci_init(struct pci_device *pcidev, unsigned short *ioaddr) +{ + pcibios_init(); + if (!pcibios_entry) { + printf("pci_init: no BIOS32 detected\r\n"); + return; + } + scan_bus(pcidev); + /* we only return one address at the moment, maybe more later? */ + *ioaddr = pci_ioaddr; +} diff --git a/netboot/pci.h b/netboot/pci.h new file mode 100644 index 000000000..d279bec75 --- /dev/null +++ b/netboot/pci.h @@ -0,0 +1,89 @@ +/* +** Support for NE2000 PCI clones added David Monro June 1997 +** Generalised for other PCI NICs by Ken Yap July 1997 +** +** Most of this is taken from: +** +** /usr/src/linux/drivers/pci/pci.c +** /usr/src/linux/include/linux/pci.h +** /usr/src/linux/arch/i386/bios32.c +** /usr/src/linux/include/linux/bios32.h +** /usr/src/linux/drivers/net/ne.c +*/ + +#define PCIBIOS_PCI_FUNCTION_ID 0xb1XX +#define PCIBIOS_PCI_BIOS_PRESENT 0xb101 +#define PCIBIOS_FIND_PCI_DEVICE 0xb102 +#define PCIBIOS_FIND_PCI_CLASS_CODE 0xb103 +#define PCIBIOS_GENERATE_SPECIAL_CYCLE 0xb106 +#define PCIBIOS_READ_CONFIG_BYTE 0xb108 +#define PCIBIOS_READ_CONFIG_WORD 0xb109 +#define PCIBIOS_READ_CONFIG_DWORD 0xb10a +#define PCIBIOS_WRITE_CONFIG_BYTE 0xb10b +#define PCIBIOS_WRITE_CONFIG_WORD 0xb10c +#define PCIBIOS_WRITE_CONFIG_DWORD 0xb10d + +#define PCI_VENDOR_ID 0x00 /* 16 bits */ +#define PCI_DEVICE_ID 0x02 /* 16 bits */ +#define PCI_COMMAND 0x04 /* 16 bits */ + +#define PCI_HEADER_TYPE 0x0e /* 8 bits */ + +#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */ + +#define PCI_BASE_ADDRESS_IO_MASK (~0x03) + +#define PCI_FUNC(devfn) ((devfn) & 0x07) + +#define BIOS32_SIGNATURE (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24)) + +/* PCI signature: "PCI " */ +#define PCI_SIGNATURE (('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24)) + +/* PCI service signature: "$PCI" */ +#define PCI_SERVICE (('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24)) + +union bios32 { + struct { + unsigned long signature; /* _32_ */ + unsigned long entry; /* 32 bit physical address */ + unsigned char revision; /* Revision level, 0 */ + unsigned char length; /* Length in paragraphs should be 01 */ + unsigned char checksum; /* All bytes must add up to zero */ + unsigned char reserved[5]; /* Must be zero */ + } fields; + char chars[16]; +}; + +#define KERN_CODE_SEG 0x8 /* This _MUST_ match start.S */ + +/* Stuff for asm */ +#define save_flags(x) \ +__asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */ :"memory") + +#define restore_flags(x) \ +__asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory") + +#define PCI_VENDOR_ID_REALTEK 0x10ec +#define PCI_DEVICE_ID_REALTEK_8029 0x8029 +#define PCI_VENDOR_ID_WINBOND2 0x1050 +#define PCI_DEVICE_ID_WINBOND2_89C940 0x0940 +#define PCI_VENDOR_ID_COMPEX 0x11f6 +#define PCI_DEVICE_ID_COMPEX_RL2000 0x1401 +#define PCI_VENDOR_ID_KTI 0x8e2e +#define PCI_DEVICE_ID_KTI_ET32P2 0x3000 +#define PCI_VENDOR_ID_INTEL 0x8086 +#define PCI_DEVICE_ID_INTEL_82557 0x1229 +#define PCI_VENDOR_ID_NETVIN 0x4a14 +#define PCI_DEVICE_ID_NETVIN_NV5000SC 0x5000 +#define PCI_VENDOR_ID_VIA 0x1106 +#define PCI_DEVICE_ID_VIA_82C926 0x0926 +#define PCI_VENDOR_ID_SURECOM 0x10bd +#define PCI_DEVICE_ID_SURECOM_NE34 0x0e34 + +struct pci_device { + unsigned short vendor, dev_id; + char *name; +}; + +extern void eth_pci_init(struct pci_device *, unsigned short *); diff --git a/stage1/Makefile.in b/stage1/Makefile.in index a6e696679..c51a8b88a 100644 --- a/stage1/Makefile.in +++ b/stage1/Makefile.in @@ -67,6 +67,8 @@ GRUB_LIBS = @GRUB_LIBS@ LD = @LD@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ +NET_CFLAGS = @NET_CFLAGS@ +NET_EXTRAFLAGS = @NET_EXTRAFLAGS@ OBJCOPY = @OBJCOPY@ PACKAGE = @PACKAGE@ PERL = @PERL@ diff --git a/stage1/stage1.S b/stage1/stage1.S index c0a23556b..f615d3672 100644 --- a/stage1/stage1.S +++ b/stage1/stage1.S @@ -398,7 +398,7 @@ lastlist: #else .long 1 /* this is the sector start parameter, in logical sectors from the start of the disk, sector 0 */ - .word 110 /* this is the number of sectors to read */ + .word 130 /* this is the number of sectors to read */ .word 0x0800 /* this is the segment of the starting address to load the data into */ #endif diff --git a/stage1/stage1_lba.S b/stage1/stage1_lba.S index 933c362f4..8e9777f1d 100644 --- a/stage1/stage1_lba.S +++ b/stage1/stage1_lba.S @@ -345,7 +345,7 @@ lastlist: #else .long 1 /* this is the sector start parameter, in logical sectors from the start of the disk, sector 0 */ - .word 110 /* this is the number of sectors to read */ + .word 130 /* this is the number of sectors to read */ .word 0x0800 /* this is the segment of the starting address to load the data into */ #endif diff --git a/stage2/Makefile.am b/stage2/Makefile.am index 1cda8ccfc..e76ba908b 100644 --- a/stage2/Makefile.am +++ b/stage2/Makefile.am @@ -43,6 +43,10 @@ stage2_exec_SOURCES = asm.S bios.c boot.c builtins.c common.c \ stage2_exec_CFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) stage2_exec_LDFLAGS = $(STAGE2_LINK) +if NETBOOT_SUPPORT +stage2_exec_LDADD = ../netboot/libdrivers.a +endif + # For e2fs_stage1_5 target. e2fs_stage1_5_exec_SOURCES = asm.S common.c char_io.c disk_io.c \ stage1_5.c fsys_ext2fs.c bios.c diff --git a/stage2/Makefile.in b/stage2/Makefile.in index c3658a3c6..c0130a95a 100644 --- a/stage2/Makefile.in +++ b/stage2/Makefile.in @@ -67,6 +67,8 @@ GRUB_LIBS = @GRUB_LIBS@ LD = @LD@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ +NET_CFLAGS = @NET_CFLAGS@ +NET_EXTRAFLAGS = @NET_EXTRAFLAGS@ OBJCOPY = @OBJCOPY@ PACKAGE = @PACKAGE@ PERL = @PERL@ @@ -132,6 +134,8 @@ stage2_exec_SOURCES = asm.S bios.c boot.c builtins.c common.c \ stage2_exec_CFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) stage2_exec_LDFLAGS = $(STAGE2_LINK) +@NETBOOT_SUPPORT_TRUE@stage2_exec_LDADD = @NETBOOT_SUPPORT_TRUE@../netboot/libdrivers.a + # For e2fs_stage1_5 target. e2fs_stage1_5_exec_SOURCES = asm.S common.c char_io.c disk_io.c \ stage1_5.c fsys_ext2fs.c bios.c @@ -223,8 +227,8 @@ stage2_exec-gunzip.o stage2_exec-fsys_ext2fs.o stage2_exec-fsys_fat.o \ stage2_exec-fsys_ffs.o stage2_exec-fsys_minix.o stage2_exec-smp-imps.o \ stage2_exec-stage2.o stage2_exec_OBJECTS = $(am_stage2_exec_OBJECTS) -stage2_exec_LDADD = $(LDADD) -stage2_exec_DEPENDENCIES = +@NETBOOT_SUPPORT_TRUE@stage2_exec_DEPENDENCIES = \ +@NETBOOT_SUPPORT_TRUE@../netboot/libdrivers.a SCRIPTS = $(noinst_SCRIPTS) COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) diff --git a/stage2/asm.S b/stage2/asm.S index 6a23c6e1e..4e26fa918 100644 --- a/stage2/asm.S +++ b/stage2/asm.S @@ -1328,6 +1328,37 @@ gottime: pop %ebp ret + +#ifndef STAGE1_5 +/* + * currticks() + * return the real time in ticks, of which there are about + * 18-20 per second + */ +ENTRY(currticks) + pushl %ebp + pushl %ecx + pushl %edx + + call EXT_C(prot_to_real) /* enter real mode */ + .code16 + + xorl %eax, %eax + int $0x1a + + DATA32 call EXT_C(real_to_prot) + .code32 + + shll $16, %ecx + movl %edx, %eax + orl %ecx, %eax + + popl %edx + popl %ecx + popl %ebp + ret +#endif /* ! STAGE1_5 */ + /* * getkey() diff --git a/stage2/char_io.c b/stage2/char_io.c index cfeaa9f02..e076f40e2 100644 --- a/stage2/char_io.c +++ b/stage2/char_io.c @@ -126,6 +126,53 @@ grub_printf (const char *format,...) } +#ifndef STAGE1_5 +int +grub_sprintf (char *buffer, const char *format, ...) +{ + /* XXX hohmuth + ugly hack -- should unify with printf() */ + int *dataptr = (int *) &format; + char c, *ptr, str[16]; + char *bp = buffer; + + dataptr++; + + while ((c = *format++) != 0) + { + if (c != '%') + *bp++ = c; /* putchar(c); */ + else + switch (c = *(format++)) + { + case 'd': case 'u': case 'x': + *convert_to_ascii (str, c, *((unsigned long *) dataptr++)) = 0; + + ptr = str; + + while (*ptr) + *bp++ = *(ptr++); /* putchar(*(ptr++)); */ + break; + + case 'c': *bp++ = (*(dataptr++))&0xff; + /* putchar((*(dataptr++))&0xff); */ + break; + + case 's': + ptr = (char *) (*(dataptr++)); + + while ((c = *ptr++) != 0) + *bp++ = c; /* putchar(c); */ + break; + } + } + + *bp = 0; + return bp - buffer; +} +#endif /* ! STAGE1_5 */ + + #ifndef STAGE1_5 void @@ -520,6 +567,24 @@ grub_isspace (int c) return 0; } +#ifndef STAGE1_5 +int +grub_memcmp (const char *s1, const char *s2, int n) +{ + while (n) + { + if (*s1 < *s2) + return -1; + else if (*s1 > *s2) + return 1; + s1++; + s2++; + n--; + } + + return 0; +} +#endif /* ! STAGE1_5 */ #if 0 int diff --git a/stage2/disk_io.c b/stage2/disk_io.c index 23fc821f2..cba6d1a4c 100644 --- a/stage2/disk_io.c +++ b/stage2/disk_io.c @@ -35,6 +35,10 @@ int print_possibilities; int fsmax; struct fsys_entry fsys_table[NUM_FSYS + 1] = { + /* TFTP should come first because others don't handle net device. */ +# ifdef FSYS_TFTP + {"tftp", tftp_mount, tftp_read, tftp_dir}, +# endif # ifdef FSYS_FAT {"fat", fat_mount, 0, fat_dir}, # endif @@ -236,6 +240,12 @@ devread (int sector, int byte_offset, int byte_len, char *buf) static int sane_partition (void) { +#ifndef STAGE1_5 + /* network drive */ + if (current_drive == 0x20) + return 1; +#endif + if (!(current_partition & 0xFF000000uL) && (current_drive & 0xFFFFFF7F) < 8 && (current_partition & 0xFF) == 0xFF @@ -440,6 +450,10 @@ real_open_partition (int flags) int i, part_no, slice_no, ext = 0; #ifndef STAGE1_5 + /* network drive */ + if (current_drive == 0x20) + return 1; + if (! sane_partition ()) return 0; #endif @@ -674,15 +688,20 @@ set_device (char *device) } #endif - if ((*device == 'f' || *device == 'h') + if ((*device == 'f' || *device == 'h' || *device == 'n') && (device += 2, (*(device - 1) != 'd'))) errnum = ERR_NUMBER_PARSING; - safe_parse_maxint (&device, (int *) ¤t_drive); - - disk_choice = 0; - if (ch == 'h') - current_drive += 0x80; + if (ch == 'n') + current_drive = 0x20; + else + { + safe_parse_maxint (&device, (int *) ¤t_drive); + + disk_choice = 0; + if (ch == 'h') + current_drive += 0x80; + } } if (errnum) diff --git a/stage2/filesys.h b/stage2/filesys.h index b8e5beb5f..de62b594f 100644 --- a/stage2/filesys.h +++ b/stage2/filesys.h @@ -60,9 +60,19 @@ int minix_dir (char *dirname); #define FSYS_MINIX_NUM 0 #endif +#ifdef FSYS_TFTP +#define FSYS_TFTP_NUM 1 +int tftp_mount (void); +int tftp_read (char *buf, int len); +int tftp_dir (char *dirname); +#else +#define FSYS_TFTP_NUM 0 +#endif + #ifndef NUM_FSYS #define NUM_FSYS \ - (FSYS_FFS_NUM + FSYS_FAT_NUM + FSYS_EXT2FS_NUM + FSYS_MINIX_NUM) + (FSYS_FFS_NUM + FSYS_FAT_NUM + FSYS_EXT2FS_NUM + FSYS_MINIX_NUM \ + + FSYS_TFTP_NUM) #endif /* defines for the block filesystem info area */ diff --git a/stage2/gunzip.c b/stage2/gunzip.c index b8061adc6..15fb84540 100644 --- a/stage2/gunzip.c +++ b/stage2/gunzip.c @@ -269,7 +269,11 @@ int gunzip_test_header (void) { unsigned char buf[10]; + int is_tftp = 0; + if (grub_strcmp (fsys_table[fsys_type].name, "tftp") == 0) + is_tftp = 1; + /* "compressed_file" is already reset to zero by this point */ /* @@ -277,12 +281,13 @@ gunzip_test_header (void) * (other than a real error with the disk) then we don't think it * is a compressed file, and simply mark it as such. */ - if (no_decompression || grub_read (buf, 10) != 10 + if (no_decompression + || grub_read (buf, 10) != 10 || ((*((unsigned short *) buf) != GZIP_HDR_LE) - & (*((unsigned short *) buf) != OLD_GZIP_HDR_LE))) + && (*((unsigned short *) buf) != OLD_GZIP_HDR_LE))) { filepos = 0; - return (!errnum); + return ! errnum; } /* @@ -290,23 +295,44 @@ gunzip_test_header (void) * problem occurs from here on, then we have corrupt or otherwise * bad data, and the error should be reported to the user. */ - if (buf[2] != DEFLATED || (buf[3] & UNSUPP_FLAGS) + if (buf[2] != DEFLATED + || (buf[3] & UNSUPP_FLAGS) || ((buf[3] & EXTRA_FIELD) - && (grub_read (buf, 2) != 2 || - bad_field (*((unsigned short *) buf)))) + && (grub_read (buf, 2) != 2 + || bad_field (*((unsigned short *) buf)))) || ((buf[3] & ORIG_NAME) && bad_field (-1)) - || ((buf[3] & COMMENT) && bad_field (-1)) - || ((gzip_data_offset = filepos), (filepos = filemax - 8), - (grub_read (buf, 8) != 8))) + || ((buf[3] & COMMENT) && bad_field (-1))) { - if (!errnum) + if (! errnum) errnum = ERR_BAD_GZIP_HEADER; - + return 0; } - gzip_crc = *((unsigned long *) buf); - gzip_fsmax = gzip_filemax = *((unsigned long *) (buf + 4)); + gzip_data_offset = filepos; + + if (! is_tftp) + filepos = filemax - 8; + + if (grub_read (buf, 8) != 8) + { + if (! errnum) + errnum = ERR_BAD_GZIP_HEADER; + + return 0; + } + + if (! is_tftp) + { + gzip_crc = *((unsigned long *) buf); + gzip_fsmax = gzip_filemax = *((unsigned long *) (buf + 4)); + } + else + { + /* We don't have gzip_crc. */ + gzip_fsmax = gzip_filemax = 16 * 1024 * 1024; + filepos = filemax; + } initialize_tables (); diff --git a/stage2/shared.h b/stage2/shared.h index 6d4ed4612..038b548fd 100644 --- a/stage2/shared.h +++ b/stage2/shared.h @@ -263,10 +263,12 @@ extern char *grub_scratch_mem; #define memset grub_memset #define isspace grub_isspace #define printf grub_printf +#define sprintf grub_sprintf #undef putchar #define putchar grub_putchar #define strncat grub_strncat #define strstr grub_strstr +#define memcmp grub_memcmp #define strcmp grub_strcmp #define tolower grub_tolower #define strlen grub_strlen @@ -494,6 +496,7 @@ int get_code_end (void); /* low-level timing info */ int getrtsecs (void); +int currticks (void); /* Clear the screen. */ void cls (void); @@ -585,12 +588,14 @@ int run_script (char *script, char *heap); /* C library replacement functions with identical semantics. */ void grub_printf (const char *format,...); +int grub_sprintf (char *buffer, const char *format, ...); int grub_tolower (int c); int grub_isspace (int c); int grub_strncat (char *s1, const char *s2, int n); char *grub_memmove (char *to, const char *from, int len); void *grub_memset (void *start, int c, int len); char *grub_strstr (const char *s1, const char *s2); +int grub_memcmp (const char *s1, const char *s2, int n); int grub_strcmp (const char *s1, const char *s2); int grub_strlen (const char *str); diff --git a/stage2/size_test b/stage2/size_test index 68710904f..e5e6ada9a 100644 --- a/stage2/size_test +++ b/stage2/size_test @@ -52,7 +52,7 @@ check minix_stage1_5 31744 # This limitation is arbitrary; If you want to make this larger, just # modify Stage 1. -check stage2 56320 +check stage2 66560 # Success. exit 0