00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00019 #include "src/common/shared.hpp"
00020 #include "src/memory/memset.hpp"
00021 #include "src/memory/align.hpp"
00022 #include "src/memory/heap.hpp"
00023 #include "src/memory/pager.hpp"
00024 #include "src/arch/x86/pcibios.hpp"
00025 #include "src/arch/x86/interr.hpp"
00026 #include "src/arch/x86/rtc.hpp"
00027 #include "src/common/io.hpp"
00028 #include "src/net/net.hpp"
00029 #include "src/net/3c556.hpp"
00030 #include "src/thread/timer.hpp"
00031
00035 namespace Arch {namespace x86 { namespace RTC {
00036 void tdelay(uint32 ticks); } } }
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00052 #define INT_INTERRUPTLATCH (1<<0)
00053 #define INT_HOSTERROR (1<<1)
00054 #define INT_TXCOMPLETE (1<<2)
00055 #define INT_RXCOMPLETE (1<<4)
00056 #define INT_RXEARLY (1<<5)
00057 #define INT_INTREQUESTED (1<<6)
00058 #define INT_UPDATESTATS (1<<7)
00059 #define INT_LINKEVENT (1<<8)
00060 #define INT_DNCOMPLETE (1<<9)
00061 #define INT_UPCOMPLETE (1<<10)
00062 #define INT_CMDINPROGRESS (1<<12)
00063 #define INT_WINDOWNUMBER (7<<13)
00064
00065
00066 typedef struct
00067 {
00068 unsigned int DnNextPtr;
00069 unsigned int FrameStartHeader;
00070 unsigned int HdrAddr;
00071 unsigned int HdrLength;
00072 unsigned int DataAddr;
00073 unsigned int DataLength;
00074 }
00075 TXD __attribute__ ((aligned(8)));
00076
00077
00078 typedef struct
00079 {
00080 unsigned int UpNextPtr;
00081 unsigned int UpPktStatus;
00082 unsigned int DataAddr;
00083 unsigned int DataLength;
00084 }
00085 RXD __attribute__ ((aligned(8)));
00086
00087
00088 struct INF_3C556_Type
00089 {
00090 uint16 IOAddr;
00091 uint8 CurrentWindow;
00092 uint16 eeprom[0x20];
00093 uint8 HWAddr[6];
00094 TXD TransmitDPD;
00095 RXD ReceiveDPD;
00096 } INF_3C556;
00097
00098
00099
00100 enum Registers
00101 {
00102 regCommandIntStatus_w= 0xe,
00103 regUpListPtr_l = 0x38,
00104 regDnListPtr_l = 0x24,
00105 regTxStatus_b = 0x1b,
00106 };
00107
00109 enum Registers0
00110 {
00111 regEepromData_0_w = 0x0c,
00112 regEepromCommand_0_w = 0x0a,
00113 regBiosRomData_0_b = 0x08,
00114 regBiosRomAddr_0_l = 0x04,
00115 };
00116
00117 enum Registers2
00118 {
00119 regResetOptions_2_w = 0x0c,
00120 regStationMask_2_3w = 0x06,
00121 regStationAddress_2_3w = 0x00,
00122 };
00123
00124 enum Registers3
00125 {
00126 regTxFree_3_w = 0x0c,
00127 regRxFree_3_w = 0x0a,
00128 regResetMediaOptions_3_w = 0x08,
00130 regMacControl_3_w = 0x06,
00131 regMaxPktSize_3_w = 0x04,
00132 regInternalConfig_3_l = 0x00,
00134 };
00135
00136
00137 enum Windows
00138 {
00139 winPowerVlan7 = 0x07,
00140 winStatistics6 = 0x06,
00141 winTxRxControl5 = 0x05,
00142 winDiagnostics4 = 0x04,
00143 winTxRxOptions3 = 0x03,
00144 winAddressing2 = 0x02,
00145 winUnused1 = 0x01,
00146 winEepromBios0 = 0x00,
00147 };
00148
00149
00150 enum Commands
00151 {
00152 cmdGlobalReset = 0x00,
00153 cmdSelectRegisterWindow = 0x01,
00154 cmdEnableDcConverter = 0x02,
00155 cmdRxDisable = 0x03,
00156 cmdRxEnable = 0x04,
00157 cmdRxReset = 0x05,
00158 cmdStallCtl = 0x06,
00159 cmdTxEnable = 0x09,
00160 cmdTxDisable = 0x0A,
00161 cmdTxReset = 0x0B,
00162 cmdRequestInterrupt = 0x0C,
00163 cmdAcknowledgeInterrupt = 0x0D,
00164 cmdSetInterruptEnable = 0x0E,
00165 cmdSetIndicationEnable = 0x0F,
00166 cmdSetRxFilter = 0x10,
00167 cmdSetRxEarlyThresh = 0x11,
00168 cmdSetTxStartThresh = 0x13,
00169 cmdStatisticsEnable = 0x15,
00170 cmdStatisticsDisable = 0x16,
00171 cmdDisableDcConverter = 0x17,
00172 cmdSetTxReclaimThresh = 0x18,
00173 cmdSetHashFilterBit = 0x19,
00174 };
00175
00176
00177
00178
00179 inline uint16 htons(uint16 hostshort) {
00180 return (hostshort<<8)+(hostshort>>8);
00181 }
00182
00183
00184
00185
00186 inline uint16 ntohs(uint16 netshort) {
00187 return (netshort<<8)+(netshort>>8);
00188 }
00189
00190 static int e3c556_internal_IssueCommand(int cmd, int param)
00191 {
00192 IOPorts::outw(INF_3C556.IOAddr + regCommandIntStatus_w, (cmd<<11)|param);
00193
00194 while (IOPorts::inw(INF_3C556.IOAddr+regCommandIntStatus_w)&INT_CMDINPROGRESS) ;
00195 return 1;
00196 }
00197
00198 static int e3c556_internal_SetWindow(int window)
00199 {
00200 if (INF_3C556.CurrentWindow==window) return 1;
00201 e3c556_internal_IssueCommand(cmdSelectRegisterWindow, window);
00202 INF_3C556.CurrentWindow=window;
00203 return 1;
00204 }
00205
00206
00207 #if 0
00208
00209
00210
00211
00212
00213
00214 static void
00215 a3c90x_reset(struct nic *nic)
00216 {
00217 int cfg;
00218
00219 #ifdef CFG_3C90X_PRESERVE_XCVR
00220
00221 a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winTxRxOptions3);
00222 cfg = inl(INF_3C90X.IOAddr + regInternalConfig_3_l);
00223 #endif
00224
00226 printf("Issuing RESET:\n");
00227 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdGlobalReset, 0);
00228
00230 while (inw(INF_3C90X.IOAddr + regCommandIntStatus_w) & INT_CMDINPROGRESS);
00231
00235 a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winAddressing2);
00236 outw(0, INF_3C90X.IOAddr + regStationMask_2_3w+0);
00237 outw(0, INF_3C90X.IOAddr + regStationMask_2_3w+2);
00238 outw(0, INF_3C90X.IOAddr + regStationMask_2_3w+4);
00239
00240 #ifdef CFG_3C90X_PRESERVE_XCVR
00241
00242 a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winTxRxOptions3);
00243 outl(cfg, INF_3C90X.IOAddr + regInternalConfig_3_l);
00244
00246 if ((cfg&0x0300) == 0x0300)
00247 {
00248 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdEnableDcConverter, 0);
00249 }
00250 #endif
00251
00253 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdTxReset, 0);
00254 while (inw(INF_3C90X.IOAddr + regCommandIntStatus_w) & INT_CMDINPROGRESS)
00255 ;
00256 if (! INF_3C90X.isBrev)
00257 outb(0x01, INF_3C90X.IOAddr + regTxFreeThresh_b);
00258 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdTxEnable, 0);
00259
00264 if (INF_3C90X.isBrev)
00265 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdRxReset, 0x04);
00266 else
00267 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdRxReset, 0x00);
00268 while (inw(INF_3C90X.IOAddr + regCommandIntStatus_w) & INT_CMDINPROGRESS);
00269 ;
00270 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdRxEnable, 0);
00271
00272 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr,
00273 cmdSetInterruptEnable, 0);
00275 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr,
00276 cmdSetIndicationEnable, 0x0014);
00278 a3c90x_internal_IssueCommand(INF_3C90X.IOAddr,
00279 cmdAcknowledgeInterrupt, 0x661);
00280
00281 return;
00282 }
00283 #endif
00284
00285
00286
00287
00288
00289
00290 #define ETH_ALEN 6
00291
00296 #define XMIT_RETRIES 250
00297 inline uint32 virt_to_bus(void *ptr)
00298 {
00299 return (Memory::Pager::kmem.pte_val((uint32)ptr&0xFFFFF000)&0xFFFFF000) + ((uint32)ptr&0xFFF);
00300 }
00301
00309 void
00310 e3c556_transmit(uint8 *d, unsigned int t,
00311 unsigned int s, uint8 *p)
00312 {
00313 struct
00314 {
00315 uint8 dst_addr[ETH_ALEN];
00316 uint8 src_addr[ETH_ALEN];
00317 uint16 type;
00318 } eth_hdr;
00319
00320
00321 eth_hdr.type=htons(t);
00323 memmove(eth_hdr.dst_addr, const_cast<uint8*>(d), ETH_ALEN);
00324 memmove(eth_hdr.src_addr, INF_3C556.HWAddr, ETH_ALEN);
00325
00326 INF_3C556.TransmitDPD.DnNextPtr = 0;
00327
00328 INF_3C556.TransmitDPD.FrameStartHeader = (s + sizeof(eth_hdr)) | 0x8000;
00329 INF_3C556.TransmitDPD.HdrAddr = virt_to_bus(ð_hdr);
00330 INF_3C556.TransmitDPD.HdrLength = sizeof(eth_hdr);
00331 INF_3C556.TransmitDPD.DataAddr = virt_to_bus((void*)p);
00332 INF_3C556.TransmitDPD.DataLength = s + (1<<31);
00333
00334 e3c556_internal_IssueCommand(cmdStallCtl, 2);
00335
00336 IOPorts::inw(INF_3C556.IOAddr + regCommandIntStatus_w);
00337 IOPorts::inw(INF_3C556.IOAddr + regCommandIntStatus_w);
00338
00339 while (IOPorts::inw(INF_3C556.IOAddr+regCommandIntStatus_w) &
00340 INT_CMDINPROGRESS)
00341 ;
00342
00343 IOPorts::outl(INF_3C556.IOAddr+regDnListPtr_l, virt_to_bus(&INF_3C556.TransmitDPD));
00344
00345
00346 e3c556_internal_IssueCommand(cmdStallCtl, 3);
00347 while(IOPorts::inl(INF_3C556.IOAddr + regDnListPtr_l) != 0)
00348 ;
00349
00350
00351 return;
00352 }
00353
00354
00355 #if 0
00356
00357 int e3c556_i(uint32 *packetlen)
00358 {
00359 int errcode;
00360
00361 if (INF_3C556.ReceiveDPD.UpPktStatus & (1<<14))
00362 {
00363 errcode = INF_3C556.ReceiveDPD.UpPktStatus;
00364 if (errcode & (1<<16))
00365 kprintf("3C90X: Rx Overrun (%hX)\n",errcode>>16);
00366 else if (errcode & (1<<17))
00367 kprintf("3C90X: Runt Frame (%hX)\n",errcode>>16);
00368 else if (errcode & (1<<18))
00369 kprintf("3C90X: Alignment Error (%hX)\n",errcode>>16);
00370 else if (errcode & (1<<19))
00371 kprintf("3C90X: CRC Error (%hX)\n",errcode>>16);
00372 else if (errcode & (1<<20))
00373 kprintf("3C90X: Oversized Frame (%hX)\n",errcode>>16);
00374 else
00375 kprintf("3C90X: Packet error (%hX)\n",errcode>>16);
00376 return 0;
00377 }
00378
00379 *packetlen = (INF_3C556.ReceiveDPD.UpPktStatus & 0x1FFF);
00380
00381 return 1;
00382 }
00383 #endif
00384
00385
00392 int e3c556_poll(uint8 *packet, uint32 *packetlen)
00393 {
00394
00395 #if 1
00396 int i, errcode;
00397
00398 if (!(IOPorts::inw(INF_3C556.IOAddr + regCommandIntStatus_w)&0x0010))
00399 {
00400 return 0;
00401 }
00402
00408 INF_3C556.ReceiveDPD.UpNextPtr = 0;
00409 INF_3C556.ReceiveDPD.UpPktStatus = 0;
00410 INF_3C556.ReceiveDPD.DataAddr = virt_to_bus(packet);
00411 INF_3C556.ReceiveDPD.DataLength = 1536 + (1<<31);
00412
00414 IOPorts::outl(
00415 INF_3C556.IOAddr + regUpListPtr_l,
00416 virt_to_bus(&(INF_3C556.ReceiveDPD)));
00417
00419 for(i=0;i<40000;i++);
00420 while((INF_3C556.ReceiveDPD.UpPktStatus & ((1<<14) | (1<<15))) == 0)
00421 for(i=0;i<40000;i++);
00422
00424 if (INF_3C556.ReceiveDPD.UpPktStatus & (1<<14))
00425 {
00426 errcode = INF_3C556.ReceiveDPD.UpPktStatus;
00427 if (errcode & (1<<16))
00428 kprintf("3C90X: Rx Overrun (%x)\n",errcode>>16);
00429 else if (errcode & (1<<17))
00430 kprintf("3C90X: Runt Frame (%x)\n",errcode>>16);
00431 else if (errcode & (1<<18))
00432 kprintf("3C90X: Alignment Error (%x)\n",errcode>>16);
00433 else if (errcode & (1<<19))
00434 kprintf("3C90X: CRC Error (%x)\n",errcode>>16);
00435 else if (errcode & (1<<20))
00436 kprintf("3C90X: Oversized Frame (%x)\n",errcode>>16);
00437 else
00438 kprintf("3C90X: Packet error (%x)\n",errcode>>16);
00439 return 0;
00440 }
00441
00443 *packetlen = (INF_3C556.ReceiveDPD.UpPktStatus & 0x1FFF);
00444
00445 return 1;
00446
00447 #endif
00448
00449 #if 0
00450
00451
00452 if (!(IOPorts::inw(INF_3C556.IOAddr + regCommandIntStatus_w)&0x0010))
00453 {
00454 return 0;
00455 }
00456
00457 INF_3C556.ReceiveDPD.UpNextPtr=0;
00458 INF_3C556.ReceiveDPD.UpPktStatus=0;
00459 INF_3C556.ReceiveDPD.DataAddr=
00460 virt_to_bus(packet);
00461
00462 INF_3C556.ReceiveDPD.DataLength=*packetlen;
00463 INF_3C556.ReceiveDPD.DataLength = 1536 + (1<<31);
00464
00465
00466 IOPorts::outl(INF_3C556.IOAddr + regUpListPtr_l,virt_to_bus(&INF_3C556.ReceiveDPD)
00467
00468 );
00469
00471 for(int i=0;i<40000;i++);
00472 while((INF_3C556.ReceiveDPD.UpPktStatus & ((1<<14) | (1<<15))) == 0)
00473 for(int i=0;i<40000;i++);
00474
00475 e3c556_i(packetlen);
00476
00477 return 1;
00478 #endif
00479 }
00480
00481 static uint16 e3c556_internal_eeprom_read(int address)
00482 {
00483 e3c556_internal_SetWindow(winEepromBios0);
00484
00485 while ( 0x8000&IOPorts::inw(INF_3C556.IOAddr+regEepromCommand_0_w));
00486
00487
00488 IOPorts::outw(INF_3C556.IOAddr+regEepromCommand_0_w, address+ 0x230);
00489 while ( 0x8000&IOPorts::inw(INF_3C556.IOAddr+regEepromCommand_0_w));
00490 return IOPorts::inw(INF_3C556.IOAddr+regEepromData_0_w);
00491 }
00492
00493
00494
00495 int e3c556_irq(struct Arch::x86::Interr::except2_t *code)
00496 {
00497
00498 uint32 IntStatus;
00499 uint8 status;
00500 uint32 i;
00501 IntStatus= IOPorts::inw(INF_3C556.IOAddr+ 0xE);
00502
00503 if (!(IntStatus & 1))
00504 return 0;
00505
00506
00507
00508
00509
00510
00511
00512 if (IntStatus & 0x400)
00513 {
00514
00515 #if 0
00516
00530 #endif
00531 Thread::Timer::add(reinterpret_cast<int(*)(int,int)>(Net::onFramesReceived),1,reinterpret_cast<uint32>(e3c556_nif),0 );
00532
00533
00534
00535
00536 }
00537 if (IntStatus & 0x4)
00538 {
00539 status = IOPorts::inb(INF_3C556.IOAddr + regTxStatus_b);
00540
00541
00542 IOPorts::outb(INF_3C556.IOAddr + regTxStatus_b, 0x00);
00543
00544
00545 if ((status & 0xbf) != 0x80)
00546 {
00547 kprintf("3C90X: Status (%x)\n", status);
00548
00549 if (status & 0x02)
00550 {
00551 kprintf("3C90X: Tx Reclaim Error (%x)\n", status);
00552
00553 }
00554 else if (status & 0x04)
00555 {
00556 kprintf("3C90X: Tx Status Overflow (%x)\n", status);
00557 for (i=0; i<32; i++)
00558 IOPorts::outb(INF_3C556.IOAddr + regTxStatus_b,0x00);
00559
00560 e3c556_internal_IssueCommand(cmdTxEnable, 0);
00561 }
00562 else if (status & 0x08)
00563 {
00564 kprintf("3C90X: Tx Max Collisions (%x)\n", status);
00565
00566 e3c556_internal_IssueCommand(cmdTxEnable, 0);
00567 }
00568 else if (status & 0x10)
00569 {
00570 kprintf("3C90X: Tx Underrun (%x)\n", status);
00571
00572 }
00573 else if (status & 0x20)
00574 {
00575 kprintf("3C90X: Tx Jabber (%x)\n", status);
00576
00577 }
00578 else if ((status & 0x80) != 0x80)
00579 {
00580 kprintf("3C90X: Internal Error - Incomplete Transmission (%x)\n",
00581 status);
00582
00583 }
00584 }
00585
00586 Thread::Timer::add(reinterpret_cast<int(*)(int,int)>( Net::onFramesTransmitted), 1, reinterpret_cast<uint32>(e3c556_nif), 0);
00587 }
00588
00589 #if 1
00590 e3c556_internal_IssueCommand(13, 1|0x400|4);
00591
00592 #endif
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603 return 1;
00604 }
00605
00607 void e3c556_mac(uint8 d[6]) {
00608 memmove(d, INF_3C556.HWAddr, ETH_ALEN);
00609 }
00610
00611 struct Net::netif *e3c556_nif;
00612
00613 int e3c556_probe(uint8 bus_no, uint8 dev_no, struct Net::netif *nif )
00614 {
00615 uint32 foo;
00616 uint16 baz,joe;
00617
00618 pci32_read_configuration_dword(&foo, Pci32_Addr, bus_no, dev_no, 0, PCI_VENDOR_ID);
00619 if ((LOWORD(foo)!=0x10b7) || (HIWORD(foo)!=0x6055))
00620 return 0;
00621
00622 pci32_read_configuration_dword(&foo, Pci32_Addr, bus_no, dev_no, 0, PCI_BASE_ADDRESS_0);
00623 INF_3C556.IOAddr=foo&(~3);
00624 INF_3C556.CurrentWindow=255;
00625 kprintf("3c556: bus %d, device %d, port %x.\n", bus_no, dev_no, INF_3C556.IOAddr);
00626
00627
00628 pci32_read_configuration_word(&baz, Pci32_Addr,bus_no,dev_no,0,PCI_COMMAND);
00629 joe= baz | PCI_COMMAND_IO|PCI_COMMAND_MASTER;
00630 if (joe != baz)
00631 {
00632 kprintf("3c556: enabling bus master and io mode.\n");
00633 pci32_write_configuration_word(baz, Pci32_Addr,bus_no,dev_no,0,PCI_COMMAND);
00634 }
00635
00636 pci32_write_configuration_byte(248, Pci32_Addr,bus_no,dev_no,0,PCI_LATENCY_TIMER);
00637 for (foo=0;foo<0x20;foo++)
00638 INF_3C556.eeprom[foo]= e3c556_internal_eeprom_read(foo);
00639
00640
00641 INF_3C556.HWAddr[0]= INF_3C556.eeprom[0]>>8;
00642 INF_3C556.HWAddr[1]= INF_3C556.eeprom[0]&0xFF;
00643 INF_3C556.HWAddr[2]= INF_3C556.eeprom[1]>>8;
00644 INF_3C556.HWAddr[3]= INF_3C556.eeprom[1]&0xFF;
00645 INF_3C556.HWAddr[4]= INF_3C556.eeprom[2]>>8;
00646 INF_3C556.HWAddr[5]= INF_3C556.eeprom[2]&0xFF;
00647 kprintf("3c556: MAC = %02x:%02x:%02x:%02x:%02x:%02x\n",
00648 INF_3C556.HWAddr[0],INF_3C556.HWAddr[1],INF_3C556.HWAddr[2],
00649 INF_3C556.HWAddr[3],INF_3C556.HWAddr[4],INF_3C556.HWAddr[5]);
00650
00651
00652 e3c556_internal_SetWindow(winAddressing2);
00653 IOPorts::outw(INF_3C556.IOAddr+regStationAddress_2_3w, htons(INF_3C556.eeprom[0]));
00654 IOPorts::outw(INF_3C556.IOAddr+regStationAddress_2_3w+2, htons(INF_3C556.eeprom[1]));
00655 IOPorts::outw(INF_3C556.IOAddr+regStationAddress_2_3w+4, htons(INF_3C556.eeprom[2]));
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670 e3c556_internal_SetWindow(winTxRxOptions3);
00671 uint16 mopt= IOPorts::inw(INF_3C556.IOAddr+regResetMediaOptions_3_w);
00672 mopt &= 0x7F;
00673 kprintf("3c556: connectors present: ");
00674 uint16 linktype;
00675 foo=0;
00676 linktype=0x0008;
00677 if (mopt & 0x01) {
00678 kprintf("%s100Base-T4",(foo++)?", ":"");
00679 linktype= 0x0006; }
00680 if (mopt & 0x04) {
00681 kprintf("%s100Base-FX",(foo++)?", ":"");
00682 linktype= 0x0005; }
00683 if (mopt & 0x10) {
00684 kprintf("%s10Base-2",(foo++)?", ":"");
00685 linktype= 0x0003; }
00686 if (mopt & 0x20) {
00687 kprintf("%sAUI",(foo++)?", ":"");
00688 linktype= 0x0001; }
00689 if (mopt & 0x40) {
00690 kprintf("%sMII",(foo++)?", ":"");
00691 linktype= 0x0006; }
00692 if ((mopt & 0xa)==0xa) {
00693 kprintf("%s10Base-T / 100Base-TX",(foo++)?", ":"");
00694 linktype= 0x0008; }
00695 if ((mopt & 0x0a)==0x02) {
00696 kprintf("%s100Base-TX",(foo++)?", ":"");
00697 linktype= 0x0008; }
00698 if ((mopt & 0xa)==0x8) {
00699 kprintf("%s10Base-T",(foo++)?", ":"");
00700 linktype= 0x0008; }
00701 kprintf("\n");
00702
00703 if ( (INF_3C556.eeprom[0x16]&0xFF00)==0x5A00)
00704 linktype= INF_3C556.eeprom[0x16]&0x000F;
00705 if (linktype==0x0009)
00706 {
00707 kprintf("MII External MAC Mode: falling back to MII Mode\n");
00708 linktype=0x0006;
00709 }
00710
00711 if (linktype==0x0003)
00712 e3c556_internal_IssueCommand(cmdEnableDcConverter, 0);
00713
00714
00715 e3c556_internal_SetWindow(winTxRxOptions3);
00716 foo= IOPorts::inl(INF_3C556.IOAddr+regInternalConfig_3_l);
00717 foo &= ~(0xF<<20);
00718 foo |= (linktype<<20);
00719 IOPorts::outl(INF_3C556.IOAddr+regInternalConfig_3_l, foo);
00720
00721
00722 e3c556_internal_IssueCommand(cmdTxReset,0x00);
00723 e3c556_internal_IssueCommand(cmdTxEnable,0x00);
00724
00725
00726 e3c556_internal_IssueCommand(cmdRxReset, 0x04);
00727
00728
00729 e3c556_internal_IssueCommand(cmdSetRxFilter, 0x1|0x4);
00730
00731 e3c556_internal_IssueCommand(cmdRxEnable, 0);
00732
00733
00734 e3c556_internal_IssueCommand(cmdSetInterruptEnable, 1|0x400|4);
00735
00736 e3c556_internal_IssueCommand(cmdSetIndicationEnable, 0x0014|0x400);
00737 e3c556_internal_IssueCommand(cmdAcknowledgeInterrupt, 0x661);
00738
00739 e3c556_nif=nif;
00740 e3c556_mac(e3c556_nif->eth_addr.d);
00741
00742
00743
00744
00745 return 1;
00746 }
00747
00748
00749
00750
00751
00752
00753