📄 sktr.c
字号:
} tp->timer.expires = jiffies + 2*HZ; add_timer(&tp->timer); if(tp->AdapterOpenFlag || tp->ReOpenInProgress) return; tp->ReOpenInProgress = 1; sktr_open_adapter(dev); return;}/* * The typical workload of the driver: Handle the network interface interrupts. */static void sktr_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct device *dev = dev_id; struct net_local *tp; int ioaddr; unsigned short irq_type; if(dev == NULL) { printk("%s: irq %d for unknown device.\n", dev->name, irq); return; } dev->interrupt = 1; ioaddr = dev->base_addr; tp = (struct net_local *)dev->priv; irq_type = inw(ioaddr + SIFSTS); while(irq_type & STS_SYSTEM_IRQ) { irq_type &= STS_IRQ_MASK; if(!sktr_chk_ssb(tp, irq_type)) { printk(KERN_INFO "%s: DATA LATE occurred\n", dev->name); break; } switch(irq_type) { case STS_IRQ_RECEIVE_STATUS: sktr_reset_interrupt(dev); sktr_rcv_status_irq(dev); break; case STS_IRQ_TRANSMIT_STATUS: /* Check if TRANSMIT.HALT command is complete */ if(tp->ssb.Parm[0] & COMMAND_COMPLETE) { tp->TransmitCommandActive = 0; tp->TransmitHaltScheduled = 0; /* Issue a new transmit command. */ sktr_exec_cmd(dev, OC_TRANSMIT); } sktr_reset_interrupt(dev); sktr_tx_status_irq(dev); break; case STS_IRQ_COMMAND_STATUS: /* The SSB contains status of last command * other than receive/transmit. */ sktr_cmd_status_irq(dev); break; case STS_IRQ_SCB_CLEAR: /* The SCB is free for another command. */ tp->ScbInUse = 0; sktr_chk_outstanding_cmds(dev); break; case STS_IRQ_RING_STATUS: sktr_ring_status_irq(dev); break; case STS_IRQ_ADAPTER_CHECK: sktr_chk_irq(dev); break; default: printk(KERN_INFO "Unknown Token Ring IRQ\n"); break; } /* Reset system interrupt if not already done. */ if(irq_type != STS_IRQ_TRANSMIT_STATUS && irq_type != STS_IRQ_RECEIVE_STATUS) { sktr_reset_interrupt(dev); } irq_type = inw(ioaddr + SIFSTS); } dev->interrupt = 0; return;}/* * Reset the INTERRUPT SYSTEM bit and issue SSB CLEAR command. */static void sktr_reset_interrupt(struct device *dev){ struct net_local *tp = (struct net_local *)dev->priv; SSB *ssb = &tp->ssb; /* * [Workaround for "Data Late"] * Set all fields of the SSB to well-defined values so we can * check if the adapter has written the SSB. */ ssb->STS = (unsigned short) -1; ssb->Parm[0] = (unsigned short) -1; ssb->Parm[1] = (unsigned short) -1; ssb->Parm[2] = (unsigned short) -1; /* Free SSB by issuing SSB_CLEAR command after reading IRQ code * and clear STS_SYSTEM_IRQ bit: enable adapter for further interrupts. */ sktr_exec_sifcmd(dev, CMD_SSB_CLEAR | CMD_CLEAR_SYSTEM_IRQ); return;}/* * Check if the SSB has actually been written by the adapter. */static unsigned char sktr_chk_ssb(struct net_local *tp, unsigned short IrqType){ SSB *ssb = &tp->ssb; /* The address of the SSB. */ /* C 0 1 2 INTERRUPT CODE * - - - - -------------- * 1 1 1 1 TRANSMIT STATUS * 1 1 1 1 RECEIVE STATUS * 1 ? ? 0 COMMAND STATUS * 0 0 0 0 SCB CLEAR * 1 1 0 0 RING STATUS * 0 0 0 0 ADAPTER CHECK * * 0 = SSB field not affected by interrupt * 1 = SSB field is affected by interrupt * * C = SSB ADDRESS +0: COMMAND * 0 = SSB ADDRESS +2: STATUS 0 * 1 = SSB ADDRESS +4: STATUS 1 * 2 = SSB ADDRESS +6: STATUS 2 */ /* Check if this interrupt does use the SSB. */ if(IrqType != STS_IRQ_TRANSMIT_STATUS && IrqType != STS_IRQ_RECEIVE_STATUS && IrqType != STS_IRQ_COMMAND_STATUS && IrqType != STS_IRQ_RING_STATUS) { return (1); /* SSB not involved. */ } /* Note: All fields of the SSB have been set to all ones (-1) after it * has last been used by the software (see DriverIsr()). * * Check if the affected SSB fields are still unchanged. */ if(ssb->STS == (unsigned short) -1) return (0); /* Command field not yet available. */ if(IrqType == STS_IRQ_COMMAND_STATUS) return (1); /* Status fields not always affected. */ if(ssb->Parm[0] == (unsigned short) -1) return (0); /* Status 1 field not yet available. */ if(IrqType == STS_IRQ_RING_STATUS) return (1); /* Status 2 & 3 fields not affected. */ /* Note: At this point, the interrupt is either TRANSMIT or RECEIVE. */ if(ssb->Parm[1] == (unsigned short) -1) return (0); /* Status 2 field not yet available. */ if(ssb->Parm[2] == (unsigned short) -1) return (0); /* Status 3 field not yet available. */ return (1); /* All SSB fields have been written by the adapter. */}/* * Evaluates the command results status in the SSB status field. */static void sktr_cmd_status_irq(struct device *dev){ struct net_local *tp = (struct net_local *)dev->priv; unsigned short ssb_cmd, ssb_parm_0; unsigned short ssb_parm_1; char *open_err = "Open error -"; char *code_err = "Open code -"; /* Copy the ssb values to local variables */ ssb_cmd = tp->ssb.STS; ssb_parm_0 = tp->ssb.Parm[0]; ssb_parm_1 = tp->ssb.Parm[1]; if(ssb_cmd == OPEN) { tp->Sleeping = 0; if(!tp->ReOpenInProgress) wake_up_interruptible(&tp->wait_for_tok_int); tp->OpenCommandIssued = 0; tp->ScbInUse = 0; if((ssb_parm_0 & 0x00FF) == GOOD_COMPLETION) { /* Success, the adapter is open. */ tp->LobeWireFaultLogged = 0; tp->AdapterOpenFlag = 1; tp->AdapterVirtOpenFlag = 1; tp->TransmitCommandActive = 0; sktr_exec_cmd(dev, OC_TRANSMIT); sktr_exec_cmd(dev, OC_RECEIVE); if(tp->ReOpenInProgress) tp->ReOpenInProgress = 0; return; } else /* The adapter did not open. */ { if(ssb_parm_0 & NODE_ADDR_ERROR) printk(KERN_INFO "%s: Node address error\n", dev->name); if(ssb_parm_0 & LIST_SIZE_ERROR) printk(KERN_INFO "%s: List size error\n", dev->name); if(ssb_parm_0 & BUF_SIZE_ERROR) printk(KERN_INFO "%s: Buffer size error\n", dev->name); if(ssb_parm_0 & TX_BUF_COUNT_ERROR) printk(KERN_INFO "%s: Tx buffer count error\n", dev->name); if(ssb_parm_0 & INVALID_OPEN_OPTION) printk(KERN_INFO "%s: Invalid open option\n", dev->name); if(ssb_parm_0 & OPEN_ERROR) { /* Show the open phase. */ switch(ssb_parm_0 & OPEN_PHASES_MASK) { case LOBE_MEDIA_TEST: if(!tp->LobeWireFaultLogged) { tp->LobeWireFaultLogged = 1; printk(KERN_INFO "%s: %s Lobe wire fault (check cable !).\n", dev->name, open_err); } tp->ReOpenInProgress = 1; tp->AdapterOpenFlag = 0; tp->AdapterVirtOpenFlag = 1; sktr_open_adapter(dev); return; case PHYSICAL_INSERTION: printk(KERN_INFO "%s: %s Physical insertion.\n", dev->name, open_err); break; case ADDRESS_VERIFICATION: printk(KERN_INFO "%s: %s Address verification.\n", dev->name, open_err); break; case PARTICIPATION_IN_RING_POLL: printk(KERN_INFO "%s: %s Participation in ring poll.\n", dev->name, open_err); break; case REQUEST_INITIALISATION: printk(KERN_INFO "%s: %s Request initialisation.\n", dev->name, open_err); break; case FULLDUPLEX_CHECK: printk(KERN_INFO "%s: %s Full duplex check.\n", dev->name, open_err); break; default: printk(KERN_INFO "%s: %s Unknown open phase\n", dev->name, open_err); break; } /* Show the open errors. */ switch(ssb_parm_0 & OPEN_ERROR_CODES_MASK) { case OPEN_FUNCTION_FAILURE: printk(KERN_INFO "%s: %s OPEN_FUNCTION_FAILURE", dev->name, code_err); tp->LastOpenStatus = OPEN_FUNCTION_FAILURE; break; case OPEN_SIGNAL_LOSS: printk(KERN_INFO "%s: %s OPEN_SIGNAL_LOSS\n", dev->name, code_err); tp->LastOpenStatus = OPEN_SIGNAL_LOSS; break; case OPEN_TIMEOUT: printk(KERN_INFO "%s: %s OPEN_TIMEOUT\n", dev->name, code_err); tp->LastOpenStatus = OPEN_TIMEOUT; break; case OPEN_RING_FAILURE: printk(KERN_INFO "%s: %s OPEN_RING_FAILURE\n", dev->name, code_err); tp->LastOpenStatus = OPEN_RING_FAILURE; break; case OPEN_RING_BEACONING: printk(KERN_INFO "%s: %s OPEN_RING_BEACONING\n", dev->name, code_err); tp->LastOpenStatus = OPEN_RING_BEACONING; break; case OPEN_DUPLICATE_NODEADDR: printk(KERN_INFO "%s: %s OPEN_DUPLICATE_NODEADDR\n", dev->name, code_err); tp->LastOpenStatus = OPEN_DUPLICATE_NODEADDR; break; case OPEN_REQUEST_INIT: printk(KERN_INFO "%s: %s OPEN_REQUEST_INIT\n", dev->name, code_err); tp->LastOpenStatus = OPEN_REQUEST_INIT; break; case OPEN_REMOVE_RECEIVED: printk(KERN_INFO "%s: %s OPEN_REMOVE_RECEIVED", dev->name, code_err); tp->LastOpenStatus = OPEN_REMOVE_RECEIVED; break; case OPEN_FULLDUPLEX_SET: printk(KERN_INFO "%s: %s OPEN_FULLDUPLEX_SET\n", dev->name, code_err); tp->LastOpenStatus = OPEN_FULLDUPLEX_SET; break; default: printk(KERN_INFO "%s: %s Unknown open err code", dev->name, code_err); tp->LastOpenStatus = OPEN_FUNCTION_FAILURE; break; } } tp->AdapterOpenFlag = 0; tp->AdapterVirtOpenFlag = 0; return; } } else { if(ssb_cmd != READ_ERROR_LOG) return; /* Add values from the error log table to the MAC * statistics counters and update the errorlogtable * memory. */ tp->MacStat.line_errors += tp->errorlogtable.Line_Error; tp->MacStat.burst_errors += tp->errorlogtable.Burst_Error; tp->MacStat.A_C_errors += tp->errorlogtable.ARI_FCI_Error; tp->MacStat.lost_frames += tp->errorlogtable.Lost_Frame_Error; tp->MacStat.recv_congest_count += tp->errorlogtable.Rx_Congest_Error; tp->MacStat.rx_errors += tp->errorlogtable.Rx_Congest_Error; tp->MacStat.frame_copied_errors += tp->errorlogtable.Frame_Copied_Error; tp->MacStat.token_errors += tp->errorlogtable.Token_Error; tp->MacStat.dummy1 += tp->errorlogtable.DMA_Bus_Error; tp->MacStat.dummy1 += tp->errorlogtable.DMA_Parity_Error; tp->MacStat.abort_delimiters += tp->errorlogtable.AbortDelimeters; tp->MacStat.frequency_errors += tp->errorlogtable.Frequency_Error; tp->MacStat.internal_errors += tp->errorlogtable.Internal_Error; } return;}/* * The inverse routine to sktr_open(). */static int sktr_close(struct device *dev){ struct net_local *tp = (struct net_local *)dev->priv; dev->tbusy = 1; dev->start = 0; del_timer(&tp->timer); /* Flush the Tx and disable Rx here. */ tp->HaltInProgress = 1; sktr_exec_cmd(dev, OC_CLOSE); tp->timer.expires = jiffies + 1*HZ; tp->timer.function = sktr_timer_end_wait; tp->timer.data = (unsigned long)dev; add_timer(&tp->timer); sktr_enable_interrupts(dev); tp->Sleeping = 1; interruptible_sleep_on(&tp->wait_for_tok_int); tp->TransmitCommandActive = 0; del_timer(&tp->timer); sktr_disable_interrupts(dev); if(dev->dma > 0) { unsigned long flags=claim_dma_lock(); disable_dma(dev->dma); release_dma_lock(flags); } outw(0xFF00, dev->base_addr + SIFCMD); if(dev->dma > 0) outb(0xff, dev->base_addr + POSREG);#ifdef MODULE MOD_DEC_USE_COUNT;#endif sktr_cancel_tx_queue(tp); return (0);}/* * Get the current statistics. This may be called with the card open * or closed. */static struct enet_statistics *sktr_get_stats(struct device *dev){ struct net_local *tp = (struct net_local *)dev->priv; return ((struct enet_statistics *)&tp->MacStat);}/* * Set or clear the multicast filter for this adapter. */static void sktr_set_multicast_list(struct device *dev){ struct net_local *tp = (struct net_local *)dev->priv; unsigned int OpenOptions; OpenOptions = tp->ocpl.OPENOptions & ~(PASS_ADAPTER_MAC_FRAMES | PASS_ATTENTION_FRAMES | PASS_BEACON_MAC_FRAMES | COPY_ALL_MAC_FRAMES | COPY_ALL_NON_MAC_FRAMES); if(dev->flags & IFF_PROMISC) /* Enable promiscuous mode */ OpenOptions |= COPY_ALL_NON_MAC_FRAMES | COPY_ALL_MAC_FRAMES; else { if(dev->flags & IFF_ALLMULTI) /* || dev->mc_count > HW_MAX_ADDRS) */ { /* Disable promiscuous mode, use normal mode. */ } else { if(dev->mc_count) { /* Walk the address list, and load the filter */ } } } tp->ocpl.OPENOptions = OpenOptions; sktr_exec_cmd(dev, OC_MODIFY_OPEN_PARMS); return;}/* * Wait for some time (microseconds) */static void sktr_wait(unsigned long time){ long tmp; tmp = jiffies + time/(1000000/HZ); do { current->state = TASK_INTERRUPTIBLE; tmp = schedule_timeout(tmp); } while(time_after(tmp, jiffies)); return;}/* * Write a command value to the SIFCMD register */static void sktr_exec_sifcmd(struct device *dev, unsigned int WriteValue){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -