📄 cs89x0.c
字号:
/* cs89x0.c: A Crystal Semiconductor CS89[02]0 driver for etherboot. *//* Permission is granted to distribute the enclosed cs89x0.[ch] driver only in conjunction with the Etherboot package. The code is ordinarily distributed under the GPL. Russ Nelson, January 2000 ChangeLog: Thu Dec 6 22:40:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de> * disabled all "advanced" features; this should make the code more reliable * reorganized the reset function * always reset the address port, so that autoprobing will continue working * some cosmetic changes * 2.5 Thu Dec 5 21:00:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de> * tested the code against a CS8900 card * lots of minor bug fixes and adjustments * this is the first release, that actually works! it still requires some changes in order to be more tolerant to different environments * 4 Fri Nov 22 23:00:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de> * read the manuals for the CS89x0 chipsets and took note of all the changes that will be neccessary in order to adapt Russel Nelson's code to the requirements of a BOOT-Prom * 6 Thu Nov 19 22:00:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de> * Synched with Russel Nelson's current code (v1.00) * 2 Thu Nov 12 18:00:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de> * Cleaned up some of the code and tried to optimize the code size. * 1.5 Sun Nov 10 16:30:00 1996 Markus Gutschke <gutschk@math.uni-muenster.de> * First experimental release. This code compiles fine, but I have no way of testing whether it actually works. * I did not (yet) bother to make the code 16bit aware, so for the time being, it will only work for Etherboot/32. * 12 */#include "etherboot.h"#include "nic.h"#include "cards.h"#include "cs89x0.h"static unsigned short eth_nic_base;static unsigned long eth_mem_start;static unsigned short eth_irq;static unsigned short eth_cs_type; /* one of: CS8900, CS8920, CS8920M */static unsigned short eth_auto_neg_cnf;static unsigned short eth_adapter_cnf;static unsigned short eth_linectl;/************************************************************************* CS89x0 - specific routines**************************************************************************/static inline int readreg(int portno){ outw(portno, eth_nic_base + ADD_PORT); return inw(eth_nic_base + DATA_PORT);}static inline void writereg(int portno, int value){ outw(portno, eth_nic_base + ADD_PORT); outw(value, eth_nic_base + DATA_PORT); return;}/*************************************************************************EEPROM access**************************************************************************/static int wait_eeprom_ready(void){ unsigned long tmo = currticks() + 4*TICKS_PER_SEC; /* check to see if the EEPROM is ready, a timeout is used - just in case EEPROM is ready when SI_BUSY in the PP_SelfST is clear */ while(readreg(PP_SelfST) & SI_BUSY) { if (currticks() >= tmo) return -1; } return 0;}static int get_eeprom_data(int off, int len, unsigned short *buffer){ int i;#ifdef EDEBUG printf("\ncs: EEPROM data from %hX for %hX:",off,len);#endif for (i = 0; i < len; i++) { if (wait_eeprom_ready() < 0) return -1; /* Now send the EEPROM read command and EEPROM location to read */ writereg(PP_EECMD, (off + i) | EEPROM_READ_CMD); if (wait_eeprom_ready() < 0) return -1; buffer[i] = readreg(PP_EEData);#ifdef EDEBUG if (!(i%10)) printf("\ncs: "); printf("%hX ", buffer[i]);#endif }#ifdef EDEBUG putchar('\n');#endif return(0);}static int get_eeprom_chksum(int off, int len, unsigned short *buffer){ int i, cksum; cksum = 0; for (i = 0; i < len; i++) cksum += buffer[i]; cksum &= 0xffff; if (cksum == 0) return 0; return -1;}/*************************************************************************Activate all of the available media and probe for network**************************************************************************/static void clrline(void){ int i; putchar('\r'); for (i = 79; i--; ) putchar(' '); printf("\rcs: "); return;}static void control_dc_dc(int on_not_off){ unsigned int selfcontrol; unsigned long tmo = currticks() + TICKS_PER_SEC; /* control the DC to DC convertor in the SelfControl register. */ selfcontrol = HCB1_ENBL; /* Enable the HCB1 bit as an output */ if (((eth_adapter_cnf & A_CNF_DC_DC_POLARITY) != 0) ^ on_not_off) selfcontrol |= HCB1; else selfcontrol &= ~HCB1; writereg(PP_SelfCTL, selfcontrol); /* Wait for the DC/DC converter to power up - 1000ms */ while (currticks() < tmo); return;}static int detect_tp(void){ unsigned long tmo; /* Turn on the chip auto detection of 10BT/ AUI */ clrline(); printf("attempting %s:","TP"); /* 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(PP_LineCTL, eth_linectl &~ AUI_ONLY); control_dc_dc(0); /* Delay for the hardware to work out if the TP cable is present - 150ms */ for (tmo = currticks() + 4; currticks() < tmo; ); if ((readreg(PP_LineST) & LINK_OK) == 0) return 0; if (eth_cs_type != CS8900) { writereg(PP_AutoNegCTL, eth_auto_neg_cnf & AUTO_NEG_MASK); if ((eth_auto_neg_cnf & AUTO_NEG_BITS) == AUTO_NEG_ENABLE) { printf(" negotiating duplex... "); while (readreg(PP_AutoNegST) & AUTO_NEG_BUSY) { if (currticks() - tmo > 40*TICKS_PER_SEC) { printf("time out "); break; } } } if (readreg(PP_AutoNegST) & FDX_ACTIVE) printf("using full duplex"); else printf("using half duplex"); } return A_CNF_MEDIA_10B_T;}/* send a test packet - return true if carrier bits are ok */static int send_test_pkt(struct nic *nic){ static unsigned char testpacket[] = { 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)*/ }; unsigned long tmo; writereg(PP_LineCTL, readreg(PP_LineCTL) | SERIAL_TX_ON); memcpy(testpacket, nic->node_addr, ETH_ALEN); memcpy(testpacket+ETH_ALEN, nic->node_addr, ETH_ALEN); outw(TX_AFTER_ALL, eth_nic_base + TX_CMD_PORT); outw(ETH_ZLEN, eth_nic_base + TX_LEN_PORT); /* Test to see if the chip has allocated memory for the packet */ for (tmo = currticks() + 2; (readreg(PP_BusST) & READY_FOR_TX_NOW) == 0; ) if (currticks() >= tmo) return(0); /* Write the contents of the packet */ outsw(eth_nic_base + TX_FRAME_PORT, testpacket, (ETH_ZLEN+1)>>1); printf(" sending test packet "); /* wait a couple of timer ticks for packet to be received */ for (tmo = currticks() + 2; currticks() < tmo; ); if ((readreg(PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) { printf("succeeded"); return 1; } printf("failed"); return 0;}static int detect_aui(struct nic *nic){ clrline(); printf("attempting %s:","AUI"); control_dc_dc(0); writereg(PP_LineCTL, (eth_linectl & ~AUTO_AUI_10BASET) | AUI_ONLY); if (send_test_pkt(nic)) { return A_CNF_MEDIA_AUI; } else return 0;}static int detect_bnc(struct nic *nic){ clrline(); printf("attempting %s:","BNC"); control_dc_dc(1); writereg(PP_LineCTL, (eth_linectl & ~AUTO_AUI_10BASET) | AUI_ONLY); if (send_test_pkt(nic)) { return A_CNF_MEDIA_10B_2; } else return 0;}/**************************************************************************ETH_RESET - Reset adapter***************************************************************************/static void cs89x0_reset(struct nic *nic){ int i; unsigned long reset_tmo; writereg(PP_SelfCTL, readreg(PP_SelfCTL) | POWER_ON_RESET); /* wait for two ticks; that is 2*55ms */ for (reset_tmo = currticks() + 2; currticks() < reset_tmo; ); if (eth_cs_type != CS8900) { /* Hardware problem requires PNP registers to be reconfigured after a reset */ if (eth_irq != 0xFFFF) { outw(PP_CS8920_ISAINT, eth_nic_base + ADD_PORT); outb(eth_irq, eth_nic_base + DATA_PORT); outb(0, eth_nic_base + DATA_PORT + 1); } if (eth_mem_start) { outw(PP_CS8920_ISAMemB, eth_nic_base + ADD_PORT); outb((eth_mem_start >> 8) & 0xff, eth_nic_base + DATA_PORT); outb((eth_mem_start >> 24) & 0xff, eth_nic_base + DATA_PORT + 1); } } /* Wait until the chip is reset */ for (reset_tmo = currticks() + 2; (readreg(PP_SelfST) & INIT_DONE) == 0 && currticks() < reset_tmo; );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -