📄 ne2000.c
字号:
mlen = len;#if DEBUG & 4 printf(" sg buf %08lx len %08x \n", (unsigned long) data, mlen); dx = 0;#endif while (0 < mlen) { /* Saved byte from previous loop? */ if (saved) { *data++ = saved_char; mlen--; saved = false; continue; } { cyg_uint8 tmp; DP_IN_DATA(dp->data, tmp);#if DEBUG & 4 printf(" %02x", tmp); if (0 == (++dx % 16)) printf("\n ");#endif *data++ = tmp;; mlen--; } }#if DEBUG & 4 printf("\n");#endif } }}static voiddp83902a_TxEvent(void){ struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; cyg_uint8 *base = dp->base; unsigned char tsr; unsigned long key; DEBUG_FUNCTION(); DP_IN(base, DP_TSR, tsr); if (dp->tx_int == 1) { key = dp->tx1_key; dp->tx1 = 0; } else { key = dp->tx2_key; dp->tx2 = 0; } /* Start next packet if one is ready */ dp->tx_started = false; if (dp->tx1) { dp83902a_start_xmit(dp->tx1, dp->tx1_len); dp->tx_int = 1; } else if (dp->tx2) { dp83902a_start_xmit(dp->tx2, dp->tx2_len); dp->tx_int = 2; } else { dp->tx_int = 0; } /* Tell higher level we sent this packet */ uboot_push_tx_done(key, 0);}/* Read the tally counters to clear them. Called in response to a CNT *//* interrupt. */static voiddp83902a_ClearCounters(void){ struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; cyg_uint8 *base = dp->base; cyg_uint8 cnt1, cnt2, cnt3; DP_IN(base, DP_FER, cnt1); DP_IN(base, DP_CER, cnt2); DP_IN(base, DP_MISSED, cnt3); DP_OUT(base, DP_ISR, DP_ISR_CNT);}/* Deal with an overflow condition. This code follows the procedure set *//* out in section 7.0 of the datasheet. */static voiddp83902a_Overflow(void){ struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)&nic; cyg_uint8 *base = dp->base; cyg_uint8 isr; /* Issue a stop command and wait 1.6ms for it to complete. */ DP_OUT(base, DP_CR, DP_CR_STOP | DP_CR_NODMA); CYGACC_CALL_IF_DELAY_US(1600); /* Clear the remote byte counter registers. */ DP_OUT(base, DP_RBCL, 0); DP_OUT(base, DP_RBCH, 0); /* Enter loopback mode while we clear the buffer. */ DP_OUT(base, DP_TCR, DP_TCR_LOCAL); DP_OUT(base, DP_CR, DP_CR_START | DP_CR_NODMA); /* Read in as many packets as we can and acknowledge any and receive */ /* interrupts. Since the buffer has overflowed, a receive event of */ /* some kind will have occured. */ dp83902a_RxEvent(); DP_OUT(base, DP_ISR, DP_ISR_RxP|DP_ISR_RxE); /* Clear the overflow condition and leave loopback mode. */ DP_OUT(base, DP_ISR, DP_ISR_OFLW); DP_OUT(base, DP_TCR, DP_TCR_NORMAL); /* If a transmit command was issued, but no transmit event has occured, */ /* restart it here. */ DP_IN(base, DP_ISR, isr); if (dp->tx_started && !(isr & (DP_ISR_TxP|DP_ISR_TxE))) { DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START); }}static voiddp83902a_poll(void){ struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; cyg_uint8 *base = dp->base; unsigned char isr; DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0 | DP_CR_START); DP_IN(base, DP_ISR, isr); while (0 != isr) { /* The CNT interrupt triggers when the MSB of one of the error */ /* counters is set. We don't much care about these counters, but */ /* we should read their values to reset them. */ if (isr & DP_ISR_CNT) { dp83902a_ClearCounters(); } /* Check for overflow. It's a special case, since there's a */ /* particular procedure that must be followed to get back into */ /* a running state.a */ if (isr & DP_ISR_OFLW) { dp83902a_Overflow(); } else { /* Other kinds of interrupts can be acknowledged simply by */ /* clearing the relevant bits of the ISR. Do that now, then */ /* handle the interrupts we care about. */ DP_OUT(base, DP_ISR, isr); /* Clear set bits */ if (!dp->running) break; /* Is this necessary? */ /* Check for tx_started on TX event since these may happen */ /* spuriously it seems. */ if (isr & (DP_ISR_TxP|DP_ISR_TxE) && dp->tx_started) { dp83902a_TxEvent(); } if (isr & (DP_ISR_RxP|DP_ISR_RxE)) { dp83902a_RxEvent(); } } DP_IN(base, DP_ISR, isr); }}/* find prom (taken from pc_net_cs.c from Linux) */#include "8390.h"typedef struct hw_info_t { u_int offset; u_char a0, a1, a2; u_int flags;} hw_info_t;#define DELAY_OUTPUT 0x01#define HAS_MISC_REG 0x02#define USE_BIG_BUF 0x04#define HAS_IBM_MISC 0x08#define IS_DL10019 0x10#define IS_DL10022 0x20#define HAS_MII 0x40#define USE_SHMEM 0x80 /* autodetected */#define AM79C9XX_HOME_PHY 0x00006B90 /* HomePNA PHY */#define AM79C9XX_ETH_PHY 0x00006B70 /* 10baseT PHY */#define MII_PHYID_REV_MASK 0xfffffff0#define MII_PHYID_REG1 0x02#define MII_PHYID_REG2 0x03static hw_info_t hw_info[] = { { /* Accton EN2212 */ 0x0ff0, 0x00, 0x00, 0xe8, DELAY_OUTPUT }, { /* Allied Telesis LA-PCM */ 0x0ff0, 0x00, 0x00, 0xf4, 0 }, { /* APEX MultiCard */ 0x03f4, 0x00, 0x20, 0xe5, 0 }, { /* ASANTE FriendlyNet */ 0x4910, 0x00, 0x00, 0x94, DELAY_OUTPUT | HAS_IBM_MISC }, { /* Danpex EN-6200P2 */ 0x0110, 0x00, 0x40, 0xc7, 0 }, { /* DataTrek NetCard */ 0x0ff0, 0x00, 0x20, 0xe8, 0 }, { /* Dayna CommuniCard E */ 0x0110, 0x00, 0x80, 0x19, 0 }, { /* D-Link DE-650 */ 0x0040, 0x00, 0x80, 0xc8, 0 }, { /* EP-210 Ethernet */ 0x0110, 0x00, 0x40, 0x33, 0 }, { /* EP4000 Ethernet */ 0x01c0, 0x00, 0x00, 0xb4, 0 }, { /* Epson EEN10B */ 0x0ff0, 0x00, 0x00, 0x48, HAS_MISC_REG | HAS_IBM_MISC }, { /* ELECOM Laneed LD-CDWA */ 0xb8, 0x08, 0x00, 0x42, 0 }, { /* Hypertec Ethernet */ 0x01c0, 0x00, 0x40, 0x4c, 0 }, { /* IBM CCAE */ 0x0ff0, 0x08, 0x00, 0x5a, HAS_MISC_REG | HAS_IBM_MISC }, { /* IBM CCAE */ 0x0ff0, 0x00, 0x04, 0xac, HAS_MISC_REG | HAS_IBM_MISC }, { /* IBM CCAE */ 0x0ff0, 0x00, 0x06, 0x29, HAS_MISC_REG | HAS_IBM_MISC }, { /* IBM FME */ 0x0374, 0x08, 0x00, 0x5a, HAS_MISC_REG | HAS_IBM_MISC }, { /* IBM FME */ 0x0374, 0x00, 0x04, 0xac, HAS_MISC_REG | HAS_IBM_MISC }, { /* Kansai KLA-PCM/T */ 0x0ff0, 0x00, 0x60, 0x87, HAS_MISC_REG | HAS_IBM_MISC }, { /* NSC DP83903 */ 0x0374, 0x08, 0x00, 0x17, HAS_MISC_REG | HAS_IBM_MISC }, { /* NSC DP83903 */ 0x0374, 0x00, 0xc0, 0xa8, HAS_MISC_REG | HAS_IBM_MISC }, { /* NSC DP83903 */ 0x0374, 0x00, 0xa0, 0xb0, HAS_MISC_REG | HAS_IBM_MISC }, { /* NSC DP83903 */ 0x0198, 0x00, 0x20, 0xe0, HAS_MISC_REG | HAS_IBM_MISC }, { /* I-O DATA PCLA/T */ 0x0ff0, 0x00, 0xa0, 0xb0, 0 }, { /* Katron PE-520 */ 0x0110, 0x00, 0x40, 0xf6, 0 }, { /* Kingston KNE-PCM/x */ 0x0ff0, 0x00, 0xc0, 0xf0, HAS_MISC_REG | HAS_IBM_MISC }, { /* Kingston KNE-PCM/x */ 0x0ff0, 0xe2, 0x0c, 0x0f, HAS_MISC_REG | HAS_IBM_MISC }, { /* Kingston KNE-PC2 */ 0x0180, 0x00, 0xc0, 0xf0, 0 }, { /* Maxtech PCN2000 */ 0x5000, 0x00, 0x00, 0xe8, 0 }, { /* NDC Instant-Link */ 0x003a, 0x00, 0x80, 0xc6, 0 }, { /* NE2000 Compatible */ 0x0ff0, 0x00, 0xa0, 0x0c, 0 }, { /* Network General Sniffer */ 0x0ff0, 0x00, 0x00, 0x65, HAS_MISC_REG | HAS_IBM_MISC }, { /* Panasonic VEL211 */ 0x0ff0, 0x00, 0x80, 0x45, HAS_MISC_REG | HAS_IBM_MISC }, { /* PreMax PE-200 */ 0x07f0, 0x00, 0x20, 0xe0, 0 }, { /* RPTI EP400 */ 0x0110, 0x00, 0x40, 0x95, 0 }, { /* SCM Ethernet */ 0x0ff0, 0x00, 0x20, 0xcb, 0 }, { /* Socket EA */ 0x4000, 0x00, 0xc0, 0x1b, DELAY_OUTPUT | HAS_MISC_REG | USE_BIG_BUF }, { /* Socket LP-E CF+ */ 0x01c0, 0x00, 0xc0, 0x1b, 0 }, { /* SuperSocket RE450T */ 0x0110, 0x00, 0xe0, 0x98, 0 }, { /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 }, { /* NEC PC-9801N-J12 */ 0x0ff0, 0x00, 0x00, 0x4c, 0 }, { /* PCMCIA Technology OEM */ 0x01c8, 0x00, 0xa0, 0x0c, 0 }};#define NR_INFO (sizeof(hw_info)/sizeof(hw_info_t))static hw_info_t default_info = { 0, 0, 0, 0, 0 };unsigned char dev_addr[6];#define PCNET_CMD 0x00#define PCNET_DATAPORT 0x10 /* NatSemi-defined port window offset. */#define PCNET_RESET 0x1f /* Issue a read to reset, a write to clear. */#define PCNET_MISC 0x18 /* For IBM CCAE and Socket EA cards */unsigned long nic_base;static void pcnet_reset_8390(void){ int i, r; PRINTK("nic base is %lx\n", nic_base);#if 1 n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD); PRINTK("cmd (at %lx) is %x\n", nic_base+ E8390_CMD, n2k_inb(E8390_CMD)); n2k_outb(E8390_NODMA+E8390_PAGE1+E8390_STOP, E8390_CMD); PRINTK("cmd (at %lx) is %x\n", nic_base+ E8390_CMD, n2k_inb(E8390_CMD)); n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD); PRINTK("cmd (at %lx) is %x\n", nic_base+ E8390_CMD, n2k_inb(E8390_CMD));#endif n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD); n2k_outb(n2k_inb(nic_base + PCNET_RESET), PCNET_RESET); for (i = 0; i < 100; i++) { if ((r = (n2k_inb(EN0_ISR) & ENISR_RESET)) != 0) break; PRINTK("got %x in reset\n", r); my_udelay(100); } n2k_outb(ENISR_RESET, EN0_ISR); /* Ack intr. */ if (i == 100) printf("pcnet_reset_8390() did not complete.\n");} /* pcnet_reset_8390 */static hw_info_t * get_prom(void ) { unsigned char prom[32]; int i, j; struct { u_char value, offset; } program_seq[] = { {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/ {0x48, EN0_DCFG}, /* Set byte-wide (0x48) access. */ {0x00, EN0_RCNTLO}, /* Clear the count regs. */ {0x00, EN0_RCNTHI}, {0x00, EN0_IMR}, /* Mask completion irq. */ {0xFF, EN0_ISR}, {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */ {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */ {32, EN0_RCNTLO}, {0x00, EN0_RCNTHI}, {0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */ {0x00, EN0_RSARHI}, {E8390_RREAD+E8390_START, E8390_CMD}, }; PRINTK("trying to get MAC via prom reading\n"); pcnet_reset_8390(); mdelay(10); for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) n2k_outb(program_seq[i].value, program_seq[i].offset); PRINTK("PROM:"); for (i = 0; i < 32; i++) { prom[i] = n2k_inb(PCNET_DATAPORT); PRINTK(" %02x", prom[i]); } PRINTK("\n"); for (i = 0; i < NR_INFO; i++) { if ((prom[0] == hw_info[i].a0) && (prom[2] == hw_info[i].a1) && (prom[4] == hw_info[i].a2)) { PRINTK("matched board %d\n", i); break; } } if ((i < NR_INFO) || ((prom[28] == 0x57) && (prom[30] == 0x57))) { for (j = 0; j < 6; j++) dev_addr[j] = prom[j<<1]; PRINTK("on exit i is %d/%ld\n", i, NR_INFO); PRINTK("MAC address is %02x:%02x:%02x:%02x:%02x:%02x\n", dev_addr[0],dev_addr[1],dev_addr[2],dev_addr[3],dev_addr[4],dev_addr[5]); return (i < NR_INFO) ? hw_info+i : &default_info; } return NULL;}/* U-boot specific routines */#define NB 5static unsigned char *pbuf = NULL;static int plen[NB];static int nrx = 0;static int pkey = -1;void uboot_push_packet_len(int len) { PRINTK("pushed len = %d, nrx = %d\n", len, nrx); if (len>=2000) { printf("NE2000: packet too big\n"); return; } if (nrx >= NB) { printf("losing packets in rx\n"); return; } plen[nrx] = len; dp83902a_recv(&pbuf[nrx*2000], len); nrx++;}void uboot_push_tx_done(int key, int val) { PRINTK("pushed key = %d\n", key); pkey = key;}int eth_init(bd_t *bd) { static hw_info_t * r; char ethaddr[20]; PRINTK("### eth_init\n"); if (!pbuf) { pbuf = malloc(NB*2000); if (!pbuf) { printf("Cannot allocate rx buffers\n"); return -1; } }#ifdef CONFIG_DRIVER_NE2000_CCR { volatile unsigned char *p = (volatile unsigned char *) CONFIG_DRIVER_NE2000_CCR; PRINTK("CCR before is %x\n", *p); *p = CONFIG_DRIVER_NE2000_VAL; PRINTK("CCR after is %x\n", *p); }#endif nic_base = CONFIG_DRIVER_NE2000_BASE; nic.base = (cyg_uint8 *) CONFIG_DRIVER_NE2000_BASE; r = get_prom(); if (!r) return -1; sprintf (ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X", dev_addr[0], dev_addr[1], dev_addr[2], dev_addr[3], dev_addr[4], dev_addr[5]) ; PRINTK("Set environment from HW MAC addr = \"%s\"\n", ethaddr); setenv ("ethaddr", ethaddr);#define DP_DATA 0x10 nic.data = nic.base + DP_DATA; nic.tx_buf1 = 0x40; nic.tx_buf2 = 0x48; nic.rx_buf_start = 0x50; nic.rx_buf_end = 0x80; if (dp83902a_init() == false) return -1; dp83902a_start(dev_addr); return 0;}void eth_halt() { PRINTK("### eth_halt\n"); dp83902a_stop();}int eth_rx() { int j, tmo; PRINTK("### eth_rx\n"); tmo = get_timer (0) + TOUT * CFG_HZ; while(1) { dp83902a_poll(); if (nrx > 0) { for(j=0; j<nrx; j++) { NetReceive(&pbuf[j*2000], plen[j]); } nrx = 0; return 1; } if (get_timer (0) >= tmo) { printf("timeout during rx\n"); return 0; } } return 0;}int eth_send(volatile void *packet, int length) { int tmo; PRINTK("### eth_send\n"); pkey = -1; dp83902a_send((unsigned char *) packet, length, 666); tmo = get_timer (0) + TOUT * CFG_HZ; while(1) { dp83902a_poll(); if (pkey != -1) { PRINTK("Packet sucesfully sent\n"); return 0; } if (get_timer (0) >= tmo) { printf("transmission error (timoeut)\n"); return 0; } } return 0;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -