?? eexpress.c
字號:
/* ToDo: decide if there are any useful statistics from the SCB. */ return &lp->stats;}#ifdef HAVE_MULTICAST/* Set or clear the multicast filter for this adaptor. num_addrs == -1 Promiscuous mode, receive all packets num_addrs == 0 Normal mode, clear multicast list num_addrs > 0 Multicast mode, receive normal and MC packets, and do best-effort filtering. */static voidset_multicast_list(struct device *dev, int num_addrs, void *addrs){ short ioaddr = dev->base_addr; if (num_addrs < 0) { /* Not written yet, this requires expanding the init_words config cmd. */ } else if (num_addrs > 0) { /* Fill in the SET_MC_CMD with the number of address bytes, followed by the list of multicast addresses to be accepted. */ outw(SET_MC_CMD + 6, ioaddr + WRITE_PTR); outw(num_addrs * 6, ioaddr); outsw(ioaddr, addrs, num_addrs*3); /* 3 = addr len in words */ /* We must trigger a whole 586 reset due to a bug. */ } else { /* Not written yet, this requires expanding the init_words config cmd. */ outw(99, ioaddr); /* Disable promiscuous mode, use normal mode */ }}#endif/* The horrible routine to read a word from the serial EEPROM. *//* The delay between EEPROM clock transitions. */#define eeprom_delay() { int _i = 40; while (--_i > 0) { __SLOW_DOWN_IO; }}#define EE_READ_CMD (6 << 6)intread_eeprom(int ioaddr, int location){ int i; unsigned short retval = 0; short ee_addr = ioaddr + EEPROM_Ctrl; int read_cmd = location | EE_READ_CMD; short ctrl_val = EE_CS | _586_RESET; outb(ctrl_val, ee_addr); /* Shift the read command bits out. */ for (i = 8; i >= 0; i--) { short outval = (read_cmd & (1 << i)) ? ctrl_val | EE_DATA_WRITE : ctrl_val; outb(outval, ee_addr); outb(outval | EE_SHIFT_CLK, ee_addr); /* EEPROM clock tick. */ eeprom_delay(); outb(outval, ee_addr); /* Finish EEPROM a clock tick. */ eeprom_delay(); } outb(ctrl_val, ee_addr); for (i = 16; i > 0; i--) { outb(ctrl_val | EE_SHIFT_CLK, ee_addr); eeprom_delay(); retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0); outb(ctrl_val, ee_addr); eeprom_delay(); } /* Terminate the EEPROM access. */ ctrl_val &= ~EE_CS; outb(ctrl_val | EE_SHIFT_CLK, ee_addr); eeprom_delay(); outb(ctrl_val, ee_addr); eeprom_delay(); return retval;}static voidinit_82586_mem(struct device *dev){ struct net_local *lp = (struct net_local *)dev->priv; short ioaddr = dev->base_addr; /* Enable loopback to protect the wire while starting up. This is Superstition From Crynwr. */ outb(inb(ioaddr + Config) | 0x02, ioaddr + Config); /* Hold the 586 in reset during the memory initialization. */ outb(_586_RESET, ioaddr + EEPROM_Ctrl); /* Place the write pointer at 0xfff6 (address-aliased to 0xfffff6). */ outw(0xfff6, ioaddr + WRITE_PTR); outsw(ioaddr, init_words, sizeof(init_words)>>1); /* Fill in the station address. */ outw(SA_OFFSET, ioaddr + WRITE_PTR); outsw(ioaddr, dev->dev_addr, 3); /* The Tx-block list is written as needed. We just set up the values. */#ifdef initial_text_tx lp->tx_cmd_link = DUMP_DATA + 4;#else lp->tx_cmd_link = IDLELOOP + 4;#endif lp->tx_head = lp->tx_reap = TX_BUF_START; init_rx_bufs(dev); /* Start the 586 by releasing the reset line. */ outb(0x00, ioaddr + EEPROM_Ctrl); /* This was time consuming to track down: you need to give two channel attention signals to reliably start up the i82586. */ outb(0, ioaddr + SIGNAL_CA); { int boguscnt = 50; while (inw(ioaddr + SCB_STATUS) == 0) if (--boguscnt == 0) { printk("%s: i82586 initialization timed out with status %04x, cmd %04x.\n", dev->name, inw(ioaddr + SCB_STATUS), inw(ioaddr + SCB_CMD)); break; } /* Issue channel-attn -- the 82586 won't start without it. */ outb(0, ioaddr + SIGNAL_CA); } /* Disable loopback. */ outb(inb(ioaddr + Config) & ~0x02, ioaddr + Config); if (net_debug > 4) printk("%s: Initialized 82586, status %04x.\n", dev->name, inw(ioaddr + SCB_STATUS)); return;}/* Initialize the Rx-block list. */static void init_rx_bufs(struct device *dev){ struct net_local *lp = (struct net_local *)dev->priv; short ioaddr = dev->base_addr; int cur_rxbuf = lp->rx_head = RX_BUF_START; /* Initialize each Rx frame + data buffer. */ do { /* While there is room for one more. */ outw(cur_rxbuf, ioaddr + WRITE_PTR); outw(0x0000, ioaddr); /* Status */ outw(0x0000, ioaddr); /* Command */ outw(cur_rxbuf + RX_BUF_SIZE, ioaddr); /* Link */ outw(cur_rxbuf + 22, ioaddr); /* Buffer offset */ outw(0xFeed, ioaddr); /* Pad for dest addr. */ outw(0xF00d, ioaddr); outw(0xF001, ioaddr); outw(0x0505, ioaddr); /* Pad for source addr. */ outw(0x2424, ioaddr); outw(0x6565, ioaddr); outw(0xdeaf, ioaddr); /* Pad for protocol. */ outw(0x0000, ioaddr); /* Buffer: Actual count */ outw(-1, ioaddr); /* Buffer: Next (none). */ outw(cur_rxbuf + 0x20, ioaddr); /* Buffer: Address low */ outw(0x0000, ioaddr); /* Finally, the number of bytes in the buffer. */ outw(0x8000 + RX_BUF_SIZE-0x20, ioaddr); lp->rx_tail = cur_rxbuf; cur_rxbuf += RX_BUF_SIZE; } while (cur_rxbuf <= RX_BUF_END - RX_BUF_SIZE); /* Terminate the list by setting the EOL bit, and wrap the pointer to make the list a ring. */ outw(lp->rx_tail + 2, ioaddr + WRITE_PTR); outw(0xC000, ioaddr); /* Command, mark as last. */ outw(lp->rx_head, ioaddr); /* Link */}static voidhardware_send_packet(struct device *dev, void *buf, short length){ struct net_local *lp = (struct net_local *)dev->priv; short ioaddr = dev->base_addr; short tx_block = lp->tx_head; /* Set the write pointer to the Tx block, and put out the header. */ outw(tx_block, ioaddr + WRITE_PTR); outw(0x0000, ioaddr); /* Tx status */ outw(CMD_INTR|CmdTx, ioaddr); /* Tx command */ outw(tx_block+16, ioaddr); /* Next command is a NoOp. */ outw(tx_block+8, ioaddr); /* Data Buffer offset. */ /* Output the data buffer descriptor. */ outw(length | 0x8000, ioaddr); /* Byte count parameter. */ outw(-1, ioaddr); /* No next data buffer. */ outw(tx_block+22, ioaddr); /* Buffer follows the NoOp command. */ outw(0x0000, ioaddr); /* Buffer address high bits (always zero). */ /* Output the Loop-back NoOp command. */ outw(0x0000, ioaddr); /* Tx status */ outw(CmdNOp, ioaddr); /* Tx command */ outw(tx_block+16, ioaddr); /* Next is myself. */ /* Output the packet using the write pointer. Hmmm, it feels a little like a 3c501! */ outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1); /* Set the old command link pointing to this send packet. */ outw(lp->tx_cmd_link, ioaddr + WRITE_PTR); outw(tx_block, ioaddr); lp->tx_cmd_link = tx_block + 20; /* Set the next free tx region. */ lp->tx_head = tx_block + TX_BUF_SIZE; if (lp->tx_head > TX_BUF_END - TX_BUF_SIZE) lp->tx_head = TX_BUF_START; if (net_debug > 4) { printk("%s: EExp @%x send length = %d, tx_block %3x, next %3x, " "reap %4x status %4.4x.\n", dev->name, ioaddr, length, tx_block, lp->tx_head, lp->tx_reap, inw(ioaddr + SCB_STATUS)); } if (lp->tx_head != lp->tx_reap) dev->tbusy = 0;}static voideexp_rx(struct device *dev){ struct net_local *lp = (struct net_local *)dev->priv; short ioaddr = dev->base_addr; short saved_write_ptr = inw(ioaddr + WRITE_PTR); short rx_head = lp->rx_head; short rx_tail = lp->rx_tail; short boguscount = 10; short frame_status; /* Set the read pointer to the Rx frame. */ outw(rx_head, ioaddr + READ_PTR); while ((frame_status = inw(ioaddr)) < 0) { /* Command complete */ short rfd_cmd = inw(ioaddr); short next_rx_frame = inw(ioaddr); short data_buffer_addr = inw(ioaddr); short pkt_len; /* Set the read pointer the data buffer. */ outw(data_buffer_addr, ioaddr + READ_PTR); pkt_len = inw(ioaddr); if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22 || pkt_len & 0xC000 != 0xC000) { printk("%s: Rx frame at %#x corrupted, status %04x cmd %04x" "next %04x data-buf @%04x %04x.\n", dev->name, rx_head, frame_status, rfd_cmd, next_rx_frame, data_buffer_addr, pkt_len); } else if ((frame_status & 0x2000) == 0) { /* Frame Rxed, but with error. */ lp->stats.rx_errors++; if (frame_status & 0x0800) lp->stats.rx_crc_errors++; if (frame_status & 0x0400) lp->stats.rx_frame_errors++; if (frame_status & 0x0200) lp->stats.rx_fifo_errors++; if (frame_status & 0x0100) lp->stats.rx_over_errors++; if (frame_status & 0x0080) lp->stats.rx_length_errors++; } else { /* Malloc up new buffer. */ int sksize; struct sk_buff *skb; pkt_len &= 0x3fff; sksize = sizeof(struct sk_buff) + pkt_len; skb = alloc_skb(sksize, GFP_ATOMIC); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); lp->stats.rx_dropped++; break; } skb->mem_len = sksize; skb->mem_addr = skb; skb->len = pkt_len; skb->dev = dev; outw(data_buffer_addr + 10, ioaddr + READ_PTR); insw(ioaddr, skb->data, (pkt_len + 1) >> 1); #ifdef HAVE_NETIF_RX netif_rx(skb);#else skb->lock = 0; if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) { kfree_s(skb, sksize); lp->stats.rx_dropped++; break; }#endif lp->stats.rx_packets++; } /* Clear the status word and set End-of-List on the rx frame. */ outw(rx_head, ioaddr + WRITE_PTR); outw(0x0000, ioaddr); outw(0xC000, ioaddr);#ifndef final_version if (next_rx_frame != rx_head + RX_BUF_SIZE && next_rx_frame != RX_BUF_START) { printk("%s: Rx next frame at %#x is %#x instead of %#x.\n", dev->name, rx_head, next_rx_frame, rx_head + RX_BUF_SIZE); next_rx_frame = rx_head + RX_BUF_SIZE; if (next_rx_frame >= RX_BUF_END - RX_BUF_SIZE) next_rx_frame = RX_BUF_START; }#endif outw(rx_tail+2, ioaddr + WRITE_PTR); outw(0x0000, ioaddr); /* Clear the end-of-list on the prev. RFD. */#ifndef final_version outw(rx_tail+4, ioaddr + READ_PTR); if (inw(ioaddr) != rx_head) { printk("%s: Rx buf link mismatch, at %04x link %04x instead of %04x.\n", dev->name, rx_tail, (outw(rx_tail+4, ioaddr + READ_PTR),inw(ioaddr)), rx_head); outw(rx_head, ioaddr); }#endif rx_tail = rx_head; rx_head = next_rx_frame; if (--boguscount == 0) break; outw(rx_head, ioaddr + READ_PTR); } lp->rx_head = rx_head; lp->rx_tail = rx_tail; /* Restore the original write pointer. */ outw(saved_write_ptr, ioaddr + WRITE_PTR);}/* * Local variables: * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -I/usr/src/linux/drivers/net -Wall -Wstrict-prototypes -O6 -m486 -c eexpress.c" * version-control: t * kept-new-versions: 5 * tab-width: 4 * End: */
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -