📄 eepro100.c
字号:
/* Shift the command bits out. */ do { short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0; outw(dataval, ee_addr); udelay(2); outw(dataval | EE_SHIFT_CLK, ee_addr); udelay(2); retval = (retval << 1) | ((inw(ee_addr) & EE_DATA_READ) ? 1 : 0); } while (--cmd_len >= 0); outw(EE_ENB, ee_addr); udelay(2); /* Terminate the EEPROM access. */ outw(EE_ENB & ~EE_CS, ee_addr); return retval;}static inline void whereami (const char *str){#if 0 printf ("%s\n", str); sleep (2);#endif}/* function: eepro100_reset * resets the card. This is used to allow Etherboot to probe the card again * from a "virginal" state.... * Arguments: none * * returns: void. */static void eepro100_reset(struct nic *nic){ outl(0, ioaddr + SCBPort);}/* function: eepro100_transmit * This transmits a packet. * * Arguments: char d[6]: destination ethernet address. * unsigned short t: ethernet protocol type. * unsigned short s: size of the data-part of the packet. * char *p: the data for the packet. * returns: void. */static void eepro100_transmit(struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p){ struct eth_hdr { unsigned char dst_addr[ETH_ALEN]; unsigned char src_addr[ETH_ALEN]; unsigned short type; } hdr; unsigned short status; int to; int s1, s2; status = inw(ioaddr + SCBStatus); /* Acknowledge all of the current interrupt sources ASAP. */ outw(status & 0xfc00, ioaddr + SCBStatus);#ifdef DEBUG printf ("transmitting type %hX packet (%d bytes). status = %hX, cmd=%hX\n", t, s, status, inw (ioaddr + SCBCmd));#endif memcpy (&hdr.dst_addr, d, ETH_ALEN); memcpy (&hdr.src_addr, nic->node_addr, ETH_ALEN); hdr.type = htons (t); txfd.status = 0; txfd.command = CmdSuspend | CmdTx | CmdTxFlex; txfd.link = virt_to_bus (&txfd); txfd.count = 0x02208000; txfd.tx_desc_addr = (u32)&txfd.tx_buf_addr0; txfd.tx_buf_addr0 = virt_to_bus (&hdr); txfd.tx_buf_size0 = sizeof (hdr); txfd.tx_buf_addr1 = virt_to_bus (p); txfd.tx_buf_size1 = s;#ifdef DEBUG printf ("txfd: \n"); hd (&txfd, sizeof (txfd));#endif outl(virt_to_bus(&txfd), ioaddr + SCBPointer); outw(INT_MASK | CU_START, ioaddr + SCBCmd); wait_for_cmd_done(ioaddr + SCBCmd); s1 = inw (ioaddr + SCBStatus); load_timer2(10*TICKS_PER_MS); /* timeout 10 ms for transmit */ while (!txfd.status && timer2_running()) /* Wait */; s2 = inw (ioaddr + SCBStatus);#ifdef DEBUG printf ("s1 = %hX, s2 = %hX.\n", s1, s2);#endif}/* function: eepro100_poll / eth_poll * This recieves a packet from the network. * * Arguments: none * * returns: 1 if a packet was recieved. * 0 if no pacet was recieved. * side effects: * returns the packet in the array nic->packet. * returns the length of the packet in nic->packetlen. */static int eepro100_poll(struct nic *nic){ if (!ACCESS(rxfd)status) return 0; /* Ok. We got a packet. Now restart the reciever.... */ ACCESS(rxfd)status = 0; ACCESS(rxfd)command = 0xc000; outl(virt_to_bus(&(ACCESS(rxfd)status)), ioaddr + SCBPointer); outw(INT_MASK | RX_START, ioaddr + SCBCmd); wait_for_cmd_done(ioaddr + SCBCmd);#ifdef DEBUG printf ("Got a packet: Len = %d.\n", ACCESS(rxfd)count & 0x3fff);#endif nic->packetlen = ACCESS(rxfd)count & 0x3fff; memcpy (nic->packet, ACCESS(rxfd)packet, nic->packetlen);#ifdef DEBUG hd (nic->packet, 0x30);#endif return 1;}static void eepro100_disable(struct nic *nic){ /* See if this PartialReset solves the problem with interfering with kernel operation after Etherboot hands over. - Ken 20001102 */ outl(2, ioaddr + SCBPort);}/* exported function: eepro100_probe / eth_probe * initializes a card * * side effects: * leaves the ioaddress of the 82557 chip in the variable ioaddr. * leaves the 82557 initialized, and ready to recieve packets. */struct nic *eepro100_probe(struct nic *nic, unsigned short *probeaddrs, struct pci_device *p){ unsigned short sum = 0; int i; int read_cmd, ee_size; unsigned short value; int options; int promisc; /* we cache only the first few words of the EEPROM data be careful not to access beyond this array */ unsigned short eeprom[16]; if (probeaddrs == 0 || probeaddrs[0] == 0) return 0; ioaddr = probeaddrs[0] & ~3; /* Mask the bit that says "this is an io addr" */ adjust_pci_device(p); if ((do_eeprom_cmd(EE_READ_CMD << 24, 27) & 0xffe0000) == 0xffe0000) { ee_size = 0x100; read_cmd = EE_READ_CMD << 24; } else { ee_size = 0x40; read_cmd = EE_READ_CMD << 22; } for (i = 0, sum = 0; i < ee_size; i++) { unsigned short value = do_eeprom_cmd(read_cmd | (i << 16), 27); if (i < (int)(sizeof(eeprom)/sizeof(eeprom[0]))) eeprom[i] = value; sum += value; } for (i=0;i<ETH_ALEN;i++) { nic->node_addr[i] = (eeprom[i/2] >> (8*(i&1))) & 0xff; } printf ("Ethernet addr: %!\n", nic->node_addr); if (sum != 0xBABA) printf("eepro100: Invalid EEPROM checksum %#hX, " "check settings before activating this device!\n", sum); outl(0, ioaddr + SCBPort); udelay (10000); whereami ("Got eeprom."); outl(virt_to_bus(&lstats), ioaddr + SCBPointer); outw(INT_MASK | CU_STATSADDR, ioaddr + SCBCmd); wait_for_cmd_done(ioaddr + SCBCmd); whereami ("set stats addr."); /* INIT RX stuff. */ /* Base = 0 */ outl(0, ioaddr + SCBPointer); outw(INT_MASK | RX_ADDR_LOAD, ioaddr + SCBCmd); wait_for_cmd_done(ioaddr + SCBCmd); whereami ("set rx base addr."); ACCESS(rxfd)status = 0x0001; ACCESS(rxfd)command = 0x0000; ACCESS(rxfd)link = virt_to_bus(&(ACCESS(rxfd)status)); ACCESS(rxfd)rx_buf_addr = (int) &nic->packet; ACCESS(rxfd)count = 0; ACCESS(rxfd)size = 1528; outl(virt_to_bus(&(ACCESS(rxfd)status)), ioaddr + SCBPointer); outw(INT_MASK | RX_START, ioaddr + SCBCmd); wait_for_cmd_done(ioaddr + SCBCmd); whereami ("started RX process."); /* Start the reciever.... */ ACCESS(rxfd)status = 0; ACCESS(rxfd)command = 0xc000; outl(virt_to_bus(&(ACCESS(rxfd)status)), ioaddr + SCBPointer); outw(INT_MASK | RX_START, ioaddr + SCBCmd); /* INIT TX stuff. */ /* Base = 0 */ outl(0, ioaddr + SCBPointer); outw(INT_MASK | CU_CMD_BASE, ioaddr + SCBCmd); wait_for_cmd_done(ioaddr + SCBCmd); whereami ("set TX base addr."); txfd.command = (CmdIASetup); txfd.status = 0x0000; txfd.link = virt_to_bus (&confcmd); { char *t = (char *)&txfd.tx_desc_addr; for (i=0;i<ETH_ALEN;i++) t[i] = nic->node_addr[i]; }#ifdef DEBUG printf ("Setup_eaddr:\n"); hd (&txfd, 0x20);#endif /* options = 0x40; */ /* 10mbps half duplex... */ options = 0x00; /* Autosense */ promisc = 0; if ( ((eeprom[6]>>8) & 0x3f) == DP83840 || ((eeprom[6]>>8) & 0x3f) == DP83840A) { int mdi_reg23 = mdio_read(eeprom[6] & 0x1f, 23) | 0x0422; if (congenb) mdi_reg23 |= 0x0100; printf(" DP83840 specific setup, setting register 23 to %hX.\n", mdi_reg23); mdio_write(eeprom[6] & 0x1f, 23, mdi_reg23); } whereami ("Done DP8340 special setup."); if (options != 0) { mdio_write(eeprom[6] & 0x1f, 0, ((options & 0x20) ? 0x2000 : 0) | /* 100mbps? */ ((options & 0x10) ? 0x0100 : 0)); /* Full duplex? */ whereami ("set mdio_register."); } confcmd.command = CmdSuspend | CmdConfigure; confcmd.status = 0x0000; confcmd.link = virt_to_bus (&txfd); confcmd.data[1] = (txfifo << 4) | rxfifo; confcmd.data[4] = rxdmacount; confcmd.data[5] = txdmacount + 0x80; confcmd.data[15] = promisc ? 0x49: 0x48; confcmd.data[19] = (options & 0x10) ? 0xC0 : 0x80; confcmd.data[21] = promisc ? 0x0D: 0x05; outl(virt_to_bus(&txfd), ioaddr + SCBPointer); outw(INT_MASK | CU_START, ioaddr + SCBCmd); wait_for_cmd_done(ioaddr + SCBCmd); whereami ("started TX thingy (config, iasetup)."); load_timer2(10*TICKS_PER_MS); while (!txfd.status && timer2_running()) /* Wait */; nic->reset = eepro100_reset; nic->poll = eepro100_poll; nic->transmit = eepro100_transmit; nic->disable = eepro100_disable; return nic;}/*********************************************************************/#ifdef DEBUG/* Hexdump a number of bytes from memory... */void hd (void *where, int n){ int i; while (n > 0) { printf ("%X ", where); for (i=0;i < ( (n>16)?16:n);i++) printf (" %hhX", ((char *)where)[i]); printf ("\n"); n -= 16; where += 16; }}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -