📄 com90io.c
字号:
static voidarc90io_inthandler(struct device *dev){ struct arcnet_local *lp=(struct arcnet_local *)dev->priv; int ioaddr=dev->base_addr, status, boguscount = 3, didsomething; AINTMASK(0); BUGMSG(D_DURING,"in arc90io_inthandler (status=%Xh, intmask=%Xh)\n", ARCSTATUS,lp->intmask); do { status = ARCSTATUS; didsomething=0; /* RESET flag was enabled - card is resetting and if RX * is disabled, it's NOT because we just got a packet. */ if (status & RESETflag) { BUGMSG(D_NORMAL,"spurious reset (status=%Xh)\n", status); arc90io_reset(dev,0); /* all other flag values are just garbage */ break; } /* RX is inhibited - we must have received something. */ if (status & lp->intmask & NORXflag) { int recbuf=lp->recbuf=!lp->recbuf; int oldaddr=0; BUGMSG(D_DURING,"receive irq (status=%Xh)\n", status); /* enable receive of our next packet */ EnableReceiver(); if (lp->intx) oldaddr=(inb(_ADDR_HI)<<8) | inb(_ADDR_LO); /* Got a packet. */ arc90io_rx(dev,!recbuf); if (lp->intx) { outb( (oldaddr >> 8), _ADDR_HI); outb( oldaddr & 0xff, _ADDR_LO); } didsomething++; } /* it can only be an xmit-done irq if we're xmitting :) */ /*if (status&TXFREEflag && !lp->in_txhandler && lp->sending)*/ if (status & lp->intmask & TXFREEflag) { struct Outgoing *out=&(lp->outgoing); int was_sending=lp->sending; lp->intmask &= ~TXFREEflag; lp->in_txhandler++; if (was_sending) lp->sending--; BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n", status,out->numsegs,out->segnum,out->skb); if (was_sending && !(status&TXACKflag)) { if (lp->lasttrans_dest != 0) { BUGMSG(D_EXTRA,"transmit was not acknowledged! (status=%Xh, dest=%02Xh)\n", status,lp->lasttrans_dest); lp->stats.tx_errors++; lp->stats.tx_carrier_errors++; } else { BUGMSG(D_DURING,"broadcast was not acknowledged; that's normal (status=%Xh, dest=%02Xh)\n", status, lp->lasttrans_dest); } } /* send packet if there is one */ arcnet_go_tx(dev,0); didsomething++; if (lp->intx) { BUGMSG(D_DURING,"TXDONE while intx! (status=%Xh, intx=%d)\n", ARCSTATUS,lp->intx); lp->in_txhandler--; continue; } if (!lp->outgoing.skb) { BUGMSG(D_DURING,"TX IRQ done: no split to continue.\n"); /* inform upper layers */ if (!lp->txready) arcnet_tx_done(dev, lp); lp->in_txhandler--; continue; } /* if more than one segment, and not all segments * are done, then continue xmit. */ if (out->segnum<out->numsegs) arcnetA_continue_tx(dev); arcnet_go_tx(dev,0); /* if segnum==numsegs, the transmission is finished; * free the skb. */ if (out->segnum>=out->numsegs) { /* transmit completed */ out->segnum++; if (out->skb) { lp->stats.tx_bytes += out->skb->len; dev_kfree_skb(out->skb); } out->skb=NULL; /* inform upper layers */ if (!lp->txready) arcnet_tx_done(dev, lp); } didsomething++; lp->in_txhandler--; } else if (lp->txready && !lp->sending && !lp->intx) { BUGMSG(D_NORMAL,"recovery from silent TX (status=%Xh)\n", status); arcnet_go_tx(dev,0); didsomething++; }#ifdef DETECT_RECONFIGS if (status & (lp->intmask) & RECONflag) { ACOMMAND(CFLAGScmd|CONFIGclear); lp->stats.tx_carrier_errors++;#ifdef SHOW_RECONFIGS BUGMSG(D_NORMAL,"Network reconfiguration detected" " (status=%Xh, config=%X)\n", status,lp->config);#endif /* SHOW_RECONFIGS */#ifdef RECON_THRESHOLD /* is the RECON info empty or old? */ if (!lp->first_recon || !lp->last_recon || jiffies-lp->last_recon > HZ*10) { if (lp->network_down) BUGMSG(D_NORMAL,"reconfiguration detected: cabling restored?\n"); lp->first_recon=lp->last_recon=jiffies; lp->num_recons=lp->network_down=0; BUGMSG(D_DURING,"recon: clearing counters.\n"); } else /* add to current RECON counter */ { lp->last_recon=jiffies; lp->num_recons++; BUGMSG(D_DURING,"recon: counter=%d, time=%lds, net=%d\n", lp->num_recons, (lp->last_recon-lp->first_recon)/HZ, lp->network_down); /* if network is marked up; * and first_recon and last_recon are 60+ sec * apart; * and the average no. of recons counted is * > RECON_THRESHOLD/min; * then print a warning message. */ if (!lp->network_down && (lp->last_recon-lp->first_recon)<=HZ*60 && lp->num_recons >= RECON_THRESHOLD) { lp->network_down=1; BUGMSG(D_NORMAL,"many reconfigurations detected: cabling problem?\n"); } else if (!lp->network_down && lp->last_recon-lp->first_recon > HZ*60) { /* reset counters if we've gone for * over a minute. */ lp->first_recon=lp->last_recon; lp->num_recons=1; } } } else if (lp->network_down && jiffies-lp->last_recon > HZ*10) { if (lp->network_down) BUGMSG(D_NORMAL,"cabling restored?\n"); lp->first_recon=lp->last_recon=0; lp->num_recons=lp->network_down=0; BUGMSG(D_DURING,"not recon: clearing counters anyway.\n");#endif }#endif /* DETECT_RECONFIGS */ } while (--boguscount && didsomething); BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n", ARCSTATUS,boguscount); BUGMSG(D_DURING,"\n"); SETMASK; /* put back interrupt mask */}/* A packet has arrived; grab it from the buffers and pass it to the generic * arcnet_rx routing to deal with it. */static voidarc90io_rx(struct device *dev,int recbuf){ struct arcnet_local *lp = (struct arcnet_local *)dev->priv; int ioaddr=dev->base_addr; union ArcPacket packetbuf; union ArcPacket *arcpacket=&packetbuf; u_char *arcsoft; short length,offset; u_char daddr,saddr; lp->stats.rx_packets++; get_whole_buffer(dev,recbuf*512,4,(char *)arcpacket); saddr=arcpacket->hardheader.source; /* if source is 0, it's a "used" packet! */ if (saddr==0) { BUGMSG(D_NORMAL,"discarding old packet. (status=%Xh)\n", ARCSTATUS); lp->stats.rx_errors++; return; } /* Set source address to zero to mark it as old */ put_buffer_byte(dev,recbuf*512,0); arcpacket->hardheader.source=0; daddr=arcpacket->hardheader.destination; if (arcpacket->hardheader.offset1) /* Normal Packet */ { offset=arcpacket->hardheader.offset1; arcsoft=&arcpacket->raw[offset]; length=256-offset; } else /* ExtendedPacket or ExceptionPacket */ { offset=arcpacket->hardheader.offset2; arcsoft=&arcpacket->raw[offset]; length=512-offset; } get_whole_buffer(dev,recbuf*512+offset,length,(char *)arcpacket+offset); arcnet_rx(lp, arcsoft, length, saddr, daddr); BUGLVL(D_RX) arcnet_dump_packet(lp->adev,arcpacket->raw,length>240,"rx");}/* Given an skb, copy a packet into the ARCnet buffers for later transmission * by arcnet_go_tx. */static voidarc90io_prepare_tx(struct device *dev,u_char *hdr,int hdrlen, char *data,int length,int daddr,int exceptA, int offset){ struct arcnet_local *lp = (struct arcnet_local *)dev->priv; lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate between 2 and 3 */ length+=hdrlen; BUGMSG(D_TX,"arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n", hdr,length,data); put_buffer_byte(dev, lp->txbuf*512+1, daddr); /* load packet into shared memory */ if (length<=MTU) /* Normal (256-byte) Packet */ put_buffer_byte(dev, lp->txbuf*512+2, offset=offset?offset:256-length); else if (length>=MinTU || offset) /* Extended (512-byte) Packet */ { put_buffer_byte(dev, lp->txbuf*512+2, 0); put_buffer_byte(dev, lp->txbuf*512+3, offset=offset?offset:512-length); } else if (exceptA) /* RFC1201 Exception Packet */ { put_buffer_byte(dev, lp->txbuf*512+2, 0); put_buffer_byte(dev, lp->txbuf*512+3, offset=512-length-4); /* exception-specific stuff - these four bytes * make the packet long enough to fit in a 512-byte * frame. */ put_buffer_byte(dev, lp->txbuf*512+offset,hdr[0]); put_whole_buffer(dev, lp->txbuf*512+offset+1,3,"\377\377\377"); offset+=4; } else /* "other" Exception packet */ { /* RFC1051 - set 4 trailing bytes to 0 */ put_whole_buffer(dev,lp->txbuf*512+508,4,"\0\0\0\0"); /* now round up to MinTU */ put_buffer_byte(dev, lp->txbuf*512+2, 0); put_buffer_byte(dev, lp->txbuf*512+3, offset=512-MinTU); } /* copy the packet into ARCnet shmem * - the first bytes of ClientData header are skipped */ put_whole_buffer(dev, 512*lp->txbuf+offset, hdrlen,(u_char *)hdr); put_whole_buffer(dev, 512*lp->txbuf+offset+hdrlen,length-hdrlen,data); BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n", daddr,length); lp->lastload_dest=daddr; lp->txready=lp->txbuf; /* packet is ready for sending */}/**************************************************************************** * * * Kernel Loadable Module Support * * * ****************************************************************************/#ifdef MODULEstatic struct device *cards[16]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};int init_module(void){ struct device *dev=cards[0]; cards[0]=dev=(struct device *)kmalloc(sizeof(struct device), GFP_KERNEL); if (!dev) return -ENOMEM; memset(dev, 0, sizeof(struct device)); dev->name=(char *)kmalloc(9, GFP_KERNEL); if (!dev->name) { kfree(dev); return -ENOMEM; } dev->init=arc90io_probe; if (device) strcpy(dev->name,device); else arcnet_makename(dev->name); dev->base_addr=io; dev->irq=irq; if (dev->irq==2) dev->irq=9; if (register_netdev(dev) != 0) return -EIO; /* Increase use count of arcnet.o */ arcnet_use_count(1); return 0;}void cleanup_module(void){ struct device *dev=cards[0]; int ioaddr=dev->base_addr; if (dev->start) (*dev->stop)(dev); /* Flush TX and disable RX */ if (ioaddr) { AINTMASK(0); /* disable IRQ's */ ACOMMAND(NOTXcmd); /* stop transmit */ ACOMMAND(NORXcmd); /* disable receive */ /* Set the thing back to MMAP mode, in case the old driver is loaded later */ outb( (inb(_CONFIG)&~IOMAPflag),_CONFIG); } if (dev->irq) { free_irq(dev->irq,dev); } if (dev->base_addr) release_region(dev->base_addr,ARCNET_TOTAL_SIZE); unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; /* Decrease use count of arcnet.o */ arcnet_use_count(0);}#else__initfunc(void com90io_setup (char *str, int *ints)){ struct device *dev; if (arcnet_num_devs == MAX_ARCNET_DEVS) { printk("com90xx IO-MAP: Too many ARCnet devices registered (max %d).\n", MAX_ARCNET_DEVS); return; } dev=&arcnet_devs[arcnet_num_devs]; if (ints[0] < 1) { printk("com90xx IO-MAP: You must give an IO address.\n"); return; } dev->init=arc90io_probe; switch(ints[0]) { case 3: /* ERROR */ printk("com90xx IO-MAP: Too many arguments.\n"); case 2: /* IRQ */ dev->irq=ints[2]; case 1: /* IO address */ dev->base_addr=ints[1]; } dev->name = (char *)&arcnet_dev_names[arcnet_num_devs]; if (str) strncpy(dev->name, str, 9); arcnet_num_devs++;}#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -