BIOS.Ethernet3Com90x.Mod 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905
  1. (* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
  2. MODULE Ethernet3Com90x; (** AUTHOR "rstrobl/jaco/prk/pjm/mvt/BdT"; PURPOSE "3Com 3C90X ethernet driver"; *)
  3. (*
  4. Aos driver for 3Com EtherLink XL ethernet adapter.
  5. Auto-select not yet supported: configure the card using the 3Com-supplied utility.
  6. Based on Native Oberon driver by Reto Strobl, Jaco Geldenhuys, Patrik Reali, Pieter Muller.
  7. Reference: 3Com, "3C90x Network Interface Cards Technical Reference: 3Com EtherLink XL NICs".
  8. Config strings:
  9. 3C90xMedia =
  10. 1 -> 10Base-T
  11. 2 -> 10 Mbps AU
  12. 4 -> 10Base2
  13. 5 -> 100Base-TX
  14. 6 -> 100Base-FX
  15. 7 -> MII
  16. 9 -> Auto (3C90xB only)
  17. 3C90xDuplex =
  18. 0 -> read duplex setting from EPROM
  19. 1 -> half-duplex
  20. 2 -> full-duplex
  21. *)
  22. IMPORT SYSTEM, Machine, KernelLog, Modules, Objects,
  23. PCI, Plugins, Network, Kernel;
  24. CONST
  25. Name = "3Com90x#";
  26. Desc = "3Com Etherlink XL ethernet driver";
  27. MaxPkt = 1514;
  28. MTU = MaxPkt-14;
  29. EarlyThresh = MAX(LONGINT);
  30. ReceiveBuffers = 128;
  31. SendTimeout = 5*1000; (* ms *)
  32. NewTries = 32;
  33. (* Media Types *)
  34. MediaMask = {20..23};
  35. Base10T = {}; (*AUI = {20};*) Base10Coax = {21, 20}; (*Base100TX = {22};*)
  36. (*Base100FX = {22, 20};*) MII = {22, 21}; Auto = {23};
  37. (* Controller flags *)
  38. Eprom230 = 0; InvertMIIPower = 1;
  39. (* models *)
  40. Model90x = 0; Model90xB = 1; Model90xC = 2;
  41. TYPE
  42. MemRangeArray = ARRAY 2 OF Machine.Range;
  43. DPD = POINTER TO RECORD (* p. 6-1 *)
  44. (* dummy : CHAR; may be used for padding, next field must be aligned at multiplee of 8 bytes *)
  45. (* start fixed-layout *)
  46. nextPhysAdr: LONGINT; (* 00H *)
  47. status: SET; (* 04 *)
  48. frag: ARRAY 5 OF RECORD
  49. dataPhysAdr: LONGINT; (* 08H, 10H, 18H, 20H, 28H *)
  50. dataLen: LONGINT (* 0CH, 14H, 1CH, 24H, 2CH *)
  51. END;
  52. dst, src: ARRAY 6 OF CHAR;
  53. type: INTEGER;
  54. (* end fixed-layout *)
  55. physAdr: LONGINT; (* assume physical address of dpd^ will not change *)
  56. END;
  57. UPD = POINTER TO RECORD (* p. 7-1 *)
  58. (* dummy : CHAR; may be used for padding, next field must be aligned at multiplee of 8 bytes *)
  59. (* start fixed-layout *)
  60. nextPhysAdr: LONGINT; (* 00H *)
  61. status: SET; (* 04 *)
  62. frag: ARRAY 3 OF RECORD
  63. dataPhysAdr: LONGINT; (* 08H, 10H, 18H *)
  64. dataLen: LONGINT (* 0CH, 14H, 1CH *)
  65. END;
  66. dst, src: ARRAY 6 OF CHAR;
  67. type: INTEGER;
  68. (* end fixed-layout *)
  69. physAdr: LONGINT; (* assume physical address of upd^ will not change *)
  70. buffer: Network.Buffer;
  71. next: UPD;
  72. END;
  73. VAR
  74. installed: LONGINT; (* number of installed devices *)
  75. NdnTxReclaimError, NdnTxStatusOverflow, NdnMaxCollisions, NdnTxUnderrun, NdnTxJabber, NnewRetry,
  76. NspuriousComplete, NupOverrun, NupRuntFrame, NupAlignmentError, NupCrcError, NupOversizedFrame,
  77. NupOverflow, NbadSize, Ninterrupt, NintHostError, NintTxComplete, NintRxEarly, NintRequested,
  78. NintUpdateStats, NintLinkEvent, NintDnComplete, NintUpComplete, NstatCarrierLost,
  79. NstatSqeErrors, NstatMultipleCollisions, NstatSingleCollisions, NstatLateCollisions, NstatRxOverruns,
  80. NstatFramesXmittedOk, NstatFramesRcvdOk, NstatFramesDeferred, NstatBytesRcvdOk,
  81. NstatBytesXmittedOk, NstatBadSSD, NupCompleteLoops, NsendTimeouts: LONGINT;
  82. TYPE
  83. Timer = OBJECT (Kernel.Timer)
  84. VAR
  85. ms: LONGINT;
  86. c: Controller;
  87. quit: BOOLEAN;
  88. PROCEDURE &Init2*(c: Controller);
  89. BEGIN
  90. SELF.c := c; SELF.quit := FALSE; SELF.ms := 1;
  91. Init
  92. END Init2;
  93. BEGIN {ACTIVE}
  94. WHILE ~quit DO
  95. c.HandleInterrupt();
  96. Sleep(ms);
  97. END
  98. END Timer;
  99. Controller* = OBJECT
  100. VAR
  101. base, irq*: LONGINT;
  102. dev: LinkDevice;
  103. flags: SET;
  104. model: LONGINT;
  105. media: SET;
  106. dpd: DPD;
  107. upd: UPD;
  108. bus, pdev, fct: LONGINT;
  109. interrupted: BOOLEAN;
  110. timer: Timer;
  111. PROCEDURE HandleInterrupt;
  112. VAR type, len: LONGINT; status: SET; int: INTEGER; ch: CHAR; buf: Network.Buffer;
  113. BEGIN
  114. interrupted := TRUE;
  115. Machine.AtomicInc(Ninterrupt);
  116. Machine.Portin16(base+0EH, SYSTEM.VAL(INTEGER, status)); (* IntStatus (p. 8-3) *)
  117. IF 1 IN status THEN (* hostError *)
  118. Machine.AtomicInc(NintHostError)
  119. (* to do: reset *)
  120. END;
  121. IF 2 IN status THEN (* txComplete *)
  122. Machine.AtomicInc(NintTxComplete);
  123. Machine.Portout8(base+1BH, 0X) (* TxStatus (p. 6-23) *)
  124. END;
  125. IF 5 IN status THEN (* rxEarly *)
  126. Machine.AtomicInc(NintRxEarly)
  127. END;
  128. IF 6 IN status THEN (* intRequested (or Countdown expiry) *)
  129. Machine.AtomicInc(NintRequested)
  130. END;
  131. IF 7 IN status THEN (* updateStats *)
  132. Machine.AtomicInc(NintUpdateStats);
  133. SetWindow(base, 6);
  134. Machine.Portin8(base+0, ch); Machine.AtomicAdd(NstatCarrierLost, ORD(ch));
  135. Machine.Portin8(base+1, ch); Machine.AtomicAdd(NstatSqeErrors, ORD(ch));
  136. Machine.Portin8(base+2, ch); Machine.AtomicAdd(NstatMultipleCollisions, ORD(ch));
  137. Machine.Portin8(base+3, ch); Machine.AtomicAdd(NstatSingleCollisions, ORD(ch));
  138. Machine.Portin8(base+4, ch); Machine.AtomicAdd(NstatLateCollisions, ORD(ch));
  139. Machine.Portin8(base+5, ch); Machine.AtomicAdd(NstatRxOverruns, ORD(ch));
  140. Machine.Portin8(base+6, ch); Machine.AtomicAdd(NstatFramesXmittedOk, ORD(ch));
  141. Machine.Portin8(base+7, ch); Machine.AtomicAdd(NstatFramesRcvdOk, ORD(ch));
  142. Machine.Portin8(base+9, ch); (* UpperFramesOk *)
  143. Machine.AtomicAdd(NstatFramesXmittedOk, ORD(ch) DIV 16 MOD 16 * 100H);
  144. Machine.AtomicAdd(NstatFramesRcvdOk, ORD(ch) MOD 16 * 100H);
  145. Machine.Portin8(base+8, ch); Machine.AtomicAdd(NstatFramesDeferred, ORD(ch));
  146. Machine.Portin16(base+0AH, int); Machine.AtomicAdd(NstatBytesRcvdOk, LONG(int) MOD 10000H);
  147. Machine.Portin16(base+0CH, int); Machine.AtomicAdd(NstatBytesXmittedOk, LONG(int) MOD 10000H);
  148. SetWindow(base, 4);
  149. Machine.Portin8(base+0CH, ch); Machine.AtomicAdd(NstatBadSSD, ORD(ch));
  150. Machine.Portin8(base+0DH, ch); (* UpperBytesOk *)
  151. Machine.AtomicAdd(NstatBytesXmittedOk, ORD(ch) DIV 16 MOD 16 * 10000H);
  152. Machine.AtomicAdd(NstatBytesRcvdOk, ORD(ch) MOD 16 * 10000H)
  153. (* now back in window 4 *)
  154. END;
  155. IF 8 IN status THEN (* linkEvent *)
  156. Machine.AtomicInc(NintLinkEvent)
  157. (* to do: read AutoNegExpansion via MII *)
  158. END;
  159. IF 9 IN status THEN
  160. Machine.AtomicInc(NintDnComplete)
  161. END;
  162. IF 10 IN status THEN (* upComplete *)
  163. Machine.AtomicInc(NintUpComplete);
  164. IF 15 IN upd.status THEN (* upComplete (p. 7-3) *)
  165. REPEAT
  166. Machine.AtomicInc(NupCompleteLoops);
  167. IF upd.status * {14,16..20,24} = {} THEN (* no error *)
  168. len := SYSTEM.VAL(LONGINT, upd.status * {0..12}) - 14;
  169. IF (len >= 60-14) & (len <= MTU) THEN
  170. buf := upd.buffer;
  171. IF buf # NIL THEN
  172. (* get buffer from UPD for upcall *)
  173. buf := upd.buffer;
  174. type := LONG(ROT(upd.type, 8)) MOD 10000H;
  175. buf.ofs := 0;
  176. buf.len := len;
  177. buf.calcChecksum := {};
  178. buf.src := SYSTEM.VAL(Network.LinkAdr, upd.src);
  179. dev.QueueBuffer(buf, type);
  180. ELSE
  181. Machine.AtomicInc(NupOverflow); (* no more upcall buffers available *)
  182. END;
  183. (* get new empty buffer for UPD *)
  184. BufferToUPD(Network.GetNewBuffer(), upd);
  185. ELSE
  186. Machine.AtomicInc(NbadSize)
  187. END
  188. ELSE
  189. ASSERT((14 IN upd.status) & (upd.status * {16..20,24} # {}));
  190. IF 16 IN upd.status THEN Machine.AtomicInc(NupOverrun) END;
  191. IF 17 IN upd.status THEN Machine.AtomicInc(NupRuntFrame) END;
  192. IF 18 IN upd.status THEN Machine.AtomicInc(NupAlignmentError) END;
  193. IF 19 IN upd.status THEN Machine.AtomicInc(NupCrcError) END;
  194. IF 20 IN upd.status THEN Machine.AtomicInc(NupOversizedFrame) END;
  195. IF 24 IN upd.status THEN Machine.AtomicInc(NupOverflow) END
  196. END;
  197. upd.status := {}; upd := upd.next;
  198. Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 3001H)) (* UpUnstall (p. 10-8) *)
  199. UNTIL ~(15 IN upd.status)
  200. ELSE
  201. Machine.AtomicInc(NspuriousComplete)
  202. END
  203. END;
  204. IF status * {0, 5, 6, 9, 10} # {} THEN
  205. Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, SHORT(6800H +
  206. SYSTEM.VAL(LONGINT, status * {0, 5, 6, 9, 10})))) (* AcknowledgeInterrupt 10 (p. 10-9) *)
  207. END
  208. END HandleInterrupt;
  209. (* Initialize the controller. *)
  210. PROCEDURE &Init*(dev: LinkDevice; base, irq, model: LONGINT; flags, media: SET);
  211. VAR res, i: LONGINT;
  212. BEGIN
  213. SELF.interrupted := FALSE;
  214. SELF.base := base; SELF.irq := irq; SELF.dev := dev; SELF.model := model; SELF.media := media;
  215. SELF.flags := flags;
  216. dev.ctrl := SELF;
  217. InitDPD(dpd);
  218. InitUPD(upd);
  219. InitAddress(dev); (* sets dev.local and dev.broadcast *)
  220. SYSTEM.MOVE(ADDRESSOF(dev.local[0]), ADDRESSOF(dpd.src[0]), 6);
  221. InitInterface(SELF);
  222. InitRegisters(SELF);
  223. IF (irq >= 1) & (irq <= 15) THEN
  224. KernelLog.Enter; KernelLog.String("Install Handler IRQ = "); KernelLog.Hex(irq, -3); KernelLog.Exit;
  225. Objects.InstallHandler(SELF.HandleInterrupt, Machine.IRQ0+irq)
  226. END;
  227. Network.registry.Add(dev, res);
  228. ASSERT(res = Plugins.Ok);
  229. INC(installed);
  230. Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 6000H)); (* RequestInterrupt (p. 10-9) *)
  231. i := 0;
  232. WHILE (i < 100) & ~interrupted DO
  233. Objects.Yield;
  234. INC(i)
  235. END;
  236. IF ~interrupted THEN (* interrupt handler not called, install timer *)
  237. KernelLog.Enter; KernelLog.String("Install Timer"); KernelLog.Exit;
  238. NEW(timer, SELF)
  239. ELSE
  240. KernelLog.Enter; KernelLog.String("No need for Timer"); KernelLog.Exit
  241. END
  242. END Init;
  243. PROCEDURE Finalize;
  244. VAR item: UPD;
  245. BEGIN {EXCLUSIVE}
  246. IF timer # NIL THEN
  247. KernelLog.Enter; KernelLog.String("Remove Timer"); KernelLog.Exit;
  248. timer.quit := TRUE
  249. END;
  250. ResetTx(base);
  251. ResetRx(SELF, FALSE);
  252. Objects.RemoveHandler(HandleInterrupt, Machine.IRQ0+irq);
  253. Network.registry.Remove(dev);
  254. dev.ctrl := NIL; dev := NIL;
  255. (* return buffers attached to UPD *)
  256. item := upd;
  257. REPEAT
  258. Network.ReturnBuffer(item.buffer);
  259. item.buffer := NIL; (* in case of concurrent interrupt *)
  260. item := item.next;
  261. UNTIL item = upd;
  262. END Finalize;
  263. END Controller;
  264. TYPE
  265. LinkDevice* = OBJECT (Network.LinkDevice)
  266. VAR
  267. hdr: ARRAY Network.MaxPacketSize OF CHAR; (* internal buffer for eventual header copy in DoSend *)
  268. ctrl*: Controller;
  269. PROCEDURE DoSend(dst: Network.LinkAdr; type: LONGINT; CONST l3hdr, l4hdr, data: ARRAY OF CHAR; h3len, h4len, dofs, dlen: LONGINT);
  270. VAR
  271. dpd: DPD;
  272. t: Kernel.MilliTimer;
  273. h3n, h4n, dn, hn, hlen, len, base, i: LONGINT;
  274. h3phys, h4phys, dphys, hphys: MemRangeArray;
  275. PROCEDURE PutToDPD(n: LONGINT; VAR phys: MemRangeArray);
  276. VAR j: LONGINT;
  277. BEGIN
  278. FOR j := 0 TO n-1 DO
  279. dpd.frag[i].dataPhysAdr := Machine.Ensure32BitAddress (phys[j].adr);
  280. dpd.frag[i].dataLen := Machine.Ensure32BitAddress (phys[j].size);
  281. INC(i);
  282. END;
  283. END PutToDPD;
  284. BEGIN {EXCLUSIVE}
  285. base := ctrl.base; dpd := ctrl.dpd;
  286. (* set up ethernet header *)
  287. SYSTEM.MOVE(ADDRESSOF(dst[0]), ADDRESSOF(dpd.dst[0]), 6);
  288. dpd.type := ROT(SHORT(type), 8);
  289. (* set up the download *)
  290. IssueCommand(base, 3002H); (* DnStall (p. 10-4) *)
  291. CheckTransmission(base);
  292. (* set up the DPD *)
  293. Machine.TranslateVirtual(ADDRESSOF(l3hdr[0]), h3len, h3n, h3phys);
  294. Machine.TranslateVirtual(ADDRESSOF(l4hdr[0]), h4len, h4n, h4phys);
  295. Machine.TranslateVirtual(ADDRESSOF(data[dofs]), dlen, dn, dphys);
  296. (* max. 2 fragments allowed (all packets smaller than one 4K page) *)
  297. ASSERT(h3n <= 2);
  298. ASSERT(h4n <= 2);
  299. ASSERT(dn <= 2);
  300. i := 1; (* start at fragment index 1 in DPD *)
  301. IF h3n + h4n + dn > 4 THEN
  302. (* max. number of fragments exceeded - occurs very rarely! only handled to avoid eventual packet loss *)
  303. (* copy l3hdr and l4hdr to hdr to reduce fragments *)
  304. Network.Copy(l3hdr, hdr, 0, 0, h3len);
  305. Network.Copy(l4hdr, hdr, 0, h3len, h4len);
  306. hlen := h3len + h4len;
  307. Machine.TranslateVirtual(ADDRESSOF(hdr[0]), hlen, hn, hphys);
  308. PutToDPD(hn, hphys);
  309. ELSE
  310. (* this is the normal case *)
  311. PutToDPD(h3n, h3phys);
  312. PutToDPD(h4n, h4phys);
  313. END;
  314. (* put data *)
  315. PutToDPD(dn, dphys);
  316. (* set "end" marker *)
  317. INC(dpd.frag[i-1].dataLen, LONGINT(80000000H));
  318. len := h3len + h4len + len +14; (* now len is total packet length including headers *)
  319. ASSERT((len >= 14) & (len <= MaxPkt)); (* packet size *)
  320. dpd.status := SYSTEM.VAL(SET, len);
  321. Machine.Portout32(base+24H, dpd.physAdr); (* DnListPtr (p. 6-17) *)
  322. Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 3003H)); (* DnUnstall (p. 10-5) *)
  323. (* wait for download to finish, so that buffer is free afterwards *)
  324. Kernel.SetTimer(t, SendTimeout);
  325. REPEAT
  326. Machine.Portin32(base+24H, i) (* downloading finished *)
  327. UNTIL (i = 0) OR Kernel.Expired(t);
  328. IF i # 0 THEN Machine.AtomicInc(NsendTimeouts) END;
  329. INC(sendCount)
  330. END DoSend;
  331. PROCEDURE Finalize(connected: BOOLEAN);
  332. BEGIN
  333. ctrl.Finalize;
  334. Finalize^(connected);
  335. END Finalize;
  336. END LinkDevice;
  337. (* Change to the specified register window. *)
  338. PROCEDURE SetWindow(base, window: LONGINT);
  339. BEGIN
  340. ASSERT((0 <= window) & (window <= 7));
  341. Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, SHORT(800H + window)))
  342. END SetWindow;
  343. (* Read a 16-bit value from the EEPROM (chapter 5). *)
  344. PROCEDURE ReadConfig(base, reg: LONGINT; flags: SET; VAR word: INTEGER);
  345. VAR x: INTEGER;
  346. BEGIN
  347. ASSERT((0 <= reg) & (reg < 64));
  348. SetWindow(base, 0);
  349. IF Eprom230 IN flags THEN INC(reg, 230H) ELSE INC(reg, 80H) END;
  350. Machine.Portout16(base+0AH, SYSTEM.VAL(INTEGER, SHORT((*80H + *)reg))); (* Read Register - 162 us *)
  351. REPEAT
  352. Machine.Portin16(base+0AH, x)
  353. UNTIL ~(15 IN SYSTEM.VAL(SET, LONG(x))); (* Wait till ~eepromBusy *)
  354. Machine.Portin16(base+0CH, word)
  355. END ReadConfig;
  356. (* Initialize the local address. *)
  357. PROCEDURE InitAddress(d: LinkDevice);
  358. VAR base, i: LONGINT; flags: SET; word: ARRAY 3 OF INTEGER;
  359. BEGIN
  360. base := d.ctrl.base;
  361. flags := d.ctrl.flags;
  362. ReadConfig(base, 0AH, flags, word[0]); (* OEM Node Address / word 0 *)
  363. ReadConfig(base, 0BH, flags, word[1]); (* OEM Node Address / word 1 *)
  364. ReadConfig(base, 0CH, flags, word[2]); (* OEM Node Address / word 2 *)
  365. SetWindow(base, 2);
  366. FOR i := 0 TO 2 DO
  367. word[i] := ROT(word[i], 8);
  368. d.local[2*i] := CHR(word[i] MOD 100H);
  369. d.local[2*i+1] := CHR(word[i] DIV 100H MOD 100H);
  370. Machine.Portout16(base+2*i, word[i]); (* StationAddress *)
  371. Machine.Portout16(base+6+2*i, SYSTEM.VAL(INTEGER, 0)) (* StationMask *)
  372. END;
  373. FOR i := 0 TO 5 DO d.broadcast[i] := 0FFX END
  374. END InitAddress;
  375. (* Get the specified setting for the NIC currently being initialized (indexed by "installed"). *)
  376. PROCEDURE GetSetting(s: ARRAY OF CHAR): LONGINT;
  377. VAR i: LONGINT; name, val: ARRAY 32 OF CHAR;
  378. BEGIN
  379. i := 0; WHILE s[i] # 0X DO name[i] := s[i]; INC(i) END;
  380. name[i] := CHR(ORD("0") + installed); name[i+1] := 0X;
  381. Machine.GetConfig(name, val);
  382. IF val[0] = 0X THEN (* specified setting not found, look for generic one *)
  383. name[i] := 0X; Machine.GetConfig(name, val)
  384. END;
  385. i := 0;
  386. RETURN Machine.StrToInt(i, val)
  387. END GetSetting;
  388. (* Initialize the communication interface. *)
  389. PROCEDURE InitInterface(ctrl: Controller);
  390. VAR config: SET; base, media: LONGINT;
  391. BEGIN
  392. base := ctrl.base;
  393. SetWindow(base, 3);
  394. Machine.Portin32(base, SYSTEM.VAL (LONGINT, config)); (* InternalConfig (p. 4-9) *)
  395. media := GetSetting("3C90xMedia");
  396. IF media # 0 THEN
  397. ASSERT((media >= 1) & (media <= 9));
  398. ctrl.media := SYSTEM.VAL(SET, LSH(media-1, 20)) * MediaMask;
  399. Machine.Portout32(base, SYSTEM.VAL (LONGINT, config - MediaMask + ctrl.media))
  400. ELSIF ~(24 IN config) THEN
  401. ctrl.media := config * MediaMask (* autoselect off, no changes needed *)
  402. ELSE
  403. media := SYSTEM.VAL(LONGINT, ctrl.media);
  404. Machine.Portout32(base, SYSTEM.VAL (LONGINT, config - MediaMask + ctrl.media));
  405. KernelLog.Enter; KernelLog.String(ctrl.dev.name); KernelLog.String(" auto-selection not supported"); KernelLog.Exit;
  406. (*HALT(3801)*) (* auto-selection not yet supported *)
  407. END
  408. ;KernelLog.Enter; KernelLog.String("Media = "); KernelLog.Hex(media, 0); KernelLog.Exit;
  409. END InitInterface;
  410. (* Issue a command and wait for completion. *)
  411. PROCEDURE IssueCommand(base, cmd: LONGINT);
  412. VAR word: INTEGER;
  413. BEGIN
  414. Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, SHORT(cmd)));
  415. REPEAT
  416. Machine.Portin16(base+0EH, word)
  417. UNTIL ~(12 IN SYSTEM.VAL(SET, LONG(word)))
  418. END IssueCommand;
  419. PROCEDURE ResetTx(base: LONGINT);
  420. BEGIN
  421. IssueCommand(base, 5800H); (* TxReset (p. 10-4) *)
  422. Machine.Portout32(base+24H, SYSTEM.VAL(LONGINT, 0)) (* DnListPtr (p. 6-17) *)
  423. END ResetTx;
  424. PROCEDURE ResetRx(ctrl: Controller; setThresh: BOOLEAN);
  425. VAR base: LONGINT;
  426. BEGIN
  427. base := ctrl.base;
  428. IssueCommand(base, 2800H); (* RxReset (p. 10-3) *)
  429. IF setThresh THEN
  430. IF EarlyThresh DIV 4 > 7FFH THEN
  431. Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 8FFFH)); (* SetRxEarlyThresh (p. 10-7) *)
  432. Machine.Portout32(base+20H, SYSTEM.VAL(LONGINT, 0H)) (* DmaCtrl (p. 6-14) *)
  433. ELSE
  434. Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 8800H + EarlyThresh DIV 4));
  435. Machine.Portout32(base+20H, SYSTEM.VAL(LONGINT, 20H)) (* DmaCtrl (p. 6-14) - upRxEarlyEnable *)
  436. END
  437. END;
  438. Machine.Portout32(base+38H, ctrl.upd.physAdr); (* UpListPtr (p. 7-14) *)
  439. Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 8007H)) (* SetRxFilter (p. 10-8) - Individual, Multicast, Broadcast *)
  440. END ResetRx;
  441. (* Check the transmitter and reset it if required. *)
  442. PROCEDURE CheckTransmission(base: LONGINT);
  443. VAR status: SET; enable, reset: BOOLEAN; ch: CHAR;
  444. BEGIN
  445. enable := FALSE; reset := FALSE;
  446. LOOP
  447. Machine.Portin8(base+1BH, ch); (* TxStatus (p. 6-23) *)
  448. status := SYSTEM.VAL(SET, LONG(ORD(ch)));
  449. IF ~(7 IN status) THEN EXIT END; (* txComplete *)
  450. IF 1 IN status THEN Machine.AtomicInc(NdnTxReclaimError) END;
  451. IF 2 IN status THEN Machine.AtomicInc(NdnTxStatusOverflow); enable := TRUE END;
  452. IF 3 IN status THEN Machine.AtomicInc(NdnMaxCollisions); enable := TRUE END;
  453. IF 4 IN status THEN Machine.AtomicInc(NdnTxUnderrun); reset := TRUE END;
  454. IF 5 IN status THEN Machine.AtomicInc(NdnTxJabber); reset := TRUE END;
  455. Machine.Portout8(base+1BH, ch) (* advance *)
  456. END;
  457. IF reset THEN IssueCommand(base, 5800H); enable := TRUE END; (* TxReset (p. 10-4) *)
  458. IF enable THEN Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 4800H)) END (* TxEnable (p. 10-6) *)
  459. END CheckTransmission;
  460. (* Allocate a DPD. Assume the physical address of the record will not change (beware copying GC). *)
  461. PROCEDURE InitDPD(VAR dpd: DPD);
  462. VAR i, n: LONGINT; phys: MemRangeArray;
  463. BEGIN
  464. i := 0;
  465. LOOP
  466. NEW(dpd);
  467. Machine.TranslateVirtual(ADDRESSOF(dpd.nextPhysAdr), SIZEOF(DPD), n, phys);
  468. IF n = 1 THEN EXIT END; (* contiguous *)
  469. INC(i); Machine.AtomicInc(NnewRetry);
  470. IF i = NewTries THEN HALT(3802) END (* can not allocate contiguous DPD *)
  471. END;
  472. ASSERT(phys[0].size = SIZEOF(DPD));
  473. dpd.physAdr := Machine.Ensure32BitAddress (phys[0].adr);
  474. ASSERT(dpd.physAdr MOD 8 = 0); (* alignment constraint (p. 6-3) *)
  475. dpd.nextPhysAdr := 0;
  476. (* entry 0 always points to ethernet header *)
  477. dpd.frag[0].dataPhysAdr := Machine.Ensure32BitAddress ((ADDRESSOF(dpd.dst[0])-ADDRESSOF(dpd.nextPhysAdr)) + dpd.physAdr);
  478. dpd.frag[0].dataLen := 14 (* ethernet header *)
  479. END InitDPD;
  480. (* Allocate the UPD ring. *)
  481. PROCEDURE InitUPD(VAR upd: UPD);
  482. VAR i, j, n: LONGINT; head, tail: UPD; phys: MemRangeArray;
  483. BEGIN
  484. head := NIL; tail := NIL;
  485. FOR j := 1 TO ReceiveBuffers DO
  486. i := 0;
  487. LOOP
  488. NEW(upd);
  489. Machine.TranslateVirtual(ADDRESSOF(upd.nextPhysAdr), SIZEOF(UPD), n, phys);
  490. IF n = 1 THEN EXIT END; (* contiguous *)
  491. INC(i); Machine.AtomicInc(NnewRetry);
  492. IF i = NewTries THEN HALT(3803) END (* can not allocate contiguous UPD *)
  493. END;
  494. ASSERT(phys[0].size = SIZEOF(UPD));
  495. upd.physAdr := Machine.Ensure32BitAddress (phys[0].adr);
  496. ASSERT(upd.physAdr MOD 8 = 0); (* alignment constraint (p. 7-2) *)
  497. upd.status := {};
  498. (* entry 0 always points to ethernet header *)
  499. upd.frag[0].dataPhysAdr := Machine.Ensure32BitAddress ((ADDRESSOF(upd.dst[0])-ADDRESSOF(upd.nextPhysAdr)) + upd.physAdr);
  500. upd.frag[0].dataLen := 14; (* ethernet header *)
  501. (* get new empty buffer and attach it to the UPD *)
  502. BufferToUPD(Network.GetNewBuffer(), upd);
  503. (* link in *)
  504. IF head # NIL THEN
  505. upd.next := head; upd.nextPhysAdr := head.physAdr
  506. ELSE
  507. upd.next := NIL; upd.nextPhysAdr := 0; tail := upd
  508. END;
  509. head := upd
  510. END;
  511. tail.next := head; tail.nextPhysAdr := head.physAdr
  512. END InitUPD;
  513. (* Set buffer as DMA receive buffer in UPD. *)
  514. PROCEDURE BufferToUPD(buffer: Network.Buffer; upd: UPD);
  515. VAR
  516. n, i: LONGINT;
  517. phys: MemRangeArray;
  518. BEGIN
  519. ASSERT(upd # NIL);
  520. IF buffer # NIL THEN
  521. (* entry 1-2 points to data *)
  522. Machine.TranslateVirtual(ADDRESSOF(buffer.data[0]), LEN(buffer.data), n, phys);
  523. ASSERT(n <= 2);
  524. FOR i := 1 TO n DO
  525. upd.frag[i].dataPhysAdr := Machine.Ensure32BitAddress (phys[i-1].adr); upd.frag[i].dataLen := Machine.Ensure32BitAddress (phys[i-1].size)
  526. END;
  527. INC(upd.frag[n].dataLen, LONGINT(80000000H)); (* end of buffer marker *)
  528. ELSE
  529. (* no buffer available at the moment. only header can be received. *)
  530. upd.frag[0].dataLen := 14; (* ethernet header *)
  531. INC(upd.frag[0].dataLen, LONGINT(80000000H)); (* end of buffer marker *)
  532. END;
  533. upd.buffer := buffer; (* attach buffer reference *)
  534. END BufferToUPD;
  535. (* Initialize the registers. *)
  536. PROCEDURE InitRegisters(ctrl: Controller);
  537. VAR base, duplex, i: LONGINT; word: INTEGER; full: BOOLEAN; ch: CHAR; flags: SET;
  538. BEGIN
  539. base := ctrl.base;
  540. flags := ctrl.flags;
  541. IF InvertMIIPower IN flags THEN
  542. SetWindow(base, 2);
  543. Machine.Portin16(base+0CH, word);
  544. word := SHORT(SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, LONG(word)) + {14}));
  545. Machine.Portout16(base+0CH, word);
  546. KernelLog.Enter; KernelLog.String("Invert MII Power "); KernelLog.Hex(word, 0); KernelLog.Exit;
  547. END;
  548. IF ctrl.media = Base10Coax THEN
  549. Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 1000H)) (* EnableDcConverter (p. 10-10) *)
  550. ELSE
  551. Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 0B800H)) (* DisableDcConverter (p. 10-10) *)
  552. END;
  553. duplex := GetSetting("3C90xDuplex");
  554. IF duplex = 0 THEN
  555. ReadConfig(base, 0DH, flags, word); (* Software Information (p. 5-5) *)
  556. full := (15 IN SYSTEM.VAL(SET, LONG(word)))
  557. ELSE
  558. full := (duplex = 2)
  559. END;
  560. SetWindow(base, 3);
  561. IF full THEN
  562. KernelLog.Enter; KernelLog.String(ctrl.dev.name); KernelLog.String(" full-duplex"); KernelLog.Exit;
  563. Machine.Portout16(base+6, SYSTEM.VAL(INTEGER, 20H)) (* MacControl (p. 12-2) *)
  564. ELSE (* half-duplex *)
  565. KernelLog.Enter; KernelLog.String(ctrl.dev.name); KernelLog.String(" half-duplex"); KernelLog.Exit;
  566. Machine.Portout16(base+6, SYSTEM.VAL(INTEGER, 0))
  567. END;
  568. ResetTx(base);
  569. ResetRx(ctrl, TRUE);
  570. SetWindow(base, 7); (* operating window *)
  571. IF ctrl.model = Model90x THEN
  572. Machine.Portout8(base+2FH, CHR((MaxPkt+255) DIV 256)) (* TxFreeThresh (p. 6-20) *)
  573. END;
  574. (* clear all interrupts & indications *)
  575. Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 7FF6H)); (* SetIndicationEnable (p. 10-9) - all *)
  576. Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, SYSTEM.VAL(LONGINT, {1, 6, 7, 10}) + 7000H)); (* SetInterruptEnable (p. 10-10, 8-4) *)
  577. Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 6F69H)); (* AcknowledgeInterrupt (p. 10-9) - all *)
  578. (* clear all statistics *)
  579. Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 0B000H)); (* StatisticsDisable (p. 10-11) *)
  580. SetWindow(base, 5);
  581. Machine.Portin16(base+0AH, word);
  582. KernelLog.Enter; KernelLog.String("IntEnable = "); KernelLog.Hex(word, 4); KernelLog.Exit;
  583. SetWindow(base, 6);
  584. FOR i := 0 TO 9 DO Machine.Portin8(base+i, ch) END;
  585. Machine.Portin16(base+0AH, word);
  586. Machine.Portin16(base+0CH, word);
  587. SetWindow(base, 4);
  588. (*
  589. Machine.Portin8(base+0AH, word);
  590. Machine.Portout8(base+0AH, SYSTEM.VAL(INTEGER, SHORT(SYSTEM.VAL(LONGINT,
  591. SYSTEM.VAL(SET, LONG(word)) - {7})))); (* MediaStatus: disable linkBeatEnable *)
  592. *)
  593. Machine.Portin8(base+0CH, ch);
  594. Machine.Portin8(base+0DH, ch);
  595. Machine.Portin16(base+6, word); (* NetworkDiagnostic (p. 9-8) *)
  596. Machine.Portout16(base+6, SYSTEM.VAL(INTEGER, SHORT(SYSTEM.VAL(LONGINT,
  597. SYSTEM.VAL(SET, LONG(word)) + {6})))); (* upperBytesEnable *)
  598. Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 0A800H)); (* StatisticsEnable (p. 10-11) *)
  599. (* start the NIC *)
  600. Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 2000H)); (* RxEnable (p. 10-6) *)
  601. Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 4800H)); (* TxEnable (p. 10-6) *)
  602. Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 3001H)) (* UpUnstall (p. 10-8) *)
  603. END InitRegisters;
  604. (* Scan the PCI bus for the specified card. *)
  605. PROCEDURE ScanPCI(vendor, device, model: LONGINT; flags, media: SET);
  606. VAR index, bus, dev, fct, res, base, irq, i: LONGINT; d: LinkDevice; c: Controller; name: Plugins.Name;
  607. BEGIN
  608. index := 0;
  609. WHILE (PCI.FindPCIDevice(device, vendor, index, bus, dev, fct) = PCI.Done) & (installed < 10) DO
  610. res := PCI.ReadConfigDword(bus, dev, fct, PCI.Adr0Reg, base); ASSERT(res = PCI.Done);
  611. ASSERT(ODD(base)); DEC(base); (* I/O mapped *)
  612. res := PCI.ReadConfigByte(bus, dev, fct, PCI.IntlReg, irq); ASSERT(res = PCI.Done);
  613. (*
  614. IF irq = 11 THEN
  615. res := PCI.WriteConfigByte(bus, dev, fct, PCI.IntlReg, 5); ASSERT(res = PCI.Done);
  616. res := PCI.ReadConfigByte(bus, dev, fct, PCI.IntlReg, irq); ASSERT(res = PCI.Done);
  617. END;
  618. *)
  619. NEW(d, Network.TypeEthernet, MTU, 6);
  620. name := Name;
  621. i := 0; WHILE name[i] # 0X DO INC(i) END;
  622. name[i] := CHR(ORD("0") + installed);
  623. name[i+1] := 0X;
  624. d.SetName(name);
  625. d.desc := Desc;
  626. NEW(c, d, base, irq, model, flags, media); (* increments "installed" when successful *)
  627. c.bus := bus; c.pdev := dev; c.fct := fct;
  628. INC(index)
  629. END
  630. END ScanPCI;
  631. (** Install a driver object for every NIC found. *)
  632. PROCEDURE Install*;
  633. BEGIN {EXCLUSIVE}
  634. IF installed = 0 THEN
  635. ScanPCI(10B7H, 9200H, Model90xC, {}, Auto);
  636. ScanPCI(10B7H, 6055H, Model90xB, {Eprom230, InvertMIIPower}, MII); (* check if C model *)
  637. ScanPCI(10B7H, 9055H, Model90xB, {}, Auto);
  638. ScanPCI(10B7H, 9056H, Model90xB, {}, MII);
  639. ScanPCI(10B7H, 9004H, Model90xB, {}, Auto);
  640. ScanPCI(10B7H, 9005H, Model90xB, {}, Auto);
  641. ScanPCI(10B7H, 9050H, Model90x, {}, MII);
  642. ScanPCI(10B7H, 9000H, Model90x, {}, Base10T);
  643. ScanPCI(10B7H, 9001H, Model90x, {}, Base10T)
  644. END;
  645. END Install;
  646. (** Remove all device driver objects. *)
  647. PROCEDURE Remove*;
  648. VAR table: Plugins.Table; i: LONGINT;
  649. BEGIN {EXCLUSIVE}
  650. Network.registry.GetAll(table);
  651. IF table # NIL THEN
  652. FOR i := 0 TO LEN(table)-1 DO
  653. IF table[i] IS LinkDevice THEN table[i](LinkDevice).Finalize(TRUE) END
  654. END
  655. END;
  656. installed := 0;
  657. END Remove;
  658. (* Request an interrupt from every controller. *)
  659. PROCEDURE Kick*;
  660. VAR i, base: LONGINT; table: Plugins.Table;
  661. BEGIN
  662. Network.registry.GetAll(table);
  663. IF table # NIL THEN
  664. FOR i := 0 TO LEN(table)-1 DO
  665. IF table[i] IS LinkDevice THEN
  666. base := table[i](LinkDevice).ctrl.base;
  667. KernelLog.Enter; KernelLog.String(table[i].name); KernelLog.Exit;
  668. Machine.Portout16(base+0EH, SYSTEM.VAL(INTEGER, 6000H)); (* RequestInterrupt (p. 10-9) *)
  669. END
  670. END
  671. END;
  672. END Kick;
  673. (* Dump all registers - may have side effects that influence the device's normal operation *)
  674. PROCEDURE Dump*;
  675. VAR i, base, win: LONGINT; int: INTEGER; table: Plugins.Table;
  676. PROCEDURE Byte(reg: ARRAY OF CHAR; ofs: LONGINT);
  677. VAR x: CHAR;
  678. BEGIN
  679. KernelLog.String(reg); KernelLog.Char("=");
  680. Machine.Portin8(base+ofs, x);
  681. KernelLog.Hex(ORD(x), -2); KernelLog.Char(" ")
  682. END Byte;
  683. PROCEDURE Word(reg: ARRAY OF CHAR; ofs: LONGINT);
  684. VAR x: INTEGER;
  685. BEGIN
  686. KernelLog.String(reg); KernelLog.Char("=");
  687. Machine.Portin16(base+ofs, x);
  688. KernelLog.Hex(LONG(x) MOD 10000H, 8); KernelLog.Char(" ")
  689. END Word;
  690. PROCEDURE DWord(reg: ARRAY OF CHAR; ofs: LONGINT);
  691. VAR x: LONGINT;
  692. BEGIN
  693. KernelLog.String(reg); KernelLog.Char("=");
  694. Machine.Portin32(base+ofs, x);
  695. KernelLog.Hex(x, 8); KernelLog.Char(" ")
  696. END DWord;
  697. PROCEDURE PCIWord(reg: ARRAY OF CHAR; ofs: LONGINT);
  698. VAR x, res: LONGINT; ctrl: Controller;
  699. BEGIN
  700. ctrl := table[i](LinkDevice).ctrl;
  701. KernelLog.String(reg); KernelLog.Char("=");
  702. res := PCI.ReadConfigWord(ctrl.bus, ctrl.pdev, ctrl.fct, ofs, x);
  703. KernelLog.Hex(x MOD 10000H, 8); KernelLog.Char(" ")
  704. END PCIWord;
  705. BEGIN
  706. Network.registry.GetAll(table);
  707. IF table # NIL THEN
  708. FOR i := 0 TO LEN(table)-1 DO
  709. IF table[i] IS LinkDevice THEN
  710. base := table[i](LinkDevice).ctrl.base;
  711. KernelLog.Enter;
  712. KernelLog.String(table[i].name); KernelLog.Char(" ");
  713. (* current window *)
  714. Machine.Portin16(base+0EH, int); win := ASH(int, -13) MOD 8;
  715. KernelLog.String("Window="); KernelLog.Int(win, 1); KernelLog.Char(" ");
  716. (* assume 3C90xB *)
  717. Byte("TxPktId", 18H); Byte("Timer", 1AH); Byte("TxStatus", 1BH);
  718. (*Word("IntStatusAuto", 1EH);*) (* reading this would clear InterruptEnable (p. 8-5) *)
  719. DWord("DmaCtrl", 20H);
  720. DWord("DnListPtr", 24H); Byte("DnBurstThresh", 2AH);
  721. Byte("DnPriorityThresh", 2CH); Byte("DnPoll", 2DH);
  722. DWord("UpPktStatus", 30H); Word("FreeTimer", 34H);
  723. Word("Countdown", 36H); DWord("UpListPtr", 38H);
  724. Byte("UpPriorityThresh", 3CH); Byte("UpPoll", 3DH);
  725. Byte("UpBurstThresh", 3EH); DWord("RealTimeCnt", 40H);
  726. Word("DnMaxBurst", 78H); Word("UpMaxBurst", 7AH);
  727. (* output windows *)
  728. SetWindow(base, 0);
  729. DWord("0.BiosRomAddr", 4); Byte("0.BiosRomData", 8);
  730. Word("0.EepromCommand", 0AH); Word("0.EepromData", 0CH);
  731. Word("0.IntStatus", 0EH);
  732. SetWindow(base, 1);
  733. Word("1.IntStatus", 0EH);
  734. SetWindow(base, 2);
  735. Word("2.StationAddress-0", 0); Word("2.StationAddress-2", 2); Word("2.StationAddress-4", 4);
  736. Word("2.StationMask-0", 6); Word("2.StationMask-2", 8); Word("2.StationMask-4", 0AH);
  737. Word("2.ResetOptions", 0CH); Word("2.IntStatus", 0EH);
  738. SetWindow(base, 3);
  739. DWord("3.InternalConfig", 0); Word("3.MaxPktSize", 4);
  740. Word("3.MacControl", 6); Word("3.MediaOptions", 8);
  741. Word("3.RxFree", 0AH); Word("3.TxFree", 0CH);
  742. Word("3.IntStatus", 0EH);
  743. SetWindow(base, 4);
  744. Word("4.VcoDiagnostic", 2); Word("4.FifoDiagnostic", 4);
  745. Word("4.NetworkDiagnostic", 6); Word("4.PhysicalMgmt", 8);
  746. Word("4.MediaStatus", 0AH); Byte("4.BadSSD", 0CH);
  747. Byte("4.UpperBytesOk", 0DH); Word("4.IntStatus", 0EH);
  748. SetWindow(base, 5);
  749. Word("5.TxStartThresh", 0); Word("5.RxEarlyThresh", 6);
  750. Byte("5.RxFilter", 8); Byte("5.TxReclaimThresh", 9);
  751. Word("5.InterruptEnable", 0AH); Word("5.IndicationEnable", 0CH);
  752. Word("5.IntStatus", 0EH);
  753. SetWindow(base, 6);
  754. Byte("6.CarrierLost", 0); Byte("6.SqeErrors", 1);
  755. Byte("6.MultipleCollisions", 2); Byte("6.SingleCollisions", 3);
  756. Byte("6.LateCollisions", 4); Byte("6.RxOverruns", 5);
  757. Byte("6.FramesXmittedOk", 6); Byte("6.FramesRcvdOk", 7);
  758. Byte("6.FramesDeferred", 8); Byte("6.UpperFramesOk", 9);
  759. Word("6.BytesRcvdOk", 0AH); Word("6.BytesXmittedOk", 0CH);
  760. Word("6.IntStatus", 0EH);
  761. SetWindow(base, 7);
  762. Word("7.VlanMask", 0); Word("7.VlanEtherType", 4);
  763. Word("7.PowerMgmtEvent", 0CH); Word("7.IntStatus", 0EH);
  764. SetWindow(base, win);
  765. Byte("Timer", 1AH); Byte("TxStatus", 1BH);
  766. (*Word("IntStatusAuto", 1EH); Reding this register clears IntEnable *)
  767. DWord("DMACtrl", 20H); DWord("DnListPtr", 24);
  768. Byte("DnBurstThresh", 2AH);
  769. Byte("DnPriorityThresh", 2CH); Byte("DnPoll", 2DH);
  770. DWord("UpPktStatus", 30H);
  771. Word("FreeTimer", 34H); Word("Countdown", 36H);
  772. DWord("UpListPtr", 38H);
  773. Byte("UpPriorityThresh", 3CH); Byte("UpPoll", 3DH); Byte("UpBurstThresh", 3EH);
  774. DWord("RealTimeCnt", 40H);
  775. Word("DnMaxBurst", 78H); Word("UpMaxBurst", 7AH);
  776. PCIWord("Status", 02H);
  777. KernelLog.Exit
  778. END
  779. END
  780. END;
  781. END Dump;
  782. PROCEDURE Cleanup;
  783. BEGIN
  784. IF Modules.shutdown = Modules.None THEN (* module is being freed *)
  785. Remove;
  786. END
  787. END Cleanup;
  788. BEGIN
  789. installed := 0;
  790. Modules.InstallTermHandler(Cleanup)
  791. END Ethernet3Com90x.
  792. (*
  793. History:
  794. 17.10.2003 mvt Changed for new Network interface
  795. 05.11.2003 mvt Implemented DMA directly to Network.Buffer
  796. ! System.Free Ethernet3Com90x ~
  797. Aos.Call Ethernet3Com90x.Install
  798. Aos.Call Ethernet3Com90x.Remove
  799. TestNet.ShowDevices
  800. TestNet.SetDevice "3Com90x#0"
  801. TestNet.SendBroadcast
  802. TestNet.SendTest 1
  803. System.State Ethernet3Com90x ~
  804. Aos.Call Ethernet3Com90x.Kick
  805. Aos.Call Ethernet3Com90x.Kick2
  806. Aos.Call Ethernet3Com90x.Dump
  807. Aos.Call Ethernet3Com90x.TestCount 100000
  808. NetSystem.Start
  809. NetSystem.Stop
  810. ftp://reali@lillian.ethz.ch
  811. *)