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

📄 if_8139.c

📁 eCos操作系统源码
💻 C
📖 第 1 页 / 共 3 页
字号:
   * from the eCos Intel 82559 driver.   */  if (rltk8139_info->interrupt_handle != 0) {    cyg_drv_interrupt_acknowledge(rltk8139_info->vector);#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE    cyg_drv_interrupt_unmask(rltk8139_info->vector);#endif  }  return true;}#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE/* * Interrupt service routine. We do not clear the interrupt status bits * (since this should really only be done after handling whatever caused * the interrupt, and that is done in the '_deliver' routine), but instead * clear the interrupt mask. * * If we are sharing interrupts with other devices, we have two options * (configurable): * * 1. Mask the interrupt vector completly. Personally I think this is a bad *    idea because the other devices sharing this interrupt are also masked *    until the network thread gets around to calling the '_deliver' routine. * * 2. Use the interrupt mask register in the 8139 to mask just the interrupt *    request coming from the 8139. This way, the other devices' requests *    can still be serviced. */static cyg_uint32rltk8139_isr(cyg_vector_t vector, cyg_addrword_t data){  Rltk8139_t *rltk8139_info;#ifdef CYGPKG_DEVS_ETH_RLTK_8139_SHARE_INTERRUPTS  cyg_uint16 isr;#endif  rltk8139_info = (Rltk8139_t *)(((struct eth_drv_sc *)data)->driver_private);#ifdef CYGPKG_DEVS_ETH_RLTK_8139_SHARE_INTERRUPTS  /*   * If interrupt sharing is enabled, check if the interrupt is really   * intended for us. Note that while the RealTek data sheet claims that   * reading the interrupt status register will clear all it's bits,   * this is not true, so we can read it without problems.   */  if (!(isr = INW(rltk8139_info->base_address + ISR)))    return 0;#endif#ifdef CYGPKG_DEVS_ETH_RLTK_8139_MASK_INTERRUPTS_IN_8139  /* Clear the interrupt mask to stop the current request. */  OUTW(0, rltk8139_info->base_address + IMR);#else  /* Mask the interrupt */  cyg_interrupt_mask(vector);#endif  /* Acknowledge the interrupt for those platforms were this is necessary */  cyg_interrupt_acknowledge(vector);  return (CYG_ISR_HANDLED | CYG_ISR_CALL_DSR);}#endif /* ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE *//* * Reset the chip. This function is not exported to higher level software. */static voidrltk8139_reset(struct eth_drv_sc *sc){  rltk8139_stop(sc);  rltk8139_start(sc, NULL, 0);}#ifdef ETH_DRV_SET_MC_LIST/* * I assume (hope !) that this is identical to Ethernet's CRC algorithm * specified in IEEE 802.3. It does seem to calculate the same CRC that * the 8139 itself does, so I think it is correct. * Note that while Ethernet's polynomial is usually specified as 04C11DB7, * we must use EDB88320 because we shift the bits to the left, not the right. * (See ftp://ftp.rocksoft.com/papers/crc_v3.txt for a good description of * CRC algorithms). */static cyg_uint32ether_crc(cyg_uint8 *data, int length){  int bit;  cyg_uint32 crc = 0xFFFFFFFFU;  while (length-- > 0) {    crc ^= *data++;    for (bit = 0; bit < 8; ++bit) {      if (crc & 1)        crc = (crc >> 1) ^ 0xEDB88320U;      else        crc = (crc >> 1);    }  }  return crc ^ 0xFFFFFFFFU;}/* * Set up multicast filtering. The way I understand existing driver code * (Linux and OpenBSD), the 8139 calculates the ethernet CRC of * incoming addresses and uses the top 6 bits as an index into a hash * table. If the corresponding bit is set in MAR0..7, the address is * accepted. */static voidrltk8139_set_multicast_list(Rltk8139_t *rltk8139_info,                            struct eth_drv_mc_list *mc_list){  cyg_uint32 mar[2], hash;  int i;  /* If 'mc_list' is NULL, accept all multicast packets. */  if (!mc_list) {    mar[0] = 0xFFFFFFFFU;    mar[1] = 0xFFFFFFFFU;  }  else {    mar[0] = 0;    mar[1] = 0;    for (i = 0; i < mc_list->len; ++i) {      hash = ether_crc(&mc_list->addrs[i][0], ETHER_ADDR_LEN) >> 26;      mar[hash >> 5] |= (1 << (hash & 0x1F));    }  }  /* Program the new filter values */  OUTL(mar[0], rltk8139_info->base_address + MAR0);  OUTL(mar[1], rltk8139_info->base_address + MAR4);}#endif /* ifdef ETH_DRV_SET_MC_LIST *//* * Initialize the network interface. Since the chips is reset by calling * _stop() and _start(), any code that will never need to be executed more * than once after system startup should go here. */static boolrltk8139_init(struct cyg_netdevtab_entry *tab){  struct eth_drv_sc *sc;  Rltk8139_t *rltk8139_info;  sc = (struct eth_drv_sc *)(tab->device_instance);  rltk8139_info = (Rltk8139_t *)(sc->driver_private);  /*   * Initialize the eCos PCI library. According to the documentation, it   * is safe to call this function multiple times, so we call it just to   * be sure it has been done.   */  cyg_pci_init();  /*   * Scan the PCI bus for the specified chip. The '_find' function will also   * do some basic PCI initialization.   */  if (!rltk8139_find(rltk8139_info->device_num, sc)) {#ifdef DEBUG_RLTK8139_DRIVER    diag_printf("rltk8139_init: could not find RealTek 8139 chip #%d.\n",                rltk8139_info->device_num);#endif    return false;  }  /* platform depends initialize */  CYGHWR_RLTK_8139_PLF_INIT(sc);  /*   * The initial tx threshold is set here to prevent it from being reset   * with every _start().   */  rltk8139_info->tx_threshold = 3;  /* Initialize upper level driver */  (sc->funs->eth_drv->init)(sc, rltk8139_info->mac);  return true;}/* * (Re)Start the chip, initializing data structures and enabling the * transmitter and receiver. Currently, 'flags' is unused by eCos. */static voidrltk8139_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags){  Rltk8139_t *rltk8139_info;  int i;#ifdef DEBUG_RLTK8139_DRIVER  diag_printf("rltk8139_start(%s)\n", sc->dev_name);#endif  rltk8139_info = (Rltk8139_t *)(sc->driver_private);  /*   * Reset the chip. Existing driver code implies that this may take up   * to 10ms; since I don't know under what exact circumstances this code may   * be called I busy wait here regardless.   */  OUTB(RST, rltk8139_info->base_address + CR);  while (INB(rltk8139_info->base_address + CR) & RST);#ifdef DEBUG_RLTK8139_DRIVER  diag_printf("rltk8139_start(%s): 8139 was successfully reset.\n",              sc->dev_name);#endif  /*   * Clear the key storage area. These keys are used by the eCos networking   * support code to keep track of individual packets.   */  for (i = 0; i < NUM_TX_DESC; ++i)    rltk8139_info->tx_desc_key[i] = 0;  /* Initialize transmission buffer control */  rltk8139_info->tx_free_desc = 0;  rltk8139_info->tx_num_free_desc = NUM_TX_DESC;  /*   * Set the requested MAC address if enaddr != NULL. This is a special   * feature of my '_start' function since it's used to reset the chip after   * errors as well.   */  if (enaddr != NULL) {    for (i = 0; i < 6; ++i) {      rltk8139_info->mac[i] = enaddr[i];      OUTB(enaddr[i], rltk8139_info->base_address + IDR0 + i);    }  }  /*   * Now setup the transmission and reception buffers. These could be done   * in _init() and kept around, but putting them here fits better logically.   */  OUTL(CYGARC_PCI_DMA_ADDRESS((cyg_uint32)(rltk8139_info->tx_buffer                                            + 0 * TX_BUF_SIZE)),       rltk8139_info->base_address + TSAD0);  OUTL(CYGARC_PCI_DMA_ADDRESS((cyg_uint32)(rltk8139_info->tx_buffer                                            + 1 * TX_BUF_SIZE)),       rltk8139_info->base_address + TSAD1);  OUTL(CYGARC_PCI_DMA_ADDRESS((cyg_uint32)(rltk8139_info->tx_buffer                                            + 2 * TX_BUF_SIZE)),       rltk8139_info->base_address + TSAD2);  OUTL(CYGARC_PCI_DMA_ADDRESS((cyg_uint32)(rltk8139_info->tx_buffer                                            + 3 * TX_BUF_SIZE)),       rltk8139_info->base_address + TSAD3);  OUTL(CYGARC_PCI_DMA_ADDRESS((cyg_uint32)rltk8139_info->rx_ring),       rltk8139_info->base_address + RBSTART);  /*   * Enable the transmitter and receiver, then clear the missed packet   * counter.   */  OUTB(INB(rltk8139_info->base_address + CR) | (TE|RE),       rltk8139_info->base_address + CR);  OUTL(0, rltk8139_info->base_address + MPC);  /*   * It seems the receiver and transmitter configuration can only   * be set after the transmitter/receiver have been enabled.   */  OUTL(TXCFG, rltk8139_info->base_address + TCR);  OUTL(RXCFG | AM, rltk8139_info->base_address + RCR);  /*   * Enable the transmitter and receiver again. I'm not sure why this is   * necessary; the Linux driver does it so we do it here just to be on   * the safe side.   */  OUTB(INB(rltk8139_info->base_address + CR) | (TE|RE),       rltk8139_info->base_address + CR);#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE  /*   * If this driver was not compiled in stand alone (without interrupts)   * mode, enable interrupts.   */  OUTW(RLTK8139_IRQ, rltk8139_info->base_address + IMR);#endif#ifdef DEBUG_RLTK8139_DRIVER  rltk8139_print_state(sc);#endif}/* * Stop the chip, disabling the transmitter and receiver. */static voidrltk8139_stop(struct eth_drv_sc *sc){  Rltk8139_t *rltk8139_info;#ifdef DEBUG_RLTK8139_DRIVER  diag_printf("rltk8139_stop(%s)\n", sc->dev_name);#endif  rltk8139_info = (Rltk8139_t *)(sc->driver_private);  /* Disable receiver and transmitter */  OUTB(INB(rltk8139_info->base_address + CR) & ~(TE|RE),       rltk8139_info->base_address + CR);  /* Mask all interrupts */  OUTW(0, rltk8139_info->base_address + IMR);}/* * 8139 control function. Unlike a 'real' ioctl function, this function is * not required to tell the caller why a request failed, only that it did * (see the eCos documentation). */static intrltk8139_control(struct eth_drv_sc *sc, unsigned long key, void *data,                 int data_length){  int i;  Rltk8139_t *rltk8139_info;#ifdef DEBUG_RLTK8139_DRIVER  diag_printf("rltk8139_control(%08x, %lx)\n", sc, key);#endif  rltk8139_info = (Rltk8139_t *)(sc->driver_private);  switch (key) {#ifdef ETH_DRV_SET_MAC_ADDRESS  case ETH_DRV_SET_MAC_ADDRESS:    if ( 6 != data_length )      return 1;    /* Set the mac address */    for (i = 0; i < 6; ++i) {      rltk8139_info->mac[i] = *(((cyg_uint8 *)data) + i);      OUTB(rltk8139_info->mac[i], rltk8139_info->base_address + IDR0 + i);    }    return 0;#endif#ifdef ETH_DRV_GET_MAC_ADDRESS    case ETH_DRV_GET_MAC_ADDRESS:      if (6 != data_length)        return 1;      memcpy(data, rltk8139_info->mac, 6);      return 0;#endif#ifdef ETH_DRV_GET_IF_STATS_UD    case ETH_DRV_GET_IF_STATS_UD: // UD == UPDATE      //ETH_STATS_INIT( sc );    // so UPDATE the statistics structure#endif      // drop through#ifdef ETH_DRV_GET_IF_STATS  case ETH_DRV_GET_IF_STATS:#endif#if defined(ETH_DRV_GET_IF_STATS) || defined (ETH_DRV_GET_IF_STATS_UD)    break;#endif#ifdef ETH_DRV_SET_MC_LIST  case ETH_DRV_SET_MC_LIST:    /*     * Program the 8139's multicast filter register. If the eth_drv_mc_list     * contains at least one element, set the accept multicast bit in the     * receive config register.     */    rltk8139_set_multicast_list(rltk8139_info, (struct eth_drv_mc_list *)data);    if (((struct eth_drv_mc_list *)data)->len > 0)      OUTL(INL(rltk8139_info->base_address + RCR) | AM,           rltk8139_info->base_address + RCR);    else      OUTL(INL(rltk8139_info->base_address + RCR) & ~AM,           rltk8139_info->base_address + RCR);    return 0;#endif // ETH_DRV_SET_MC_LIST#ifdef ETH_DRV_SET_MC_ALL  case ETH_DRV_SET_MC_ALL:    /*     * Set the accept multicast bit in the receive config register and     * program the multicast filter to accept all addresses.     */    rltk8139_set_multicast_list(rltk8139_info, NULL);    OUTL(INL(rltk8139_info->base_address + RCR) | AM,         rltk8139_info->base_address + RCR);    return 0;#endif // ETH_DRV_SET_MC_ALL  default:    return 1;  }  return 1;}/* * Check if a new packet can be sent. */static intrltk8139_can_send(struct eth_drv_sc *sc){  return ((Rltk8139_t *)(sc->driver_private))->tx_num_free_desc;}/* * Send a packet over the wire. */static voidrltk8139_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,              int total_len, unsigned long key){  Rltk8139_t *rltk8139_info;  cyg_uint8 *tx_buffer;  struct eth_drv_sg *last_sg;  int desc;

⌨️ 快捷键说明

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