📄 eth16i.c
字号:
dev->irq = eth16i_get_irq(ioaddr); } } else {#endif dev->irq = eth16i_get_irq(ioaddr); /* Try to obtain interrupt vector */ if (request_irq(dev->irq, (void *)ð16i_interrupt, 0, "eth16i", dev)) { printk(KERN_WARNING "%s: %s at %#3x, but is unusable due conflicting IRQ %d.\n", dev->name, cardname, ioaddr, dev->irq); return -EAGAIN; }#if 0 irq2dev_map[dev->irq] = dev;#endif printk(KERN_INFO "%s: %s at %#3x, IRQ %d, ", dev->name, cardname, ioaddr, dev->irq); /* Let's grab the region */ request_region(ioaddr, ETH16I_IO_EXTENT, "eth16i"); /* Now we will have to lock the chip's io address */ eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr); outb(0x38, ioaddr + TRANSCEIVER_MODE_REG); eth16i_initialize(dev); /* Initialize rest of the chip's registers */ /* Now let's same some energy by shutting down the chip ;) */ BITCLR(ioaddr + CONFIG_REG_1, POWERUP); /* Initialize the device structure */ if(dev->priv == NULL) { dev->priv = kmalloc(sizeof(struct eth16i_local), GFP_KERNEL); if(dev->priv == NULL) return -ENOMEM; } memset(dev->priv, 0, sizeof(struct eth16i_local)); dev->open = eth16i_open; dev->stop = eth16i_close; dev->hard_start_xmit = eth16i_tx; dev->get_stats = eth16i_get_stats; dev->set_multicast_list = ð16i_multicast; /* Fill in the fields of the device structure with ethernet values. */ ether_setup(dev); boot = 0; return 0;}static void eth16i_initialize(struct device *dev){ int ioaddr = dev->base_addr; int i, node_w = 0; unsigned char node_byte = 0; /* Setup station address */ eth16i_select_regbank(NODE_ID_RB, ioaddr); for(i = 0 ; i < 3 ; i++) { unsigned short node_val = eth16i_read_eeprom(ioaddr, E_NODEID_0 + i); ((unsigned short *)dev->dev_addr)[i] = ntohs(node_val); } for(i = 0; i < 6; i++) { outb( ((unsigned char *)dev->dev_addr)[i], ioaddr + NODE_ID_0 + i); if(boot) { printk("%02x", inb(ioaddr + NODE_ID_0 + i)); if(i != 5) printk(":"); } } /* Now we will set multicast addresses to accept none */ eth16i_select_regbank(HASH_TABLE_RB, ioaddr); for(i = 0; i < 8; i++) outb(0x00, ioaddr + HASH_TABLE_0 + i); /* Now let's disable the transmitter and receiver, set the buffer ram cycle time, bus width and buffer data path width. Also we shall set transmit buffer size and total buffer size. */ eth16i_select_regbank(2, ioaddr); node_byte = 0; node_w = eth16i_read_eeprom(ioaddr, E_PRODUCT_CFG); if( (node_w & 0xFF00) == 0x0800) node_byte |= BUFFER_WIDTH_8; node_byte |= SRAM_BS1; if( (node_w & 0x00FF) == 64) node_byte |= SRAM_BS0; node_byte |= DLC_EN | SRAM_CYCLE_TIME_100NS | (ETH16I_TX_BUF_SIZE << 2); outb(node_byte, ioaddr + CONFIG_REG_0); /* We shall halt the transmitting, if 16 collisions are detected */ outb(HALT_ON_16, ioaddr + COL_16_REG);#ifdef MODULE /* if_port already set by init_module() */#else dev->if_port = (dev->mem_start < E_PORT_FROM_EPROM) ? dev->mem_start : E_PORT_FROM_EPROM;#endif /* Set interface port type */ if(boot) { char *porttype[] = {"BNC", "DIX", "TP", "AUTO", "FROM_EPROM" }; switch(dev->if_port) { case E_PORT_FROM_EPROM: dev->if_port = eth16i_read_eeprom(ioaddr, E_PORT_SELECT); break; case E_PORT_AUTO: dev->if_port = eth16i_probe_port(ioaddr); break; case E_PORT_BNC: case E_PORT_TP: case E_PORT_DIX: break; } printk(" %s interface.\n", porttype[dev->if_port]); eth16i_set_port(ioaddr, dev->if_port); } /* Set Receive Mode to normal operation */ outb(MODE_2, ioaddr + RECEIVE_MODE_REG);}static int eth16i_probe_port(int ioaddr){ int i; int retcode; unsigned char dummy_packet[64] = { 0 }; /* Powerup the chip */ outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1); BITSET(ioaddr + CONFIG_REG_0, DLC_EN); eth16i_select_regbank(NODE_ID_RB, ioaddr); for(i = 0; i < 6; i++) { dummy_packet[i] = inb(ioaddr + NODE_ID_0 + i); dummy_packet[i+6] = inb(ioaddr + NODE_ID_0 + i); } dummy_packet[12] = 0x00; dummy_packet[13] = 0x04; eth16i_select_regbank(2, ioaddr); for(i = 0; i < 3; i++) { BITSET(ioaddr + CONFIG_REG_0, DLC_EN); BITCLR(ioaddr + CONFIG_REG_0, DLC_EN); eth16i_set_port(ioaddr, i); if(eth16i_debug > 1) printk(KERN_DEBUG "Set port number %d\n", i); retcode = eth16i_send_probe_packet(ioaddr, dummy_packet, 64); if(retcode == 0) { retcode = eth16i_receive_probe_packet(ioaddr); if(retcode != -1) { if(eth16i_debug > 1) printk(KERN_DEBUG "Eth16i interface port found at %d\n", i); return i; } } else { if(eth16i_debug > 1) printk(KERN_DEBUG "TRANSMIT_DONE timeout when probing interface port\n"); } } if( eth16i_debug > 1) printk(KERN_DEBUG "Using default port\n"); return E_PORT_BNC;}static void eth16i_set_port(int ioaddr, int porttype){ unsigned short temp = 0; eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr); outb(LOOPBACK_CONTROL, ioaddr + TRANSMIT_MODE_REG); temp |= DIS_AUTO_PORT_SEL; switch(porttype) { case E_PORT_BNC : temp |= AUI_SELECT; break; case E_PORT_TP : break; case E_PORT_DIX : temp |= AUI_SELECT; BITSET(ioaddr + TRANSMIT_MODE_REG, CONTROL_OUTPUT); break; } outb(temp, ioaddr + TRANSCEIVER_MODE_REG); if(eth16i_debug > 1) { printk(KERN_DEBUG "TRANSMIT_MODE_REG = %x\n", inb(ioaddr + TRANSMIT_MODE_REG)); printk(KERN_DEBUG "TRANSCEIVER_MODE_REG = %x\n", inb(ioaddr+TRANSCEIVER_MODE_REG)); }}static int eth16i_send_probe_packet(int ioaddr, unsigned char *b, int l){ int starttime; outb(0xff, ioaddr + TX_STATUS_REG); outw(l, ioaddr + DATAPORT); outsw(ioaddr + DATAPORT, (unsigned short *)b, (l + 1) >> 1); starttime = jiffies; outb(TX_START | 1, ioaddr + TRANSMIT_START_REG); while( (inb(ioaddr + TX_STATUS_REG) & 0x80) == 0) { if( (jiffies - starttime) > TX_TIMEOUT) { return -1; } } return 0;}static int eth16i_receive_probe_packet(int ioaddr){ int starttime; starttime = jiffies; while((inb(ioaddr + TX_STATUS_REG) & 0x20) == 0) { if( (jiffies - starttime) > TX_TIMEOUT) { if(eth16i_debug > 1) printk(KERN_DEBUG "Timeout occurred waiting transmit packet received\n"); starttime = jiffies; while((inb(ioaddr + RX_STATUS_REG) & 0x80) == 0) { if( (jiffies - starttime) > TX_TIMEOUT) { if(eth16i_debug > 1) printk(KERN_DEBUG "Timeout occurred waiting receive packet\n"); return -1; } } if(eth16i_debug > 1) printk(KERN_DEBUG "RECEIVE_PACKET\n"); return(0); /* Found receive packet */ } } if(eth16i_debug > 1) { printk(KERN_DEBUG "TRANSMIT_PACKET_RECEIVED %x\n", inb(ioaddr + TX_STATUS_REG)); printk(KERN_DEBUG "RX_STATUS_REG = %x\n", inb(ioaddr + RX_STATUS_REG)); } return(0); /* Return success */}#if 0static int eth16i_set_irq(struct device* dev){ const int ioaddr = dev->base_addr; const int irq = dev->irq; int i = 0; if(ioaddr < 0x1000) { while(eth16i_irqmap[i] && eth16i_irqmap[i] != irq) i++; if(i < NUM_OF_ISA_IRQS) { u8 cbyte = inb(ioaddr + JUMPERLESS_CONFIG); cbyte = (cbyte & 0x3F) | (i << 6); outb(cbyte, ioaddr + JUMPERLESS_CONFIG); return 0; } } else { printk(KERN_NOTICE "%s: EISA Interrupt cannot be set. Use EISA Configuration utility.\n", dev->name); } return -1;}#endifstatic int eth16i_get_irq(int ioaddr){ unsigned char cbyte; if( ioaddr < 0x1000) { cbyte = inb(ioaddr + JUMPERLESS_CONFIG); return( eth16i_irqmap[ ((cbyte & 0xC0) >> 6) ] ); } else { /* Oh..the card is EISA so method getting IRQ different */ unsigned short index = 0; cbyte = inb(ioaddr + EISA_IRQ_REG); while( (cbyte & 0x01) == 0) { cbyte = cbyte >> 1; index++; } return( eth32i_irqmap[ index ] ); }}static int eth16i_check_signature(int ioaddr){ int i; unsigned char creg[4] = { 0 }; for(i = 0; i < 4 ; i++) { creg[i] = inb(ioaddr + TRANSMIT_MODE_REG + i); if(eth16i_debug > 1) printk("eth16i: read signature byte %x at %x\n", creg[i], ioaddr + TRANSMIT_MODE_REG + i); } creg[0] &= 0x0F; /* Mask collision cnr */ creg[2] &= 0x7F; /* Mask DCLEN bit */#ifdef 0 /* This was removed because the card was sometimes left to state from which it couldn't be find anymore. If there is need to more strict check still this have to be fixed. */ if( ! ((creg[0] == 0x06) && (creg[1] == 0x41)) ) { if(creg[1] != 0x42) return -1; }#endif if( !((creg[2] == 0x36) && (creg[3] == 0xE0)) ) { creg[2] &= 0x40; creg[3] &= 0x03; if( !((creg[2] == 0x40) && (creg[3] == 0x00)) ) return -1; } if(eth16i_read_eeprom(ioaddr, E_NODEID_0) != 0) return -1; if((eth16i_read_eeprom(ioaddr, E_NODEID_1) & 0xFF00) != 0x4B00) return -1; return 0;}static int eth16i_read_eeprom(int ioaddr, int offset){ int data = 0; eth16i_eeprom_cmd(ioaddr, EEPROM_READ | offset); outb(CS_1, ioaddr + EEPROM_CTRL_REG); data = eth16i_read_eeprom_word(ioaddr); outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG); return(data); }static int eth16i_read_eeprom_word(int ioaddr){ int i; int data = 0; for(i = 16; i > 0; i--) { outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG); eeprom_slow_io(); outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG); eeprom_slow_io(); data = (data << 1) | ((inb(ioaddr + EEPROM_DATA_REG) & DI_1) ? 1 : 0); eeprom_slow_io(); } return(data);}static void eth16i_eeprom_cmd(int ioaddr, unsigned char command){ int i; outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG); outb(DI_0, ioaddr + EEPROM_DATA_REG); outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG); outb(DI_1, ioaddr + EEPROM_DATA_REG); outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG); for(i = 7; i >= 0; i--) { short cmd = ( (command & (1 << i)) ? DI_1 : DI_0 ); outb(cmd, ioaddr + EEPROM_DATA_REG); outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG); eeprom_slow_io(); outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG); eeprom_slow_io(); } }static int eth16i_open(struct device *dev){ struct eth16i_local *lp = (struct eth16i_local *)dev->priv; int ioaddr = dev->base_addr; /* Powerup the chip */ outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1); /* Initialize the chip */ eth16i_initialize(dev); /* Set the transmit buffer size */ lp->tx_buf_size = eth16i_tx_buf_map[ETH16I_TX_BUF_SIZE & 0x03]; if(eth16i_debug > 0) printk(KERN_DEBUG "%s: transmit buffer size %d\n", dev->name, lp->tx_buf_size); /* Now enable Transmitter and Receiver sections */ BITCLR(ioaddr + CONFIG_REG_0, DLC_EN); /* Now switch to register bank 2, for run time operation */ eth16i_select_regbank(2, ioaddr); lp->open_time = jiffies; lp->tx_started = 0; lp->tx_queue = 0; lp->tx_queue_len = 0; /* Turn on interrupts*/ outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG); dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; MOD_INC_USE_COUNT; return 0;}static int eth16i_close(struct device *dev){ struct eth16i_local *lp = (struct eth16i_local *)dev->priv; int ioaddr = dev->base_addr; eth16i_reset(dev); /* Turn off interrupts*/ outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG); dev->start = 0; dev->tbusy = 1; lp->open_time = 0; /* Disable transmit and receive */ BITSET(ioaddr + CONFIG_REG_0, DLC_EN); /* Reset the chip */ /* outb(0xff, ioaddr + RESET); */ /* outw(0xffff, ioaddr + TX_STATUS_REG); */ outb(0x00, ioaddr + CONFIG_REG_1); MOD_DEC_USE_COUNT; return 0;}static int eth16i_tx(struct sk_buff *skb, struct device *dev){ struct eth16i_local *lp = (struct eth16i_local *)dev->priv; int ioaddr = dev->base_addr; int status = 0; if(dev->tbusy) { /* If we get here, some higher level has decided that we are broken. There should really be a "kick me" function call instead. */ int tickssofar = jiffies - dev->trans_start; if(tickssofar < TX_TIMEOUT) return 1; outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG); printk(KERN_WARNING "%s: transmit timed out with status %04x, %s ?\n", dev->name, inw(ioaddr + TX_STATUS_REG), (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ? "IRQ conflict" : "network cable problem"); dev->trans_start = jiffies; /* Let's dump all registers */ if(eth16i_debug > 0) { printk(KERN_DEBUG "%s: timeout: %02x %02x %02x %02x %02x %02x %02x %02x.\n", dev->name, inb(ioaddr + 0),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -