From 1cef34125c07277f10e6f4b81b6a912e28084e22 Mon Sep 17 00:00:00 2001 From: Alexei Svitkine Date: Sat, 6 Jun 2015 12:15:29 -0400 Subject: [PATCH] Add Etherner drive source code and CodeWarrior project file, from: https://web.archive.org/web/20131124123749/http://gwenole.beauchesne.free.fr/sheepshaver/files/SheepShaver-Ethernet.tar.bz2 The project can be used in CodeWarrior to build a binary blob that can then be converted into EthernetDriverFull.i by hexconv.cpp. --- SheepShaver/src/EthernetDriver/.finf/Ethernet | Bin 0 -> 32 bytes .../src/EthernetDriver/.finf/Ethernet Data | Bin 0 -> 32 bytes .../src/EthernetDriver/.finf/Ethernet.cpp | Bin 0 -> 32 bytes .../src/EthernetDriver/.finf/cpu_emulation.h | Bin 0 -> 32 bytes SheepShaver/src/EthernetDriver/.finf/debug.h | Bin 0 -> 32 bytes .../src/EthernetDriver/.finf/ether.cpp | Bin 0 -> 32 bytes SheepShaver/src/EthernetDriver/.finf/ether.h | Bin 0 -> 32 bytes .../src/EthernetDriver/.finf/ether_defs.h | Bin 0 -> 32 bytes .../src/EthernetDriver/.finf/ethernet.ndrv | Bin 0 -> 32 bytes .../src/EthernetDriver/.finf/macos_util.cpp | Bin 0 -> 32 bytes .../src/EthernetDriver/.finf/macos_util.h | Bin 0 -> 32 bytes .../src/EthernetDriver/.finf/sysdeps.h | Bin 0 -> 32 bytes .../src/EthernetDriver/.finf/xlowmem.h | Bin 0 -> 32 bytes .../src/EthernetDriver/.rsrc/Ethernet.cpp | Bin 0 -> 410 bytes .../src/EthernetDriver/.rsrc/cpu_emulation.h | Bin 0 -> 410 bytes SheepShaver/src/EthernetDriver/.rsrc/debug.h | Bin 0 -> 410 bytes .../src/EthernetDriver/.rsrc/ether.cpp | Bin 0 -> 410 bytes SheepShaver/src/EthernetDriver/.rsrc/ether.h | Bin 0 -> 410 bytes .../src/EthernetDriver/.rsrc/ether_defs.h | Bin 0 -> 410 bytes .../src/EthernetDriver/.rsrc/ethernet.ndrv | Bin 0 -> 398 bytes .../src/EthernetDriver/.rsrc/macos_util.cpp | Bin 0 -> 410 bytes .../src/EthernetDriver/.rsrc/macos_util.h | Bin 0 -> 410 bytes .../src/EthernetDriver/.rsrc/sysdeps.h | Bin 0 -> 410 bytes .../Ethernet Data/.finf/CWSettingsMacOS.stg | Bin 0 -> 32 bytes .../.finf/PPC Debug MacOS Toolbox | Bin 0 -> 32 bytes .../.finf/PPC Final MacOS Toolbox | Bin 0 -> 32 bytes .../Ethernet Data/CWSettingsMacOS.stg | Bin 0 -> 4344 bytes .../.finf/TargetDataMacOS.tdt | Bin 0 -> 32 bytes .../.rsrc/TargetDataMacOS.tdt | Bin 0 -> 286 bytes .../TargetDataMacOS.tdt | Bin 0 -> 46180 bytes .../.finf/TargetDataMacOS.tdt | Bin 0 -> 32 bytes .../.rsrc/TargetDataMacOS.tdt | Bin 0 -> 286 bytes .../TargetDataMacOS.tdt | Bin 0 -> 46304 bytes SheepShaver/src/EthernetDriver/Ethernet.cpp | 308 +++ SheepShaver/src/EthernetDriver/Ethernet.mcp | Bin 0 -> 103293 bytes .../src/EthernetDriver/cpu_emulation.h | 1 + SheepShaver/src/EthernetDriver/debug.h | 1 + SheepShaver/src/EthernetDriver/ether.cpp | 1734 +++++++++++++++++ SheepShaver/src/EthernetDriver/ether.h | 113 ++ SheepShaver/src/EthernetDriver/ether_defs.h | 552 ++++++ SheepShaver/src/EthernetDriver/ethernet.ndrv | Bin 0 -> 11316 bytes SheepShaver/src/EthernetDriver/macos_util.cpp | 1 + SheepShaver/src/EthernetDriver/macos_util.h | 1 + SheepShaver/src/EthernetDriver/sysdeps.h | 1 + SheepShaver/src/EthernetDriver/xlowmem.h | 64 + 45 files changed, 2776 insertions(+) create mode 100644 SheepShaver/src/EthernetDriver/.finf/Ethernet create mode 100644 SheepShaver/src/EthernetDriver/.finf/Ethernet Data create mode 100644 SheepShaver/src/EthernetDriver/.finf/Ethernet.cpp create mode 100644 SheepShaver/src/EthernetDriver/.finf/cpu_emulation.h create mode 100644 SheepShaver/src/EthernetDriver/.finf/debug.h create mode 100644 SheepShaver/src/EthernetDriver/.finf/ether.cpp create mode 100644 SheepShaver/src/EthernetDriver/.finf/ether.h create mode 100644 SheepShaver/src/EthernetDriver/.finf/ether_defs.h create mode 100644 SheepShaver/src/EthernetDriver/.finf/ethernet.ndrv create mode 100644 SheepShaver/src/EthernetDriver/.finf/macos_util.cpp create mode 100644 SheepShaver/src/EthernetDriver/.finf/macos_util.h create mode 100644 SheepShaver/src/EthernetDriver/.finf/sysdeps.h create mode 100644 SheepShaver/src/EthernetDriver/.finf/xlowmem.h create mode 100644 SheepShaver/src/EthernetDriver/.rsrc/Ethernet.cpp create mode 100644 SheepShaver/src/EthernetDriver/.rsrc/cpu_emulation.h create mode 100644 SheepShaver/src/EthernetDriver/.rsrc/debug.h create mode 100644 SheepShaver/src/EthernetDriver/.rsrc/ether.cpp create mode 100644 SheepShaver/src/EthernetDriver/.rsrc/ether.h create mode 100644 SheepShaver/src/EthernetDriver/.rsrc/ether_defs.h create mode 100644 SheepShaver/src/EthernetDriver/.rsrc/ethernet.ndrv create mode 100644 SheepShaver/src/EthernetDriver/.rsrc/macos_util.cpp create mode 100644 SheepShaver/src/EthernetDriver/.rsrc/macos_util.h create mode 100644 SheepShaver/src/EthernetDriver/.rsrc/sysdeps.h create mode 100644 SheepShaver/src/EthernetDriver/Ethernet Data/.finf/CWSettingsMacOS.stg create mode 100644 SheepShaver/src/EthernetDriver/Ethernet Data/.finf/PPC Debug MacOS Toolbox create mode 100644 SheepShaver/src/EthernetDriver/Ethernet Data/.finf/PPC Final MacOS Toolbox create mode 100644 SheepShaver/src/EthernetDriver/Ethernet Data/CWSettingsMacOS.stg create mode 100644 SheepShaver/src/EthernetDriver/Ethernet Data/PPC Debug MacOS Toolbox/.finf/TargetDataMacOS.tdt create mode 100644 SheepShaver/src/EthernetDriver/Ethernet Data/PPC Debug MacOS Toolbox/.rsrc/TargetDataMacOS.tdt create mode 100644 SheepShaver/src/EthernetDriver/Ethernet Data/PPC Debug MacOS Toolbox/TargetDataMacOS.tdt create mode 100644 SheepShaver/src/EthernetDriver/Ethernet Data/PPC Final MacOS Toolbox/.finf/TargetDataMacOS.tdt create mode 100644 SheepShaver/src/EthernetDriver/Ethernet Data/PPC Final MacOS Toolbox/.rsrc/TargetDataMacOS.tdt create mode 100644 SheepShaver/src/EthernetDriver/Ethernet Data/PPC Final MacOS Toolbox/TargetDataMacOS.tdt create mode 100644 SheepShaver/src/EthernetDriver/Ethernet.cpp create mode 100644 SheepShaver/src/EthernetDriver/Ethernet.mcp create mode 100644 SheepShaver/src/EthernetDriver/cpu_emulation.h create mode 100644 SheepShaver/src/EthernetDriver/debug.h create mode 100644 SheepShaver/src/EthernetDriver/ether.cpp create mode 100644 SheepShaver/src/EthernetDriver/ether.h create mode 100644 SheepShaver/src/EthernetDriver/ether_defs.h create mode 100644 SheepShaver/src/EthernetDriver/ethernet.ndrv create mode 100644 SheepShaver/src/EthernetDriver/macos_util.cpp create mode 100644 SheepShaver/src/EthernetDriver/macos_util.h create mode 100644 SheepShaver/src/EthernetDriver/sysdeps.h create mode 100644 SheepShaver/src/EthernetDriver/xlowmem.h diff --git a/SheepShaver/src/EthernetDriver/.finf/Ethernet b/SheepShaver/src/EthernetDriver/.finf/Ethernet new file mode 100644 index 0000000000000000000000000000000000000000..07b9b6a81ae87b1e58a60cacb95bb48fc00bd657 GIT binary patch literal 32 XcmebE4JdLB_jF}sU}#_j66gQ`Qp5uY literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/.finf/Ethernet Data b/SheepShaver/src/EthernetDriver/.finf/Ethernet Data new file mode 100644 index 0000000000000000000000000000000000000000..c90c8351a1cdb369364406121dea19aba532aa61 GIT binary patch literal 32 acmZQzfB@zPj0_BnjO-xZVF!p9hy(y39s%(H literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/.finf/Ethernet.cpp b/SheepShaver/src/EthernetDriver/.finf/Ethernet.cpp new file mode 100644 index 0000000000000000000000000000000000000000..468e347d2375853ebe0bfafbb9bcdbd189299e6f GIT binary patch literal 32 XcmWG>jR* literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/.finf/cpu_emulation.h b/SheepShaver/src/EthernetDriver/.finf/cpu_emulation.h new file mode 100644 index 0000000000000000000000000000000000000000..0f9350b2d9043b00b05dbe796393d747ef499ed4 GIT binary patch literal 32 XcmWG>jRjRjR*jR*jR*{R literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/.finf/macos_util.cpp b/SheepShaver/src/EthernetDriver/.finf/macos_util.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d9cb0d5403722e0667ea74ac77143ea0c131addf GIT binary patch literal 32 XcmWG>jRRbm4$ literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/.finf/macos_util.h b/SheepShaver/src/EthernetDriver/.finf/macos_util.h new file mode 100644 index 0000000000000000000000000000000000000000..c13d137a708ff59369b5d8fff8524f8c919e91d7 GIT binary patch literal 32 XcmWG>jRjRRdxe0 literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/.finf/xlowmem.h b/SheepShaver/src/EthernetDriver/.finf/xlowmem.h new file mode 100644 index 0000000000000000000000000000000000000000..47ae769e884243fa9f05c42effee7eaf005bfae6 GIT binary patch literal 32 XcmWG>jR*kaQf!wB_`+N@i-F$3qvM@J`*$3QW(AOo$O==2L3i6 zZf9T+-~)vtP!%I6KvBa~E@_qkLl{t21{l7Kz5&5OK(>%?xRVo*mScYV|38oh1LhB4 IwhxE{0H>oBaR2}S literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/.rsrc/cpu_emulation.h b/SheepShaver/src/EthernetDriver/.rsrc/cpu_emulation.h new file mode 100644 index 0000000000000000000000000000000000000000..ad39a249f0d166d63de5684b7aaeb24dec196748 GIT binary patch literal 410 zcmZQzU}RumUkaQf!wB_`+N@i-F$3quNnB$GQ+HjLi)_Ov8W$7Lu6 zha*rGBZz?-rh0+r6&POu)yV+Em(e#MI0(oV@(p)#0@8BKZ~y-X(qO>+0nGLRaRB%T B7PtTa literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/.rsrc/debug.h b/SheepShaver/src/EthernetDriver/.rsrc/debug.h new file mode 100644 index 0000000000000000000000000000000000000000..d802217225a33ff17e8c97b74d9c3bf3691a9311 GIT binary patch literal 410 zcmZQzU}RumUkaQf!wB_`+N@i-F$3qu)$9FrGQ0gT@F_VhZSj!-BD zha*rGBZz?-rh0+r6&Qqo>STc7%jg>r90X(w`Gz|=0cknrxBveGX)s{^0A~AuH~`3f B6}A8X literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/.rsrc/ether.cpp b/SheepShaver/src/EthernetDriver/.rsrc/ether.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6b48328656c1708c26e807b929daded957bdf01e GIT binary patch literal 410 zcmZQzU}RumUkaQf!wB_`+N@i-F$3xfs&7vmwO1{l5XomwHX4p2A( zRWX7B6g5oc689cphyu#W0K=EjHy}6&$QJSqcX9&Ka?Ef4{|C}w!2AKs_5pDKfeRH& literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/.rsrc/ether.h b/SheepShaver/src/EthernetDriver/.rsrc/ether.h new file mode 100644 index 0000000000000000000000000000000000000000..510308e19676c79180376e8a6965d56547460f70 GIT binary patch literal 410 zcmZQzU}RumUkaQf!wB_`+N@i-F$3qwCcB$Fo7c^JL#oy=ke239)= zW}g5GN1!T3P=KO_sb2I=14bdBtPC)G8GQqSgMe%y-*6`kaQf!wB_`+N@i-F$3qu8iEt3$_W*EKi&ErW743g&| zSU3R`jzCq6pa4Y;Q@x;_28?Y$Ss7sXGWrGt2LahazTr+zKw6IZ?f?Hk8Vr~}fZ0AE F4giOq7!m*g literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/.rsrc/ethernet.ndrv b/SheepShaver/src/EthernetDriver/.rsrc/ethernet.ndrv new file mode 100644 index 0000000000000000000000000000000000000000..63653eda90f5d8e837d4382137fe949f517a6ea2 GIT binary patch literal 398 zcmZQzU}RumV2lA0AZ!H0BMn3#c^DKJ=zy`HydW7}5Xi?=Yr&gZl95`Jms+Bimr_&) lQGy6txx~E(7>a;8WkBJaoK}<$WOFev{QnO!T`p<94gfd$5i0-y literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/.rsrc/macos_util.cpp b/SheepShaver/src/EthernetDriver/.rsrc/macos_util.cpp new file mode 100644 index 0000000000000000000000000000000000000000..23ff9840b173b76ddb697e4a37db895ba4caa7af GIT binary patch literal 410 zcmZQzU}RumUkaQf!wB_`+N@i-F$3xhdB7?V5G3K+fbozMdY2CknF z3=Bh%b`~H7WT1wrUd-_e3|T-~8DRJ_`UV6C0og*n;Z9CKT8{bc|NlT5446NF**+i+ E0A(5%^8f$< literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/.rsrc/macos_util.h b/SheepShaver/src/EthernetDriver/.rsrc/macos_util.h new file mode 100644 index 0000000000000000000000000000000000000000..2f5014423c79d1e5ca861644c798355a6f521964 GIT binary patch literal 410 zcmZQzU}RumUkaQf!wB_`+N@i-F$3qulv5#t}G6)<|=I~g$s2KE97 zW_=F|N1!T3P=KO_sb2I=1BP8dSs7sXGWrGt2LahazTr+zKw6IZ?f?Hk8Vr~}fZ0AE F4gi;u7)Ag9 literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/.rsrc/sysdeps.h b/SheepShaver/src/EthernetDriver/.rsrc/sysdeps.h new file mode 100644 index 0000000000000000000000000000000000000000..4f537acf8e5a67c8fe394623e623209bb261a36a GIT binary patch literal 410 zcmZQzU}RumUkaQf!wB_`+N@i-F$3xfs&7vmwO1{l5Xo$Owqj+0Of z4o9FWMi2uvO!X4#6&St&)yV+Em(e#MI0(oV@(p)#0@8BKZ~y-X(qO>+0nGLRaR3&T B7VQ84 literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/Ethernet Data/.finf/CWSettingsMacOS.stg b/SheepShaver/src/EthernetDriver/Ethernet Data/.finf/CWSettingsMacOS.stg new file mode 100644 index 0000000000000000000000000000000000000000..2c25cdbdb1112cee1ca86ec8cff8942b51e4be7c GIT binary patch literal 32 RcmWG>aSU+|_jF~z0RTd#0#*P3 literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/Ethernet Data/.finf/PPC Debug MacOS Toolbox b/SheepShaver/src/EthernetDriver/Ethernet Data/.finf/PPC Debug MacOS Toolbox new file mode 100644 index 0000000000000000000000000000000000000000..4e4e4935707a596987ec1cc32e3d0d587dbe4f04 GIT binary patch literal 32 KcmZQzzz+ZbAOHaX literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/Ethernet Data/.finf/PPC Final MacOS Toolbox b/SheepShaver/src/EthernetDriver/Ethernet Data/.finf/PPC Final MacOS Toolbox new file mode 100644 index 0000000000000000000000000000000000000000..4e4e4935707a596987ec1cc32e3d0d587dbe4f04 GIT binary patch literal 32 KcmZQzzz+ZbAOHaX literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/Ethernet Data/CWSettingsMacOS.stg b/SheepShaver/src/EthernetDriver/Ethernet Data/CWSettingsMacOS.stg new file mode 100644 index 0000000000000000000000000000000000000000..7848ef0bfd9293284e5d924000b90d76e0b1cf39 GIT binary patch literal 4344 zcmeHK&o9J46n^d2mJlR}#Hlyp;OruiEH+}X*C5i#Xz#nBG-4J_`pDuG8fyVwB%NX8< zv`f$}(q4kjN?WO)F_7}jobo&{=PB1ei}<}>JbxCRb@|&Ywa)AiH6Pv3YpjnrX|!}L zaBec^Oun>Gl=oAV@YIt6s^MI7ol7 zn6oCtN>sIyQ@MgOe8t<2hG3G7UQUmvlJ2V$P#HJ8M>zkw}l eKoc>Iy~O`E4_wyX9ZhsyX1wj<(g%)ui|7Rrv4Twi literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/Ethernet Data/PPC Debug MacOS Toolbox/.finf/TargetDataMacOS.tdt b/SheepShaver/src/EthernetDriver/Ethernet Data/PPC Debug MacOS Toolbox/.finf/TargetDataMacOS.tdt new file mode 100644 index 0000000000000000000000000000000000000000..2c25cdbdb1112cee1ca86ec8cff8942b51e4be7c GIT binary patch literal 32 RcmWG>aSU+|_jF~z0RTd#0#*P3 literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/Ethernet Data/PPC Debug MacOS Toolbox/.rsrc/TargetDataMacOS.tdt b/SheepShaver/src/EthernetDriver/Ethernet Data/PPC Debug MacOS Toolbox/.rsrc/TargetDataMacOS.tdt new file mode 100644 index 0000000000000000000000000000000000000000..7c9986b9e0bcfb616df3c616ba39e2f18aa1a8a6 GIT binary patch literal 286 ecmZQzU}RtbV<5%AAO|K#6oJG4G7NJ6{{sLh?E-lK literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/Ethernet Data/PPC Debug MacOS Toolbox/TargetDataMacOS.tdt b/SheepShaver/src/EthernetDriver/Ethernet Data/PPC Debug MacOS Toolbox/TargetDataMacOS.tdt new file mode 100644 index 0000000000000000000000000000000000000000..48fe5d703923e17c899a20b29a62202c67d6bb8b GIT binary patch literal 46180 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 literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/Ethernet Data/PPC Final MacOS Toolbox/.finf/TargetDataMacOS.tdt b/SheepShaver/src/EthernetDriver/Ethernet Data/PPC Final MacOS Toolbox/.finf/TargetDataMacOS.tdt new file mode 100644 index 0000000000000000000000000000000000000000..2c25cdbdb1112cee1ca86ec8cff8942b51e4be7c GIT binary patch literal 32 RcmWG>aSU+|_jF~z0RTd#0#*P3 literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/Ethernet Data/PPC Final MacOS Toolbox/.rsrc/TargetDataMacOS.tdt b/SheepShaver/src/EthernetDriver/Ethernet Data/PPC Final MacOS Toolbox/.rsrc/TargetDataMacOS.tdt new file mode 100644 index 0000000000000000000000000000000000000000..7c9986b9e0bcfb616df3c616ba39e2f18aa1a8a6 GIT binary patch literal 286 ecmZQzU}RtbV<5%AAO|K#6oJG4G7NJ6{{sLh?E-lK literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/Ethernet Data/PPC Final MacOS Toolbox/TargetDataMacOS.tdt b/SheepShaver/src/EthernetDriver/Ethernet Data/PPC Final MacOS Toolbox/TargetDataMacOS.tdt new file mode 100644 index 0000000000000000000000000000000000000000..cdb3ae7c538a7cb15e14bbe16d1b473ea3eb2c97 GIT binary patch literal 46304 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 +#include "xlowmem.h" +#include "ether_defs.h" + + +// Macro for tail-calling native code from assembly functions +#define ASM_TAIL_CALL_NATIVE(NAME) \ + lwz r0,XLM_##NAME(r0) ;\ + lwz r2,XLM_TOC(r0) ;\ + mtctr r0 ;\ + bctr + +// Macro for calling native code from assembly functions +#define ASM_CALL_NATIVE(NAME) \ + mflr r0 ;\ + stw r2,12(r1) ;\ + stw r0,8(r1) ;\ + stwu r1,-64(r1) ;\ + lwz r0,XLM_##NAME(r0) ;\ + lwz r2,XLM_TOC(r0) ;\ + mtlr r0 ;\ + blrl ;\ + lwz r0,64+8(r1) ;\ + lwz r2,64+12(r1) ;\ + mtlr r0 ;\ + addi r1,r1,64 ;\ + blr + + +/* + * Driver Description structure + */ + +struct DriverDescription { + uint32 driverDescSignature; + uint32 driverDescVersion; + char nameInfoStr[32]; + uint32 version; + uint32 driverRuntime; + char driverName[32]; + uint32 driverDescReserved[8]; + uint32 nServices; + uint32 serviceCategory; + uint32 serviceType; + uint32 serviceVersion; +}; + +#pragma export on +DriverDescription TheDriverDescription = { + 'mtej', + 0, + "\pSheepShaver Ethernet", + 0x01008000, // V1.0.0final + 4, // kDriverIsUnderExpertControl + "\penet", + 0, 0, 0, 0, 0, 0, 0, 0, + 1, + 'otan', + 0x000a0b01, // Ethernet, Framing: Ethernet/EthernetIPX/802.2, IsDLPI + 0x01000000, // V1.0.0 +}; +#pragma export off + + +/* + * install_info and related structures + */ + +#ifdef BUILD_ETHER_FULL_DRIVER +#define ETHERDECL extern +#else +#define ETHERDECL static +#endif + +ETHERDECL int ether_open(queue_t *rdq, void *dev, int flag, int sflag, void *creds); +ETHERDECL int ether_close(queue_t *rdq, int flag, void *creds); +ETHERDECL int ether_wput(queue_t *q, msgb *mp); +ETHERDECL int ether_wsrv(queue_t *q); +ETHERDECL int ether_rput(queue_t *q, msgb *mp); +ETHERDECL int ether_rsrv(queue_t *q); + +struct ot_module_info { + uint16 mi_idnum; + char *mi_idname; + int32 mi_minpsz; // Minimum packet size + int32 mi_maxpsz; // Maximum packet size + uint32 mi_hiwat; // Queue hi-water mark + uint32 mi_lowat; // Queue lo-water mark +}; + +static ot_module_info module_information = { + kEnetModuleID, + "SheepShaver Ethernet", + 0, + kEnetTSDU, + 6000, + 5000 +}; + +typedef int (*putp_t)(queue_t *, msgb *); +typedef int (*srvp_t)(queue_t *); +typedef int (*openp_t)(queue_t *, void *, int, int, void *); +typedef int (*closep_t)(queue_t *, int, void *); + +struct qinit { + putp_t qi_putp; + srvp_t qi_srvp; + openp_t qi_qopen; + closep_t qi_qclose; + void *qi_qadmin; + struct ot_module_info *qi_minfo; + void *qi_mstat; +}; + +static qinit read_side = { + NULL, + ether_rsrv, + ether_open, + ether_close, + NULL, + &module_information, + NULL +}; + +static qinit write_side = { + ether_wput, + NULL, + ether_open, + ether_close, + NULL, + &module_information, + NULL +}; + +struct streamtab { + struct qinit *st_rdinit; + struct qinit *st_wrinit; + struct qinit *st_muxrinit; + struct qinit *st_muxwinit; +}; + +static streamtab the_streamtab = { + &read_side, + &write_side, + NULL, + NULL +}; + +struct install_info { + struct streamtab *install_str; + uint32 install_flags; + uint32 install_sqlvl; + char *install_buddy; + void *ref_load; + uint32 ref_count; +}; + +enum { + kOTModIsDriver = 0x00000001, + kOTModUpperIsDLPI = 0x00002000, + SQLVL_MODULE = 3, +}; + +static install_info the_install_info = { + &the_streamtab, + kOTModIsDriver /*| kOTModUpperIsDLPI */, + SQLVL_MODULE, + NULL, + NULL, + 0 +}; + + +// Prototypes for exported functions +extern "C" { +#pragma export on +extern uint32 ValidateHardware(void *theID); +extern install_info* GetOTInstallInfo(); +extern uint8 InitStreamModule(void *theID); +extern void TerminateStreamModule(void); +#pragma export off +} + + +/* + * Validate that our hardware is available (always available) + */ + +uint32 ValidateHardware(void *theID) +{ + return 0; +} + + +/* + * Return pointer to install_info structure + */ + +install_info *GetOTInstallInfo(void) +{ + return &the_install_info; +} + +/* + * Init module + */ + +#ifdef BUILD_ETHER_FULL_DRIVER +asm bool NativeInitStreamModule(register void *theID) +{ + ASM_CALL_NATIVE(ETHER_INIT) +} +#else +asm uint8 InitStreamModule(register void *theID) +{ + ASM_TAIL_CALL_NATIVE(ETHER_INIT) +} +#endif + + +/* + * Terminate module + */ + +#ifdef BUILD_ETHER_FULL_DRIVER +asm void NativeTerminateStreamModule(void) +{ + ASM_CALL_NATIVE(ETHER_TERM) +} +#else +asm void TerminateStreamModule(void) +{ + ASM_TAIL_CALL_NATIVE(ETHER_TERM) +} +#endif + + +/* + * DLPI functions + */ + +#ifndef BUILD_ETHER_FULL_DRIVER +static asm int ether_open(register queue_t *rdq, register void *dev, register int flag, register int sflag, register void *creds) +{ + ASM_TAIL_CALL_NATIVE(ETHER_OPEN) +} + +static asm int ether_close(register queue_t *rdq, register int flag, register void *creds) +{ + ASM_TAIL_CALL_NATIVE(ETHER_CLOSE) +} + +static asm int ether_wput(register queue_t *q, register msgb *mp) +{ + ASM_TAIL_CALL_NATIVE(ETHER_WPUT) +} + +static asm int ether_rsrv(register queue_t *q) +{ + ASM_TAIL_CALL_NATIVE(ETHER_RSRV) +} +#endif + + +/* + * Hooks to add-on low-level functions + */ + +asm void AO_get_ethernet_address(register uint32) +{ + ASM_CALL_NATIVE(ETHER_AO_GET_HWADDR) +} + +asm void AO_enable_multicast(register uint32 addr) +{ + ASM_CALL_NATIVE(ETHER_AO_ADD_MULTI) +} + +asm void AO_disable_multicast(register uint32 addr) +{ + ASM_CALL_NATIVE(ETHER_AO_DEL_MULTI) +} + +asm void AO_transmit_packet(register uint32 mp) +{ + ASM_CALL_NATIVE(ETHER_AO_SEND_PACKET) +} diff --git a/SheepShaver/src/EthernetDriver/Ethernet.mcp b/SheepShaver/src/EthernetDriver/Ethernet.mcp new file mode 100644 index 0000000000000000000000000000000000000000..6e14f02ef295d82326ff6262c91b74de8ce5dc08 GIT binary patch literal 103293 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 #define bug printf #endif /* DEBUG_H */ \ No newline at end of file diff --git a/SheepShaver/src/EthernetDriver/ether.cpp b/SheepShaver/src/EthernetDriver/ether.cpp new file mode 100644 index 00000000..71309582 --- /dev/null +++ b/SheepShaver/src/EthernetDriver/ether.cpp @@ -0,0 +1,1734 @@ +/* + * ether.cpp - SheepShaver Ethernet Device Driver (DLPI) + * + * SheepShaver (C) 1997-2005 Marc Hellwig and Christian Bauer + * + * 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. + * + * 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 + */ + +/* + * TODO + * - 802.2 TEST/XID + * - MIB statistics + */ + +#include + +#include "sysdeps.h" +#include "cpu_emulation.h" +#include "ether.h" +#include "ether_defs.h" +#include "macos_util.h" + +#define DEBUG 0 +#include "debug.h" + +// Packet types +enum { + kPktDIX = 0, + kPkt8022SAP = 1, + kPkt8022GroupSAP = 2, + kPkt8022SNAP = 3, + kPktIPX = 4, + kPktUnknown = 5 +}; + + +/* + * Stream private data structure + */ + +static const int kGroupSAPMapSize = 128/32; // Number of 32-bit values we need for 128 bits +static const int kGSshift = 6; +static const int kGSmask = 0x1F; + +struct multicast_node { + nw_multicast_node_p next; + uint8 addr[kEnetPhysicalAddressLength]; +}; + +struct DLPIStream { + void SetGroupSAP(uint8 sap) + { + group_sap[sap >> kGSshift] |= (1L << ((sap >> 1) & kGSmask)); + } + + void ClearGroupSAP(uint8 sap) + { + group_sap[sap >> kGSshift] &= ~(1L << ((sap >> 1) & kGSmask)); + } + + void ClearAllGroupSAPs(void) + { + for (int i=0; i> kGSshift] & (1L << ((sap >> 1) & kGSmask)); + } + + void AddMulticast(uint8 *addr) + { + multicast_node *n = (multicast_node *)Mac2HostAddr(Mac_sysalloc(sizeof(multicast_node))); + memcpy(n->addr, addr, kEnetPhysicalAddressLength); + n->next = multicast_list; + multicast_list = n; + } + + void RemoveMulticast(uint8 *addr) + { + multicast_node *p = multicast_list; + while (p) { + if (memcmp(addr, p->addr, kEnetPhysicalAddressLength) == 0) + goto found; + p = p->next; + } + return; + found: + multicast_node *q = (multicast_node *)&multicast_list; + while (q) { + if (q->next == p) { + q->next = p->next; + Mac_sysfree(Host2MacAddr((uint8 *)p)); + return; + } + q = q->next; + } + } + + uint8 *IsMulticastRegistered(uint8 *addr) + { + multicast_node *n = multicast_list; + while (n) { + if (memcmp(addr, n->addr, kEnetPhysicalAddressLength) == 0) + return n->addr; + n = n->next; + } + return NULL; + } + + nw_uint32 minor_num; // Minor device number of this stream + nw_uint32 dlpi_state; // DLPI state of this stream + nw_uint32 flags; // Flags + nw_uint16 dlsap; // SAP bound to this stream + nw_bool framing_8022; // Using 802.2 framing? This is only used to report the MAC type for DL_INFO_ACK and can be set with an ioctl() call + nw_queue_p rdq; // Read queue for this stream + nw_uint32 group_sap[kGroupSAPMapSize]; // Map of bound group SAPs + uint8 snap[k8022SNAPLength]; // SNAP bound to this stream + nw_multicast_node_p multicast_list; // List of enabled multicast addresses +}; + +// Hack to make DLPIStream list initialization early to NULL (do we really need this?) +struct DLPIStreamInit { + DLPIStreamInit(nw_DLPIStream_p *dlpi_stream_p) { *dlpi_stream_p = NULL; } +}; + +// Stream flags +enum { + kSnapStream = 0x00000001, + kAcceptMulticasts = 0x00000002, + kAcceptAll8022Packets = 0x00000004, + kFastPathMode = 0x00000008 +}; + +// List of opened streams (used internally by OpenTransport) +static nw_DLPIStream_p dlpi_stream_list; +static DLPIStreamInit dlpi_stream_init(&dlpi_stream_list); + +// Are we open? +bool ether_driver_opened = false; + +// Our ethernet hardware address +static uint8 hardware_address[6] = {0, 0, 0, 0, 0, 0}; + +// Statistics +int32 num_wput = 0; +int32 num_error_acks = 0; +int32 num_tx_packets = 0; +int32 num_tx_raw_packets = 0; +int32 num_tx_normal_packets = 0; +int32 num_tx_buffer_full = 0; +int32 num_rx_packets = 0; +int32 num_ether_irq = 0; +int32 num_unitdata_ind = 0; +int32 num_rx_fastpath = 0; +int32 num_rx_no_mem = 0; +int32 num_rx_dropped = 0; +int32 num_rx_stream_not_ready = 0; +int32 num_rx_no_unitdata_mem = 0; + + +// Function pointers of imported functions +typedef mblk_t *(*allocb_ptr)(size_t size, int pri); +static uint32 allocb_tvect = 0; +mblk_t *allocb(size_t arg1, int arg2) +{ + return (mblk_t *)Mac2HostAddr((uint32)CallMacOS2(allocb_ptr, allocb_tvect, arg1, arg2)); +} +typedef void (*freeb_ptr)(mblk_t *); +static uint32 freeb_tvect = 0; +static inline void freeb(mblk_t *arg1) +{ + CallMacOS1(freeb_ptr, freeb_tvect, arg1); +} +typedef int16 (*freemsg_ptr)(mblk_t *); +static uint32 freemsg_tvect = 0; +static inline int16 freemsg(mblk_t *arg1) +{ + return (int16)CallMacOS1(freemsg_ptr, freemsg_tvect, arg1); +} +typedef mblk_t *(*copyb_ptr)(mblk_t *); +static uint32 copyb_tvect = 0; +static inline mblk_t *copyb(mblk_t *arg1) +{ + return (mblk_t *)Mac2HostAddr((uint32)CallMacOS1(copyb_ptr, copyb_tvect, arg1)); +} +typedef mblk_t *(*dupmsg_ptr)(mblk_t *); +static uint32 dupmsg_tvect = 0; +static inline mblk_t *dupmsg(mblk_t *arg1) +{ + return (mblk_t *)Mac2HostAddr((uint32)CallMacOS1(dupmsg_ptr, dupmsg_tvect, arg1)); +} +typedef mblk_t *(*getq_ptr)(queue_t *); +static uint32 getq_tvect = 0; +static inline mblk_t *getq(queue_t *arg1) +{ + return (mblk_t *)Mac2HostAddr((uint32)CallMacOS1(getq_ptr, getq_tvect, arg1)); +} +typedef int (*putq_ptr)(queue_t *, mblk_t *); +static uint32 putq_tvect = 0; +static inline int putq(queue_t *arg1, mblk_t *arg2) +{ + return (int)CallMacOS2(putq_ptr, putq_tvect, arg1, arg2); +} +typedef int (*putnext_ptr)(queue_t *, mblk_t *); +static uint32 putnext_tvect = 0; +static inline int putnext(queue_t *arg1, mblk_t *arg2) +{ + return (int)CallMacOS2(putnext_ptr, putnext_tvect, arg1, arg2); +} +typedef int (*putnextctl1_ptr)(queue_t *, int type, int c); +static uint32 putnextctl1_tvect = 0; +static inline int putnextctl1(queue_t *arg1, int arg2, int arg3) +{ + return (int)CallMacOS3(putnextctl1_ptr, putnextctl1_tvect, arg1, arg2, arg3); +} +typedef int (*canputnext_ptr)(queue_t *); +static uint32 canputnext_tvect = 0; +static inline int canputnext(queue_t *arg1) +{ + return (int)CallMacOS1(canputnext_ptr, canputnext_tvect, arg1); +} +typedef int (*qreply_ptr)(queue_t *, mblk_t *); +static uint32 qreply_tvect = 0; +static inline int qreply(queue_t *arg1, mblk_t *arg2) +{ + return (int)CallMacOS2(qreply_ptr, qreply_tvect, arg1, arg2); +} +typedef void (*flushq_ptr)(queue_t *, int flag); +static uint32 flushq_tvect = 0; +static inline void flushq(queue_t *arg1, int arg2) +{ + CallMacOS2(flushq_ptr, flushq_tvect, arg1, arg2); +} +typedef int (*msgdsize_ptr)(const mblk_t *); +static uint32 msgdsize_tvect = 0; +static inline int msgdsize(const mblk_t *arg1) +{ + return (int)CallMacOS1(msgdsize_ptr, msgdsize_tvect, arg1); +} +typedef void (*otenterint_ptr)(void); +static uint32 otenterint_tvect = 0; +void OTEnterInterrupt(void) +{ + CallMacOS(otenterint_ptr, otenterint_tvect); +} +typedef void (*otleaveint_ptr)(void); +static uint32 otleaveint_tvect = 0; +void OTLeaveInterrupt(void) +{ + CallMacOS(otleaveint_ptr, otleaveint_tvect); +} +typedef int (*mi_open_comm_ptr)(DLPIStream **mi_opp_orig, size_t size, queue_t *q, void *dev, int flag, int sflag, void *credp); +static uint32 mi_open_comm_tvect = 0; +static inline int mi_open_comm(DLPIStream **arg1, size_t arg2, queue_t *arg3, void *arg4, int arg5, int arg6, void *arg7) +{ + return (int)CallMacOS7(mi_open_comm_ptr, mi_open_comm_tvect, arg1, arg2, arg3, arg4, arg5, arg6, arg7); +} +typedef int (*mi_close_comm_ptr)(DLPIStream **mi_opp_orig, queue_t *q); +static uint32 mi_close_comm_tvect = 0; +static inline int mi_close_comm(DLPIStream **arg1, queue_t *arg2) +{ + return (int)CallMacOS2(mi_close_comm_ptr, mi_close_comm_tvect, arg1, arg2); +} +typedef DLPIStream *(*mi_next_ptr_ptr)(DLPIStream *); +static uint32 mi_next_ptr_tvect = 0; +static inline DLPIStream *mi_next_ptr(DLPIStream *arg1) +{ + return (DLPIStream *)Mac2HostAddr((uint32)CallMacOS1(mi_next_ptr_ptr, mi_next_ptr_tvect, arg1)); +} +#ifdef USE_ETHER_FULL_DRIVER +typedef void (*ether_dispatch_packet_ptr)(uint32 p, uint32 size); +static uint32 ether_dispatch_packet_tvect = 0; +#endif + +// Prototypes +static void ether_ioctl(DLPIStream *the_stream, queue_t* q, mblk_t* mp); +static void ether_flush(queue_t* q, mblk_t* mp); +static mblk_t *build_tx_packet_header(DLPIStream *the_stream, mblk_t *mp, bool fast_path); +static void transmit_packet(mblk_t *mp); +static void DLPI_error_ack(DLPIStream *the_stream, queue_t *q, mblk_t *ack_mp, uint32 prim, uint32 err, uint32 uerr); +static void DLPI_ok_ack(DLPIStream *the_stream, queue_t *q, mblk_t *ack_mp, uint32 prim); +static void DLPI_info(DLPIStream *the_stream, queue_t *q, mblk_t *mp); +static void DLPI_phys_addr(DLPIStream *the_stream, queue_t *q, mblk_t *mp); +static void DLPI_bind(DLPIStream *the_stream, queue_t *q, mblk_t *mp); +static void DLPI_unbind(DLPIStream *the_stream, queue_t *q, mblk_t *mp); +static void DLPI_subs_bind(DLPIStream *the_stream, queue_t *q, mblk_t *mp); +static void DLPI_subs_unbind(DLPIStream *the_stream, queue_t *q, mblk_t *mp); +static void DLPI_enable_multi(DLPIStream *the_stream, queue_t *q, mblk_t *mp); +static void DLPI_disable_multi(DLPIStream *the_stream, queue_t *q, mblk_t *mp); +static void DLPI_unit_data(DLPIStream *the_stream, queue_t *q, mblk_t *mp); + + +/* + * Initialize ethernet stream module + */ + +static uint8 InitStreamModuleImpl(void *theID) +{ + D(bug("InitStreamModule\n")); + + // Don't re-open if already open + if (ether_driver_opened) + return true; + ether_driver_opened = false; + + // Import functions from OTKernelLib + allocb_tvect = FindLibSymbol("\013OTKernelLib", "\006allocb"); + D(bug("allocb TVECT at %08lx\n", allocb_tvect)); + if (allocb_tvect == 0) + return false; + freeb_tvect = FindLibSymbol("\013OTKernelLib", "\005freeb"); + D(bug("freeb TVECT at %08lx\n", freeb_tvect)); + if (freeb_tvect == 0) + return false; + freemsg_tvect = FindLibSymbol("\013OTKernelLib", "\007freemsg"); + D(bug("freemsg TVECT at %08lx\n", freemsg_tvect)); + if (freemsg_tvect == 0) + return false; + copyb_tvect = FindLibSymbol("\013OTKernelLib", "\005copyb"); + D(bug("copyb TVECT at %08lx\n", copyb_tvect)); + if (copyb_tvect == 0) + return false; + dupmsg_tvect = FindLibSymbol("\013OTKernelLib", "\006dupmsg"); + D(bug("dupmsg TVECT at %08lx\n", dupmsg_tvect)); + if (dupmsg_tvect == 0) + return false; + getq_tvect = FindLibSymbol("\013OTKernelLib", "\004getq"); + D(bug("getq TVECT at %08lx\n", getq_tvect)); + if (getq_tvect == 0) + return false; + putq_tvect = FindLibSymbol("\013OTKernelLib", "\004putq"); + D(bug("putq TVECT at %08lx\n", putq_tvect)); + if (putq_tvect == 0) + return false; + putnext_tvect = FindLibSymbol("\013OTKernelLib", "\007putnext"); + D(bug("putnext TVECT at %08lx\n", putnext_tvect)); + if (putnext_tvect == 0) + return false; + putnextctl1_tvect = FindLibSymbol("\013OTKernelLib", "\013putnextctl1"); + D(bug("putnextctl1 TVECT at %08lx\n", putnextctl1_tvect)); + if (putnextctl1_tvect == 0) + return false; + canputnext_tvect = FindLibSymbol("\013OTKernelLib", "\012canputnext"); + D(bug("canputnext TVECT at %08lx\n", canputnext_tvect)); + if (canputnext_tvect == 0) + return false; + qreply_tvect = FindLibSymbol("\013OTKernelLib", "\006qreply"); + D(bug("qreply TVECT at %08lx\n", qreply_tvect)); + if (qreply_tvect == 0) + return false; + flushq_tvect = FindLibSymbol("\013OTKernelLib", "\006flushq"); + D(bug("flushq TVECT at %08lx\n", flushq_tvect)); + if (flushq_tvect == 0) + return false; + msgdsize_tvect = FindLibSymbol("\013OTKernelLib", "\010msgdsize"); + D(bug("msgdsize TVECT at %08lx\n", msgdsize_tvect)); + if (msgdsize_tvect == 0) + return false; + otenterint_tvect = FindLibSymbol("\017OTKernelUtilLib", "\020OTEnterInterrupt"); + D(bug("OTEnterInterrupt TVECT at %08lx\n", otenterint_tvect)); + if (otenterint_tvect == 0) + return false; + otleaveint_tvect = FindLibSymbol("\017OTKernelUtilLib", "\020OTLeaveInterrupt"); + D(bug("OTLeaveInterrupt TVECT at %08lx\n", otleaveint_tvect)); + if (otleaveint_tvect == 0) + return false; + mi_open_comm_tvect = FindLibSymbol("\013OTKernelLib", "\014mi_open_comm"); + D(bug("mi_open_comm TVECT at %08lx\n", mi_open_comm_tvect)); + if (mi_open_comm_tvect == 0) + return false; + mi_close_comm_tvect = FindLibSymbol("\013OTKernelLib", "\015mi_close_comm"); + D(bug("mi_close_comm TVECT at %08lx\n", mi_close_comm_tvect)); + if (mi_close_comm_tvect == 0) + return false; + mi_next_ptr_tvect = FindLibSymbol("\013OTKernelLib", "\013mi_next_ptr"); + D(bug("mi_next_ptr TVECT at %08lx\n", mi_next_ptr_tvect)); + if (mi_next_ptr_tvect == 0) + return false; + +#ifndef USE_ETHER_FULL_DRIVER + // Initialize stream list (which might be leftover) + dlpi_stream_list = NULL; + + // Ask add-on for ethernet hardware address + AO_get_ethernet_address(Host2MacAddr(hardware_address)); +#endif + + // Yes, we're open + ether_driver_opened = true; + return true; +} + +uint8 InitStreamModule(void *theID) +{ + // Common initialization code + bool net_open = InitStreamModuleImpl(theID); + + // Call InitStreamModule() in native side +#ifdef BUILD_ETHER_FULL_DRIVER + extern bool NativeInitStreamModule(void *); + if (!NativeInitStreamModule((void *)ether_dispatch_packet)) + net_open = false; +#endif + + // Import functions from the Ethernet driver +#ifdef USE_ETHER_FULL_DRIVER + ether_dispatch_packet_tvect = (uintptr)theID; + D(bug("ether_dispatch_packet TVECT at %08lx\n", ether_dispatch_packet_tvect)); + if (ether_dispatch_packet_tvect == 0) + net_open = false; +#endif + + return net_open; +} + + +/* + * Terminate ethernet stream module + */ + +static void TerminateStreamModuleImpl(void) +{ + D(bug("TerminateStreamModule\n")); + +#ifndef USE_ETHER_FULL_DRIVER + // This happens sometimes. I don't know why. + if (dlpi_stream_list != NULL) + printf("FATAL: TerminateStreamModule() called, but streams still open\n"); +#endif + + // Sorry, we're closed + ether_driver_opened = false; +} + +void TerminateStreamModule(void) +{ + // Common termination code + TerminateStreamModuleImpl(); + + // Call TerminateStreamModule() in native side +#ifdef BUILD_ETHER_FULL_DRIVER + extern void NativeTerminateStreamModule(void); + NativeTerminateStreamModule(); +#endif +} + + +/* + * Open new stream + */ + +int ether_open(queue_t *rdq, void *dev, int flag, int sflag, void *creds) +{ + D(bug("ether_open(%p,%p,%d,%d,%p)\n", rdq, dev, flag, sflag, creds)); + + // Return if driver was closed + if (!ether_driver_opened) { + printf("FATAL: ether_open(): Ethernet driver not opened\n"); + return MAC_ENXIO; + } + + // If we're being reopened, just return + if (rdq->q_ptr != NULL) + return 0; + + // Allocate DLPIStream structure + int err = mi_open_comm((DLPIStream **)&dlpi_stream_list, sizeof(DLPIStream), rdq, dev, flag, sflag, creds); + if (err) + return err; + DLPIStream *the_stream = (DLPIStream *)rdq->q_ptr; + the_stream->rdq = rdq; + the_stream->dlpi_state = DL_UNBOUND; + the_stream->flags = 0; + the_stream->dlsap = 0; + the_stream->framing_8022 = false; + the_stream->multicast_list = NULL; + return 0; +} + + +/* + * Close stream + */ + +int ether_close(queue_t *rdq, int flag, void *creds) +{ + D(bug("ether_close(%p,%d,%p)\n", rdq, flag, creds)); + + // Return if driver was closed + if (!ether_driver_opened) { + printf("FATAL: ether_close(): Ethernet driver not opened\n"); + return MAC_ENXIO; + } + + // Get stream + DLPIStream *the_stream = (DLPIStream *)rdq->q_ptr; + + // Don't close if never opened + if (the_stream == NULL) + return 0; + + // Disable all registered multicast addresses + while (the_stream->multicast_list) { + AO_disable_multicast(Host2MacAddr(the_stream->multicast_list->addr)); + the_stream->RemoveMulticast(the_stream->multicast_list->addr); + } + the_stream->multicast_list = NULL; + + // Delete the DLPIStream + return mi_close_comm((DLPIStream **)&dlpi_stream_list, rdq); +} + + +/* + * Put something on the write queue + */ + +int ether_wput(queue_t *q, mblk_t *mp) +{ + D(bug("ether_wput(%p,%p)\n", q, mp)); + + // Return if driver was closed + if (!ether_driver_opened) { + printf("FATAL: ether_wput(): Ethernet driver not opened\n"); + return MAC_ENXIO; + } + + // Get stream + DLPIStream *the_stream = (DLPIStream *)q->q_ptr; + if (the_stream == NULL) + return MAC_ENXIO; + + D(bug(" db_type %d\n", (int)mp->b_datap->db_type)); + switch (mp->b_datap->db_type) { + + case M_DATA: + // Transmit raw packet + D(bug(" raw packet\n")); + num_tx_raw_packets++; + transmit_packet(mp); + break; + + case M_PROTO: + case M_PCPROTO: { + union DL_primitives *dlp = (union DL_primitives *)(void *)mp->b_rptr; + uint32 prim = dlp->dl_primitive; + D(bug(" dl_primitive %d\n", prim)); + switch (prim) { + case DL_UNITDATA_REQ: + // Transmit normal packet + num_tx_normal_packets++; + DLPI_unit_data(the_stream, q, mp); + break; + + case DL_INFO_REQ: + DLPI_info(the_stream, q, mp); + break; + + case DL_PHYS_ADDR_REQ: + DLPI_phys_addr(the_stream, q, mp); + break; + + case DL_BIND_REQ: + DLPI_bind(the_stream, q, mp); + break; + + case DL_UNBIND_REQ: + DLPI_unbind(the_stream, q, mp); + break; + + case DL_SUBS_BIND_REQ: + DLPI_subs_bind(the_stream, q, mp); + break; + + case DL_SUBS_UNBIND_REQ: + DLPI_subs_unbind(the_stream, q, mp); + break; + + case DL_ENABMULTI_REQ: + DLPI_enable_multi(the_stream, q, mp); + break; + + case DL_DISABMULTI_REQ: + DLPI_disable_multi(the_stream, q, mp); + break; + + default: + D(bug("WARNING: ether_wsrv(): Unknown primitive\n")); + DLPI_error_ack(the_stream, q, mp, prim, DL_NOTSUPPORTED, 0); + break; + } + break; + } + + case M_IOCTL: + ether_ioctl(the_stream, q, mp); + break; + + case M_FLUSH: + ether_flush(q, mp); + break; + + default: + D(bug("WARNING: ether_wput(): Unknown message type\n")); + freemsg(mp); + break; + } + num_wput++; + return 0; +} + + +/* + * Dequeue and process messages from the read queue + */ + +int ether_rsrv(queue_t *q) +{ + mblk_t *mp; + while ((mp = getq(q)) != NULL) { + if (canputnext(q)) + putnext(q, mp); + else { + freemsg(mp); + flushq(q, FLUSHDATA); + break; + } + } + return 0; +} + + +/* + * Handle ioctl calls + */ + +static void ether_ioctl(DLPIStream *the_stream, queue_t *q, mblk_t *mp) +{ + struct iocblk *ioc = (struct iocblk *)(void *)mp->b_rptr; + D(bug(" ether_ioctl(%p,%p) cmd %d\n", q, mp, (int)ioc->ioc_cmd)); + + switch (ioc->ioc_cmd) { + + case I_OTSetFramingType: { // Toggles what the general info primitive returns for dl_mac_type in dl_info_ack_t structure + mblk_t *info_mp = mp->b_cont; + if (info_mp == NULL || ((info_mp->b_wptr - info_mp->b_rptr) != sizeof(uint32))) { + ioc->ioc_error = MAC_EINVAL; + goto ioctl_error; + } + uint32 framing_type = ntohl(*(uint32 *)(void *)info_mp->b_rptr); + D(bug(" I_OTSetFramingType type %d\n", framing_type)); + if (framing_type != kOTGetFramingValue) + the_stream->framing_8022 = (framing_type == kOTFraming8022); + mp->b_cont = NULL; + freemsg(info_mp); + if (the_stream->framing_8022) + ioc->ioc_rval = kOTFraming8022; + else + ioc->ioc_rval = kOTFramingEthernet; + goto ioctl_ok; + } + + case DL_IOC_HDR_INFO: { // Special Mentat call, for fast transmits + D(bug(" DL_IOC_HDR_INFO\n")); + mblk_t *info_mp = mp->b_cont; + + // Copy DL_UNITDATA_REQ block + mblk_t *unitdata_mp = copyb(info_mp); + if (unitdata_mp == NULL) { + ioc->ioc_error = MAC_ENOMEM; + goto ioctl_error; + } + unitdata_mp->b_datap->db_type = M_PROTO; + + // Construct header (converts DL_UNITDATA_REQ -> M_DATA) + mblk_t *header_mp = build_tx_packet_header(the_stream, unitdata_mp, true); + + if (header_mp == NULL) { + // Could not allocate a message block large enough + ioc->ioc_error = MAC_ENOMEM; + goto ioctl_error; + } + + // Attach header block at the end + mp->b_cont->b_cont = header_mp; + the_stream->flags |= kFastPathMode; + goto ioctl_ok; + } + + case I_OTSetRawMode: { + mblk_t *info_mp = mp->b_cont; + dl_recv_control_t *dlrc; + if (info_mp == NULL || ((info_mp->b_wptr - info_mp->b_rptr) != sizeof(dlrc->dl_primitive))) { + ioc->ioc_error = MAC_EINVAL; + goto ioctl_error; + } + dlrc = (dl_recv_control_t *)(void *)info_mp->b_rptr; + D(bug(" I_OTSetRawMode primitive %d\n", (int)dlrc->dl_primitive)); + ioc->ioc_error = MAC_EINVAL; + goto ioctl_error; + } + + default: + D(bug("WARNING: Unknown ether_ioctl() call\n")); + ioc->ioc_error = MAC_EINVAL; + goto ioctl_error; + } + +ioctl_ok: + ioc->ioc_count = 0; + for (mblk_t *mp1 = mp; (mp1 = mp1->b_cont) != NULL;) + ioc->ioc_count += mp1->b_wptr - mp1->b_rptr; + ioc->ioc_error = 0; + mp->b_datap->db_type = M_IOCACK; + qreply(q, mp); + return; + +ioctl_error: + mp->b_datap->db_type = M_IOCNAK; + qreply(q, mp); + return; +} + + +/* + * Flush call, send it up to the read side of the stream + */ + +static void ether_flush(queue_t* q, mblk_t* mp) +{ + D(bug(" ether_flush(%p,%p)\n", q, mp)); + + uint8 *rptr = mp->b_rptr; + if (*rptr & FLUSHW) + flushq(q, FLUSHALL); + if (*rptr & FLUSHR) { + flushq(RD(q), FLUSHALL); + *rptr &= ~FLUSHW; + qreply(q, mp); + } else + freemsg(mp); +} + + +/* + * Classify packet into the different types of protocols + */ + +static uint16 classify_packet_type(uint16 primarySAP, uint16 secondarySAP) +{ + if (primarySAP >= kMinDIXSAP) + return kPktDIX; + + if ((primarySAP == kIPXSAP) && (secondarySAP == kIPXSAP)) + return kPktIPX; + + if (primarySAP == kSNAPSAP) + return kPkt8022SNAP; + + if (primarySAP <= k8022GlobalSAP) + return kPkt8022SAP; + + return kPktUnknown; +} + + +/* + * Check if the address is a multicast, broadcast or standard address + */ + +static int32 get_address_type(uint8 *addr) +{ + if (addr[0] & 1) { // Multicast/broadcast flag + if (OTIs48BitBroadcastAddress(addr)) + return keaBroadcast; + else + return keaMulticast; + } else + return keaStandardAddress; +} + + +/* + * Reuse a message block, make room for more data + */ + +static mblk_t *reuse_message_block(mblk_t *mp, uint16 needed_size) +{ + mblk_t *nmp; + + if ((mp->b_datap->db_ref == 1) && ((mp->b_datap->db_lim - mp->b_datap->db_base) >= needed_size)) { + mp->b_datap->db_type = M_DATA; + mp->b_rptr = mp->b_datap->db_base; + mp->b_wptr = mp->b_datap->db_base + needed_size; + } else { + nmp = mp->b_cont; // Grab the M_DATA blocks + mp->b_cont = NULL; // Detach the M_(PC)PROTO + freemsg(mp); // Free the M_(PC)PROTO + mp = nmp; // Point to the M_DATA blocks + + // Try to get space on the first M_DATA block + if (mp && (mp->b_datap->db_ref == 1) && ((mp->b_rptr - mp->b_datap->db_base) >= needed_size)) + mp->b_rptr -= needed_size; + else { + // Try to allocate a new message + if ((nmp = allocb(needed_size, BPRI_HI)) == NULL) { + // Could not get a new message block so lets forget about the message altogether + freemsg(mp); // Free the original M_DATA portion of the message + mp = NULL; // Indicates the reuse failed + } else { + nmp->b_cont = mp; // Attach the new message block as the head + nmp->b_wptr += needed_size; + mp = nmp; + } + } + } + + return mp; +} + + +/* + * Built header for packet to be transmitted (convert DL_UNITDATA_REQ -> M_DATA) + * The passed-in message has the header info in the first message block and the data + * in the following blocks + */ + +static mblk_t *build_tx_packet_header(DLPIStream *the_stream, mblk_t *mp, bool fast_path) +{ + // Only handle unit_data requests + dl_unitdata_req_t *req = (dl_unitdata_req_t *)(void *)mp->b_rptr; + if (req->dl_primitive != DL_UNITDATA_REQ) { + freemsg(mp); + return NULL; + } + + // Extract destination address and its length + uint8 *destAddrOrig = ((uint8 *)req) + req->dl_dest_addr_offset; + uint32 destAddrLen = req->dl_dest_addr_length; + uint8 ctrl = 0x03; + + // Extract DLSAP + uint16 dlsap; + switch (destAddrLen) { + case kEnetPhysicalAddressLength: + dlsap = the_stream->dlsap; + break; + case kEnetAndSAPAddressLength: + dlsap = ntohs(*(uint16 *)(destAddrOrig + kEnetPhysicalAddressLength)); + break; + case kEnetPhysicalAddressLength + k8022DLSAPLength + k8022SNAPLength: // SNAP SAP + dlsap = ntohs(*(uint16 *)(destAddrOrig + kEnetPhysicalAddressLength)); + break; + default: + dlsap = the_stream->dlsap; + break; + } + + // Extract data size (excluding header info) and packet type + uint16 datasize = msgdsize(mp); + uint16 packetType = classify_packet_type(the_stream->dlsap, dlsap); + + // Calculate header size and protocol type/size field + uint16 hdrsize, proto; + switch (packetType) { + case kPktDIX: + hdrsize = kEnetPacketHeaderLength; + proto = dlsap; + break; + case kPkt8022SAP: + hdrsize = kEnetPacketHeaderLength + k8022BasicHeaderLength; + if (fast_path) + proto = 0; + else + proto = datasize + k8022BasicHeaderLength; + break; + case kPkt8022SNAP: + hdrsize = kEnetPacketHeaderLength + k8022SNAPHeaderLength; + if (fast_path) + proto = 0; + else + proto = datasize + k8022SNAPHeaderLength; + break; + case kPktIPX: + hdrsize = kEnetPacketHeaderLength; + if (fast_path) + proto = 0; + else + proto = datasize; + break; + default: + hdrsize = kEnetPacketHeaderLength; + proto = dlsap; + break; + } + + // We need to copy the dest address info in the message before we can reuse it + uint8 destAddrCopy[kMaxBoundAddrLength]; + memcpy(destAddrCopy, destAddrOrig, destAddrLen); + + // Resize header info in message block + if ((mp = reuse_message_block(mp, hdrsize)) == NULL) + return NULL; + struct T8022FullPacketHeader *packetHeader = (struct T8022FullPacketHeader *)(void *)mp->b_rptr; + + // Set protocol type/size field + packetHeader->fEnetPart.fProto = proto; + + // Set destination ethernet address + OTCopy48BitAddress(destAddrCopy, packetHeader->fEnetPart.fDestAddr); + + // Set other header fields + switch (packetType) { + case kPkt8022SAP: + packetHeader->f8022Part.fDSAP = (uint8)dlsap; + packetHeader->f8022Part.fSSAP = (uint8)the_stream->dlsap; + packetHeader->f8022Part.fCtrl = ctrl; + break; + case kPkt8022SNAP: { + uint8 *snapStart; + packetHeader->f8022Part.fDSAP = (uint8)dlsap; + packetHeader->f8022Part.fSSAP = (uint8)the_stream->dlsap; + packetHeader->f8022Part.fCtrl = ctrl; + if (destAddrLen >= kEnetAndSAPAddressLength + k8022SNAPLength) + snapStart = destAddrCopy + kEnetAndSAPAddressLength; + else + snapStart = the_stream->snap; + OTCopy8022SNAP(snapStart, packetHeader->f8022Part.fSNAP); + break; + } + } + + // Return updated message + return mp; +} + + +/* + * Transmit packet + */ + +static void transmit_packet(mblk_t *mp) +{ + EnetPacketHeader *enetHeader = (EnetPacketHeader *)(void *)mp->b_rptr; + + // Fill in length in 802.3 packets + if (enetHeader->fProto == 0) + enetHeader->fProto = msgdsize(mp) - sizeof(EnetPacketHeader); + + // Fill in ethernet source address + OTCopy48BitAddress(hardware_address, enetHeader->fSourceAddr); + + // Tell add-on to transmit packet + AO_transmit_packet(Host2MacAddr((uint8 *)mp)); + freemsg(mp); +} + + +/* + * Handle incoming packet (one stream), construct DL_UNITDATA_IND message + */ + +static void handle_received_packet(DLPIStream *the_stream, mblk_t *mp, uint16 packet_type, int32 dest_addr_type) +{ + // Find address and header length + uint32 addr_len; + uint32 header_len; + switch (packet_type) { + case kPkt8022SAP: + addr_len = kEnetAndSAPAddressLength; + header_len = kEnetPacketHeaderLength + k8022BasicHeaderLength; + break; + case kPkt8022SNAP: + addr_len = kEnetAndSAPAddressLength + k8022SNAPLength; + header_len = kEnetPacketHeaderLength + k8022SNAPHeaderLength; + break; + default: // DIX and IPX + addr_len = kEnetAndSAPAddressLength; + header_len = kEnetPacketHeaderLength; + break; + } + + // In Fast Path mode, don't send DL_UNITDATA_IND messages for unicast packets + if ((the_stream->flags & kFastPathMode) && dest_addr_type == keaStandardAddress) { + mp->b_rptr += header_len; + num_rx_fastpath++; + putq(the_stream->rdq, mp); + return; + } + + // Allocate the dl_unitdata_ind_t message + mblk_t *nmp; + if ((nmp = allocb(sizeof(dl_unitdata_ind_t) + 2*addr_len, BPRI_HI)) == NULL) { + freemsg(mp); + num_rx_no_unitdata_mem++; + return; + } + + // Set message type + nmp->b_datap->db_type = M_PROTO; + dl_unitdata_ind_t *ind = (dl_unitdata_ind_t*)(void *)nmp->b_rptr; + ind->dl_primitive = DL_UNITDATA_IND; + nmp->b_wptr += (sizeof(dl_unitdata_ind_t) + 2*addr_len); + + // Link M_DATA block + nmp->b_cont = mp; + + // Set address fields + ind->dl_dest_addr_length = addr_len; + ind->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t); + ind->dl_src_addr_length = addr_len; + ind->dl_src_addr_offset = sizeof(dl_unitdata_ind_t) + addr_len; + + // Set address type + ind->dl_group_address = dest_addr_type; + + // Set address fields + T8022FullPacketHeader *packetHeader = (T8022FullPacketHeader *)(void *)mp->b_rptr; + T8022AddressStruct *destAddr = ((T8022AddressStruct*)(nmp->b_rptr + ind->dl_dest_addr_offset)); + T8022AddressStruct *srcAddr = ((T8022AddressStruct*)(nmp->b_rptr + ind->dl_src_addr_offset)); + + OTCopy48BitAddress(packetHeader->fEnetPart.fDestAddr, destAddr->fHWAddr); + OTCopy48BitAddress(packetHeader->fEnetPart.fSourceAddr, srcAddr->fHWAddr); + + destAddr->fSAP = packetHeader->f8022Part.fDSAP; + srcAddr->fSAP = packetHeader->f8022Part.fSSAP; + + if (packet_type == kPkt8022SNAP) { + OTCopy8022SNAP(packetHeader->f8022Part.fSNAP, destAddr->fSNAP); + OTCopy8022SNAP(packetHeader->f8022Part.fSNAP, srcAddr->fSNAP); + } + + // "Hide" the ethernet and protocol header(s) + mp->b_rptr += header_len; + + // Pass message up the stream + num_unitdata_ind++; + putq(the_stream->rdq, nmp); + return; +} + + +/* + * Packet received, distribute it to the streams that want it + */ + +void ether_packet_received(mblk_t *mp) +{ + // Extract address and types + EnetPacketHeader *pkt = (EnetPacketHeader *)(void *)mp->b_rptr; + T8022FullPacketHeader *fullpkt = (T8022FullPacketHeader *)pkt; + uint16 sourceSAP, destSAP; + destSAP = fullpkt->fEnetPart.fProto; + if (destSAP >= kMinDIXSAP) { + // Classic ethernet + sourceSAP = destSAP; + } else { + destSAP = fullpkt->f8022Part.fDSAP; + sourceSAP = fullpkt->f8022Part.fSSAP; + } + uint16 packetType = classify_packet_type(sourceSAP, destSAP); + int32 destAddressType = get_address_type(pkt->fDestAddr); + + // Look which streams want it + DLPIStream *the_stream, *found_stream = NULL; + uint16 found_packetType = 0; + int32 found_destAddressType = 0; + for (the_stream = dlpi_stream_list; the_stream != NULL; the_stream = mi_next_ptr(the_stream)) { + + // Don't send to unbound streams + if (the_stream->dlpi_state == DL_UNBOUND) + continue; + + // Does this stream want all 802.2 packets? + if ((the_stream->flags & kAcceptAll8022Packets) && (destSAP <= 0xff)) + goto type_found; + + // No, check SAP/SNAP + if (destSAP == the_stream->dlsap) { + if (the_stream->flags & kSnapStream) { + // Check SNAPs if necessary + uint8 sum = fullpkt->f8022Part.fSNAP[0] ^ the_stream->snap[0]; + sum |= fullpkt->f8022Part.fSNAP[1] ^ the_stream->snap[1]; + sum |= fullpkt->f8022Part.fSNAP[2] ^ the_stream->snap[2]; + sum |= fullpkt->f8022Part.fSNAP[3] ^ the_stream->snap[3]; + sum |= fullpkt->f8022Part.fSNAP[4] ^ the_stream->snap[4]; + if (sum == 0) + goto type_found; + } else { + // No SNAP, found a match since saps match + goto type_found; + } + } else { + // Check for an 802.3 Group/Global (odd) + if (((packetType == kPkt8022SAP) || (packetType == kPkt8022SNAP)) && (destSAP & 1) && the_stream->TestGroupSAP(destSAP)) + goto type_found; + } + + // No stream for this SAP/SNAP found + continue; + +type_found: + // If it's a multicast packet, it must be in the stream's multicast list + if ((destAddressType == keaMulticast) && (the_stream->flags & kAcceptMulticasts) && (!the_stream->IsMulticastRegistered(pkt->fDestAddr))) + continue; + + // Send packet to stream + // found_stream keeps a pointer to the previously found stream, so that only the last + // stream gets the original message, the other ones get duplicates + if (found_stream) + handle_received_packet(found_stream, dupmsg(mp), found_packetType, found_destAddressType); + found_stream = the_stream; + found_packetType = packetType; + found_destAddressType = destAddressType; + } + + // Send original message to last found stream + if (found_stream) + handle_received_packet(found_stream, mp, found_packetType, found_destAddressType); + else { + freemsg(mp); // Nobody wants it *snief* + num_rx_dropped++; + } +} + +void ether_dispatch_packet(uint32 p, uint32 size) +{ +#ifdef USE_ETHER_FULL_DRIVER + // Call handler from the Ethernet driver + D(bug("ether_dispatch_packet\n")); + D(bug(" packet data at %p, %d bytes\n", p, size)); + CallMacOS2(ether_dispatch_packet_ptr, ether_dispatch_packet_tvect, p, size); +#else + // Wrap packet in message block + num_rx_packets++; + mblk_t *mp; + if ((mp = allocb(size, 0)) != NULL) { + D(bug(" packet data at %p\n", (void *)mp->b_rptr)); + Mac2Host_memcpy(mp->b_rptr, p, size); + mp->b_wptr += size; + ether_packet_received(mp); + } else { + D(bug("WARNING: Cannot allocate mblk for received packet\n")); + num_rx_no_mem++; + } +#endif +} + + +/* + * Build and send an error acknowledge + */ + +static void DLPI_error_ack(DLPIStream *the_stream, queue_t *q, mblk_t *ack_mp, uint32 prim, uint32 err, uint32 uerr) +{ + D(bug(" DLPI_error_ack(%p,%p) prim %d, err %d, uerr %d\n", the_stream, ack_mp, prim, err, uerr)); + num_error_acks++; + + if (ack_mp != NULL) + freemsg(ack_mp); + if ((ack_mp = allocb(sizeof(dl_error_ack_t), BPRI_HI)) == NULL) + return; + + ack_mp->b_datap->db_type = M_PCPROTO; + dl_error_ack_t *errp = (dl_error_ack_t *)(void *)ack_mp->b_wptr; + errp->dl_primitive = DL_ERROR_ACK; + errp->dl_error_primitive = prim; + errp->dl_errno = err; + errp->dl_unix_errno = uerr; + ack_mp->b_wptr += sizeof(dl_error_ack_t); + qreply(q, ack_mp); +} + + +/* + * Build and send an OK acknowledge + */ + +static void DLPI_ok_ack(DLPIStream *the_stream, queue_t *q, mblk_t *ack_mp, uint32 prim) +{ + if (ack_mp->b_datap->db_ref != 1) { + // Message already in use, create a new one + freemsg(ack_mp); + if ((ack_mp = allocb(sizeof(dl_error_ack_t), BPRI_HI)) == NULL) + return; + } else { + // Message free + if (ack_mp->b_cont != NULL) { + freemsg(ack_mp->b_cont); + ack_mp->b_cont = NULL; + } + } + + ack_mp->b_datap->db_type = M_PCPROTO; + dl_ok_ack_t *ackp = (dl_ok_ack_t *)(void *)ack_mp->b_rptr; + ackp->dl_primitive = DL_OK_ACK; + ackp->dl_correct_primitive = prim; + ack_mp->b_wptr = ack_mp->b_rptr + sizeof(dl_ok_ack_t); + qreply(q, ack_mp); +} + + +/* + * Handle DL_INFO_REQ (report general information) + */ + +static void DLPI_info(DLPIStream *the_stream, queue_t *q, mblk_t *mp) +{ + D(bug(" DLPI_info(%p)\n", the_stream)); + uint32 saplen = 0; + uint32 addrlen = kEnetPhysicalAddressLength; + uint32 bcastlen = kEnetPhysicalAddressLength; + uint32 hdrlen = kEnetPacketHeaderLength; + + // Calculate header length + if (the_stream->dlpi_state != DL_UNBOUND) { + saplen = (the_stream->flags & kSnapStream) ? k8022DLSAPLength+k8022SNAPLength : k8022DLSAPLength; + if (the_stream->dlsap == kSNAPSAP) + hdrlen = kEnetPacketHeaderLength + k8022SNAPHeaderLength; // SNAP address + else if ((the_stream->dlsap <= kMax8022SAP) || (the_stream->dlsap == kIPXSAP)) + hdrlen = kEnetPacketHeaderLength + k8022BasicHeaderLength; // SAP or IPX + else + hdrlen = kEnetPacketHeaderLength; // Basic Ethernet + } + + // Allocate message block for reply + mblk_t *ack_mp; + if ((ack_mp = allocb(sizeof(dl_info_ack_t) + addrlen + saplen + bcastlen, BPRI_LO)) == NULL) { + DLPI_error_ack(the_stream, q, mp, DL_INFO_REQ, DL_SYSERR, MAC_ENOMEM); + return; + } + + // Set up message type + ack_mp->b_datap->db_type = M_PCPROTO; + dl_info_ack_t *ackp = (dl_info_ack_t *)(void *)ack_mp->b_rptr; + ackp->dl_primitive = DL_INFO_ACK; + + // Info/version fields + ackp->dl_service_mode = DL_CLDLS; + ackp->dl_provider_style = DL_STYLE1; + ackp->dl_version = DL_VERSION_2; + ackp->dl_current_state = the_stream->dlpi_state; + ackp->dl_mac_type = the_stream->framing_8022 ? DL_CSMACD : DL_ETHER; + ackp->dl_reserved = 0; + ackp->dl_qos_length = 0; + ackp->dl_qos_offset = (uint32)DL_UNKNOWN; + ackp->dl_qos_range_length = 0; + ackp->dl_qos_range_offset = (uint32)DL_UNKNOWN; + ackp->dl_growth = 0; + ackp->dl_min_sdu = 1; + ackp->dl_max_sdu = kEnetTSDU - hdrlen; + + // Address fields + ackp->dl_sap_length = -saplen; // Negative to indicate sap follows physical address + ackp->dl_addr_length = addrlen + saplen; + ackp->dl_addr_offset = sizeof(dl_info_ack_t); + T8022AddressStruct *boundAddr = ((T8022AddressStruct *)(ack_mp->b_rptr + ackp->dl_addr_offset)); + OTCopy48BitAddress(hardware_address, boundAddr->fHWAddr); + if (saplen) { + boundAddr->fSAP = the_stream->dlsap; + if (the_stream->flags & kSnapStream) + OTCopy8022SNAP(the_stream->snap, boundAddr->fSNAP); + } + ackp->dl_brdcst_addr_length = bcastlen; + ackp->dl_brdcst_addr_offset = sizeof(dl_info_ack_t) + addrlen + saplen; + OTSet48BitBroadcastAddress(ack_mp->b_rptr + ackp->dl_brdcst_addr_offset); + + // Advance write pointer + ack_mp->b_wptr += sizeof(dl_info_ack_t) + addrlen + saplen + bcastlen; + + // Free request + freemsg(mp); + + // Send reply + qreply(q, ack_mp); + return; +} + + +/* + * Handle DL_PHYS_ADDR_REQ (report physical address) + */ + +static void DLPI_phys_addr(DLPIStream *the_stream, queue_t *q, mblk_t *mp) +{ + D(bug(" DLPI_phys_addr(%p,%p)\n", the_stream, mp)); + dl_phys_addr_req_t *req = (dl_phys_addr_req_t *)(void *)mp->b_rptr; + + // Allocate message block for reply + mblk_t *ack_mp; + if ((ack_mp = allocb(sizeof(dl_phys_addr_ack_t) + kEnetPhysicalAddressLength, BPRI_HI)) == NULL) { + DLPI_error_ack(the_stream, q, mp, DL_PHYS_ADDR_REQ, DL_SYSERR, MAC_ENOMEM); + return; + } + + // Set up message type + ack_mp->b_datap->db_type = M_PCPROTO; + dl_phys_addr_ack_t *ackp = (dl_phys_addr_ack_t *)(void *)ack_mp->b_wptr; + ackp->dl_primitive = DL_PHYS_ADDR_ACK; + + // Fill in address + ackp->dl_addr_length = kEnetPhysicalAddressLength; + ackp->dl_addr_offset = sizeof(dl_phys_addr_ack_t); + ack_mp->b_wptr += sizeof(dl_phys_addr_ack_t) + kEnetPhysicalAddressLength; + if (req->dl_addr_type == DL_CURR_PHYS_ADDR || req->dl_addr_type == DL_FACT_PHYS_ADDR) + OTCopy48BitAddress(hardware_address, ack_mp->b_rptr + ackp->dl_addr_offset); + else { + DLPI_error_ack(the_stream, q, mp, DL_PHYS_ADDR_REQ, DL_BADPRIM, 0); + return; + } + + // Free request + freemsg(mp); + + // Send reply + qreply(q, ack_mp); + return; +} + + +/* + * Handle DL_BIND_REQ (bind a stream) + */ + +static void DLPI_bind(DLPIStream *the_stream, queue_t *q, mblk_t *mp) +{ + dl_bind_req_t *req = (dl_bind_req_t *)(void *)mp->b_rptr; + uint32 sap = req->dl_sap; + D(bug(" DLPI_bind(%p,%p) SAP %04x\n", the_stream, mp, sap)); + + // Stream must be unbound + if (the_stream->dlpi_state != DL_UNBOUND) { + DLPI_error_ack(the_stream, q, mp, DL_BIND_REQ, DL_OUTSTATE, 0); + return; + } + + // We only support connectionless data link services + if (req->dl_service_mode != DL_CLDLS || req->dl_max_conind != 0) { + DLPI_error_ack(the_stream, q, mp, DL_BIND_REQ, DL_UNSUPPORTED, 0); + return; + } + + // Don't bind to 802.2 group saps, can't check 802.2 global sap (0xFF) + // because it looks like IPX + if ((sap <= kMax8022SAP) && (sap & 1)) { + DLPI_error_ack(the_stream, q, mp, DL_BIND_REQ, DL_BADADDR, 0); + return; + } + + if (classify_packet_type(sap, sap) == kPktUnknown) { + DLPI_error_ack(the_stream, q, mp, DL_BIND_REQ, DL_BADADDR, 0); + return; + } + + // Allocate message block for reply + mblk_t *ack_mp; + if ((ack_mp = allocb(sizeof(dl_bind_ack_t) + kEnetAndSAPAddressLength, BPRI_HI)) == NULL) { + DLPI_error_ack(the_stream, q, mp, DL_BIND_REQ, DL_SYSERR, MAC_ENOMEM); + return; + } + + // Set up message type + ack_mp->b_datap->db_type = M_PCPROTO; + dl_bind_ack_t *ackp = (dl_bind_ack_t *)(void *)ack_mp->b_rptr; + ackp->dl_primitive = DL_BIND_ACK; + + // Fill in other fields + ackp->dl_sap = sap; + ackp->dl_addr_length = kEnetAndSAPAddressLength; + ackp->dl_addr_offset = sizeof(dl_bind_ack_t); + ackp->dl_max_conind = 0; + ackp->dl_xidtest_flg = 0; + + T8022AddressStruct *addrInfo = (T8022AddressStruct *)(ack_mp->b_rptr + sizeof(dl_bind_ack_t)); + OTCopy48BitAddress(hardware_address, addrInfo->fHWAddr); + addrInfo->fSAP = sap; + + // Must move b_wptr past the address info data + ack_mp->b_wptr = ack_mp->b_rptr + sizeof(dl_bind_ack_t) + kEnetAndSAPAddressLength; + + // Set group SAP if necessary + the_stream->ClearAllGroupSAPs(); + if (sap <= kMax8022SAP) + the_stream->SetGroupSAP(k8022GlobalSAP); + + // The stream is now bound and idle + the_stream->dlpi_state = DL_IDLE; + the_stream->dlsap = sap; + the_stream->flags &= ~kSnapStream; + + // Free request + freemsg(mp); + + // Send reply + qreply(q, ack_mp); + return; +} + + +/* + * Handle DL_UNBIND_REQ (unbind a stream) + */ + +static void DLPI_unbind(DLPIStream *the_stream, queue_t *q, mblk_t *mp) +{ + D(bug(" DLPI_unbind(%p,%p)\n", the_stream, mp)); + + // Stream must be bound and idle + if (the_stream->dlpi_state != DL_IDLE) { + DLPI_error_ack(the_stream, q, mp, DL_UNBIND_REQ, DL_OUTSTATE, 0); + return; + } + + // Stream is now unbound + the_stream->dlpi_state = DL_UNBOUND; + the_stream->dlsap = 0; + + // Flush all pending outbound messages + flushq(q, FLUSHDATA); + + // Flush all inbound messages pending on the stream + flushq(RD(q), FLUSHDATA); + putnextctl1(RD(q), M_FLUSH, FLUSHRW); + + // Send reply + DLPI_ok_ack(the_stream, q, mp, DL_UNBIND_REQ); + return; +} + + +/* + * Handle DL_SUBS_BIND_REQ (register 802.2 SAP group addresses and SNAPs) + */ + +static void DLPI_subs_bind(DLPIStream *the_stream, queue_t *q, mblk_t *mp) +{ + dl_subs_bind_req_t *req = (dl_subs_bind_req_t *)(void *)mp->b_rptr; + uint8 *sap = ((uint8 *)req) + req->dl_subs_sap_offset; + int32 length = req->dl_subs_sap_length; + uint16 theSap = ntohs(*((uint16 *)sap)); + int32 error = 0; + D(bug(" DLPI_subs_bind(%p,%p) SAP %02x%02x%02x%02x%02x\n", the_stream, mp, sap[0], sap[1], sap[2], sap[3], sap[4])); + + // Stream must be idle + if (the_stream->dlpi_state != DL_IDLE) { + DLPI_error_ack(the_stream, q, mp, DL_SUBS_BIND_REQ, DL_OUTSTATE, 0); + return; + } + + // Check if address is valid + switch (req->dl_subs_bind_class) { + case DL_PEER_BIND: // Bind a group address + if (the_stream->dlsap <= kMax8022SAP) { + if ((theSap & 1) && (length == sizeof(theSap))) + the_stream->SetGroupSAP(theSap); + else + if (theSap == 0x0000) // special case to receive all 802.2 packets + the_stream->flags |= kAcceptAll8022Packets; + else + error = DL_BADADDR; + } else + error = DL_UNSUPPORTED; + break; + + case DL_HIERARCHICAL_BIND: // Bind an additional SNAP + if (the_stream->dlsap == kSNAPSAP) { + if (the_stream->flags & kSnapStream) + error = DL_TOOMANY; // only one SNAP binding allowed + else { + OTCopy8022SNAP(sap, the_stream->snap); + the_stream->flags |= kSnapStream; + } + } else + error = DL_BADADDR; + break; + + default: + error = DL_UNSUPPORTED; + break; + } + if (error) { + DLPI_error_ack(the_stream, q, mp, DL_SUBS_BIND_REQ, error, 0); + return; + } + + // Allocate message block for reply + mblk_t *ack_mp; + if ((ack_mp = allocb(sizeof(dl_subs_bind_ack_t) + length, BPRI_HI)) == NULL) { + DLPI_error_ack(the_stream, q, mp, DL_SUBS_BIND_REQ, DL_SYSERR, MAC_ENOMEM); + return; + } + + // Set up message type + ack_mp->b_datap->db_type = M_PCPROTO; + dl_subs_bind_ack_t *ackp = (dl_subs_bind_ack_t *)(void *)ack_mp->b_wptr; + memset(ackp, 0, sizeof(dl_subs_bind_ack_t) + length); + ackp->dl_primitive = DL_SUBS_BIND_ACK; + + // Fill in other fields + ackp->dl_subs_sap_length = length; + ackp->dl_subs_sap_offset = length ? sizeof(dl_subs_bind_ack_t) : 0; + ack_mp->b_wptr += sizeof(dl_subs_bind_ack_t); + if (length) + memcpy(ack_mp->b_wptr, sap, length); + ack_mp->b_wptr += length; + + // Free request + freemsg(mp); + + // Send reply + qreply(q, ack_mp); + return; +} + + +/* + * Handle DL_SUBS_UNBIND_REQ (unregister 802.2 SAP group addresses and snaps) + */ + +static void DLPI_subs_unbind(DLPIStream *the_stream, queue_t *q, mblk_t *mp) +{ + dl_subs_unbind_req_t *req = (dl_subs_unbind_req_t *)(void *)mp->b_rptr; + uint8 *sap = ((uint8 *)req) + req->dl_subs_sap_offset; + int32 length = req->dl_subs_sap_length; + int32 error = 0; + D(bug(" DLPI_subs_unbind(%p,%p) SAP %02x%02x%02x%02x%02x\n", the_stream, mp, sap[0], sap[1], sap[2], sap[3], sap[4])); + + // Stream must be idle + if (the_stream->dlpi_state != DL_IDLE) { + DLPI_error_ack(the_stream, q, mp, DL_SUBS_UNBIND_REQ, DL_OUTSTATE, 0); + return; + } + + // Check if we are unbinding from an address we are bound to + if (length == k8022SAPLength) { + if ((*sap & 1) && (*sap != kIPXSAP)) { + if (the_stream->dlsap <= kMax8022SAP) + the_stream->ClearGroupSAP(*sap); + else + error = DL_UNSUPPORTED; + } else + error = DL_BADADDR; + } else if (length == k8022SNAPLength) { + if (the_stream->dlsap == kSNAPSAP) { + if (the_stream->flags & kSnapStream) { + if (memcmp(the_stream->snap, sap, length) != 0) + error = DL_BADADDR; + } else + error = DL_BADADDR; + } else + error = DL_UNSUPPORTED; + } + if (error) { + DLPI_error_ack(the_stream, q, mp, DL_SUBS_UNBIND_REQ, error, 0); + return; + } + + // Stream is no longer bound to SNAP + the_stream->flags &= ~kSnapStream; + + // Send reply + DLPI_ok_ack(the_stream, q, mp, DL_SUBS_UNBIND_REQ); + return; +} + + +/* + * Handles DL_ENABMULTI_REQ (enable multicast address) + */ + +static void DLPI_enable_multi(DLPIStream *the_stream, queue_t *q, mblk_t *mp) +{ + dl_enabmulti_req_t* req = (dl_enabmulti_req_t*)(void *)mp->b_rptr; + uint8 *reqaddr = (uint8 *)(mp->b_rptr + req->dl_addr_offset); + D(bug(" DLPI_enable_multi(%p,%p) addr %02x%02x%02x%02x%02x%02x\n", the_stream, mp, reqaddr[0], reqaddr[1], reqaddr[2], reqaddr[3], reqaddr[4], reqaddr[5])); + + // Address must be a multicast address + if (get_address_type(reqaddr) != keaMulticast) { + DLPI_error_ack(the_stream, q, mp, DL_ENABMULTI_REQ, DL_BADADDR, 0); + return; + } + + // Address already in multicast list? + if (the_stream->IsMulticastRegistered(reqaddr)) { + DLPI_error_ack(the_stream, q, mp, DL_ENABMULTI_REQ, DL_BADADDR, 0); + return; + } + + // Tell add-on to enable multicast address + AO_enable_multicast(Host2MacAddr((uint8 *)reqaddr)); + + // Add new address to multicast list + uint8 *addr = Mac2HostAddr(Mac_sysalloc(kEnetPhysicalAddressLength)); + OTCopy48BitAddress(reqaddr, addr); + the_stream->AddMulticast(addr); + + // On receive now check multicast packets + the_stream->flags |= kAcceptMulticasts; + + // Send reply + DLPI_ok_ack(the_stream, q, mp, DL_ENABMULTI_REQ); + return; +} + + +/* + * Handles DL_DISABMULTI_REQ (disable multicast address) + */ + +static void DLPI_disable_multi(DLPIStream *the_stream, queue_t *q, mblk_t *mp) +{ + dl_disabmulti_req_t *req = (dl_disabmulti_req_t*)(void *)mp->b_rptr; + uint8 *reqaddr = (uint8 *)(mp->b_rptr + req->dl_addr_offset); + D(bug(" DLPI_disable_multi(%p,%p) addr %02x%02x%02x%02x%02x%02x\n", the_stream, mp, reqaddr[0], reqaddr[1], reqaddr[2], reqaddr[3], reqaddr[4], reqaddr[5])); + + // Address must be a multicast address + if (get_address_type(reqaddr) != keaMulticast) { + DLPI_error_ack(the_stream, q, mp, DL_DISABMULTI_REQ, DL_BADADDR, 0); + return; + } + + // Find address in multicast list + uint8 *addr = the_stream->IsMulticastRegistered(reqaddr); + if (addr == NULL) { + DLPI_error_ack(the_stream, q, mp, DL_DISABMULTI_REQ, DL_BADADDR, 0); + return; + } + + // Found, then remove + the_stream->RemoveMulticast(addr); + Mac_sysfree(Host2MacAddr(addr)); + + // Tell add-on to disable multicast address + AO_disable_multicast(Host2MacAddr((uint8 *)reqaddr)); + + // No longer check multicast packets if no multicast addresses are registered + if (the_stream->multicast_list == NULL) + the_stream->flags &= ~kAcceptMulticasts; + + // Send reply + DLPI_ok_ack(the_stream, q, mp, DL_DISABMULTI_REQ); + return; +} + + +/* + * Handle DL_UNITDATA_REQ (transmit packet) + */ + +static void DLPI_unit_data(DLPIStream *the_stream, queue_t *q, mblk_t *mp) +{ + D(bug(" DLPI_unit_data(%p,%p)\n", the_stream, mp)); + dl_unitdata_req_t *req = (dl_unitdata_req_t *)(void *)mp->b_rptr; + + // Stream must be idle + if (the_stream->dlpi_state != DL_IDLE) { + + // Not idle, send error response + dl_uderror_ind_t *errp; + mblk_t *bp; + + int i = sizeof(dl_uderror_ind_t) + req->dl_dest_addr_length; + if ((bp = allocb(i, BPRI_HI)) == NULL) { + freemsg(mp); + return; + } + bp->b_datap->db_type = M_PROTO; + errp = (dl_uderror_ind_t *)(void *)bp->b_wptr; + errp->dl_primitive = DL_UDERROR_IND; + errp->dl_errno = DL_OUTSTATE; + errp->dl_unix_errno = 0; + errp->dl_dest_addr_length = req->dl_dest_addr_length; + errp->dl_dest_addr_offset = sizeof(dl_uderror_ind_t); + bp->b_wptr += sizeof(dl_uderror_ind_t); + memcpy((uint8 *)bp->b_wptr, ((uint8 *)req) + req->dl_dest_addr_offset, req->dl_dest_addr_length); + bp->b_wptr += req->dl_dest_addr_length; + qreply(q, bp); + + freemsg(mp); + return; + } + + // Build packet header and transmit packet + if ((mp = build_tx_packet_header(the_stream, mp, false)) != NULL) + transmit_packet(mp); +} + + +/* + * Ethernet packet allocator + */ + +#if SIZEOF_VOID_P != 4 || REAL_ADDRESSING == 0 +static uint32 ether_packet = 0; // Ethernet packet (cached allocation) +static uint32 n_ether_packets = 0; // Number of ethernet packets allocated so far (should be at most 1) + +EthernetPacket::EthernetPacket() +{ + ++n_ether_packets; + if (ether_packet && n_ether_packets == 1) + packet = ether_packet; + else { + packet = Mac_sysalloc(1516); + assert(packet != 0); + Mac_memset(packet, 0, 1516); + if (ether_packet == 0) + ether_packet = packet; + } +} + +EthernetPacket::~EthernetPacket() +{ + --n_ether_packets; + if (packet != ether_packet) + Mac_sysfree(packet); + if (n_ether_packets > 0) { + bug("WARNING: Nested allocation of ethernet packets!\n"); + } +} +#endif diff --git a/SheepShaver/src/EthernetDriver/ether.h b/SheepShaver/src/EthernetDriver/ether.h new file mode 100644 index 00000000..7ea2c881 --- /dev/null +++ b/SheepShaver/src/EthernetDriver/ether.h @@ -0,0 +1,113 @@ +/* + * ether.h - SheepShaver Ethernet Device Driver + * + * SheepShaver (C) 1997-2005 Marc Hellwig and Christian Bauer + * + * 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. + * + * 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 + */ + +#ifndef ETHER_H +#define ETHER_H + +struct queue; +struct msgb; +typedef struct queue queue_t; +typedef struct msgb mblk_t; + +// Prototypes for exported functions +extern "C" { +#pragma export on +extern uint32 ValidateHardware(void *theID); +struct install_info; +extern install_info* GetOTInstallInfo(); +extern uint8 InitStreamModule(void *theID); +extern void TerminateStreamModule(void); +#pragma export off +} + +extern bool NativeInitStreamModule(void *); +extern void NativeTerminateStreamModule(void); + +extern int ether_open(queue_t *rdq, void *dev, int flag, int sflag, void *creds); +extern int ether_close(queue_t *rdq, int flag, void *creds); +extern int ether_wput(queue_t *q, mblk_t *mp); +extern int ether_rsrv(queue_t *q); + +// System specific and internal functions/data +extern void EtherInit(void); +extern void EtherExit(void); + +extern void EtherIRQ(void); + +extern void AO_get_ethernet_address(uint32 addr); +extern void AO_enable_multicast(uint32 addr); +extern void AO_disable_multicast(uint32 addr); +extern void AO_transmit_packet(uint32 mp); + +extern mblk_t *allocb(size_t size, int pri); +extern void OTEnterInterrupt(void); +extern void OTLeaveInterrupt(void); + +extern void ether_dispatch_packet(uint32 p, uint32 length); +extern void ether_packet_received(mblk_t *mp); + +extern bool ether_driver_opened; + +// Ethernet packet allocator (optimized for 32-bit platforms in real addressing mode) +class EthernetPacket { +#if SIZEOF_VOID_P == 4 && REAL_ADDRESSING + uint8 packet[1516]; + public: + uint32 addr(void) const { return (uint32)packet; } +#else + uint32 packet; + public: + EthernetPacket(); + ~EthernetPacket(); + uint32 addr(void) const { return packet; } +#endif +}; + +// Copy packet data from message block to linear buffer (must hold at +// least 1514 bytes), returns packet length +static inline int ether_msgb_to_buffer(uint32 mp, uint8 *p) +{ + int len = 0; + while (mp) { + uint32 size = ReadMacInt32(mp + 16) - ReadMacInt32(mp + 12); + Mac2Host_memcpy(p, ReadMacInt32(mp + 12), size); + len += size; + p += size; + mp = ReadMacInt32(mp + 8); + } + return len; +} + +extern int32 num_wput; +extern int32 num_error_acks; +extern int32 num_tx_packets; +extern int32 num_tx_raw_packets; +extern int32 num_tx_normal_packets; +extern int32 num_tx_buffer_full; +extern int32 num_rx_packets; +extern int32 num_ether_irq; +extern int32 num_unitdata_ind; +extern int32 num_rx_fastpath; +extern int32 num_rx_no_mem; +extern int32 num_rx_dropped; +extern int32 num_rx_stream_not_ready; +extern int32 num_rx_no_unitdata_mem; + +#endif diff --git a/SheepShaver/src/EthernetDriver/ether_defs.h b/SheepShaver/src/EthernetDriver/ether_defs.h new file mode 100644 index 00000000..72bb58ed --- /dev/null +++ b/SheepShaver/src/EthernetDriver/ether_defs.h @@ -0,0 +1,552 @@ +/* + * ether_defs.h - Definitions for DLPI Ethernet Driver + * + * SheepShaver (C) 1997-2005 Marc Hellwig and Christian Bauer + * + * 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. + * + * 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 + */ + +#ifndef ETHER_DEFS_H +#define ETHER_DEFS_H + + +#if __MWERKS__ && __POWERPC__ +#ifndef PRAGMA_ALIGN_SUPPORTED +#define PRAGMA_ALIGN_SUPPORTED 1 +#endif +#define PACKED__ +#else +#define PACKED__ __attribute__ ((packed)) +#endif + + +/* + * Macros + */ + +// Get pointer to the read queue, assumes 'q' is a write queue ptr +#define RD(q) (&q[-1]) + +// Get pointer to the write queue, assumes 'q' is a read queue ptr +#define WR(q) (&q[1]) + +#define OTCompare48BitAddresses(p1, p2) \ + (*(const uint32*)((const uint8*)(p1)) == *(const uint32*)((const uint8*)(p2)) && \ + *(const uint16*)(((const uint8*)(p1))+4) == *(const uint16*)(((const uint8*)(p2))+4) ) + +#define OTCopy48BitAddress(p1, p2) \ + (*(uint32*)((uint8*)(p2)) = *(const uint32*)((const uint8*)(p1)), \ + *(uint16*)(((uint8*)(p2))+4) = *(const uint16*)(((const uint8*)(p1))+4) ) + +#define OTClear48BitAddress(p1) \ + (*(uint32*)((uint8*)(p1)) = 0, \ + *(uint16*)(((uint8*)(p1))+4) = 0 ) + +#define OTCompare8022SNAP(p1, p2) \ + (*(const uint32*)((const uint8*)(p1)) == *(const uint32*)((const uint8*)(p2)) && \ + *(((const uint8*)(p1))+4) == *(((const uint8*)(p2))+4) ) + +#define OTCopy8022SNAP(p1, p2) \ + (*(uint32*)((uint8*)(p2)) = *(const uint32*)((const uint8*)(p1)), \ + *(((uint8*)(p2))+4) = *(((const uint8*)(p1))+4) ) + +#define OTIs48BitBroadcastAddress(p1) \ + (*(uint32*)((uint8*)(p1)) == 0xffffffff && \ + *(uint16*)(((uint8*)(p1))+4) == 0xffff ) + +#define OTSet48BitBroadcastAddress(p1) \ + (*(uint32*)((uint8*)(p1)) = 0xffffffff, \ + *(uint16*)(((uint8*)(p1))+4) = 0xffff ) + +#define OTIs48BitZeroAddress(p1) \ + (*(uint32*)((uint8*)(p1)) == 0 && \ + *(uint16*)(((uint8*)(p1))+4) == 0 ) + + +/* + * Constants + */ + +enum { + // Address and packet lengths + kEnetPhysicalAddressLength = 6, + k8022SAPLength = 1, + k8022DLSAPLength = 2, + k8022SNAPLength = 5, + kMaxBoundAddrLength = 6 + 2 + 5, // addr/SAP/SNAP + kEnetAndSAPAddressLength = kEnetPhysicalAddressLength + k8022DLSAPLength, + kEnetPacketHeaderLength = (2 * kEnetPhysicalAddressLength) + k8022DLSAPLength, + k8022BasicHeaderLength = 3, // SSAP/DSAP/Control + k8022SNAPHeaderLength = k8022SNAPLength + k8022BasicHeaderLength, + kMinDIXSAP = 1501, + kEnetTSDU = 1514, + + // Special addresses + kSNAPSAP = 0xaa, + kMax8022SAP = 0xfe, + k8022GlobalSAP = 0xff, + kIPXSAP = 0xff, + + // DLPI interface states + DL_UNBOUND = 0, + + // Message types + M_DATA = 0, + M_PROTO = 1, + M_IOCTL = 14, + M_IOCACK = 129, + M_IOCNAK = 130, + M_PCPROTO = 131, // priority message + M_FLUSH = 134, + FLUSHDATA = 0, + FLUSHALL = 1, + FLUSHR = 1, + FLUSHW = 2, + FLUSHRW = 3, + + // DLPI primitives + DL_INFO_REQ = 0, + DL_BIND_REQ = 1, + DL_PEER_BIND = 1, + DL_HIERARCHICAL_BIND = 2, + DL_UNBIND_REQ = 2, + DL_INFO_ACK = 3, + DL_BIND_ACK = 4, + DL_ERROR_ACK = 5, + DL_OK_ACK = 6, + DL_UNITDATA_REQ = 7, + DL_UNITDATA_IND = 8, + DL_UDERROR_IND = 9, + DL_SUBS_UNBIND_REQ = 21, + DL_SUBS_BIND_REQ = 27, + DL_SUBS_BIND_ACK = 28, + DL_ENABMULTI_REQ = 29, + DL_DISABMULTI_REQ = 30, + DL_PHYS_ADDR_REQ = 49, + DL_PHYS_ADDR_ACK = 50, + DL_FACT_PHYS_ADDR = 1, + DL_CURR_PHYS_ADDR = 2, + + // DLPI states + DL_IDLE = 3, + + // DLPI error codes + DL_BADADDR = 1, // improper address format + DL_OUTSTATE = 3, // improper state + DL_SYSERR = 4, // UNIX system error + DL_UNSUPPORTED = 7, // service unsupported + DL_BADPRIM = 9, // primitive unknown + DL_NOTSUPPORTED = 18, // primitive not implemented + DL_TOOMANY = 19, // limit exceeded + + // errnos + MAC_ENXIO = 6, + MAC_ENOMEM = 12, + MAC_EINVAL = 22, + + // Various DLPI constants + DL_CLDLS = 2, // connectionless data link service + DL_STYLE1 = 0x500, + DL_VERSION_2 = 2, + DL_CSMACD = 0, + DL_ETHER = 4, + DL_UNKNOWN = -1, + + // ioctl() codes + I_OTSetFramingType = (('O' << 8) | 2), + kOTGetFramingValue = -1, + kOTFramingEthernet = 1, + kOTFramingEthernetIPX = 2, + kOTFramingEthernet8023 = 4, + kOTFraming8022 = 8, + I_OTSetRawMode = (('O' << 8) | 3), + DL_IOC_HDR_INFO = (('l' << 8) | 10), + + // Buffer allocation priority + BPRI_LO = 1, + BPRI_HI = 3, + + // Misc constants + kEnetModuleID = 7101 +}; + +enum EAddrType { + keaStandardAddress = 0, + keaMulticast, + keaBroadcast, + keaBadAddress +}; + + +/* + * Data member wrappers + */ + +// Forward declarations +struct datab; +struct msgb; +struct queue; +struct multicast_node; +struct DLPIStream; + +// Optimize for 32-bit big endian targets +#if defined(WORDS_BIGENDIAN) && (SIZEOF_VOID_P == 4) + +// Predefined member types +typedef int8 nw_int8; +typedef int16 nw_int16; +typedef int32 nw_int32; +typedef uint8 nw_uint8; +typedef uint16 nw_uint16; +typedef uint32 nw_uint32; +typedef int nw_bool; +typedef uint8 * nw_uint8_p; +typedef void * nw_void_p; +typedef datab * nw_datab_p; +typedef msgb * nw_msgb_p; +typedef queue * nw_queue_p; +typedef multicast_node *nw_multicast_node_p; +typedef DLPIStream * nw_DLPIStream_p; + +#else + +// Big-endian memory accessor +template< int nbytes > +struct nw_memory_helper; + +template<> +struct nw_memory_helper<1> { + static inline uint8 load(void *ptr) { return *((uint8 *)ptr); } + static inline void store(void *ptr, uint8 val) { *((uint8 *)ptr) = val; } +}; + +template<> +struct nw_memory_helper<2> { + static inline uint16 load(void *ptr) { return ntohs(*((uint16 *)ptr)); } + static inline void store(void *ptr, uint16 val) { *((uint16 *)ptr) = htons(val); } +}; + +template<> +struct nw_memory_helper<4> { + static inline uint32 load(void *ptr) { return ntohl(*((uint32 *)ptr)); } + static inline void store(void *ptr, uint32 val) { *((uint32 *)ptr) = htonl(val); } +}; + +// Scalar data member wrapper (specialise for pointer member types?) +template< class type, class public_type > +class nw_scalar_member_helper { + uint8 _pad[sizeof(type)]; +public: + operator public_type () const { + return (public_type)(uintptr)nw_memory_helper::load((void *)this); + } + public_type operator -> () const { + return this->operator public_type (); + } + nw_scalar_member_helper & operator = (public_type val) { + nw_memory_helper::store((void *)this, (type)(uintptr)val); + return *this; + } + nw_scalar_member_helper & operator += (int val) { + *this = *this + val; + return *this; + } + nw_scalar_member_helper & operator -= (int val) { + *this = *this - val; + return *this; + } + nw_scalar_member_helper & operator &= (int val) { + *this = *this & val; + return *this; + } + nw_scalar_member_helper & operator |= (int val) { + *this = *this | val; + return *this; + } +}; + +// Predefined member types +typedef nw_scalar_member_helper nw_int8; +typedef nw_scalar_member_helper nw_int16; +typedef nw_scalar_member_helper nw_int32; +typedef nw_scalar_member_helper nw_uint8; +typedef nw_scalar_member_helper nw_uint16; +typedef nw_scalar_member_helper nw_uint32; +typedef nw_scalar_member_helper nw_bool; +typedef nw_scalar_member_helper nw_uint8_p; +typedef nw_scalar_member_helper nw_void_p; +typedef nw_scalar_member_helper nw_datab_p; +typedef nw_scalar_member_helper nw_msgb_p; +typedef nw_scalar_member_helper nw_queue_p; +typedef nw_scalar_member_helper nw_multicast_node_p; +typedef nw_scalar_member_helper nw_DLPIStream_p; + +#endif + + +/* + * Structures + */ + +// Data block +struct datab { + nw_datab_p db_freep; + nw_uint8_p db_base; + nw_uint8_p db_lim; + nw_uint8 db_ref; + nw_uint8 db_type; + // ... +}; + +// Message block +struct msgb { + nw_msgb_p b_next; + nw_msgb_p b_prev; + nw_msgb_p b_cont; + nw_uint8_p b_rptr; + nw_uint8_p b_wptr; + nw_datab_p b_datap; + // ... +}; + +// Queue (full structure required because of size) +struct queue { + nw_void_p q_qinfo; + nw_msgb_p q_first; + nw_msgb_p q_last; + nw_queue_p q_next; + nw_queue_p q_link; + nw_DLPIStream_p q_ptr; + nw_uint32 q_count; + nw_int32 q_minpsz; + nw_int32 q_maxpsz; + nw_uint32 q_hiwat; + nw_uint32 q_lowat; + nw_void_p q_bandp; + nw_uint16 q_flag; + nw_uint8 q_nband; + uint8 _q_pad1[1]; + nw_void_p q_osx; + nw_queue_p q_ffcp; + nw_queue_p q_bfcp; +}; +typedef struct queue queue_t; + +// M_IOCTL parameters +struct iocblk { + nw_int32 ioc_cmd; + nw_void_p ioc_cr; + nw_uint32 ioc_id; + nw_uint32 ioc_count; + nw_int32 ioc_error; + nw_int32 ioc_rval; + int32 _ioc_filler[4]; +}; + +// Priority specification +struct dl_priority_t { + nw_int32 dl_min, dl_max; +}; + +// DPLI primitives +struct dl_info_req_t { + nw_uint32 dl_primitive; // DL_INFO_REQ +}; + +struct dl_info_ack_t { + nw_uint32 dl_primitive; // DL_INFO_ACK + nw_uint32 dl_max_sdu; + nw_uint32 dl_min_sdu; + nw_uint32 dl_addr_length; + nw_uint32 dl_mac_type; + nw_uint32 dl_reserved; + nw_uint32 dl_current_state; + nw_int32 dl_sap_length; + nw_uint32 dl_service_mode; + nw_uint32 dl_qos_length; + nw_uint32 dl_qos_offset; + nw_uint32 dl_qos_range_length; + nw_uint32 dl_qos_range_offset; + nw_uint32 dl_provider_style; + nw_uint32 dl_addr_offset; + nw_uint32 dl_version; + nw_uint32 dl_brdcst_addr_length; + nw_uint32 dl_brdcst_addr_offset; + nw_uint32 dl_growth; +}; + +struct dl_bind_req_t { + nw_uint32 dl_primitive; // DL_BIND_REQ + nw_uint32 dl_sap; + nw_uint32 dl_max_conind; + nw_uint16 dl_service_mode; + nw_uint16 dl_conn_mgmt; + nw_uint32 dl_xidtest_flg; +}; + +struct dl_bind_ack_t { + nw_uint32 dl_primitive; // DL_BIND_ACK + nw_uint32 dl_sap; + nw_uint32 dl_addr_length; + nw_uint32 dl_addr_offset; + nw_uint32 dl_max_conind; + nw_uint32 dl_xidtest_flg; +}; + +struct dl_error_ack_t { + nw_uint32 dl_primitive; // DL_ERROR_ACK + nw_uint32 dl_error_primitive; + nw_uint32 dl_errno; + nw_uint32 dl_unix_errno; +}; + +struct dl_ok_ack_t { + nw_uint32 dl_primitive; // DL_ERROR_ACK + nw_uint32 dl_correct_primitive; +}; + +struct dl_unitdata_req_t { + nw_uint32 dl_primitive; // DL_UNITDATA_REQ + nw_uint32 dl_dest_addr_length; + nw_uint32 dl_dest_addr_offset; + dl_priority_t dl_priority; +}; + +struct dl_unitdata_ind_t { + nw_uint32 dl_primitive; // DL_UNITDATA_IND + nw_uint32 dl_dest_addr_length; + nw_uint32 dl_dest_addr_offset; + nw_uint32 dl_src_addr_length; + nw_uint32 dl_src_addr_offset; + nw_uint32 dl_group_address; +}; + +struct dl_uderror_ind_t { + nw_uint32 dl_primitive; // DL_UDERROR_IND + nw_uint32 dl_dest_addr_length; + nw_uint32 dl_dest_addr_offset; + nw_uint32 dl_unix_errno; + nw_uint32 dl_errno; +}; + +struct dl_subs_bind_req_t { + nw_uint32 dl_primitive; // DL_SUBS_BIND_REQ + nw_uint32 dl_subs_sap_offset; + nw_uint32 dl_subs_sap_length; + nw_uint32 dl_subs_bind_class; +}; + +struct dl_subs_bind_ack_t { + nw_uint32 dl_primitive; // DL_SUBS_BIND_ACK + nw_uint32 dl_subs_sap_offset; + nw_uint32 dl_subs_sap_length; +}; + +struct dl_subs_unbind_req_t { + nw_uint32 dl_primitive; // DL_SUBS_UNBIND_REQ + nw_uint32 dl_subs_sap_offset; + nw_uint32 dl_subs_sap_length; +}; + +struct dl_enabmulti_req_t { + nw_uint32 dl_primitive; // DL_ENABMULTI_REQ + nw_uint32 dl_addr_length; + nw_uint32 dl_addr_offset; +}; + +struct dl_disabmulti_req_t { + nw_uint32 dl_primitive; // DL_DISABMULTI_REQ + nw_uint32 dl_addr_length; + nw_uint32 dl_addr_offset; +}; + +struct dl_phys_addr_req_t { + nw_uint32 dl_primitive; // DL_PHYS_ADDR_REQ + nw_uint32 dl_addr_type; +}; + +struct dl_phys_addr_ack_t { + nw_uint32 dl_primitive; // DL_PHYS_ADDR_ACK + nw_uint32 dl_addr_length; + nw_uint32 dl_addr_offset; +}; + +// Parameters for I_OTSetRawMode/kOTSetRecvMode ioctl() +struct dl_recv_control_t { + nw_uint32 dl_primitive; + nw_uint32 dl_flags; + nw_uint32 dl_truncation_length; +}; + +union DL_primitives { + nw_uint32 dl_primitive; + dl_info_req_t info_req; + dl_info_ack_t info_ack; + dl_bind_req_t bind_req; + dl_bind_ack_t bind_ack; + dl_error_ack_t error_ack; + dl_ok_ack_t ok_ack; + dl_unitdata_req_t unitdata_req; + dl_unitdata_ind_t unitdata_ind; + dl_uderror_ind_t uderror_ind; + dl_subs_bind_req_t subs_bind_req; + dl_subs_bind_ack_t subs_bind_ack; + dl_subs_unbind_req_t subs_unbind_req; + dl_enabmulti_req_t enabmulti_req; + dl_disabmulti_req_t disabmulti_req; + dl_phys_addr_req_t phys_addr_req; + dl_phys_addr_ack_t phys_addr_ack; +}; + +#ifdef PRAGMA_ALIGN_SUPPORTED +#pragma options align=mac68k +#endif + +// Packet headers +struct EnetPacketHeader { + uint8 fDestAddr[6]; + uint8 fSourceAddr[6]; + nw_uint16 fProto; +} PACKED__; + +struct T8022Header { + uint8 fDSAP; + uint8 fSSAP; + uint8 fCtrl; +} PACKED__; + +struct T8022SNAPHeader { + uint8 fDSAP; + uint8 fSSAP; + uint8 fCtrl; + uint8 fSNAP[k8022SNAPLength]; +} PACKED__; + +struct T8022FullPacketHeader { + EnetPacketHeader fEnetPart; + T8022SNAPHeader f8022Part; +} PACKED__; + +struct T8022AddressStruct { + uint8 fHWAddr[6]; + nw_uint16 fSAP; + uint8 fSNAP[k8022SNAPLength]; +} PACKED__; + +#ifdef PRAGMA_ALIGN_SUPPORTED +#pragma options align=reset +#endif + +#endif diff --git a/SheepShaver/src/EthernetDriver/ethernet.ndrv b/SheepShaver/src/EthernetDriver/ethernet.ndrv new file mode 100644 index 0000000000000000000000000000000000000000..857c765eb5c0e4d7e988e5d641675f6d431045ce GIT binary patch literal 11316 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 literal 0 HcmV?d00001 diff --git a/SheepShaver/src/EthernetDriver/macos_util.cpp b/SheepShaver/src/EthernetDriver/macos_util.cpp new file mode 100644 index 00000000..0cf05e35 --- /dev/null +++ b/SheepShaver/src/EthernetDriver/macos_util.cpp @@ -0,0 +1 @@ +#include "sysdeps.h" #include "macos_util.h" #include "xlowmem.h" #include #include #include #define DEBUG 0 #include "debug.h" /* * Find symbol in shared library (using CFM) * lib and sym must be Pascal strings! */ typedef OpaqueCFragConnectionID * ConnectionID; typedef unsigned char SymClass; static uint32 FindLibSymbol(Str63 lib, Str255 sym) { ConnectionID conn_id = 0; Ptr main_addr = NULL; Str255 err = ""; Ptr sym_addr = NULL; SymClass sym_class = 0; int16 res; res = GetSharedLibrary(lib, FOURCC('p','w','p','c'), 1, &conn_id, &main_addr, err); D(bug(" GetSharedLibrary: ret %d, connection ID %ld, main %p\n", res, conn_id, main_addr)); if (res) return NULL; res = FindSymbol(conn_id, sym, &sym_addr, &sym_class); D(bug(" FindSymbol: ret %d, sym_addr %p, sym_class %ld\n", res, sym_addr, sym_class));//!!?? CloseConnection(&conn_id); if (res) return NULL; else return (uint32)sym_addr; } uint32 FindLibSymbol(char *lib_name, char *sym_name) { Str63 lib; memcpy(&lib[0], lib_name, lib_name[0]+1); Str255 sym; memcpy(&sym[0], sym_name, sym_name[0]+1); return FindLibSymbol(lib, sym); } /* * Memory allocators in MacOS system heap zone */ uint32 Mac_sysalloc(uint32 size) { return (uint32)NewPtrSys(size); } void Mac_sysfree(uint32 addr) { DisposePtr((char *)addr); } /* * Glue for calling MacOS routines */ #define prolog ;\ mflr r0 ;\ stw r0,8(r1) ;\ stw r2,12(r1) ;\ stwu r1,-64(r1) ;\ lwz r0,0(r3) ;\ lwz r2,4(r3) ;\ mtctr r0 #define epilog ;\ bctrl ;\ lwz r0,64+8(r1) ;\ lwz r2,64+12(r1);\ mtlr r0 ;\ addi r1,r1,64 ;\ blr asm uint32 call_macos(register uint32 tvect) { prolog epilog } asm uint32 call_macos1(register uint32 tvect, register uint32 arg1) { prolog mr r3,r4 epilog } asm uint32 call_macos2(register uint32 tvect, register uint32 arg1, register uint32 arg2) { prolog mr r3,r4 mr r4,r5 epilog } asm uint32 call_macos3(register uint32 tvect, register uint32 arg1, register uint32 arg2, register uint32 arg3) { prolog mr r3,r4 mr r4,r5 mr r5,r6 epilog } asm uint32 call_macos4(register uint32 tvect, register uint32 arg1, register uint32 arg2, register uint32 arg3, register uint32 arg4) { prolog mr r3,r4 mr r4,r5 mr r5,r6 mr r6,r7 epilog } asm uint32 call_macos5(register uint32 tvect, register uint32 arg1, register uint32 arg2, register uint32 arg3, register uint32 arg4, register uint32 arg5) { prolog mr r3,r4 mr r4,r5 mr r5,r6 mr r6,r7 mr r7,r8 epilog } asm uint32 call_macos6(register uint32 tvect, register uint32 arg1, register uint32 arg2, register uint32 arg3, register uint32 arg4, register uint32 arg5, register uint32 arg6) { prolog mr r3,r4 mr r4,r5 mr r5,r6 mr r6,r7 mr r7,r8 mr r8,r9 epilog } asm uint32 call_macos7(register uint32 tvect, register uint32 arg1, register uint32 arg2, register uint32 arg3, register uint32 arg4, register uint32 arg5, register uint32 arg6, register uint32 arg7) { prolog mr r3,r4 mr r4,r5 mr r5,r6 mr r6,r7 mr r7,r8 mr r8,r9 mr r9,r10 epilog } /* * Some standard C library implementations */ extern "C" void *memcpy(void *dest, const void *src, size_t n); void *memcpy(void *dest, const void *src, size_t n) { BlockMoveData(src, dest, n); return dest; } extern "C" void *memset(void *s, int c, size_t n); void *memset(void *s, int c, size_t n) { if (c == 0) BlockZero(s, n); else { char *p = (char *)s; n++; while (--n) *p++ = c; } return s; } extern "C" int memcmp(const void *s1, const void *s2, size_t n); int memcmp(const void *s1, const void *s2, size_t n) { const unsigned char *d = (const unsigned char *)s1; const unsigned char *s = (const unsigned char *)s2; n++; while (--n) { int r; if (r = (*d - *s)) return r; ++d; ++s; } return 0; } extern "C" int printf(const char *format, ...); int printf(const char *format, ...) { return 0; } \ No newline at end of file diff --git a/SheepShaver/src/EthernetDriver/macos_util.h b/SheepShaver/src/EthernetDriver/macos_util.h new file mode 100644 index 00000000..20cc5ec4 --- /dev/null +++ b/SheepShaver/src/EthernetDriver/macos_util.h @@ -0,0 +1 @@ +#ifndef MACOS_UTIL_H #define MACOS_UTIL_H // Macro for calling MacOS routines #define CallMacOS(type, tvect) call_macos((uintptr)tvect) #define CallMacOS1(type, tvect, arg1) call_macos1((uintptr)tvect, (uintptr)arg1) #define CallMacOS2(type, tvect, arg1, arg2) call_macos2((uintptr)tvect, (uintptr)arg1, (uintptr)arg2) #define CallMacOS3(type, tvect, arg1, arg2, arg3) call_macos3((uintptr)tvect, (uintptr)arg1, (uintptr)arg2, (uintptr)arg3) #define CallMacOS4(type, tvect, arg1, arg2, arg3, arg4) call_macos4((uintptr)tvect, (uintptr)arg1, (uintptr)arg2, (uintptr)arg3, (uintptr)arg4) #define CallMacOS5(type, tvect, arg1, arg2, arg3, arg4, arg5) call_macos5((uintptr)tvect, (uintptr)arg1, (uintptr)arg2, (uintptr)arg3, (uintptr)arg4, (uintptr)arg5) #define CallMacOS6(type, tvect, arg1, arg2, arg3, arg4, arg5, arg6) call_macos6((uintptr)tvect, (uintptr)arg1, (uintptr)arg2, (uintptr)arg3, (uintptr)arg4, (uintptr)arg5, (uintptr)arg6) #define CallMacOS7(type, tvect, arg1, arg2, arg3, arg4, arg5, arg6, arg7) call_macos7((uintptr)tvect, (uintptr)arg1, (uintptr)arg2, (uintptr)arg3, (uintptr)arg4, (uintptr)arg5, (uintptr)arg6, (uintptr)arg7) #ifdef __cplusplus extern "C" { #endif extern uint32 call_macos(uint32 tvect); extern uint32 call_macos1(uint32 tvect, uint32 arg1); extern uint32 call_macos2(uint32 tvect, uint32 arg1, uint32 arg2); extern uint32 call_macos3(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3); extern uint32 call_macos4(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4); extern uint32 call_macos5(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5); extern uint32 call_macos6(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5, uint32 arg6); extern uint32 call_macos7(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5, uint32 arg6, uint32 arg7); #ifdef __cplusplus } #endif // Construct four-character-code from string #define FOURCC(a,b,c,d) (((uint32)(a) << 24) | ((uint32)(b) << 16) | ((uint32)(c) << 8) | (uint32)(d)) extern uint32 FindLibSymbol(char *lib, char *sym); // Find symbol in shared library extern uint32 Mac_sysalloc(uint32 size); // Allocate block in MacOS system heap zone extern void Mac_sysfree(uint32 addr); // Release block occupied by the nonrelocatable block p #endif /* MACOS_UTIL_H */ \ No newline at end of file diff --git a/SheepShaver/src/EthernetDriver/sysdeps.h b/SheepShaver/src/EthernetDriver/sysdeps.h new file mode 100644 index 00000000..ffd90e06 --- /dev/null +++ b/SheepShaver/src/EthernetDriver/sysdeps.h @@ -0,0 +1 @@ +#ifndef SYSDEPS_H #define SYSDEPS_H #include #define SIZEOF_VOID_P 4 #define WORDS_BIGENDIAN 1 #define REAL_ADDRESSING 1 /* Define to build the Ethernet driver completly in MacOS space */ #define BUILD_ETHER_FULL_DRIVER 1 #define ntohl(x) ((uint32)(x)) #define ntohs(x) ((uint16)(x)) #define assert(expr) typedef int bool; typedef signed char int8; typedef signed short int16; typedef signed int int32; typedef unsigned char uint8; typedef unsigned short uint16; typedef unsigned int uint32; typedef uint32 uintptr; #endif /* SYSDEPS_H */ \ No newline at end of file diff --git a/SheepShaver/src/EthernetDriver/xlowmem.h b/SheepShaver/src/EthernetDriver/xlowmem.h new file mode 100644 index 00000000..a37282b3 --- /dev/null +++ b/SheepShaver/src/EthernetDriver/xlowmem.h @@ -0,0 +1,64 @@ +/* + * xlowmem.h - Definitions for extra Low Memory globals (0x2800..) + * + * SheepShaver (C) 1997-2005 Christian Bauer and Marc Hellwig + * + * 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. + * + * 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 + */ + +#ifndef XLOWMEM_H +#define XLOWMEM_H + +// Modes for XLM_RUN_MODE +#define MODE_68K 0 // 68k emulator active +#define MODE_NATIVE 1 // Switched to native mode +#define MODE_EMUL_OP 2 // 68k emulator active, within EMUL_OP routine + +#define XLM_SIGNATURE 0x2800 // SheepShaver signature +#define XLM_KERNEL_DATA 0x2804 // Pointer to Kernel Data +#define XLM_TOC 0x2808 // TOC pointer of emulator +#define XLM_SHEEP_OBJ 0x280c // Pointer to SheepShaver object +#define XLM_RUN_MODE 0x2810 // Current run mode, see enum above +#define XLM_68K_R25 0x2814 // Contents of the 68k emulator's r25 (which contains the interrupt level), saved upon entering EMUL_OP mode, used by Execute68k() and the USR1 signal handler +#define XLM_IRQ_NEST 0x2818 // Interrupt disable nesting counter (>0: disabled) +#define XLM_PVR 0x281c // Theoretical PVR +#define XLM_BUS_CLOCK 0x2820 // Bus clock speed in Hz (for DriverServicesLib patch) +#define XLM_EMUL_RETURN_PROC 0x2824 // Pointer to EMUL_RETURN routine +#define XLM_EXEC_RETURN_PROC 0x2828 // Pointer to EXEC_RETURN routine +#define XLM_EMUL_OP_PROC 0x282c // Pointer to EMUL_OP routine +#define XLM_EMUL_RETURN_STACK 0x2830 // Stack pointer for EMUL_RETURN +#define XLM_RES_LIB_TOC 0x2834 // TOC pointer of Resources library +#define XLM_GET_RESOURCE 0x2838 // Pointer to native GetResource() routine +#define XLM_GET_1_RESOURCE 0x283c // Pointer to native Get1Resource() routine +#define XLM_GET_IND_RESOURCE 0x2840 // Pointer to native GetIndResource() routine +#define XLM_GET_1_IND_RESOURCE 0x2844 // Pointer to native Get1IndResource() routine +#define XLM_R_GET_RESOURCE 0x2848 // Pointer to native RGetResource() routine +#define XLM_EXEC_RETURN_OPCODE 0x284c // EXEC_RETURN opcode for Execute68k() +#define XLM_ZERO_PAGE 0x2850 // Pointer to read-only page with all bits set to 0 +#define XLM_R13 0x2854 // Pointer to .sdata section (Linux) + +#define XLM_ETHER_AO_GET_HWADDR 0x28b0 // Pointer to ethernet A0_get_ethernet_address() function +#define XLM_ETHER_AO_ADD_MULTI 0x28b4 // Pointer to ethernet A0_enable_multicast() function +#define XLM_ETHER_AO_DEL_MULTI 0x28b8 // Pointer to ethernet A0_disable_multicast() function +#define XLM_ETHER_AO_SEND_PACKET 0x28bc // Pointer to ethernet A0_transmit_packet() function +#define XLM_ETHER_INIT 0x28c0 // Pointer to ethernet InitStreamModule() function +#define XLM_ETHER_TERM 0x28c4 // Pointer to ethernet TerminateStreamModule() function +#define XLM_ETHER_OPEN 0x28c8 // Pointer to ethernet ether_open() function +#define XLM_ETHER_CLOSE 0x28cc // Pointer to ethernet ether_close() function +#define XLM_ETHER_WPUT 0x28d0 // Pointer to ethernet ether_wput() function +#define XLM_ETHER_RSRV 0x28d4 // Pointer to ethernet ether_rsrv() function +#define XLM_VIDEO_DOIO 0x28d8 // Pointer to video DoDriverIO() function + +#endif