📄 rtl_3c59x.c
字号:
if (vci->drv_flags & EEPROM_8BIT) base = 0x230; else if (vci->drv_flags & EEPROM_OFFSET) base = EEPROM_Read + 0x30; else base = EEPROM_Read; for (i = 0; i < 0x40; i++) { int timer; /* This means that we want to read EepromCommand Register and disable writting */ /* Issuing ReadRegister & WriteDisable */ outw(base + i, ioaddr + Wn0EepromCmd); for (timer = 10; timer >= 0; timer--) { /* The read data is available through the EepromData register 162us after */ /* the ReadRegister command has been issued */ rtl_delay(162000); /* Bit 15th (eepromBusy) of EepromCommand register is a read-only bit asserted */ /* during the execution of EEProm commands. Further commans should not be issued */ /* to the EepromCommand register, nor should data be read from the EepromData */ /* register while this bit is true */ if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0) break; } /* Save the contents of the 3C90xC NIC's EEPROM */ eeprom[i] = inw(ioaddr + Wn0EepromData); } }//EL3WINDOW(0) configuration finished /* EEPROM can be checksummed in order to assure that reading was OK */ for (i = 0; i < 0x18; i++) checksum ^= eeprom[i]; checksum = (checksum ^ (checksum >> 8)) & 0xff; if (checksum != 0x00) { /* Grrr, needless incompatible change 3Com. */ while (i < 0x21) checksum ^= eeprom[i++]; checksum = (checksum ^ (checksum >> 8)) & 0xff; } if ((checksum != 0x00) && !(vci->drv_flags & IS_TORNADO)) printk(" ***INVALID CHECKSUM %4.4x*** ", checksum); /* Save HW address into dev_addr (MAC address in format 00:04:75:bd:ea:e7) */ for (i = 0; i < 3; i++) ((u16 *)private_data.dev_addr)[i] = htons(eeprom[i + 10]); /* This writes into the StationAddress register the NIC's HW address in order */ /* to define the individual destination address that the NIC responds to when */ /* receiving packets */ EL3WINDOW(2); for (i = 0; i < 6; i++) outb(private_data.dev_addr[i], ioaddr + i); EL3WINDOW(4); step = (inb(ioaddr + Wn4_NetDiag) & 0x1e) >> 1; if (dev && vci->drv_flags & HAS_CB_FNS) { unsigned long fn_st_addr; /* Cardbus function status space */ unsigned short n; fn_st_addr = pci_resource_start (dev, 2); if (fn_st_addr) { private_data.cb_fn_base = ioremap(fn_st_addr, 128); retval = -ENOMEM; if (!private_data.cb_fn_base) goto free_ring; } EL3WINDOW(2); n = inw(ioaddr + Wn2_ResetOptions) & ~0x4010; if (private_data.drv_flags & INVERT_LED_PWR) n |= 0x10; if (private_data.drv_flags & INVERT_MII_PWR) n |= 0x4000; outw(n, ioaddr + Wn2_ResetOptions); } /* Extract our information from the EEPROM data. */ private_data.info1 = eeprom[13]; private_data.info2 = eeprom[15]; private_data.capabilities = eeprom[16]; if (private_data.info1 & 0x8000){ private_data.full_duplex = 1; printk(KERN_INFO "Full duplex capable\n"); } { unsigned int config; EL3WINDOW(3); /* This reads the MediaOptions register which shows what physical media */ /* connections are available in the NIC */ private_data.available_media = inw(ioaddr + Wn3_Options); //Wn3_Options = 8 vp.available_media = 0xa if ((private_data.available_media & 0xff) == 0) /* Broken 3c916 */ private_data.available_media = 0x40; /* This reads the InternalConfig register which provides a way to set */ /* NIC-specific, non-host-related configuration settings */ config = inl(ioaddr + Wn3_Config); //Wn3_Config = 0 private_data.default_media = XCVR(config); if (private_data.default_media == XCVR_NWAY) private_data.has_nway = 1; private_data.autoselect = AUTOSELECT(config); } if (private_data.media_override != 7) { private_data.if_port = private_data.media_override; } else private_data.if_port = private_data.default_media; if (private_data.if_port == XCVR_MII || private_data.if_port == XCVR_NWAY) { int phy, phy_idx = 0; EL3WINDOW(4); mii_preamble_required++; mii_preamble_required++; rtl_3COM905C_mdio_read(24, 1); for (phy = 0; phy < 32 && phy_idx < 1; phy++) { int mii_status, phyx; /* * For the 3c905CX we look at index 24 first, because it bogusly * reports an external PHY at all indices */ if (phy == 0) phyx = 24; else if (phy <= 24) phyx = phy - 1; else phyx = phy; mii_status = rtl_3COM905C_mdio_read(phyx, 1); if (mii_status && mii_status != 0xffff) { private_data.phys[phy_idx++] = phyx; if ((mii_status & 0x0040) == 0) mii_preamble_required++; } } mii_preamble_required--; if (phy_idx == 0) { private_data.phys[0] = 24; } else { private_data.advertising = rtl_3COM905C_mdio_read(private_data.phys[0], 4); if (private_data.full_duplex) { /* Only advertise the FD media types. */ private_data.advertising &= ~0x02A0; rtl_3COM905C_mdio_write(private_data.phys[0], 4, private_data.advertising); } } } if (private_data.capabilities & CapBusMaster) { private_data.full_bus_master_tx = 1; private_data.full_bus_master_rx = (private_data.info2 & 1) ? 1 : 2; private_data.bus_master = 0; /* AKPM: vortex only */ } if (private_data.pdev && private_data.enable_wol) { private_data.pm_state_valid = 1; rt_pci_save_state(dev, private_data.power_state); rtl_3COM905C_acpi_set_WOL(); } vortex_open(dev); }// if(dev) return 0; free_ring: pci_free_consistent(dev, sizeof(struct boom_rx_desc) * RX_RING_SIZE, private_data.rx_ring, private_data.rx_ring_dma); pci_free_consistent(dev, sizeof(struct boom_tx_desc) * TX_RING_SIZE, private_data.tx_ring, private_data.tx_ring_dma); return -1; free_region: if (private_data.must_free_region){ release_region(ioaddr, vci->io_size); private_data.must_free_region = 0; } printk("vortex_probe1 fails. Returns %d\n", retval); return -1;}/***************************************************************************************//* ACPI: Advanced Configuration and Power Interface. *//* Set Wake-On-LAN mode and put the board into D3 (power-down) state. *//***************************************************************************************/static void rtl_3COM905C_acpi_set_WOL(void){ long ioaddr = private_data.ioaddr; /* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */ EL3WINDOW(7); outw(2, ioaddr + 0x0c); /* The RxFilter must accept the WOL frames. */ outw(SetRxFilter|RxStation|RxBroadcast, ioaddr + EL3_CMD); //RxMulticast outw(RxEnable, ioaddr + EL3_CMD); /* Change the power state to D3; RxEnable doesn't take effect. */ rt_pci_enable_wake(private_data.pdev, 0, 1); rt_pci_set_power_state(private_data.pdev, 3);}/***************************************************************************************//* This function registers the interrupt handler and reserves memory for buffers which *//* only will be accessed by the card. *//***************************************************************************************/static int vortex_open(struct pci_dev *dev){ int i; int retval; /* Use the now-standard shared IRQ implementation. */ if ((retval = rtl_request_irq(dev->irq, &boomerang_interrupt))) { printk(KERN_ERR "%s: Could not reserve IRQ %d\n", dev->name, dev->irq); goto out; }else private_data.must_free_irq = 1; if (private_data.full_bus_master_rx) { /* Boomerang bus master. */ /* RX RING INITIALIZATION */ for (i = 0; i < RX_RING_SIZE; i++) { unsigned char *skb; private_data.rx_ring[i].next = cpu_to_le32(private_data.rx_ring_dma + sizeof(struct boom_rx_desc) * (i+1)); private_data.rx_ring[i].status = 0; /* Clear complete bit. */ private_data.rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LAST_FRAG); skb = rtl_malloc(PKT_BUF_SZ); private_data.rx_skbuff[i] = skb; if (skb == NULL) break; /* Bad news! */ private_data.rx_ring[i].addr = cpu_to_le32(pci_map_single(private_data.pdev, skb, PKT_BUF_SZ, PCI_DMA_FROMDEVICE)); } if (i != RX_RING_SIZE) { int j; printk(KERN_EMERG "%s: no memory for rx ring\n", dev->name); for (j = 0; j < i; j++) { if (private_data.rx_skbuff[j]) { rtl_free(private_data.rx_skbuff[j]); private_data.rx_skbuff[j] = 0; } } retval = -ENOMEM; goto out_free_irq; } /* Wrap the ring. */ private_data.rx_ring[i-1].next = cpu_to_le32(private_data.rx_ring_dma); /* TX RING INITIALIZATION */ for (i = 0; i < TX_RING_SIZE; i++) { unsigned char *skb; private_data.tx_ring[i].next = 0; private_data.tx_ring[i].status = 0; /* Clear complete bit. */ private_data.tx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LAST_FRAG); skb = rtl_malloc(PKT_BUF_SZ); private_data.tx_skbuff[i] = skb; if (skb == NULL) break; /* Bad news! */ private_data.tx_ring[i].addr = cpu_to_le32(pci_map_single(private_data.pdev, skb, PKT_BUF_SZ, PCI_DMA_FROMDEVICE)); } if (i != TX_RING_SIZE) { int j; printk(KERN_EMERG "%s: no memory for tx ring\n", dev->name); for (j = 0; j < i; j++) { if (private_data.tx_skbuff[j]) { rtl_free(private_data.tx_skbuff[j]); private_data.tx_skbuff[j] = 0; } } retval = -ENOMEM; goto out_free_irq; } /* Wrap the ring. */ private_data.tx_ring[i-1].next = cpu_to_le32(private_data.tx_ring_dma); } vortex_up(dev); return 0; out_free_irq: rtl_free_irq(dev->irq); out: return retval;}/***************************************************************************************//* This function is also used to initialise the card. In this function we indicate *//* which interrupts do we want the card to generate. *//***************************************************************************************/static void vortex_up(struct pci_dev *dev){ long ioaddr = private_data.ioaddr; unsigned int config; int i; private_data.rx_packets = 0; private_data.rx_frames_for_us = 0; if (private_data.pdev && private_data.enable_wol) { rt_pci_set_power_state(dev, 0); /* Go active */ rt_pci_restore_state(dev, private_data.power_state); } /* Before initializing select the active media port. */ EL3WINDOW(3); config = inl(ioaddr + Wn3_Config); if (private_data.media_override != 7) { private_data.if_port = private_data.media_override; } else if (private_data.autoselect) { if (private_data.has_nway) { } else { /* Find first available media type, starting with 100baseTx. */ private_data.if_port = XCVR_100baseTx; while (! (private_data.available_media & media_tbl[private_data.if_port].mask)) private_data.if_port = media_tbl[private_data.if_port].next; } } else { private_data.if_port = private_data.default_media; } private_data.full_duplex = private_data.force_fd; config = BFINS(config, private_data.if_port, 20, 4); outl(config, ioaddr + Wn3_Config); if (private_data.if_port == XCVR_MII || private_data.if_port == XCVR_NWAY) { int mii_reg1, mii_reg5; EL3WINDOW(4); /* Read BMSR (reg1) only to clear old status. */ mii_reg1 = rtl_3COM905C_mdio_read(private_data.phys[0], 1); mii_reg5 = rtl_3COM905C_mdio_read(private_data.phys[0], 5); if (mii_reg5 == 0xffff || mii_reg5 == 0x0000) ; /* No MII device or no link partner report */ else if ((mii_reg5 & 0x0100) != 0 /* 100baseTx-FD */ || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */ private_data.full_duplex = 1; private_data.partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0); EL3WINDOW(3); } private_data.full_duplex = 1; /* Set the full-duplex bit. */ outw( ((private_data.info1 & 0x8000) || private_data.full_duplex ? 0x20 : 0) | (private_data.mtu > 1500 ? 0x40 : 0) | ((private_data.full_duplex && private_data.flow_ctrl && private_data.partner_flow_ctrl) ? 0x100 : 0), ioaddr + Wn3_MAC_Ctrl); rtl_3COM905C_issue_and_wait(TxReset); /* * Don't reset the PHY - that upsets autonegotiation during DHCP operations. */ rtl_3COM905C_issue_and_wait(RxReset|0x04); outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD); EL3WINDOW(4); /* Set the station address and mask in window 2 each time opened. */ EL3WINDOW(2); for (i = 0; i < 6; i++) outb(private_data.dev_addr[i], ioaddr + i); for (; i < 12; i+=2) outw(0, ioaddr + i); if (private_data.cb_fn_base) { unsigned short n = inw(ioaddr + Wn2_ResetOptions) & ~0x4010; if (private_data.drv_flags & INVERT_LED_PWR) n |= 0x10; if (private_data.drv_flags & INVERT_MII_PWR) n |= 0x4000; outw(n, ioaddr + Wn2_ResetOptions); } if (private_data.if_port == XCVR_10base2) /* Start the thinnet transceiver. We should really wait 50ms...*/ outw(StartCoax, ioaddr + EL3_CMD); if (private_data.if_port != XCVR_NWAY) { EL3WINDOW(4); outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) | media_tbl[private_data.if_port].media_bits, ioaddr + Wn4_Media);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -