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

📄 ni65.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 3 页
字号:
    dev->dma = dmatab[inw(ioaddr+L_CONFIG)&3];    printk("IRQ %d (from card), DMA %d (from card).\n",dev->irq,dev->dma);  }  else {    if(dev->dma == 0) {		/* 'stuck test' from lance.c */      int dma_channels = ((inb(DMA1_STAT_REG) >> 4) & 0x0f) | (inb(DMA2_STAT_REG) & 0xf0);      for(i=1;i<5;i++) {        int dma = dmatab[i];        if(test_bit(dma,&dma_channels) || request_dma(dma,"ni6510"))          continue;        disable_dma(dma);        set_dma_mode(dma,DMA_MODE_CASCADE);        enable_dma(dma);        ni65_init_lance(p,dev->dev_addr,0,0); /* trigger memory access */        disable_dma(dma);        free_dma(dma);        if(readreg(CSR0) & CSR0_IDON)          break;      }      if(i == 5) {        printk("Can't detect DMA channel!\n");        ni65_free_buffer(p);        return -EAGAIN;      }      dev->dma = dmatab[i];      printk("DMA %d (autodetected), ",dev->dma);    }    else      printk("DMA %d (assigned), ",dev->dma);    if(dev->irq < 2)    {      ni65_init_lance(p,dev->dev_addr,0,0);      autoirq_setup(0);      writereg(CSR0_INIT|CSR0_INEA,CSR0); /* trigger interrupt */      if(!(dev->irq = autoirq_report(2)))      {        printk("Failed to detect IRQ line!\n");        ni65_free_buffer(p);        return -EAGAIN;      }      printk("IRQ %d (autodetected).\n",dev->irq);    }    else      printk("IRQ %d (assigned).\n",dev->irq);  }  if(request_dma(dev->dma, cards[p->cardno].cardname ) != 0)  {    printk("%s: Can't request dma-channel %d\n",dev->name,(int) dev->dma);    ni65_free_buffer(p);    return -EAGAIN;  }  /*    * Grab the region so we can find another board.    */  request_region(ioaddr,cards[p->cardno].total_size,cards[p->cardno].cardname);  dev->base_addr = ioaddr;  dev->open               = ni65_open;  dev->stop               = ni65_close;  dev->hard_start_xmit    = ni65_send_packet;  dev->get_stats          = ni65_get_stats;  dev->set_multicast_list = set_multicast_list;  ether_setup(dev);  dev->interrupt      = 0;  dev->tbusy          = 0;  dev->start          = 0;  return 0; /* everything is OK */}/* * set lance register and trigger init  */static void ni65_init_lance(struct priv *p,unsigned char *daddr,int filter,int mode) {  int i;  u32 pib;  writereg(CSR0_CLRALL|CSR0_STOP,CSR0);  for(i=0;i<6;i++)    p->ib.eaddr[i] = daddr[i];  for(i=0;i<8;i++)    p->ib.filter[i] = filter;  p->ib.mode = mode;  p->ib.trp = (u32) virt_to_bus(p->tmdhead) | TMDNUMMASK;  p->ib.rrp = (u32) virt_to_bus(p->rmdhead) | RMDNUMMASK;  writereg(0,CSR3);  /* busmaster/no word-swap */  pib = (u32) virt_to_bus(&p->ib);  writereg(pib & 0xffff,CSR1);  writereg(pib >> 16,CSR2);  writereg(CSR0_INIT,CSR0); /* this changes L_ADDRREG to CSR0 */  for(i=0;i<32;i++)  {    udelay(4000);    if(inw(PORT+L_DATAREG) & (CSR0_IDON | CSR0_MERR) )      break; /* init ok ? */  }}/* * allocate memory area and check the 16MB border */static void *ni65_alloc_mem(struct device *dev,char *what,int size,int type){  struct sk_buff *skb=NULL;  unsigned char *ptr;  void *ret;  if(type) {    ret = skb = alloc_skb(2+16+size,GFP_KERNEL|GFP_DMA);    if(!skb) {      printk("%s: unable to allocate %s memory.\n",dev->name,what);      return NULL;    }    skb->dev = dev;    skb_reserve(skb,2+16);    skb_put(skb,R_BUF_SIZE);   /* grab the whole space .. (not necessary) */    ptr = skb->data;  }  else {    ret = ptr = kmalloc(T_BUF_SIZE,GFP_KERNEL | GFP_DMA);    if(!ret) {      printk("%s: unable to allocate %s memory.\n",dev->name,what);      return NULL;    }  }  if( (u32) virt_to_bus(ptr+size) > 0x1000000) {    printk("%s: unable to allocate %s memory in lower 16MB!\n",dev->name,what);    if(type)      kfree_skb(skb,FREE_WRITE);    else      kfree(ptr);    return NULL;  }  return ret;}/* * allocate all memory structures .. send/recv buffers etc ... */static int ni65_alloc_buffer(struct device *dev){  unsigned char *ptr;  struct priv *p;  int i;   /*    * we need 8-aligned memory ..   */  ptr = ni65_alloc_mem(dev,"BUFFER",sizeof(struct priv)+8,0);  if(!ptr)    return -ENOMEM;  p = dev->priv = (struct priv *) (((unsigned long) ptr + 7) & ~0x7);  memset((char *) dev->priv,0,sizeof(struct priv));  p->self = ptr;  for(i=0;i<TMDNUM;i++)  {#ifdef XMT_VIA_SKB    p->tmd_skb[i] = NULL;#endif    p->tmdbounce[i] = ni65_alloc_mem(dev,"XMIT",T_BUF_SIZE,0);    if(!p->tmdbounce[i]) {      ni65_free_buffer(p);      return -ENOMEM;    }  }  for(i=0;i<RMDNUM;i++)  {#ifdef RCV_VIA_SKB    p->recv_skb[i] = ni65_alloc_mem(dev,"RECV",R_BUF_SIZE,1);    if(!p->recv_skb[i]) {      ni65_free_buffer(p);      return -ENOMEM;    }#else    p->recvbounce[i] = ni65_alloc_mem(dev,"RECV",R_BUF_SIZE,0);    if(!p->recvbounce[i]) {      ni65_free_buffer(p);      return -ENOMEM;    }#endif  }  return 0; /* everything is OK */}/* * free buffers and private struct  */static void ni65_free_buffer(struct priv *p){  int i;  if(!p)    return;  for(i=0;i<TMDNUM;i++) {    if(p->tmdbounce[i])      kfree(p->tmdbounce[i]);#ifdef XMT_VIA_SKB    if(p->tmd_skb[i])      dev_kfree_skb(p->tmd_skb[i],FREE_WRITE);#endif  }  for(i=0;i<RMDNUM;i++)  {#ifdef RCV_VIA_SKB    if(p->recv_skb[i])      dev_kfree_skb(p->recv_skb[i],FREE_WRITE);#else    if(p->recvbounce[i])      kfree(p->recvbounce[i]);#endif  }  if(p->self)    kfree(p->self);}/* * stop and (re)start lance .. e.g after an error */static void ni65_stop_start(struct device *dev,struct priv *p){  int csr0 = CSR0_INEA;  writedatareg(CSR0_STOP);  if(debuglevel > 1)    printk("ni65_stop_start\n");  if(p->features & INIT_RING_BEFORE_START) {    int i;#ifdef XMT_VIA_SKB    struct sk_buff *skb_save[TMDNUM];#endif    unsigned long buffer[TMDNUM];    short blen[TMDNUM];    if(p->xmit_queued) {      while(1) {        if((p->tmdhead[p->tmdlast].u.s.status & XMIT_OWN))          break;        p->tmdlast = (p->tmdlast + 1) & (TMDNUM-1);        if(p->tmdlast == p->tmdnum)          break;      }    }        for(i=0;i<TMDNUM;i++) {      struct tmd *tmdp = p->tmdhead + i;#ifdef XMT_VIA_SKB      skb_save[i] = p->tmd_skb[i];#endif      buffer[i] = (u32) bus_to_virt(tmdp->u.buffer);      blen[i] = tmdp->blen;      tmdp->u.s.status = 0x0;    }    for(i=0;i<RMDNUM;i++) {      struct rmd *rmdp = p->rmdhead + i;      rmdp->u.s.status = RCV_OWN;    }    p->tmdnum = p->xmit_queued = 0;    writedatareg(CSR0_STRT | csr0);    for(i=0;i<TMDNUM;i++) {      int num = (i + p->tmdlast) & (TMDNUM-1);      p->tmdhead[i].u.buffer = (u32) virt_to_bus((char *)buffer[num]); /* status is part of buffer field */      p->tmdhead[i].blen = blen[num];      if(p->tmdhead[i].u.s.status & XMIT_OWN) {         p->tmdnum = (p->tmdnum + 1) & (TMDNUM-1);         p->xmit_queued = 1;	 writedatareg(CSR0_TDMD | CSR0_INEA | csr0);      }#ifdef XMT_VIA_SKB      p->tmd_skb[i] = skb_save[num];#endif    }    p->rmdnum = p->tmdlast = 0;    if(!p->lock)      dev->tbusy = (p->tmdnum || !p->xmit_queued) ? 0 : 1;    dev->trans_start = jiffies;  }   else    writedatareg(CSR0_STRT | csr0);}/*  * init lance (write init-values .. init-buffers) (open-helper) */static int ni65_lance_reinit(struct device *dev){   int i;   struct priv *p = (struct priv *) dev->priv;   p->lock = 0;   p->xmit_queued = 0;   disable_dma(dev->dma); /* I've never worked with dma, but we do it like the packetdriver */   set_dma_mode(dev->dma,DMA_MODE_CASCADE);   enable_dma(dev->dma);    outw(inw(PORT+L_RESET),PORT+L_RESET); /* first: reset the card */   if( (i=readreg(CSR0) ) != 0x4)   {     printk(KERN_ERR "%s: can't RESET %s card: %04x\n",dev->name,              cards[p->cardno].cardname,(int) i);     disable_dma(dev->dma);     return 0;   }   p->rmdnum = p->tmdnum = p->tmdlast = p->tmdbouncenum = 0;   for(i=0;i<TMDNUM;i++)   {     struct tmd *tmdp = p->tmdhead + i;#ifdef XMT_VIA_SKB     if(p->tmd_skb[i]) {       dev_kfree_skb(p->tmd_skb[i],FREE_WRITE);       p->tmd_skb[i] = NULL;     }#endif     tmdp->u.buffer = 0x0;     tmdp->u.s.status = XMIT_START | XMIT_END;     tmdp->blen = tmdp->status2 = 0;   }   for(i=0;i<RMDNUM;i++)   {     struct rmd *rmdp = p->rmdhead + i;#ifdef RCV_VIA_SKB     rmdp->u.buffer = (u32) virt_to_bus(p->recv_skb[i]->data);#else     rmdp->u.buffer = (u32) virt_to_bus(p->recvbounce[i]);#endif     rmdp->blen = -(R_BUF_SIZE-8);     rmdp->mlen = 0;     rmdp->u.s.status = RCV_OWN;   }      if(dev->flags & IFF_PROMISC)     ni65_init_lance(p,dev->dev_addr,0x00,M_PROM);   else if(dev->mc_count || dev->flags & IFF_ALLMULTI)     ni65_init_lance(p,dev->dev_addr,0xff,0x0);   else      ni65_init_lance(p,dev->dev_addr,0x00,0x00);  /*   * ni65_set_lance_mem() sets L_ADDRREG to CSR0   * NOW, WE WILL NEVER CHANGE THE L_ADDRREG, CSR0 IS ALWAYS SELECTED    */   if(inw(PORT+L_DATAREG) & CSR0_IDON)  {     ni65_set_performance(p);           /* init OK: start lance , enable interrupts */     writedatareg(CSR0_CLRALL | CSR0_INEA | CSR0_STRT);     return 1; /* ->OK */   }   printk(KERN_ERR "%s: can't init lance, status: %04x\n",dev->name,(int) inw(PORT+L_DATAREG));   disable_dma(dev->dma);   return 0; /* ->Error */} /*  * interrupt handler   */static void ni65_interrupt(int irq, void * dev_id, struct pt_regs * regs){  int csr0;  struct device *dev = (struct device *) irq2dev_map[irq];  struct priv *p;  int bcnt = 32;  if (dev == NULL) {    printk (KERN_ERR "ni65_interrupt(): irq %d for unknown device.\n", irq);    return;  }  if(set_bit(0,(int *) &dev->interrupt)) {    printk("ni65: oops .. interrupt while proceeding interrupt\n");    return;  }  p = (struct priv *) dev->priv;  while(--bcnt) {    csr0 = inw(PORT+L_DATAREG);#if 0    writedatareg( (csr0 & CSR0_CLRALL) ); /* ack interrupts, disable int. */#else    writedatareg( (csr0 & CSR0_CLRALL) | CSR0_INEA ); /* ack interrupts, interrupts enabled */#endif

⌨️ 快捷键说明

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