📄 sktr.c
字号:
/* Wait for interrupt from hardware. If interrupt does not come, * there will be a timeout from the timer. */ tp->Sleeping = 1; interruptible_sleep_on(&tp->wait_for_tok_int); del_timer(&tp->timer); /* If AdapterVirtOpenFlag is 1, the adapter is now open for use */ if(tp->AdapterVirtOpenFlag == 0) { sktr_disable_interrupts(dev); return (-1); } dev->start = 1; tp->StartTime = jiffies; /* Start function control timer */ tp->timer.expires = jiffies + 2*HZ; tp->timer.function = sktr_timer_chk; tp->timer.data = (unsigned long)dev; add_timer(&tp->timer);#ifdef MODULE MOD_INC_USE_COUNT;#endif return (0);}/* * Timeout function while waiting for event */static void sktr_timer_end_wait(unsigned long data){ struct device *dev = (struct device*)data; struct net_local *tp = (struct net_local *)dev->priv; if(tp->Sleeping) { tp->Sleeping = 0; wake_up_interruptible(&tp->wait_for_tok_int); } return;}/* * Initialize the chipset */static int sktr_chipset_init(struct device *dev){ struct net_local *tp = (struct net_local *)dev->priv; unsigned char PosReg, Tmp; int i, err; sktr_init_ipb(tp); sktr_init_opb(tp); sktr_init_net_local(dev); /* Set pos register: selects irq and dma channel. * Only for ISA bus adapters. */ if(dev->dma > 0) { PosReg = 0; for(i = 0; sktr_irqlist[i] != 0; i++) { if(sktr_irqlist[i] == dev->irq) break; } /* Choose default cycle time, 500 nsec */ PosReg |= CYCLE_TIME << 2; PosReg |= i << 4; i = dev->dma - 5; PosReg |= i; if(tp->DataRate == SPEED_4) PosReg |= LINE_SPEED_BIT; else PosReg &= ~LINE_SPEED_BIT; outb(PosReg, dev->base_addr + POSREG); Tmp = inb(dev->base_addr + POSREG); if((Tmp & ~CYCLE_TIME) != (PosReg & ~CYCLE_TIME)) printk(KERN_INFO "%s: POSREG error\n", dev->name); } err = sktr_reset_adapter(dev); if(err < 0) return (-1); err = sktr_bringup_diags(dev); if(err < 0) return (-1); err = sktr_init_adapter(dev); if(err < 0) return (-1); return (0);}/* * Initializes the net_local structure. */static void sktr_init_net_local(struct device *dev){ struct net_local *tp = (struct net_local *)dev->priv; int i; tp->scb.CMD = 0; tp->scb.Parm[0] = 0; tp->scb.Parm[1] = 0; tp->ssb.STS = 0; tp->ssb.Parm[0] = 0; tp->ssb.Parm[1] = 0; tp->ssb.Parm[2] = 0; tp->CMDqueue = 0; tp->AdapterOpenFlag = 0; tp->AdapterVirtOpenFlag = 0; tp->ScbInUse = 0; tp->OpenCommandIssued = 0; tp->ReOpenInProgress = 0; tp->HaltInProgress = 0; tp->TransmitHaltScheduled = 0; tp->LobeWireFaultLogged = 0; tp->LastOpenStatus = 0; tp->MaxPacketSize = DEFAULT_PACKET_SIZE; skb_queue_head_init(&tp->SendSkbQueue); tp->QueueSkb = MAX_TX_QUEUE; /* Create circular chain of transmit lists */ for (i = 0; i < TPL_NUM; i++) { tp->Tpl[i].NextTPLAddr = htonl((unsigned long) virt_to_bus(&tp->Tpl[(i+1) % TPL_NUM])); tp->Tpl[i].Status = 0; tp->Tpl[i].FrameSize = 0; tp->Tpl[i].FragList[0].DataCount = 0; tp->Tpl[i].FragList[0].DataAddr = 0; tp->Tpl[i].NextTPLPtr = &tp->Tpl[(i+1) % TPL_NUM]; tp->Tpl[i].MData = NULL; tp->Tpl[i].TPLIndex = i; tp->Tpl[i].BusyFlag = 0; } tp->TplFree = tp->TplBusy = &tp->Tpl[0]; /* Create circular chain of receive lists */ for (i = 0; i < RPL_NUM; i++) { tp->Rpl[i].NextRPLAddr = htonl((unsigned long) virt_to_bus(&tp->Rpl[(i+1) % RPL_NUM])); tp->Rpl[i].Status = (RX_VALID | RX_START_FRAME | RX_END_FRAME | RX_FRAME_IRQ); tp->Rpl[i].FrameSize = 0; tp->Rpl[i].FragList[0].DataCount = SWAPB(tp->MaxPacketSize); /* Alloc skb and point adapter to data area */ tp->Rpl[i].Skb = dev_alloc_skb(tp->MaxPacketSize); /* skb == NULL ? then use local buffer */ if(tp->Rpl[i].Skb == NULL) { tp->Rpl[i].SkbStat = SKB_UNAVAILABLE; tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[i])); tp->Rpl[i].MData = tp->LocalRxBuffers[i]; } else /* SKB != NULL */ { tp->Rpl[i].Skb->dev = dev; skb_put(tp->Rpl[i].Skb, tp->MaxPacketSize); /* data unreachable for DMA ? then use local buffer */ if(virt_to_bus(tp->Rpl[i].Skb->data) + tp->MaxPacketSize > ISA_MAX_ADDRESS) { tp->Rpl[i].SkbStat = SKB_DATA_COPY; tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[i])); tp->Rpl[i].MData = tp->LocalRxBuffers[i]; } else /* DMA directly in skb->data */ { tp->Rpl[i].SkbStat = SKB_DMA_DIRECT; tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->Rpl[i].Skb->data)); tp->Rpl[i].MData = tp->Rpl[i].Skb->data; } } tp->Rpl[i].NextRPLPtr = &tp->Rpl[(i+1) % RPL_NUM]; tp->Rpl[i].RPLIndex = i; } tp->RplHead = &tp->Rpl[0]; tp->RplTail = &tp->Rpl[RPL_NUM-1]; tp->RplTail->Status = (RX_START_FRAME | RX_END_FRAME | RX_FRAME_IRQ); return;}/* * Initializes the initialisation parameter block. */static void sktr_init_ipb(struct net_local *tp){ tp->ipb.Init_Options = BURST_MODE; tp->ipb.CMD_Status_IV = 0; tp->ipb.TX_IV = 0; tp->ipb.RX_IV = 0; tp->ipb.Ring_Status_IV = 0; tp->ipb.SCB_Clear_IV = 0; tp->ipb.Adapter_CHK_IV = 0; tp->ipb.RX_Burst_Size = BURST_SIZE; tp->ipb.TX_Burst_Size = BURST_SIZE; tp->ipb.DMA_Abort_Thrhld = DMA_RETRIES; tp->ipb.SCB_Addr = 0; tp->ipb.SSB_Addr = 0; return;}/* * Initializes the open parameter block. */static void sktr_init_opb(struct net_local *tp){ unsigned long Addr; unsigned short RplSize = RPL_SIZE; unsigned short TplSize = TPL_SIZE; unsigned short BufferSize = BUFFER_SIZE; tp->ocpl.OPENOptions = 0; tp->ocpl.OPENOptions |= ENABLE_FULL_DUPLEX_SELECTION; tp->ocpl.OPENOptions |= PAD_ROUTING_FIELD; tp->ocpl.FullDuplex = 0; tp->ocpl.FullDuplex |= OPEN_FULL_DUPLEX_OFF; /* Fixme: If mac address setable: * for (i=0; i<LENGTH_OF_ADDRESS; i++) * mac->Vam->ocpl.NodeAddr[i] = mac->CurrentAddress[i]; */ tp->ocpl.GroupAddr = 0; tp->ocpl.FunctAddr = 0; tp->ocpl.RxListSize = SWAPB(RplSize); tp->ocpl.TxListSize = SWAPB(TplSize); tp->ocpl.BufSize = SWAPB(BufferSize); tp->ocpl.Reserved = 0; tp->ocpl.TXBufMin = TX_BUF_MIN; tp->ocpl.TXBufMax = TX_BUF_MAX; Addr = htonl(virt_to_bus(tp->ProductID)); tp->ocpl.ProdIDAddr[0] = LOWORD(Addr); tp->ocpl.ProdIDAddr[1] = HIWORD(Addr); return;}/* * Send OPEN command to adapter */static void sktr_open_adapter(struct device *dev){ struct net_local *tp = (struct net_local *)dev->priv; if(tp->OpenCommandIssued) return; tp->OpenCommandIssued = 1; sktr_exec_cmd(dev, OC_OPEN); return;}/* * Clear the adapter's interrupt flag. Clear system interrupt enable * (SINTEN): disable adapter to system interrupts. */static void sktr_disable_interrupts(struct device *dev){ outb(0, dev->base_addr + SIFACL); return;}/* * Set the adapter's interrupt flag. Set system interrupt enable * (SINTEN): enable adapter to system interrupts. */static void sktr_enable_interrupts(struct device *dev){ outb(ACL_SINTEN, dev->base_addr + SIFACL); return;}/* * Put command in command queue, try to execute it. */static void sktr_exec_cmd(struct device *dev, unsigned short Command){ struct net_local *tp = (struct net_local *)dev->priv; tp->CMDqueue |= Command; sktr_chk_outstanding_cmds(dev); return;}/* * Linux always gives 18 byte of source routing information in the frame header. * But the length field can indicate shorter length. Then cut header * appropriate. */static unsigned char *sktr_fix_srouting(unsigned char *buf, short *FrameLen){ struct trh_hdr *trh = (struct trh_hdr *)buf; int len; if(buf[8] & TR_RII) { trh->rcf &= ~SWAPB((unsigned short) TR_RCF_LONGEST_FRAME_MASK); trh->rcf |= SWAPB((unsigned short) TR_RCF_FRAME4K); len = (SWAPB(trh->rcf) & TR_RCF_LEN_MASK) >> 8; if(len < 18) { memcpy(&buf[18-len],buf,sizeof(struct trh_hdr)-18+len); *FrameLen -= (18 - len); } return (&buf[18-len]); } return (buf);}/* * Gets skb from system, queues it and checks if it can be sent */static int sktr_send_packet(struct sk_buff *skb, struct device *dev){ struct net_local *tp = (struct net_local *)dev->priv; if(dev->tbusy) { /* * If we get here, some higher level has decided we are broken. * There should really be a "kick me" function call instead. * * Resetting the token ring adapter takes a long time so just * fake transmission time and go on trying. Our own timeout * routine is in sktr_timer_chk() */ dev->tbusy = 0; dev->trans_start = jiffies; return (1); } /* * If some higher layer thinks we've missed an tx-done interrupt we * are passed NULL. */ if(skb == NULL) return (0); /* * Block a timer-based transmit from overlapping. This could better be * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ if(test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return (1); } if(tp->QueueSkb == 0) return (1); /* Return with tbusy set: queue full */ tp->QueueSkb--; skb_queue_tail(&tp->SendSkbQueue, skb); sktr_hardware_send_packet(dev, tp); if(tp->QueueSkb > 0) dev->tbusy = 0; return (0);}/* * Move frames from internal skb queue into adapter tx queue */static void sktr_hardware_send_packet(struct device *dev, struct net_local* tp){ TPL *tpl; short length; unsigned char *buf, *newbuf; struct sk_buff *skb; int i; for(;;) { /* Try to get a free TPL from the chain. * * NOTE: We *must* always leave one unused TPL in the chain, * because otherwise the adapter might send frames twice. */ if(tp->TplFree->NextTPLPtr->BusyFlag) /* No free TPL */ { printk(KERN_INFO "%s: No free TPL\n", dev->name); return; } /* Send first buffer from queue */ skb = skb_dequeue(&tp->SendSkbQueue); if(skb == NULL) return; tp->QueueSkb++; /* Is buffer reachable for Busmaster-DMA? */ if(virt_to_bus((void*)(((long) skb->data) + skb->len)) > ISA_MAX_ADDRESS) { /* Copy frame to local buffer */ i = tp->TplFree->TPLIndex; length = skb->len; buf = tp->LocalTxBuffers[i]; memcpy(buf, skb->data, length); newbuf = sktr_fix_srouting(buf, &length); } else { /* Send direct from skb->data */ length = skb->len; newbuf = sktr_fix_srouting(skb->data, &length); } /* Source address in packet? */ sktr_chk_src_addr(newbuf, dev->dev_addr); tp->LastSendTime = jiffies; tpl = tp->TplFree; /* Get the "free" TPL */ tpl->BusyFlag = 1; /* Mark TPL as busy */ tp->TplFree = tpl->NextTPLPtr; /* Save the skb for delayed return of skb to system */ tpl->Skb = skb; tpl->FragList[0].DataCount = (unsigned short) SWAPB(length); tpl->FragList[0].DataAddr = htonl(virt_to_bus(newbuf)); /* Write the data length in the transmit list. */ tpl->FrameSize = (unsigned short) SWAPB(length); tpl->MData = newbuf; /* Transmit the frame and set the status values. */ sktr_write_tpl_status(tpl, TX_VALID | TX_START_FRAME | TX_END_FRAME | TX_PASS_SRC_ADDR | TX_FRAME_IRQ); /* Let adapter send the frame. */ sktr_exec_sifcmd(dev, CMD_TX_VALID); } return;}/* * Write the given value to the 'Status' field of the specified TPL. * NOTE: This function should be used whenever the status of any TPL must be * modified by the driver, because the compiler may otherwise change the * order of instructions such that writing the TPL status may be executed at * an undesireable time. When this function is used, the status is always * written when the function is called. */static void sktr_write_tpl_status(TPL *tpl, unsigned int Status){ tpl->Status = Status;}static void sktr_chk_src_addr(unsigned char *frame, unsigned char *hw_addr){ unsigned char SRBit; if((((unsigned long)frame[8]) & ~0x80) != 0) /* Compare 4 bytes */ return; if((unsigned short)frame[12] != 0) /* Compare 2 bytes */ return; SRBit = frame[8] & 0x80; memcpy(&frame[8], hw_addr, 6); frame[8] |= SRBit; return;}/* * The timer routine: Check if adapter still open and working, reopen if not. */static void sktr_timer_chk(unsigned long data){ struct device *dev = (struct device*)data; struct net_local *tp = (struct net_local*)dev->priv; if(tp->HaltInProgress) return; sktr_chk_outstanding_cmds(dev); if(time_before(tp->LastSendTime + SEND_TIMEOUT, jiffies) && (tp->QueueSkb < MAX_TX_QUEUE || tp->TplFree != tp->TplBusy)) { /* Anything to send, but stalled to long */ tp->LastSendTime = jiffies; sktr_exec_cmd(dev, OC_CLOSE); /* Does reopen automatically */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -