summaryrefslogtreecommitdiff
path: root/sys/src/9/pc/ether589.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/9/pc/ether589.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/9/pc/ether589.c')
-rwxr-xr-xsys/src/9/pc/ether589.c215
1 files changed, 215 insertions, 0 deletions
diff --git a/sys/src/9/pc/ether589.c b/sys/src/9/pc/ether589.c
new file mode 100755
index 000000000..4cc03fd69
--- /dev/null
+++ b/sys/src/9/pc/ether589.c
@@ -0,0 +1,215 @@
+/*
+ * 3C589 and 3C562.
+ * To do:
+ * check xcvr10Base2 still works (is GlobalReset necessary?).
+ */
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+#include "../port/netif.h"
+
+#include "etherif.h"
+
+enum { /* all windows */
+ CommandR = 0x000E,
+ IntStatusR = 0x000E,
+};
+
+enum { /* Commands */
+ GlobalReset = 0x0000,
+ SelectRegisterWindow = 0x0001,
+ RxReset = 0x0005,
+ TxReset = 0x000B,
+ AcknowledgeInterrupt = 0x000D,
+};
+
+enum { /* IntStatus bits */
+ commandInProgress = 0x1000,
+};
+
+#define COMMAND(port, cmd, a) outs((port)+CommandR, ((cmd)<<11)|(a))
+#define STATUS(port) ins((port)+IntStatusR)
+
+enum { /* Window 0 - setup */
+ Wsetup = 0x0000,
+ /* registers */
+ ManufacturerID = 0x0000, /* 3C5[08]*, 3C59[27] */
+ ProductID = 0x0002, /* 3C5[08]*, 3C59[27] */
+ ConfigControl = 0x0004, /* 3C5[08]*, 3C59[27] */
+ AddressConfig = 0x0006, /* 3C5[08]*, 3C59[27] */
+ ResourceConfig = 0x0008, /* 3C5[08]*, 3C59[27] */
+ EepromCommand = 0x000A,
+ EepromData = 0x000C,
+ /* AddressConfig Bits */
+ autoSelect9 = 0x0080,
+ xcvrMask9 = 0xC000,
+ /* ConfigControl bits */
+ Ena = 0x0001,
+ base10TAvailable9 = 0x0200,
+ coaxAvailable9 = 0x1000,
+ auiAvailable9 = 0x2000,
+ /* EepromCommand bits */
+ EepromReadRegister = 0x0080,
+ EepromBusy = 0x8000,
+};
+
+enum { /* Window 1 - operating set */
+ Wop = 0x0001,
+};
+
+enum { /* Window 3 - FIFO management */
+ Wfifo = 0x0003,
+ /* registers */
+ InternalConfig = 0x0000, /* 3C509B, 3C589, 3C59[0257] */
+ /* InternalConfig bits */
+ xcvr10BaseT = 0x00000000,
+ xcvr10Base2 = 0x00300000,
+};
+
+enum { /* Window 4 - diagnostic */
+ Wdiagnostic = 0x0004,
+ /* registers */
+ MediaStatus = 0x000A,
+ /* MediaStatus bits */
+ linkBeatDetect = 0x0800,
+};
+
+extern int etherelnk3reset(Ether*);
+
+static char *tcmpcmcia[] = {
+ "3C589", /* 3COM 589[ABCD] */
+ "3C562", /* 3COM 562 */
+ "589E", /* 3COM Megahertz 589E */
+ nil,
+};
+
+static int
+configASIC(Ether* ether, int port, int xcvr)
+{
+ int x;
+
+ /* set Window 0 configuration registers */
+ COMMAND(port, SelectRegisterWindow, Wsetup);
+ outs(port+ConfigControl, Ena);
+
+ /* IRQ must be 3 on 3C589/3C562 */
+ outs(port + ResourceConfig, 0x3F00);
+
+ x = ins(port+AddressConfig) & ~xcvrMask9;
+ x |= (xcvr>>20)<<14;
+ outs(port+AddressConfig, x);
+
+ COMMAND(port, TxReset, 0);
+ while(STATUS(port) & commandInProgress)
+ ;
+ COMMAND(port, RxReset, 0);
+ while(STATUS(port) & commandInProgress)
+ ;
+
+ return etherelnk3reset(ether);
+}
+
+static int
+reset(Ether* ether)
+{
+ int i, t, slot;
+ char *type;
+ int port;
+ enum { WantAny, Want10BT, Want10B2 };
+ int want;
+ uchar ea[6];
+ char *p;
+
+ if(ether->irq == 0)
+ ether->irq = 10;
+ if(ether->port == 0)
+ ether->port = 0x240;
+ port = ether->port;
+
+ if(ioalloc(port, 0x10, 0, "3C589") < 0)
+ return -1;
+
+ type = nil;
+ slot = -1;
+ for(i = 0; tcmpcmcia[i] != nil; i++){
+ type = tcmpcmcia[i];
+ if((slot = pcmspecial(type, ether)) >= 0)
+ break;
+ }
+ ether->type = type; /* must be set before calling configASIC */
+ if(slot < 0){
+ iofree(port);
+ return -1;
+ }
+
+ /*
+ * Read Ethernet address from card memory
+ * on 3C562, but only if the user has not
+ * overridden it.
+ */
+ memset(ea, 0, sizeof ea);
+ if(memcmp(ea, ether->ea, 6) == 0 && strcmp(type, "3C562") == 0) {
+ if(pcmcistuple(slot, 0x88, -1, ea, 6) == 6) {
+ for(i = 0; i < 6; i += 2){
+ t = ea[i];
+ ea[i] = ea[i+1];
+ ea[i+1] = t;
+ }
+ memmove(ether->ea, ea, 6);
+ }
+ }
+ /*
+ * Allow user to specify desired media in plan9.ini
+ */
+ want = WantAny;
+ for(i = 0; i < ether->nopt; i++){
+ if(cistrncmp(ether->opt[i], "media=", 6) != 0)
+ continue;
+ p = ether->opt[i]+6;
+ if(cistrcmp(p, "10base2") == 0)
+ want = Want10B2;
+ else if(cistrcmp(p, "10baseT") == 0)
+ want = Want10BT;
+ }
+
+ /* try configuring as a 10BaseT */
+ if(want==WantAny || want==Want10BT){
+ if(configASIC(ether, port, xcvr10BaseT) < 0){
+ pcmspecialclose(slot);
+ iofree(port);
+ return -1;
+ }
+ delay(100);
+ COMMAND(port, SelectRegisterWindow, Wdiagnostic);
+ if((ins(port+MediaStatus)&linkBeatDetect) || want==Want10BT){
+ COMMAND(port, SelectRegisterWindow, Wop);
+ print("#l%d: xcvr10BaseT %s\n", ether->ctlrno, type);
+ return 0;
+ }
+ }
+
+ /* try configuring as a 10base2 */
+ if(want==WantAny || want==Want10B2){
+ COMMAND(port, GlobalReset, 0);
+ if(configASIC(ether, port, xcvr10Base2) < 0){
+ pcmspecialclose(slot);
+ iofree(port);
+ return -1;
+ }
+ print("#l%d: xcvr10Base2 %s\n", ether->ctlrno, type);
+ return 0;
+ }
+ return -1; /* not reached */
+}
+
+void
+ether589link(void)
+{
+ addethercard("3C589", reset);
+ addethercard("3C562", reset);
+ addethercard("589E", reset);
+}