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

📄 ewrk3.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 4 页
字号:
      /*      ** Set up shared memory window and pointer into the window      */      if (lp->shmem_length == IO_ONLY) {	outb(page, EWRK3_IOPR);      } else if (lp->shmem_length == SHMEM_2K) {	buf = lp->shmem_base;	outb(page, EWRK3_MPR);      } else if (lp->shmem_length == SHMEM_32K) {	buf = ((((short)page << 11) & 0x7800) + lp->shmem_base);	outb((page >> 4), EWRK3_MPR);      } else if (lp->shmem_length == SHMEM_64K) {	buf = ((((short)page << 11) & 0xf800) + lp->shmem_base);	outb((page >> 5), EWRK3_MPR);      } else {	status = -1;	printk("%s: Oops - your private data area is hosed!\n",dev->name);      }      if (!status) {	char rx_status;	int pkt_len;	if (lp->shmem_length == IO_ONLY) {	  rx_status = inb(EWRK3_DATA);	  pkt_len = inb(EWRK3_DATA);	  pkt_len |= ((u_short)inb(EWRK3_DATA) << 8);	} else {	  rx_status = readb(buf);	  buf+=1;	  pkt_len = readw(buf);	  buf+=3;	}	if (!(rx_status & R_ROK)) {	    /* There was an error. */	  lp->stats.rx_errors++;            /* Update the error stats. */	  if (rx_status & R_DBE) lp->stats.rx_frame_errors++;	  if (rx_status & R_CRC) lp->stats.rx_crc_errors++;	  if (rx_status & R_PLL) lp->stats.rx_fifo_errors++;	} else {	  struct sk_buff *skb;          if ((skb = dev_alloc_skb(pkt_len+2)) != NULL) {            unsigned char *p;	    skb->dev = dev;	    skb_reserve(skb,2);             /* Align to 16 bytes */	    p = skb_put(skb,pkt_len);	    if (lp->shmem_length == IO_ONLY) {	      *p = inb(EWRK3_DATA);         /* dummy read */	      for (i=0; i<pkt_len; i++) {		*p++ = inb(EWRK3_DATA);	      }	    } else {	      memcpy_fromio(p, buf, pkt_len);	    }	    /* 	    ** Notify the upper protocol layers that there is another 	    ** packet to handle	    */	    skb->protocol=eth_type_trans(skb,dev);	    netif_rx(skb);	    /*	    ** Update stats	    */	    lp->stats.rx_packets++;	    for (i=1; i<EWRK3_PKT_STAT_SZ-1; i++) {	      if (pkt_len < i*EWRK3_PKT_BIN_SZ) {		lp->pktStats.bins[i]++;		i = EWRK3_PKT_STAT_SZ;	      }	    }	    p = skb->data;                  /* Look at the dest addr */	    if (p[0] & 0x01) {              /* Multicast/Broadcast */	      if ((*(s32 *)&p[0] == -1) && (*(s16 *)&p[4] == -1)) {		lp->pktStats.broadcast++;	      } else {		lp->pktStats.multicast++;	      }	    } else if ((*(s32 *)&p[0] == *(s32 *)&dev->dev_addr[0]) &&		       (*(s16 *)&p[4] == *(s16 *)&dev->dev_addr[4])) {	      lp->pktStats.unicast++;	    }	    lp->pktStats.bins[0]++;           /* Duplicates stats.rx_packets */	    if (lp->pktStats.bins[0] == 0) {  /* Reset counters */	      memset(&lp->pktStats, 0, sizeof(lp->pktStats));	    }	  } else {	    printk("%s: Insufficient memory; nuking packet.\n", dev->name);	    lp->stats.rx_dropped++;	      /* Really, deferred. */	    break;	  }        }      }      /*      ** Return the received buffer to the free memory queue      */      outb(page, EWRK3_FMQ);      if (tmpLock) {                          /* If a lock was preempted */	if (lp->shmem_length == IO_ONLY) {    /* Replace old page */	  outb(tmpPage, EWRK3_IOPR);	} else {	  outb(tmpPage, EWRK3_MPR);	}      }      lp->lock = 0;                           /* Unlock the page register */    } else {      printk("ewrk3_rx(): Illegal page number, page %d\n",page);      printk("ewrk3_rx(): CSR: %02x ICR: %02x FMQC: %02x\n",inb(EWRK3_CSR),inb(EWRK3_ICR),inb(EWRK3_FMQC));    }  }  return status;}/*** Buffer sent - check for TX buffer errors.*/static intewrk3_tx(struct device *dev){  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;  u_long iobase = dev->base_addr;  u_char tx_status;  while ((tx_status = inb(EWRK3_TDQ)) > 0) {  /* Whilst there's old buffers */    if (tx_status & T_VSTS) {                 /* The status is valid */      if (tx_status & T_TXE) {	lp->stats.tx_errors++;	if (tx_status & T_NCL)    lp->stats.tx_carrier_errors++;	if (tx_status & T_LCL)    lp->stats.tx_window_errors++;	if (tx_status & T_CTU) {	  if ((tx_status & T_COLL) ^ T_XUR) {	    lp->pktStats.tx_underruns++;	  } else {	    lp->pktStats.excessive_underruns++;	  }	} else 	if (tx_status & T_COLL) {	  if ((tx_status & T_COLL) ^ T_XCOLL) {	    lp->stats.collisions++;	  } else {	    lp->pktStats.excessive_collisions++;	  }	}      } else {	lp->stats.tx_packets++;      }    }  }  return 0;}static intewrk3_close(struct device *dev){  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;  u_long iobase = dev->base_addr;  u_char icr, csr;  dev->start = 0;  dev->tbusy = 1;  if (ewrk3_debug > 1) {    printk("%s: Shutting down ethercard, status was %2.2x.\n",	   dev->name, inb(EWRK3_CSR));  }  /*   ** We stop the EWRK3 here... mask interrupts and stop TX & RX  */  DISABLE_IRQs;  STOP_EWRK3;  /*  ** Clean out the TX and RX queues here (note that one entry  ** may get added to either the TXD or RX queues if the TX or RX  ** just starts processing a packet before the STOP_EWRK3 command  ** is received. This will be flushed in the ewrk3_open() call).  */  while (inb(EWRK3_TQ));  while (inb(EWRK3_TDQ));  while (inb(EWRK3_RQ));  if (!lp->hard_strapped) {    free_irq(dev->irq, NULL);        irq2dev_map[dev->irq] = 0;  }  MOD_DEC_USE_COUNT;  return 0;}static struct enet_statistics *ewrk3_get_stats(struct device *dev){  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;  /* Null body since there is no framing error counter */      return &lp->stats;}/*** Set or clear the multicast filter for this adapter.*/static voidset_multicast_list(struct device *dev){  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;  u_long iobase = dev->base_addr;  u_char csr;  if (irq2dev_map[dev->irq] != NULL) {    csr = inb(EWRK3_CSR);        if (lp->shmem_length == IO_ONLY) {      lp->mctbl = (char *) PAGE0_HTE;    } else {      lp->mctbl = (char *)(lp->shmem_base + PAGE0_HTE);    }    csr &= ~(CSR_PME | CSR_MCE);    if (dev->flags & IFF_PROMISC) {         /* set promiscuous mode */      csr |= CSR_PME;      outb(csr, EWRK3_CSR);    } else {      SetMulticastFilter(dev);      csr |= CSR_MCE;      outb(csr, EWRK3_CSR);    }  }}/*** Calculate the hash code and update the logical address filter** from a list of ethernet multicast addresses.** Little endian crc one liner from Matt Thomas, DEC.**** Note that when clearing the table, the broadcast bit must remain asserted** to receive broadcast messages.*/static void SetMulticastFilter(struct device *dev){  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;  struct dev_mc_list *dmi=dev->mc_list;  u_long iobase = dev->base_addr;  int i;  char *addrs, j, bit, byte;  short *p = (short *) lp->mctbl;  u16 hashcode;  s32 crc, poly = CRC_POLYNOMIAL_LE;  while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */  if (lp->shmem_length == IO_ONLY) {    outb(0, EWRK3_IOPR);    outw(EEPROM_OFFSET(lp->mctbl), EWRK3_PIR1);  } else {    outb(0, EWRK3_MPR);  }  if (dev->flags & IFF_ALLMULTI) {    for (i=0; i<(HASH_TABLE_LEN >> 3); i++) {      if (lp->shmem_length == IO_ONLY) {	outb(0xff, EWRK3_DATA);      } else {                /* memset didn't work here */	writew(0xffff, p);	p++; i++;      }    }  } else {    /* Clear table except for broadcast bit */    if (lp->shmem_length == IO_ONLY) {      for (i=0; i<(HASH_TABLE_LEN >> 4) - 1; i++) {	outb(0x00, EWRK3_DATA);      }       outb(0x80, EWRK3_DATA); i++;           /* insert the broadcast bit */      for (; i<(HASH_TABLE_LEN >> 3); i++) {	outb(0x00, EWRK3_DATA);      }     } else {      memset_io(lp->mctbl, 0, (HASH_TABLE_LEN >> 3));      writeb(0x80, (char *)(lp->mctbl + (HASH_TABLE_LEN >> 4) - 1));    }    /* Update table */    for (i=0;i<dev->mc_count;i++) {          /* for each address in the list */      addrs=dmi->dmi_addr;      dmi=dmi->next;      if ((*addrs & 0x01) == 1) {            /* multicast address? */ 	crc = 0xffffffff;                    /* init CRC for each address */	for (byte=0;byte<ETH_ALEN;byte++) {  /* for each address byte */	                                     /* process each address bit */ 	  for (bit = *addrs++,j=0;j<8;j++, bit>>=1) {	    crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0);	  }	}	hashcode = crc & ((1 << 9) - 1);     /* hashcode is 9 LSb of CRC */	byte = hashcode >> 3;                /* bit[3-8] -> byte in filter */	bit = 1 << (hashcode & 0x07);        /* bit[0-2] -> bit in byte */	if (lp->shmem_length == IO_ONLY) {	  u_char tmp;	  outw((short)((long)lp->mctbl) + byte, EWRK3_PIR1);	  tmp = inb(EWRK3_DATA);	  tmp |= bit;	  outw((short)((long)lp->mctbl) + byte, EWRK3_PIR1);	  outb(tmp, EWRK3_DATA); 	} else {	  writeb(readb(lp->mctbl + byte) | bit, lp->mctbl + byte);	}      }    }  }  lp->lock = 0;                              /* Unlock the page register */  return;}/*** ISA bus I/O device probe*/static void isa_probe(struct device *dev, u_long ioaddr){  int i = num_ewrk3s, maxSlots;  u_long iobase;  if (!ioaddr && autoprobed) return ;            /* Been here before ! */  if (ioaddr >= 0x400) return;                   /* Not ISA */  if (ioaddr == 0) {                     /* Autoprobing */    iobase = EWRK3_IO_BASE;              /* Get the first slot address */    maxSlots = 24;  } else {                               /* Probe a specific location */    iobase = ioaddr;    maxSlots = i + 1;  }  for (; (i<maxSlots) && (dev!=NULL);iobase+=EWRK3_IOP_INC, i++) {    if (!check_region(iobase, EWRK3_TOTAL_SIZE)) {          if (DevicePresent(iobase) == 0) {	if ((dev = alloc_device(dev, iobase)) != NULL) {	  if (ewrk3_hw_init(dev, iobase) == 0) {	    num_ewrk3s++;	  }	  num_eth++;	}      }    } else if (autoprobed) {      printk("%s: region already allocated at 0x%04lx.\n", dev->name, iobase);    }  }  return;}/*** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually** the motherboard.*/static void eisa_probe(struct device *dev, u_long ioaddr){  int i, maxSlots;  u_long iobase;  char name[EWRK3_STRLEN];  if (!ioaddr && autoprobed) return ;            /* Been here before ! */  if (ioaddr < 0x1000) return;                   /* Not EISA */  if (ioaddr == 0) {                     /* Autoprobing */    iobase = EISA_SLOT_INC;              /* Get the first slot address */    i = 1;    maxSlots = MAX_EISA_SLOTS;  } else {                               /* Probe a specific location */    iobase = ioaddr;    i = (ioaddr >> 12);    maxSlots = i + 1;  }  for (i=1; (i<maxSlots) && (dev!=NULL); i++, iobase+=EISA_SLOT_INC) {    if (EISA_signature(name, EISA_ID) == 0) {      if (!check_region(iobase, EWRK3_TOTAL_SIZE)) {	if (DevicePresent(iobase) == 0) {	  if ((dev = alloc_device(dev, iobase)) != NULL) {	    if (ewrk3_hw_init(dev, iobase) == 0) {	      num_ewrk3s++;	    }	    num_eth++;	  }	}      } else if (autoprobed) {	printk("%s: region already allocated at 0x%04lx.\n", dev->name, iobase);      }    }  }  return;}/*** Search the entire 'eth' device list for a fixed probe. If a match isn't** found then check for an autoprobe or unused device location. If they** are not available then insert a new device structure at the end of** the current list.*/static struct device *alloc_device(struct device *dev, u_long iobase){    struct device *adev = NULL;    int fixed = 0, new_dev = 0;    num_eth = ewrk3_dev_index(dev->name);    if (loading_module) return dev;        while (1) {	if (((dev->base_addr == EWRK3_NDA) || (dev->base_addr==0)) && !adev) {	    adev=dev;	} else if ((dev->priv == NULL) && (dev->base_addr==iobase)) {	    fixed = 1;	} else {	    if (dev->next == NULL) {		new_dev = 1;	    } else if (strncmp(dev->next->name, "eth", 3) != 0) {		new_dev = 1;	    }	}	if ((dev->next == NULL) || new_dev || fixed) break;	dev = dev->next;	num_eth++;    }    if (adev && !fixed) {	dev = adev;	num_eth = ewrk3_dev_index(dev->name);	new_dev = 0;    }    if (((dev->next == NULL) &&  	((dev->base_addr != EWRK3_NDA) && (dev->base_addr != 0)) && !fixed) ||	new_dev) {	num_eth++;                         /* New device */	dev = insert_device(dev, iobase, ewrk3_probe);    }        return dev;}/*** If at end of eth device list and can't use current entry, malloc** one up. If memory could not be allocated, print an error message.*/static struct device *insert_device(struct device *dev, u_long iobase, int (*init)(struct device *)){    struct device *new;    new = (struct device *)kmalloc(sizeof(struct device)+8, GFP_KERNEL);    if (new == NULL) {	printk("eth%d: Device not initialised, insufficient memory\n",num_eth);	return NULL;    } else {	new->next = dev->next;	dev->next = new;	dev = dev->next;               /* point to the new device */	dev->name = (char *)(dev + 1);	if (num_eth > 9999) {	    sprintf(dev->name,"eth????");/* New device name */	} else {	    sprintf(dev->name,"eth%d", num_eth);/* New device name */	}	dev->base_addr = iobase;       /* assign the io address */

⌨️ 快捷键说明

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