📄 cs89x0.c
字号:
printk(" IRQ %d", dev->irq); /* print the ethernet address. */ for (i = 0; i < ETH_ALEN; i++) printk(" %2.2x", dev->dev_addr[i]); /* Grab the region so we can find another board if autoIRQ fails. */ request_region(ioaddr, NETCARD_IO_EXTENT,"cs89x0"); dev->open = net_open; dev->stop = net_close; dev->hard_start_xmit = net_send_packet; dev->get_stats = net_get_stats; dev->set_multicast_list = &set_multicast_list; dev->set_mac_address = &set_mac_address; /* Fill in the fields of the device structure with ethernet values. */ ether_setup(dev); printk("\n"); return 0;}__initfunc(voidreset_chip(struct device *dev)){ struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; int reset_start_time; writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET); /* wait 30 ms */ current->state = TASK_INTERRUPTIBLE; schedule_timeout(30*HZ/1000); if (lp->chip_type != CS8900) { /* Hardware problem requires PNP registers to be reconfigured after a reset */ outw(PP_CS8920_ISAINT, ioaddr + ADD_PORT); outb(dev->irq, ioaddr + DATA_PORT); outb(0, ioaddr + DATA_PORT + 1); outw(PP_CS8920_ISAMemB, ioaddr + ADD_PORT); outb((dev->mem_start >> 8) & 0xff, ioaddr + DATA_PORT); outb((dev->mem_start >> 24) & 0xff, ioaddr + DATA_PORT + 1); } /* Wait until the chip is reset */ reset_start_time = jiffies; while( (readreg(dev, PP_SelfST) & INIT_DONE) == 0 && jiffies - reset_start_time < 2) ;}static voidcontrol_dc_dc(struct device *dev, int on_not_off){ struct net_local *lp = (struct net_local *)dev->priv; unsigned int selfcontrol; int timenow = jiffies; /* control the DC to DC convertor in the SelfControl register. */ selfcontrol = HCB1_ENBL; /* Enable the HCB1 bit as an output */ if (((lp->adapter_cnf & A_CNF_DC_DC_POLARITY) != 0) ^ on_not_off) selfcontrol |= HCB1; else selfcontrol &= ~HCB1; writereg(dev, PP_SelfCTL, selfcontrol); /* Wait for the DC/DC converter to power up - 500ms */ while (jiffies - timenow < 100) ;}static intdetect_tp(struct device *dev){ struct net_local *lp = (struct net_local *)dev->priv; int timenow = jiffies; if (net_debug > 1) printk("%s: Attempting TP\n", dev->name); /* If connected to another full duplex capable 10-Base-T card the link pulses seem to be lost when the auto detect bit in the LineCTL is set. To overcome this the auto detect bit will be cleared whilst testing the 10-Base-T interface. This would not be necessary for the sparrow chip but is simpler to do it anyway. */ writereg(dev, PP_LineCTL, lp->linectl &~ AUI_ONLY); control_dc_dc(dev, 0); /* Delay for the hardware to work out if the TP cable is present - 150ms */ for (timenow = jiffies; jiffies - timenow < 15; ) ; if ((readreg(dev, PP_LineST) & LINK_OK) == 0) return 0; if (lp->chip_type != CS8900) { writereg(dev, PP_AutoNegCTL, lp->auto_neg_cnf & AUTO_NEG_MASK); if ((lp->auto_neg_cnf & AUTO_NEG_BITS) == AUTO_NEG_ENABLE) { printk("%s: negotiating duplex...\n",dev->name); while (readreg(dev, PP_AutoNegST) & AUTO_NEG_BUSY) { if (jiffies - timenow > 4000) { printk("**** Full / half duplex auto-negotiation timed out ****\n"); break; } } } if (readreg(dev, PP_AutoNegST) & FDX_ACTIVE) printk("%s: using full duplex\n", dev->name); else printk("%s: using half duplex\n", dev->name); } return A_CNF_MEDIA_10B_T;}/* send a test packet - return true if carrier bits are ok */static intsend_test_pkt(struct device *dev){ int ioaddr = dev->base_addr; char test_packet[] = { 0,0,0,0,0,0, 0,0,0,0,0,0, 0, 46, /* A 46 in network order */ 0, 0, /* DSAP=0 & SSAP=0 fields */ 0xf3, 0 /* Control (Test Req + P bit set) */ }; long timenow = jiffies; writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_TX_ON); memcpy(test_packet, dev->dev_addr, ETH_ALEN); memcpy(test_packet+ETH_ALEN, dev->dev_addr, ETH_ALEN); outw(TX_AFTER_ALL, ioaddr + TX_CMD_PORT); outw(ETH_ZLEN, ioaddr + TX_LEN_PORT); /* Test to see if the chip has allocated memory for the packet */ while (jiffies - timenow < 5) if (readreg(dev, PP_BusST) & READY_FOR_TX_NOW) break; if (jiffies - timenow >= 5) return 0; /* this shouldn't happen */ /* Write the contents of the packet */ if (dev->mem_start) { memcpy((void *)dev->mem_start + PP_TxFrame, test_packet, ETH_ZLEN); } else { outsw(ioaddr + TX_FRAME_PORT,test_packet,(ETH_ZLEN+1) >>1); } if (net_debug > 1) printk("Sending test packet "); /* wait a couple of jiffies for packet to be received */ for (timenow = jiffies; jiffies - timenow < 3; ) ; if ((readreg(dev, PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) { if (net_debug > 1) printk("succeeded\n"); return 1; } if (net_debug > 1) printk("failed\n"); return 0;}static intdetect_aui(struct device *dev){ struct net_local *lp = (struct net_local *)dev->priv; if (net_debug > 1) printk("%s: Attempting AUI\n", dev->name); control_dc_dc(dev, 0); writereg(dev, PP_LineCTL, (lp->linectl &~ AUTO_AUI_10BASET) | AUI_ONLY); if (send_test_pkt(dev)) return A_CNF_MEDIA_AUI; else return 0;}static intdetect_bnc(struct device *dev){ struct net_local *lp = (struct net_local *)dev->priv; if (net_debug > 1) printk("%s: Attempting BNC\n", dev->name); control_dc_dc(dev, 1); writereg(dev, PP_LineCTL, (lp->linectl &~ AUTO_AUI_10BASET) | AUI_ONLY); if (send_test_pkt(dev)) return A_CNF_MEDIA_10B_2; else return 0;}static voidwrite_irq(struct device *dev, int chip_type, int irq){ int i; if (chip_type == CS8900) { switch(irq) { case 10: i = 0; break; case 11: i = 1; break; case 12: i = 2; break; case 5: i = 3; break; default: i = 3; break; } writereg(dev, PP_CS8900_ISAINT, i); } else { writereg(dev, PP_CS8920_ISAINT, irq); }}/* Open/initialize the board. This is called (in the current kernel) sometime after booting when the 'ifconfig' program is run. This routine should set everything up anew at each open, even registers that "should" only need to be set once at boot, so that there is non-reboot way to recover if something goes wrong. */static intnet_open(struct device *dev){ struct net_local *lp = (struct net_local *)dev->priv; int result = 0; int i; if (dev->irq < 2) { /* Allow interrupts to be generated by the chip */ writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON); for (i = 2; i < CS8920_NO_INTS; i++) if ((1 << dev->irq) & lp->irq_map) { if (request_irq (i, NULL, 0, "cs8920", dev) != -EBUSY) { write_irq(dev, lp->chip_type, i); writereg(dev, PP_BufCFG, GENERATE_SW_INTERRUPT); if (request_irq (dev->irq = i, &net_interrupt, 0, "cs89x0", dev) == 0) break; } } if (i >= CS8920_NO_INTS) { writereg(dev, PP_BusCTL, 0); /* disable interrupts. */ return -EAGAIN; } } else { if (((1 << dev->irq) & lp->irq_map) == 0) { printk("%s: IRQ %d is not in our map of allowable IRQs, which is %x\n", dev->name, dev->irq, lp->irq_map); return -EAGAIN; } writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON); write_irq(dev, lp->chip_type, dev->irq); if (request_irq(dev->irq, &net_interrupt, 0, "cs89x0", dev)) { return -EAGAIN; } } /* set the Ethernet address */ for (i=0; i < ETH_ALEN/2; i++) writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8)); /* while we're testing the interface, leave interrupts disabled */ writereg(dev, PP_BusCTL, MEMORY_ON); /* Set the LineCTL quintuplet based on adapter configuration read from EEPROM */ if ((lp->adapter_cnf & A_CNF_EXTND_10B_2) && (lp->adapter_cnf & A_CNF_LOW_RX_SQUELCH)) lp->linectl = LOW_RX_SQUELCH; else lp->linectl = 0; /* check to make sure that they have the "right" hardware available */ switch(lp->adapter_cnf & A_CNF_MEDIA_TYPE) { case A_CNF_MEDIA_10B_T: result = lp->adapter_cnf & A_CNF_10B_T; break; case A_CNF_MEDIA_AUI: result = lp->adapter_cnf & A_CNF_AUI; break; case A_CNF_MEDIA_10B_2: result = lp->adapter_cnf & A_CNF_10B_2; break; default: result = lp->adapter_cnf & (A_CNF_10B_T | A_CNF_AUI | A_CNF_10B_2); } if (!result) { printk("%s: EEPROM is configured for unavailable media\n", dev->name); release_irq: writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON)); free_irq(dev->irq, dev); return -EAGAIN; } /* set the hardware to the configured choice */ switch(lp->adapter_cnf & A_CNF_MEDIA_TYPE) { case A_CNF_MEDIA_10B_T: result = detect_tp(dev); if (!result) printk("%s: 10Base-T (RJ-45) has no cable\n", dev->name); if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */ result = A_CNF_MEDIA_10B_T; /* Yes! I don't care if I see a link pulse */ break; case A_CNF_MEDIA_AUI: result = detect_aui(dev); if (!result) printk("%s: 10Base-5 (AUI) has no cable\n", dev->name); if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */ result = A_CNF_MEDIA_AUI; /* Yes! I don't care if I see a carrrier */ break; case A_CNF_MEDIA_10B_2: result = detect_bnc(dev); if (!result) printk("%s: 10Base-2 (BNC) has no cable\n", dev->name); if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */ result = A_CNF_MEDIA_10B_2; /* Yes! I don't care if I can xmit a packet */ break; case A_CNF_MEDIA_AUTO: writereg(dev, PP_LineCTL, lp->linectl | AUTO_AUI_10BASET); if (lp->adapter_cnf & A_CNF_10B_T) if ((result = detect_tp(dev)) != 0) break; if (lp->adapter_cnf & A_CNF_AUI) if ((result = detect_aui(dev)) != 0) break; if (lp->adapter_cnf & A_CNF_10B_2) if ((result = detect_bnc(dev)) != 0) break; printk("%s: no media detected\n", dev->name); goto release_irq; } switch(result) { case 0: printk("%s: no network cable attached to configured media\n", dev->name); goto release_irq; case A_CNF_MEDIA_10B_T: printk("%s: using 10Base-T (RJ-45)\n", dev->name);break; case A_CNF_MEDIA_AUI: printk("%s: using 10Base-5 (AUI)\n", dev->name);break; case A_CNF_MEDIA_10B_2: printk("%s: using 10Base-2 (BNC)\n", dev->name);break; default: printk("%s: unexpected result was %x\n", dev->name, result); goto release_irq; } /* Turn on both receive and transmit operations */ writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON); /* Receive only error free packets addressed to this card */ lp->rx_mode = 0; writereg(dev, PP_RxCTL, DEF_RX_ACCEPT); lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL; if (lp->isa_config & STREAM_TRANSFER) lp->curr_rx_cfg |= RX_STREAM_ENBL; writereg(dev, PP_RxCFG, lp->curr_rx_cfg); writereg(dev, PP_TxCFG, TX_LOST_CRS_ENBL | TX_SQE_ERROR_ENBL | TX_OK_ENBL | TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL); writereg(dev, PP_BufCFG, READY_FOR_TX_ENBL | RX_MISS_COUNT_OVRFLOW_ENBL | TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL); /* now that we've got our act together, enable everything */ writereg(dev, PP_BusCTL, ENABLE_IRQ ); dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; MOD_INC_USE_COUNT; return 0;}static intnet_send_packet(struct sk_buff *skb, struct device *dev){ if (dev->tbusy) { /* If we get here, some higher level has decided we are broken.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -