⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtl_3c905cx_drv.c

📁 最新rtlinux内核源码
💻 C
📖 第 1 页 / 共 4 页
字号:
      if (fn_st_addr) {	rt_3c905c_vp.cb_fn_base = ioremap(fn_st_addr, 128);	retval = -ENOMEM;	if (!rt_3c905c_vp.cb_fn_base)	  goto free_ring;      }      EL3WINDOW(2);            n = inw(ioaddr + Wn2_ResetOptions) & ~0x4010;      if (rt_3c905c_vp.drv_flags & INVERT_LED_PWR)	n |= 0x10;      if (rt_3c905c_vp.drv_flags & INVERT_MII_PWR)	n |= 0x4000;      outw(n, ioaddr + Wn2_ResetOptions);    }    /* Extract our information from the EEPROM data. */    rt_3c905c_vp.info1 = eeprom[13];    rt_3c905c_vp.info2 = eeprom[15];    rt_3c905c_vp.capabilities = eeprom[16];     if (rt_3c905c_vp.info1 & 0x8000){      rt_3c905c_vp.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                                 */      rt_3c905c_vp.available_media = inw(ioaddr + Wn3_Options); //Wn3_Options = 8 vp.available_media = 0xa      if ((rt_3c905c_vp.available_media & 0xff) == 0)		/* Broken 3c916 */	rt_3c905c_vp.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      rt_3c905c_vp.default_media = XCVR(config);      if (rt_3c905c_vp.default_media == XCVR_NWAY)	rt_3c905c_vp.has_nway = 1;      rt_3c905c_vp.autoselect = AUTOSELECT(config);    }    if (rt_3c905c_vp.media_override != 7) {      rt_3c905c_vp.if_port = rt_3c905c_vp.media_override;    } else      rt_3c905c_vp.if_port = rt_3c905c_vp.default_media;    if (rt_3c905c_vp.if_port == XCVR_MII || rt_3c905c_vp.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) {	  rt_3c905c_vp.phys[phy_idx++] = phyx;	  	  if ((mii_status & 0x0040) == 0)	    mii_preamble_required++;	}      }		      mii_preamble_required--;      if (phy_idx == 0) {	rt_3c905c_vp.phys[0] = 24;      } else {	rt_3c905c_vp.advertising = rtl_3COM905C_mdio_read(rt_3c905c_vp.phys[0], 4);	if (rt_3c905c_vp.full_duplex) {	  /* Only advertise the FD media types. */	  rt_3c905c_vp.advertising &= ~0x02A0;	  rtl_3COM905C_mdio_write(rt_3c905c_vp.phys[0], 4, rt_3c905c_vp.advertising);	}      }    }    if (rt_3c905c_vp.capabilities & CapBusMaster) {      rt_3c905c_vp.full_bus_master_tx = 1;            rt_3c905c_vp.full_bus_master_rx = (rt_3c905c_vp.info2 & 1) ? 1 : 2;      rt_3c905c_vp.bus_master = 0;		/* AKPM: vortex only */    }    if (rt_3c905c_vp.pdev && rt_3c905c_vp.enable_wol) {      rt_3c905c_vp.pm_state_valid = 1;      rt_pci_save_state(dev, rt_3c905c_vp.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, rt_3c905c_vp.rx_ring, rt_3c905c_vp.rx_ring_dma);  pci_free_consistent(dev, sizeof(struct boom_tx_desc) * TX_RING_SIZE, rt_3c905c_vp.tx_ring, rt_3c905c_vp.tx_ring_dma);  return -1; free_region:  if (rt_3c905c_vp.must_free_region){    release_region(ioaddr, vci->io_size);    rt_3c905c_vp.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 = rt_3c905c_vp.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(rt_3c905c_vp.pdev, 0, 1);  rt_pci_set_power_state(rt_3c905c_vp.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    rt_3c905c_vp.must_free_irq = 1;  if (rt_3c905c_vp.full_bus_master_rx) { /* Boomerang bus master. */    /* RX RING INITIALIZATION */    for (i = 0; i < RX_RING_SIZE; i++) {      unsigned char *skb;      rt_3c905c_vp.rx_ring[i].next = cpu_to_le32(rt_3c905c_vp.rx_ring_dma + sizeof(struct boom_rx_desc) * (i+1));      rt_3c905c_vp.rx_ring[i].status = 0;	/* Clear complete bit. */      rt_3c905c_vp.rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LAST_FRAG);      skb = rtl_malloc(PKT_BUF_SZ);      rt_3c905c_vp.rx_skbuff[i] = skb;      if (skb == NULL)	break;			/* Bad news!  */      rt_3c905c_vp.rx_ring[i].addr = cpu_to_le32(pci_map_single(rt_3c905c_vp.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 (rt_3c905c_vp.rx_skbuff[j]) {	  rtl_free(rt_3c905c_vp.rx_skbuff[j]);	  rt_3c905c_vp.rx_skbuff[j] = 0;	}      }      retval = -ENOMEM;      goto out_free_irq;    }    /* Wrap the ring. */    rt_3c905c_vp.rx_ring[i-1].next = cpu_to_le32(rt_3c905c_vp.rx_ring_dma);    /* TX RING INITIALIZATION */    for (i = 0; i < TX_RING_SIZE; i++) {      unsigned char *skb;      rt_3c905c_vp.tx_ring[i].next = 0;       rt_3c905c_vp.tx_ring[i].status = 0;	/* Clear complete bit. */      rt_3c905c_vp.tx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LAST_FRAG);      skb = rtl_malloc(PKT_BUF_SZ);      rt_3c905c_vp.tx_skbuff[i] = skb;      if (skb == NULL)	break;			/* Bad news!  */      rt_3c905c_vp.tx_ring[i].addr = cpu_to_le32(pci_map_single(rt_3c905c_vp.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 (rt_3c905c_vp.tx_skbuff[j]) {	  rtl_free(rt_3c905c_vp.tx_skbuff[j]);	  rt_3c905c_vp.tx_skbuff[j] = 0;	}      }      retval = -ENOMEM;      goto out_free_irq;    }    /* Wrap the ring. */    rt_3c905c_vp.tx_ring[i-1].next = cpu_to_le32(rt_3c905c_vp.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 = rt_3c905c_vp.ioaddr;  unsigned int config;  int i;    rt_3c905c_vp.rx_packets = 0;  rt_3c905c_vp.rx_frames_for_us = 0;  if (rt_3c905c_vp.pdev && rt_3c905c_vp.enable_wol) {    rt_pci_set_power_state(dev, 0);	/* Go active */    rt_pci_restore_state(dev, rt_3c905c_vp.power_state);  }    /* Before initializing select the active media port. */  EL3WINDOW(3);  config = inl(ioaddr + Wn3_Config);  if (rt_3c905c_vp.media_override != 7) {    rt_3c905c_vp.if_port = rt_3c905c_vp.media_override;  } else if (rt_3c905c_vp.autoselect) {    if (rt_3c905c_vp.has_nway) {    } else {      /* Find first available media type, starting with 100baseTx. */      rt_3c905c_vp.if_port = XCVR_100baseTx;      while (! (rt_3c905c_vp.available_media & media_tbl[rt_3c905c_vp.if_port].mask))	rt_3c905c_vp.if_port = media_tbl[rt_3c905c_vp.if_port].next;    }  } else {    rt_3c905c_vp.if_port = rt_3c905c_vp.default_media;      }  rt_3c905c_vp.full_duplex = rt_3c905c_vp.force_fd;  config = BFINS(config, rt_3c905c_vp.if_port, 20, 4);  outl(config, ioaddr + Wn3_Config);    if (rt_3c905c_vp.if_port == XCVR_MII || rt_3c905c_vp.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(rt_3c905c_vp.phys[0], 1);    mii_reg5 = rtl_3COM905C_mdio_read(rt_3c905c_vp.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 */      rt_3c905c_vp.full_duplex = 1;    rt_3c905c_vp.partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0);    EL3WINDOW(3);  }  rt_3c905c_vp.full_duplex = 1;  /* Set the full-duplex bit. */  outw(	((rt_3c905c_vp.info1 & 0x8000) || rt_3c905c_vp.full_duplex ? 0x20 : 0) |	(rt_3c905c_vp.mtu > 1500 ? 0x40 : 0) |	((rt_3c905c_vp.full_duplex && rt_3c905c_vp.flow_ctrl && rt_3c905c_vp.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(rt_3c905c_vp.dev_addr[i], ioaddr + i);  for (; i < 12; i+=2)    outw(0, ioaddr + i);    if (rt_3c905c_vp.cb_fn_base) {    unsigned short n = inw(ioaddr + Wn2_ResetOptions) & ~0x4010;    if (rt_3c905c_vp.drv_flags & INVERT_LED_PWR)      n |= 0x10;    if (rt_3c905c_vp.drv_flags & INVERT_MII_PWR)      n |= 0x4000;    outw(n, ioaddr + Wn2_ResetOptions);  }    if (rt_3c905c_vp.if_port == XCVR_10base2)    /* Start the thinnet transceiver. We should really wait 50ms...*/    outw(StartCoax, ioaddr + EL3_CMD);  if (rt_3c905c_vp.if_port != XCVR_NWAY) {    EL3WINDOW(4);    outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) |	 media_tbl[rt_3c905c_vp.if_port].media_bits, ioaddr + Wn4_Media);  }    /* RTOS and statistic??? Let's disable stats. */  outw(StatsDisable, ioaddr + EL3_CMD);  EL3WINDOW(6);  for (i = 0; i < 10; i++)    inb(ioaddr + i);  inw(ioaddr + 10);  inw(ioaddr + 12);  /* New: On the Vortex we must also clear the BadSSD counter. */  EL3WINDOW(4);  inb(ioaddr + 12);    /* Switch to register set 7 for normal use. */  EL3WINDOW(7);    if (rt_3c905c_vp.full_bus_master_rx) { /* Boomerang bus master. */    rt_3c905c_vp.cur_rx = rt_3c905c_vp.dirty_rx = rt_3c905c_vp.cur_tx = 0;    outl(rt_3c905c_vp.rx_ring_dma, ioaddr + UpListPtr);  }  if (rt_3c905c_vp.full_bus_master_tx) { 		/* Boomerang bus master Tx. */    rt_3c905c_vp.cur_tx = rt_3c905c_vp.dirty_tx = 0;    if (rt_3c905c_vp.drv_flags & IS_BOOMERANG)      outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */    /* Clear the Rx, Tx rings. */    for (i = 0; i < RX_RING_SIZE; i++)	/* AKPM: this is done in vortex_open, too */      rt_3c905c_vp.rx_ring[i].status = 0;    outl(0, ioaddr + DownListPtr);  }  /* Set receiver mode: presumably accept b-case and phys addr only. */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -