📄 sbni.c
字号:
/* * Initialize the device structure. */ dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); if(dev->priv == NULL) { DP( printk("%s: cannot allocate memory\n", dev->name); ) free_irq(dev->irq, dev); return -ENOMEM; } memset(dev->priv, 0, sizeof(struct net_local)); dev->base_addr = ioaddr; request_region(ioaddr, SBNI_IO_EXTENT, "sbni"); /* * generate Ethernet address (0x00ff01xxxxxx) */ *(u16*)dev->dev_addr = htons(0x00ff); *(u32*)(dev->dev_addr+2) = htonl(((def_mac ? def_mac : (u32) dev->priv) & 0x00ffffff) | 0x01000000); lp = dev->priv; if(def_rxl < 0) { /* autodetect receive level */ lp->rxl_curr = 0xf; lp->rxl_delta = -1; } else { /* fixed receive level */ lp->rxl_curr = def_rxl & 0xf; lp->rxl_delta = 0; } lp->csr1.rxl = rxl_tab[lp->rxl_curr]; lp->csr1.rate = def_baud & 3; lp->frame_len = DEF_FRAME_LEN; printk("%s: sbni adapter at %#lx, using %sIRQ %d, MAC: 00:ff:01:%x:%x:%x\n", dev->name, dev->base_addr, autoirq ? "auto":"assigned ", dev->irq, *(unsigned char*)(dev->dev_addr+3), *(unsigned char*)(dev->dev_addr+4), *(unsigned char*)(dev->dev_addr+5) ); printk("%s: receive level: ", dev->name); if(lp->rxl_delta == 0) printk ("%#1x (fixed)", lp->rxl_curr); else printk ("autodetect"); printk(", baud rate: %u\n", (unsigned)lp->csr1.rate); /* * The SBNI-specific entries in the device structure. */ dev->open = &sbni_open; dev->hard_start_xmit = &sbni_start_xmit; dev->stop = &sbni_close; dev->get_stats = &sbni_get_stats; dev->set_multicast_list = &set_multicast_list; dev->set_mac_address = &sbni_set_mac_address; dev->do_ioctl = &sbni_ioctl; /* * Setup the generic properties */ ether_setup(dev); dev->hard_header = sbni_header; dev->hard_header_len = sizeof(struct sbni_hard_header); dev->rebuild_header=sbni_rebuild_header; dev->mtu = DEF_FRAME_LEN; dev->hard_header_cache = sbni_header_cache; dev->header_cache_update = sbni_header_cache_update; spin_lock_init(&lp->lock); lp->m=dev; lp->me=dev; lp->next_lp=NULL; return 0;}/* * Open/initialize the board. */static int sbni_open(struct net_device *dev){ struct net_local* lp = (struct net_local*)dev->priv; struct timer_list* watchdog = &lp->watchdog; unsigned long flags; DP( printk("%s: sbni_open\n", dev->name); ) save_flags(flags); cli(); lp->currframe = NULL; card_start(dev); /* set timer watchdog */ init_timer(watchdog); watchdog->expires = jiffies + SBNI_TIMEOUT; watchdog->data = (unsigned long)dev; watchdog->function = sbni_watchdog; add_timer(watchdog); DP( printk("%s: sbni timer watchdog initialized\n", dev->name); ); restore_flags(flags); netif_start_queue(dev); MOD_INC_USE_COUNT; return 0;}static int sbni_close(struct net_device *dev){ int ioaddr = dev->base_addr; struct net_local* lp = (struct net_local*) dev->priv; struct timer_list* watchdog = &lp->watchdog; unsigned long flags; DP( printk("%s: sbni_close\n", dev->name); ) netif_stop_queue(dev); save_flags(flags); cli(); sbni_drop_tx_queue(dev); del_timer(watchdog); outb(0, ioaddr + CSR0); restore_flags(flags); MOD_DEC_USE_COUNT; return 0;}static int sbni_start_xmit(struct sk_buff *skb, struct net_device *dev){ struct net_local *lp = (struct net_local*)dev->priv; struct sbni_hard_header *hh=(struct sbni_hard_header *)skb->data; unsigned long flags; #ifdef KATYUSHA struct net_local *nl; int stop;#endif DP( printk("%s: sbni_start_xmit In \n", dev->name); ); if(lp->me != dev) panic("sbni: lp->me != dev !!!\nMail to developer (xenon@granch.ru) if you noticed this error\n"); hh->number = 1; hh->reserv = 0; hh->packetlen = (skb->len - sizeof (unsigned short) - (sizeof(struct sbni_hard_header) - SBNI_HH_SZ)) | PACKET_SEND_OK | PACKET_FIRST_FRAME; /* we should use hairy method to calculate crc because of extra bytes are livin between hard header and data*/ hh->crc = calc_crc((void*)&hh->packetlen, SBNI_HH_SZ - sizeof(unsigned), CRC32_INITIAL); hh->crc = calc_crc(skb->data + sizeof(struct sbni_hard_header), skb->len - sizeof(struct sbni_hard_header), hh->crc); spin_lock_irqsave(&lp->lock, flags);#ifdef KATYUSHA /* looking for first idle device */ for (stop=0,nl=lp; nl && !stop; nl=nl->next_lp) { if((!nl->currframe) && (nl->carrier)) /* if idle */ { skb->dev = lp->me; nl->currframe = skb; /* set request for transmit */ outb(inb(nl->me->base_addr + CSR0) | TR_REQ, nl->me->base_addr + CSR0); stop=1; } } if(!stop) /* we havent found any idle.*/ { skb_queue_tail(&lp->queue,skb); outb(inb(dev->base_addr + CSR0) | TR_REQ, dev->base_addr + CSR0); } #else if (lp->currframe || 1) { skb_queue_tail(&lp->queue,skb); } else { lp->currframe = skb; } /* set request for transmit */ outb(inb(dev->base_addr + CSR0) | TR_REQ, dev->base_addr + CSR0);#endif spin_unlock_irqrestore(&lp->lock, flags); return 0;}static void card_start(struct net_device *dev){ struct net_local *lp = (struct net_local*)dev->priv; DP( printk("%s: card_start\n",dev->name); ) lp->wait_frame_number = 0; lp->inppos = lp->outpos = 0; lp->eth_trans_buffer_len = 0; lp->tr_err = TR_ERROR_COUNT; lp->last_receive_OK = FALSE; lp->tr_resend = FALSE; lp->timer_ticks = CHANGE_LEVEL_START_TICKS; lp->timeout_rxl = 0; lp->waitack=0; skb_queue_head_init(&lp->queue); sbni_drop_tx_queue(dev); /* Reset the card and set start parameters */ outb(PR_RES | *(char*)&lp->csr1, dev->base_addr + CSR1); outb(EN_INT, dev->base_addr + CSR0);}void sbni_nirvana(struct net_device *dev){ sbni_outs(dev->base_addr+DAT,magic_reply,9);}static inline unsigned short sbni_recv(struct net_device *dev){ struct net_local *lp = (struct net_local*)dev->priv; unsigned long crc; unsigned short packetlen = 0; unsigned short packetinf, packetfirst, receiveframeresend; unsigned char current_frame; unsigned int i, j; unsigned char delme,rcv_res=RCV_WR; lp->in_stats.all_rx_number++; if((delme=inb(dev->base_addr + DAT)) == SBNI_SIG) { crc = CRC32_INITIAL; *(((unsigned char *)&packetlen) + 0) = inb(dev->base_addr + DAT); crc = CRC32(*(((unsigned char *)&packetlen) + 0), crc); *(((unsigned char *)&packetlen) + 1) = inb(dev->base_addr + DAT); crc = CRC32(*(((unsigned char *)&packetlen) + 1), crc); packetinf = packetlen & PACKET_INF_MASK; packetfirst = packetlen & PACKET_FIRST_FRAME; receiveframeresend = packetlen & RECEIVE_FRAME_RESEND; packetlen = packetlen & PACKET_LEN_MASK; if((packetlen <= SB_MAX_BUFFER_ARRAY - 3) && (packetlen >= 6)) { /* read frame number */ current_frame = inb(dev->base_addr + DAT); crc = CRC32(current_frame, crc); /* read HandShake counter */ lp->HSCounter = inb(dev->base_addr + DAT); crc = CRC32(lp->HSCounter, crc); packetlen -= 2; sbni_ins(dev->base_addr + DAT, lp->eth_rcv_buffer + lp->inppos, packetlen); for(i = lp->inppos; i < (packetlen + lp->inppos); i++) { crc = CRC32(lp->eth_rcv_buffer[i], crc); } if(crc == CRC32_REMAINDER) { if(packetlen > 4) rcv_res=RCV_OK; else if(packetlen == 4) rcv_res=RCV_NO; if(lp->waitack && packetinf == PACKET_RESEND) lp->in_stats.resend_tx_number++; switch(packetinf) { case PACKET_SEND_OK: { lp->tr_err = TR_ERROR_COUNT; lp->tr_resend = FALSE; /* if(lp->trans_frame_number){ */ lp->outpos += lp->realframelen; /* SendComplete * not supported */ DP( printk("%s: sbni_recv SendComplete\n",dev->name); ); /* * We sucessfully sent current packet */ if(lp->waitack) { dev_kfree_skb(lp->currframe); lp->stats.tx_packets++;#ifdef KATYUSHA lp->currframe=skb_dequeue(&(((struct net_local*) (lp->m->priv))->queue));#else lp->currframe=skb_dequeue(&lp->queue);#endif lp->in_stats.all_tx_number++; lp->waitack=0; } /* * reset output active flags */ netif_wake_queue(dev); /*} if */ } case PACKET_RESEND: { if(lp->tr_err) /**/ lp->tr_err--; if(lp->ok_curr < 0xffffffff) lp->ok_curr++; if(packetlen > 4 && !(lp->last_receive_OK && receiveframeresend)) { if(packetfirst) { if(lp->wait_frame_number) { for(i = lp->inppos, j = 0; i < (lp->inppos + packetlen - 4); i++, j++) lp->eth_rcv_buffer[j] = lp->eth_rcv_buffer[i]; } lp->wait_frame_number = current_frame; lp->inppos = 0; } if(current_frame == lp->wait_frame_number) { lp->inppos += (packetlen - 4); if(lp->wait_frame_number == 1) { sbni_get_packet(dev); lp->inppos = 0; } lp->wait_frame_number--; } } lp->last_receive_OK = TRUE; break; } default: break; } } else { DP(printk("%s: bad CRC32\n",dev->name)); change_level(dev); } } else { DP(printk("%s: bad len\n ",dev->name)); change_level(dev); lp->stats.rx_over_errors++; } } else { DP(printk("%s: bad sig\n",dev->name)); change_level(dev); } outb(inb(dev->base_addr + CSR0) ^ CT_ZER, dev->base_addr + CSR0); return (rcv_res);}void change_level(struct net_device *dev){ struct net_local *lp = (struct net_local*)dev->priv; lp->in_stats.bad_rx_number++; lp->stats.tx_errors++; if(lp->rxl_delta == 0) return; /* * set new rxl_delta value */ if(lp->rxl_curr == 0) lp->rxl_delta = 1; else if(lp->rxl_curr == 0xf) lp->rxl_delta = -1; else if(lp->ok_curr < lp->ok_prev) lp->rxl_delta = -lp->rxl_delta; /* * set new rxl_curr value */ lp->csr1.rxl = rxl_tab[lp->rxl_curr += lp->rxl_delta]; outb(*(char*)&lp->csr1, dev->base_addr + CSR1); /* * update ok_prev/ok_curr counters */ lp->ok_prev = lp->ok_curr; lp->ok_curr = 0; DP( printk("%s: receive error, rxl_curr = %d, rxl_delta = %d\n",\ dev->name,lp->rxl_curr, lp->rxl_delta); ) }static inline void sbni_xmit(struct net_device *dev){ struct net_local* lp = (struct net_local *)dev->priv; struct sk_buff *skb; skb=lp->currframe; DP( printk("%s: sbni_xmit CSR0=%02x\n",dev->name, (unsigned char)inb(dev->base_addr + CSR0)); ); /* push signature*/ outb(SBNI_SIG, dev->base_addr + DAT); /* push frame w/o crc [HAiRY]*/ sbni_outs(dev->base_addr + DAT, &((struct sbni_hard_header *)(skb->data))->packetlen, SBNI_HH_SZ - sizeof(unsigned)); sbni_outs(dev->base_addr + DAT, skb->data + sizeof(struct sbni_hard_header), skb->len - sizeof(struct sbni_hard_header)); /* 沼信磐 泡
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -