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

📄 rtl_3c905cx_drv.c

📁 最新rtlinux内核源码
💻 C
📖 第 1 页 / 共 4 页
字号:
  rtl_3COM905C_set_rx_mode();  outw(StatsDisable, ioaddr + EL3_CMD);   /* Turn off statistics ASAP. */    outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */  outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */  /* Allow status bits to be seen. */  rt_3c905c_vp.status_enable = SetStatusEnb |     (rt_3c905c_vp.full_bus_master_rx ? UpComplete : RxComplete) | DownComplete;  rt_3c905c_vp.intr_enable = SetIntrEnb | UpComplete | DownComplete;  outw(rt_3c905c_vp.status_enable, ioaddr + EL3_CMD);  /* Ack all pending events, and set active indicator mask. */  outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,       ioaddr + EL3_CMD);  outw(rt_3c905c_vp.intr_enable, ioaddr + EL3_CMD);  if (rt_3c905c_vp.cb_fn_base)	    writel(0x8000, rt_3c905c_vp.cb_fn_base + 4);}/***************************************************************************************//* This function is used to issue commands to the card and wait till the command has   *//* been successfuly carried out.                                                       *//***************************************************************************************/static voidrtl_3COM905C_issue_and_wait(int cmd){  int i;  outw(cmd, rt_3c905c_vp.ioaddr + EL3_CMD);  for (i = 0; i < 2000; i++) {    if (!(inw(rt_3c905c_vp.ioaddr + EL3_STATUS) & CmdInProgress))      return;  }    /* OK, that didn't work.  Do it the slow way.  One second */  for (i = 0; i < 100000; i++) {    if (!(inw(rt_3c905c_vp.ioaddr + EL3_STATUS) & CmdInProgress)) {      return;    }    usleep(10);  }  printk(KERN_ERR ": command 0x%04x did not complete! Status=0x%x\n",	  cmd, inw(rt_3c905c_vp.ioaddr + EL3_STATUS));}/***************************************************************************************//* This functions sets the receive mode of the card.                                   *//* Pre-Cyclone chips have no documented multicast filter, so the only                  *//* multicast setting is to receive all multicast frames.  At least                     *//* the chip has a very clean way to set the mode, unlike many others.                  *//***************************************************************************************/static void rtl_3COM905C_set_rx_mode(void){  long ioaddr = rt_3c905c_vp.ioaddr;  int new_mode;    new_mode = SetRxFilter|RxStation|RxBroadcast;//RxMulticast|RxBroadcast;		  outw(new_mode, ioaddr + EL3_CMD);}/***************************************************************************************//* This function is used to release the card. It is called from the close call.        *//***************************************************************************************/static void vortex_down(struct pci_dev *dev){  long ioaddr = rt_3c905c_vp.ioaddr;    /* Turn off statistics ASAP.  We update rt_3c905c_vp->stats below. */  outw(StatsDisable, ioaddr + EL3_CMD);    /* Disable the receiver and transmitter. */  outw(RxDisable, ioaddr + EL3_CMD);  outw(TxDisable, ioaddr + EL3_CMD);    if (rt_3c905c_vp.if_port == XCVR_10base2)    /* Turn off thinnet power.  Green! */    outw(StopCoax, ioaddr + EL3_CMD);    outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);    if (rt_3c905c_vp.full_bus_master_rx)    outl(0, ioaddr + UpListPtr);  if (rt_3c905c_vp.full_bus_master_tx)    outl(0, ioaddr + DownListPtr);    if (rt_3c905c_vp.pdev && rt_3c905c_vp.enable_wol) {    rt_pci_save_state(rt_3c905c_vp.pdev, rt_3c905c_vp.power_state);    rtl_3COM905C_acpi_set_WOL();  }}/***************************************************************************************//* This function is used to release the card.                                          *//***************************************************************************************/static int vortex_close(struct pci_dev *dev){  int i;    vortex_down(dev);  if(rt_3c905c_vp.must_free_irq){    rtl_free_irq(dev->irq);    rt_3c905c_vp.must_free_irq = 0;  }    if (rt_3c905c_vp.full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */    for (i = 0; i < RX_RING_SIZE; i++)      if (rt_3c905c_vp.rx_skbuff[i]) {	rtl_free(rt_3c905c_vp.rx_skbuff[i]);      }  }  if (rt_3c905c_vp.full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */    for (i = 0; i < TX_RING_SIZE; i++)      if (rt_3c905c_vp.tx_skbuff[i]) {	rtl_free(rt_3c905c_vp.tx_skbuff[i]);      }  }  return 0;}/***************************************************************************************//* This function is never called, but it is intended to solve errors in the card.      *//* Handle uncommon interrupt sources.  This is a separate routine to minimize          */ /* the cache impact.                                                                   *//***************************************************************************************/ static void vortex_error(struct pci_dev *dev, int status){  long ioaddr = rt_3c905c_vp.ioaddr;  int do_tx_reset = 0, reset_mask = 0;    if (status & RxEarly) {				/* Rx early is unused. */    outw(AckIntr | RxEarly, ioaddr + EL3_CMD);  }  if (status & StatsFull) {			/* Empty statistics. */    static int DoneDidThat;    printk(KERN_DEBUG "%s: Updating stats.\n", dev->name);    /* HACK: Disable statistics as an interrupt source. */    /* This occurs when we have the wrong media type! */    if (DoneDidThat == 0  &&	inw(ioaddr + EL3_STATUS) & StatsFull) {      printk(KERN_WARNING "%s: Updating statistics failed, disabling "	     "stats as an interrupt source.\n", dev->name);      EL3WINDOW(5);      outw(SetIntrEnb | (inw(ioaddr + 10) & ~StatsFull), ioaddr + EL3_CMD);      rt_3c905c_vp.intr_enable &= ~StatsFull;      EL3WINDOW(7);      DoneDidThat++;    }  }  if (status & IntReq) {		/* Restore all interrupt sources.  */    outw(rt_3c905c_vp.status_enable, ioaddr + EL3_CMD);    outw(rt_3c905c_vp.intr_enable, ioaddr + EL3_CMD);  }  if (status & HostError) {    u16 fifo_diag;    EL3WINDOW(4);    fifo_diag = inw(ioaddr + Wn4_FIFODiag);    printk(KERN_ERR "%s: Host error, FIFO diagnostic register %4.4x.\n",	   dev->name, fifo_diag);    /* Adapter failure requires Tx/Rx reset and reinit. */    if (rt_3c905c_vp.full_bus_master_tx) {      int bus_status = inl(ioaddr + PktStatus);      /* 0x80000000 PCI master abort. */      /* 0x40000000 PCI target abort. */            printk(KERN_ERR "%s: PCI bus error, bus status %8.8x\n", dev->name, bus_status);            /* In this case, blow the card away */      vortex_down(dev);      rtl_3COM905C_issue_and_wait(TotalReset | 0xff);      vortex_up(dev);		/* AKPM: bug.  vortex_up() assumes that the rx ring is full. It may not be. */    } else if (fifo_diag & 0x0400)      do_tx_reset = 1;    if (fifo_diag & 0x3000) {      /* Reset Rx fifo and upload logic */      rtl_3COM905C_issue_and_wait(RxReset|0x07);      /* Set the Rx filter to the current state. */      rtl_3COM905C_set_rx_mode();      outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */      outw(AckIntr | HostError, ioaddr + EL3_CMD);    }  }    if (do_tx_reset) {    rtl_3COM905C_issue_and_wait(TxReset|reset_mask);    outw(TxEnable, ioaddr + EL3_CMD);  }}/***************************************************************************************//* This function is called during the release phase. It is mainly used to update pci   *//* stuff.                                                                              *//***************************************************************************************/static void vortex_remove_one (struct pci_dev *pdev){    outw(TotalReset|0x14, rt_3c905c_vp.ioaddr + EL3_CMD);    if (rt_3c905c_vp.pdev && rt_3c905c_vp.enable_wol) {    rt_pci_set_power_state(rt_3c905c_vp.pdev, 0);	/* Go active */    if (rt_3c905c_vp.pm_state_valid)      pci_restore_state(rt_3c905c_vp.pdev, rt_3c905c_vp.power_state);  }    pci_free_consistent(pdev,		      sizeof(struct boom_rx_desc) * RX_RING_SIZE,		      rt_3c905c_vp.rx_ring,		      rt_3c905c_vp.rx_ring_dma);  pci_free_consistent(pdev,		      sizeof(struct boom_tx_desc) * TX_RING_SIZE,		      rt_3c905c_vp.tx_ring,		      rt_3c905c_vp.tx_ring_dma);  if (rt_3c905c_vp.must_free_region){    release_region(rt_3c905c_vp.ioaddr, rt_3c905c_vp.io_size);    rt_3c905c_vp.must_free_region = 0;  }}/***************************************************************************************//* This function is used to send a packet. It writes into the internal buffers of the  *//* card.                                                                               *//***************************************************************************************/static int rt_3c905c_send_packet(const char *buffer, size_t size){  long ioaddr = rt_3c905c_vp.ioaddr;  unsigned char *buff;  int entry = rt_3c905c_vp.cur_tx % TX_RING_SIZE;  int previous = (rt_3c905c_vp.cur_tx + TX_RING_SIZE - 1) % TX_RING_SIZE;  struct boom_tx_desc *actual = &rt_3c905c_vp.tx_ring[entry];  rt_3c905c_writting = 1;  /* Wait for the stall to complete. */  rtl_3COM905C_issue_and_wait(DownStall);    buff = rt_3c905c_vp.tx_skbuff[entry];    if(buff)    memcpy(buff, buffer, size);    actual->length = cpu_to_le32(size | LAST_FRAG);    if (inl(ioaddr + DownListPtr) == 0) {    outl(rt_3c905c_vp.tx_ring_dma + entry * sizeof(struct boom_tx_desc), ioaddr + DownListPtr);    {      int tmp = previous;      while((rt_3c905c_vp.tx_ring[tmp].next != 0) && (tmp != entry)){	rt_3c905c_vp.tx_ring[tmp].next = 0;	tmp = (tmp + TX_RING_SIZE - 1) % TX_RING_SIZE;      }    }    rt_3c905c_vp.queued_packet++;  }else    rt_3c905c_vp.tx_ring[previous].next = cpu_to_le32(rt_3c905c_vp.tx_ring_dma + sizeof(struct boom_tx_desc) * entry);          outw(DownUnstall, ioaddr + EL3_CMD);    rt_3c905c_vp.cur_tx++;    rt_3c905c_writting = 0;  return size;}/* MII transceiver control section.   Read and write the MII registers using software-generated serial   MDIO protocol.  See the MII specifications or DP83840A data sheet   for details. *//* The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually   met by back-to-back PCI I/O cycles, but we insert a delay to avoid   "overclocking" issues. */#define rtl_3COM905C_mdio_delay() inl(mdio_addr)#define MDIO_SHIFT_CLK	0x01#define MDIO_DIR_WRITE	0x04#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE)#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE)#define MDIO_DATA_READ	0x02#define MDIO_ENB_IN		0x00/***************************************************************************************//* Generate the preamble required for initial synchronization and a few older          *//* transceivers.                                                                       *//***************************************************************************************/static void rtl_3COM905C_mdio_sync(long ioaddr, int bits){	long mdio_addr = ioaddr + Wn4_PhysicalMgmt;	/* Establish sync by sending at least 32 logic ones. */	while (-- bits >= 0) {		outw(MDIO_DATA_WRITE1, mdio_addr);		rtl_3COM905C_mdio_delay();		outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);		rtl_3COM905C_mdio_delay();	}}/***************************************************************************************/static int rtl_3COM905C_mdio_read(int phy_id, int location){	int i;	long ioaddr = rt_3c905c_vp.ioaddr;	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;	unsigned int retval = 0;	long mdio_addr = ioaddr + Wn4_PhysicalMgmt;	if (mii_preamble_required)		rtl_3COM905C_mdio_sync(ioaddr, 32);	/* Shift the read command bits out. */	for (i = 14; i >= 0; i--) {		int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;		outw(dataval, mdio_addr);		rtl_3COM905C_mdio_delay();		outw(dataval | MDIO_SHIFT_CLK, mdio_addr);		rtl_3COM905C_mdio_delay();	}	/* Read the two transition, 16 data, and wire-idle bits. */	for (i = 19; i > 0; i--) {		outw(MDIO_ENB_IN, mdio_addr);		rtl_3COM905C_mdio_delay();		retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);		outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);		rtl_3COM905C_mdio_delay();	}	return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff;}/***************************************************************************************/static void rtl_3COM905C_mdio_write(int phy_id, int location, int value){	long ioaddr = rt_3c905c_vp.ioaddr;	int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;	long mdio_addr = ioaddr + Wn4_PhysicalMgmt;	int i;	if (mii_preamble_required)		rtl_3COM905C_mdio_sync(ioaddr, 32);	/* Shift the command bits out. */	for (i = 31; i >= 0; i--) {		int dataval = (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;		outw(dataval, mdio_addr);		rtl_3COM905C_mdio_delay();		outw(dataval | MDIO_SHIFT_CLK, mdio_addr);		rtl_3COM905C_mdio_delay();	}	/* Leave the interface idle. */	for (i = 1; i >= 0; i--) {		outw(MDIO_ENB_IN, mdio_addr);		rtl_3COM905C_mdio_delay();		outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);		rtl_3COM905C_mdio_delay();	}	return;}

⌨️ 快捷键说明

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