|  | /************************************************************************** | 
|  | Etherboot -  BOOTP/TFTP Bootstrap Program | 
|  | Intel EEPRO/10 NIC driver for Etherboot | 
|  | Adapted from Linux eepro.c from kernel 2.2.17 | 
|  |  | 
|  | This board accepts a 32 pin EEPROM (29C256), however a test with a | 
|  | 27C010 shows that this EPROM also works in the socket, but it's not clear | 
|  | how repeatably. The two top address pins appear to be held low, thus | 
|  | the bottom 32kB of the 27C010 is visible in the CPU's address space. | 
|  | To be sure you could put 4 copies of the code in the 27C010, then | 
|  | it doesn't matter whether the extra lines are held low or high, just | 
|  | hopefully not floating as CMOS chips don't like floating inputs. | 
|  |  | 
|  | Be careful with seating the EPROM as the socket on my board actually | 
|  | has 34 pins, the top row of 2 are not used. | 
|  | ***************************************************************************/ | 
|  |  | 
|  | /* | 
|  | * This program is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU General Public License as | 
|  | * published by the Free Software Foundation; either version 2, or (at | 
|  | * your option) any later version. | 
|  | */ | 
|  |  | 
|  | /* to get some global routines like printf */ | 
|  | #include "etherboot.h" | 
|  | /* to get the interface to the body of the program */ | 
|  | #include "nic.h" | 
|  | /* to get our own prototype */ | 
|  | #include "cards.h" | 
|  | /* we use timer2 for microsecond waits */ | 
|  | #include "timer.h" | 
|  |  | 
|  | #undef	DEBUG		/* only after include files */ | 
|  |  | 
|  | /* Different 82595 chips */ | 
|  | #define LAN595		0 | 
|  | #define LAN595TX	1 | 
|  | #define LAN595FX	2 | 
|  | #define LAN595FX_10ISA	3 | 
|  |  | 
|  | #define	SLOW_DOWN	inb(0x80); | 
|  |  | 
|  | /* The station (ethernet) address prefix, used for IDing the board. */ | 
|  | #define SA_ADDR0 0x00	/* Etherexpress Pro/10 */ | 
|  | #define SA_ADDR1 0xaa | 
|  | #define SA_ADDR2 0x00 | 
|  |  | 
|  | #define GetBit(x,y) ((x & (1<<y))>>y) | 
|  |  | 
|  | /* EEPROM Word 0: */ | 
|  | #define ee_PnP       0  /* Plug 'n Play enable bit */ | 
|  | #define ee_Word1     1  /* Word 1? */ | 
|  | #define ee_BusWidth  2  /* 8/16 bit */ | 
|  | #define ee_FlashAddr 3  /* Flash Address */ | 
|  | #define ee_FlashMask 0x7   /* Mask */ | 
|  | #define ee_AutoIO    6  /* */ | 
|  | #define ee_reserved0 7  /* =0! */ | 
|  | #define ee_Flash     8  /* Flash there? */ | 
|  | #define ee_AutoNeg   9  /* Auto Negotiation enabled? */ | 
|  | #define ee_IO0       10 /* IO Address LSB */ | 
|  | #define ee_IO0Mask   0x /*...*/ | 
|  | #define ee_IO1       15 /* IO MSB */ | 
|  |  | 
|  | /* EEPROM Word 1: */ | 
|  | #define ee_IntSel    0   /* Interrupt */ | 
|  | #define ee_IntMask   0x7 | 
|  | #define ee_LI        3   /* Link Integrity 0= enabled */ | 
|  | #define ee_PC        4   /* Polarity Correction 0= enabled */ | 
|  | #define ee_TPE_AUI   5   /* PortSelection 1=TPE */ | 
|  | #define ee_Jabber    6   /* Jabber prevention 0= enabled */ | 
|  | #define ee_AutoPort  7   /* Auto Port Selection 1= Disabled */ | 
|  | #define ee_SMOUT     8   /* SMout Pin Control 0= Input */ | 
|  | #define ee_PROM      9   /* Flash EPROM / PROM 0=Flash */ | 
|  | #define ee_reserved1 10  /* .. 12 =0! */ | 
|  | #define ee_AltReady  13  /* Alternate Ready, 0=normal */ | 
|  | #define ee_reserved2 14  /* =0! */ | 
|  | #define ee_Duplex    15 | 
|  |  | 
|  | /* Word2,3,4: */ | 
|  | #define ee_IA5       0 /*bit start for individual Addr Byte 5 */ | 
|  | #define ee_IA4       8 /*bit start for individual Addr Byte 5 */ | 
|  | #define ee_IA3       0 /*bit start for individual Addr Byte 5 */ | 
|  | #define ee_IA2       8 /*bit start for individual Addr Byte 5 */ | 
|  | #define ee_IA1       0 /*bit start for individual Addr Byte 5 */ | 
|  | #define ee_IA0       8 /*bit start for individual Addr Byte 5 */ | 
|  |  | 
|  | /* Word 5: */ | 
|  | #define ee_BNC_TPE   0 /* 0=TPE */ | 
|  | #define ee_BootType  1 /* 00=None, 01=IPX, 10=ODI, 11=NDIS */ | 
|  | #define ee_BootTypeMask 0x3 | 
|  | #define ee_NumConn   3  /* Number of Connections 0= One or Two */ | 
|  | #define ee_FlashSock 4  /* Presence of Flash Socket 0= Present */ | 
|  | #define ee_PortTPE   5 | 
|  | #define ee_PortBNC   6 | 
|  | #define ee_PortAUI   7 | 
|  | #define ee_PowerMgt  10 /* 0= disabled */ | 
|  | #define ee_CP        13 /* Concurrent Processing */ | 
|  | #define ee_CPMask    0x7 | 
|  |  | 
|  | /* Word 6: */ | 
|  | #define ee_Stepping  0 /* Stepping info */ | 
|  | #define ee_StepMask  0x0F | 
|  | #define ee_BoardID   4 /* Manucaturer Board ID, reserved */ | 
|  | #define ee_BoardMask 0x0FFF | 
|  |  | 
|  | /* Word 7: */ | 
|  | #define ee_INT_TO_IRQ 0 /* int to IRQ Mapping  = 0x1EB8 for Pro/10+ */ | 
|  | #define ee_FX_INT2IRQ 0x1EB8 /* the _only_ mapping allowed for FX chips */ | 
|  |  | 
|  | /*..*/ | 
|  | #define ee_SIZE 0x40 /* total EEprom Size */ | 
|  | #define ee_Checksum 0xBABA /* initial and final value for adding checksum */ | 
|  |  | 
|  |  | 
|  | /* Card identification via EEprom:   */ | 
|  | #define ee_addr_vendor 0x10  /* Word offset for EISA Vendor ID */ | 
|  | #define ee_addr_id 0x11      /* Word offset for Card ID */ | 
|  | #define ee_addr_SN 0x12      /* Serial Number */ | 
|  | #define ee_addr_CRC_8 0x14   /* CRC over last thee Bytes */ | 
|  |  | 
|  |  | 
|  | #define ee_vendor_intel0 0x25  /* Vendor ID Intel */ | 
|  | #define ee_vendor_intel1 0xD4 | 
|  | #define ee_id_eepro10p0 0x10   /* ID for eepro/10+ */ | 
|  | #define ee_id_eepro10p1 0x31 | 
|  |  | 
|  | /* now this section could be used by both boards: the oldies and the ee10: | 
|  | * ee10 uses tx buffer before of rx buffer and the oldies the inverse. | 
|  | * (aris) | 
|  | */ | 
|  | #define	RAM_SIZE	0x8000 | 
|  |  | 
|  | #define	RCV_HEADER	8 | 
|  | #define RCV_DEFAULT_RAM	0x6000 | 
|  | #define RCV_RAM 	rcv_ram | 
|  |  | 
|  | static unsigned rcv_ram = RCV_DEFAULT_RAM; | 
|  |  | 
|  | #define XMT_HEADER	8 | 
|  | #define XMT_RAM		(RAM_SIZE - RCV_RAM) | 
|  |  | 
|  | #define XMT_START	((rcv_start + RCV_RAM) % RAM_SIZE) | 
|  |  | 
|  | #define RCV_LOWER_LIMIT	(rcv_start >> 8) | 
|  | #define RCV_UPPER_LIMIT	(((rcv_start + RCV_RAM) - 2) >> 8) | 
|  | #define XMT_LOWER_LIMIT	(XMT_START >> 8) | 
|  | #define XMT_UPPER_LIMIT	(((XMT_START + XMT_RAM) - 2) >> 8) | 
|  |  | 
|  | #define RCV_START_PRO	0x00 | 
|  | #define RCV_START_10	XMT_RAM | 
|  | /* by default the old driver */ | 
|  | static unsigned rcv_start = RCV_START_PRO; | 
|  |  | 
|  | #define	RCV_DONE	0x0008 | 
|  | #define	RX_OK		0x2000 | 
|  | #define	RX_ERROR	0x0d81 | 
|  |  | 
|  | #define	TX_DONE_BIT	0x0080 | 
|  | #define	CHAIN_BIT	0x8000 | 
|  | #define	XMT_STATUS	0x02 | 
|  | #define	XMT_CHAIN	0x04 | 
|  | #define	XMT_COUNT	0x06 | 
|  |  | 
|  | #define	BANK0_SELECT	0x00 | 
|  | #define	BANK1_SELECT	0x40 | 
|  | #define	BANK2_SELECT	0x80 | 
|  |  | 
|  | /* Bank 0 registers */ | 
|  | #define	COMMAND_REG	0x00	/* Register 0 */ | 
|  | #define	MC_SETUP	0x03 | 
|  | #define	XMT_CMD		0x04 | 
|  | #define	DIAGNOSE_CMD	0x07 | 
|  | #define	RCV_ENABLE_CMD	0x08 | 
|  | #define	RCV_DISABLE_CMD	0x0a | 
|  | #define	STOP_RCV_CMD	0x0b | 
|  | #define	RESET_CMD	0x0e | 
|  | #define	POWER_DOWN_CMD	0x18 | 
|  | #define	RESUME_XMT_CMD	0x1c | 
|  | #define	SEL_RESET_CMD	0x1e | 
|  | #define	STATUS_REG	0x01	/* Register 1 */ | 
|  | #define	RX_INT		0x02 | 
|  | #define	TX_INT		0x04 | 
|  | #define	EXEC_STATUS	0x30 | 
|  | #define	ID_REG		0x02	/* Register 2	*/ | 
|  | #define	R_ROBIN_BITS	0xc0	/* round robin counter */ | 
|  | #define	ID_REG_MASK	0x2c | 
|  | #define	ID_REG_SIG	0x24 | 
|  | #define	AUTO_ENABLE	0x10 | 
|  | #define	INT_MASK_REG	0x03	/* Register 3	*/ | 
|  | #define	RX_STOP_MASK	0x01 | 
|  | #define	RX_MASK		0x02 | 
|  | #define	TX_MASK		0x04 | 
|  | #define	EXEC_MASK	0x08 | 
|  | #define	ALL_MASK	0x0f | 
|  | #define	IO_32_BIT	0x10 | 
|  | #define	RCV_BAR		0x04	/* The following are word (16-bit) registers */ | 
|  | #define	RCV_STOP	0x06 | 
|  |  | 
|  | #define	XMT_BAR_PRO	0x0a | 
|  | #define	XMT_BAR_10	0x0b | 
|  | static unsigned xmt_bar = XMT_BAR_PRO; | 
|  |  | 
|  | #define	HOST_ADDRESS_REG	0x0c | 
|  | #define	IO_PORT		0x0e | 
|  | #define	IO_PORT_32_BIT	0x0c | 
|  |  | 
|  | /* Bank 1 registers */ | 
|  | #define	REG1	0x01 | 
|  | #define	WORD_WIDTH	0x02 | 
|  | #define	INT_ENABLE	0x80 | 
|  | #define INT_NO_REG	0x02 | 
|  | #define	RCV_LOWER_LIMIT_REG	0x08 | 
|  | #define	RCV_UPPER_LIMIT_REG	0x09 | 
|  |  | 
|  | #define	XMT_LOWER_LIMIT_REG_PRO	0x0a | 
|  | #define	XMT_UPPER_LIMIT_REG_PRO	0x0b | 
|  | #define	XMT_LOWER_LIMIT_REG_10	0x0b | 
|  | #define	XMT_UPPER_LIMIT_REG_10	0x0a | 
|  | static unsigned xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_PRO; | 
|  | static unsigned xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_PRO; | 
|  |  | 
|  | /* Bank 2 registers */ | 
|  | #define	XMT_Chain_Int	0x20	/* Interrupt at the end of the transmit chain */ | 
|  | #define	XMT_Chain_ErrStop	0x40 /* Interrupt at the end of the chain even if there are errors */ | 
|  | #define	RCV_Discard_BadFrame	0x80 /* Throw bad frames away, and continue to receive others */ | 
|  | #define	REG2		0x02 | 
|  | #define	PRMSC_Mode	0x01 | 
|  | #define	Multi_IA	0x20 | 
|  | #define	REG3		0x03 | 
|  | #define	TPE_BIT		0x04 | 
|  | #define	BNC_BIT		0x20 | 
|  | #define	REG13		0x0d | 
|  | #define	FDX		0x00 | 
|  | #define	A_N_ENABLE	0x02 | 
|  |  | 
|  | #define	I_ADD_REG0	0x04 | 
|  | #define	I_ADD_REG1	0x05 | 
|  | #define	I_ADD_REG2	0x06 | 
|  | #define	I_ADD_REG3	0x07 | 
|  | #define	I_ADD_REG4	0x08 | 
|  | #define	I_ADD_REG5	0x09 | 
|  |  | 
|  | #define EEPROM_REG_PRO	0x0a | 
|  | #define EEPROM_REG_10	0x0b | 
|  | static unsigned eeprom_reg = EEPROM_REG_PRO; | 
|  |  | 
|  | #define EESK 0x01 | 
|  | #define EECS 0x02 | 
|  | #define EEDI 0x04 | 
|  | #define EEDO 0x08 | 
|  |  | 
|  | /* The horrible routine to read a word from the serial EEPROM. */ | 
|  | /* IMPORTANT - the 82595 will be set to Bank 0 after the eeprom is read */ | 
|  |  | 
|  | /* The delay between EEPROM clock transitions. */ | 
|  | #define eeprom_delay() { udelay(40); } | 
|  | #define EE_READ_CMD (6 << 6) | 
|  |  | 
|  | /* do a full reset */ | 
|  | #define eepro_full_reset(ioaddr)	outb(RESET_CMD, ioaddr); udelay(40); | 
|  |  | 
|  | /* do a nice reset */ | 
|  | #define eepro_sel_reset(ioaddr) 	{ \ | 
|  | outb(SEL_RESET_CMD, ioaddr); \ | 
|  | SLOW_DOWN; \ | 
|  | SLOW_DOWN; \ | 
|  | } | 
|  |  | 
|  | /* clear all interrupts */ | 
|  | #define	eepro_clear_int(ioaddr)	outb(ALL_MASK, ioaddr + STATUS_REG) | 
|  |  | 
|  | /* enable rx */ | 
|  | #define	eepro_en_rx(ioaddr)	outb(RCV_ENABLE_CMD, ioaddr) | 
|  |  | 
|  | /* disable rx */ | 
|  | #define	eepro_dis_rx(ioaddr)	outb(RCV_DISABLE_CMD, ioaddr) | 
|  |  | 
|  | /* switch bank */ | 
|  | #define eepro_sw2bank0(ioaddr) outb(BANK0_SELECT, ioaddr) | 
|  | #define eepro_sw2bank1(ioaddr) outb(BANK1_SELECT, ioaddr) | 
|  | #define eepro_sw2bank2(ioaddr) outb(BANK2_SELECT, ioaddr) | 
|  |  | 
|  | static unsigned int	rx_start, tx_start; | 
|  | static int		tx_last; | 
|  | static unsigned		tx_end; | 
|  | static int		eepro = 0; | 
|  | static unsigned short	ioaddr = 0; | 
|  | static unsigned int	mem_start, mem_end = RCV_DEFAULT_RAM / 1024; | 
|  |  | 
|  | #define	udelay(n)	waiton_timer2(((n)*TICKS_PER_MS)/1000) | 
|  |  | 
|  | /************************************************************************** | 
|  | RESET - Reset adapter | 
|  | ***************************************************************************/ | 
|  | static void eepro_reset(struct nic *nic) | 
|  | { | 
|  | int		temp_reg, i; | 
|  |  | 
|  | /* put the card in its initial state */ | 
|  | eepro_sw2bank2(ioaddr);	/* be careful, bank2 now */ | 
|  | temp_reg = inb(ioaddr + eeprom_reg); | 
|  | #ifdef	DEBUG | 
|  | printf("Stepping %d\n", temp_reg >> 5); | 
|  | #endif | 
|  | if (temp_reg & 0x10)	/* check the TurnOff Enable bit */ | 
|  | outb(temp_reg & 0xEF, ioaddr + eeprom_reg); | 
|  | for (i = 0; i < ETH_ALEN; i++)	/* fill the MAC address */ | 
|  | outb(nic->node_addr[i], ioaddr + I_ADD_REG0 + i); | 
|  | temp_reg = inb(ioaddr + REG1); | 
|  | /* setup Transmit Chaining and discard bad RCV frames */ | 
|  | outb(temp_reg | XMT_Chain_Int | XMT_Chain_ErrStop | 
|  | | RCV_Discard_BadFrame, ioaddr + REG1); | 
|  | temp_reg = inb(ioaddr + REG2);		/* match broadcast */ | 
|  | outb(temp_reg | 0x14, ioaddr + REG2); | 
|  | temp_reg = inb(ioaddr + REG3); | 
|  | outb(temp_reg & 0x3F, ioaddr + REG3);	/* clear test mode */ | 
|  | /* set the receiving mode */ | 
|  | eepro_sw2bank1(ioaddr);	/* be careful, bank1 now */ | 
|  | /* initialise the RCV and XMT upper and lower limits */ | 
|  | outb(RCV_LOWER_LIMIT, ioaddr + RCV_LOWER_LIMIT_REG); | 
|  | outb(RCV_UPPER_LIMIT, ioaddr + RCV_UPPER_LIMIT_REG); | 
|  | outb(XMT_LOWER_LIMIT, ioaddr + xmt_lower_limit_reg); | 
|  | outb(XMT_UPPER_LIMIT, ioaddr + xmt_upper_limit_reg); | 
|  | eepro_sw2bank0(ioaddr);	/* Switch back to bank 0 */ | 
|  | eepro_clear_int(ioaddr); | 
|  | /* Initialise RCV */ | 
|  | outw(rx_start = (RCV_LOWER_LIMIT << 8), ioaddr + RCV_BAR); | 
|  | outw(((RCV_UPPER_LIMIT << 8) | 0xFE), ioaddr + RCV_STOP); | 
|  | /* Intialise XMT */ | 
|  | outw((XMT_LOWER_LIMIT << 8), ioaddr + xmt_bar); | 
|  | eepro_sel_reset(ioaddr); | 
|  | tx_start = tx_end = (XMT_LOWER_LIMIT << 8); | 
|  | tx_last = 0; | 
|  | eepro_en_rx(ioaddr); | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | POLL - Wait for a frame | 
|  | ***************************************************************************/ | 
|  | static int eepro_poll(struct nic *nic) | 
|  | { | 
|  | int		i; | 
|  | unsigned int	rcv_car = rx_start; | 
|  | unsigned int	rcv_event, rcv_status, rcv_next_frame, rcv_size; | 
|  |  | 
|  | /* return true if there's an ethernet packet ready to read */ | 
|  | /* nic->packet should contain data on return */ | 
|  | /* nic->packetlen should contain length of data */ | 
|  | #if	0 | 
|  | if ((inb(ioaddr + STATUS_REG) & 0x40) == 0) | 
|  | return (0); | 
|  | outb(0x40, ioaddr + STATUS_REG); | 
|  | #endif | 
|  | outw(rcv_car, ioaddr + HOST_ADDRESS_REG); | 
|  | rcv_event = inw(ioaddr + IO_PORT); | 
|  | if (rcv_event != RCV_DONE) | 
|  | return (0); | 
|  | rcv_status = inw(ioaddr + IO_PORT); | 
|  | rcv_next_frame = inw(ioaddr + IO_PORT); | 
|  | rcv_size = inw(ioaddr + IO_PORT); | 
|  | #if	0 | 
|  | printf("%hX %hX %d %hhX\n", rcv_status, rcv_next_frame, rcv_size, | 
|  | inb(ioaddr + STATUS_REG)); | 
|  | #endif | 
|  | if ((rcv_status & (RX_OK|RX_ERROR)) != RX_OK) { | 
|  | printf("Receive error %hX\n", rcv_status); | 
|  | return (0); | 
|  | } | 
|  | rcv_size &= 0x3FFF; | 
|  | insw(ioaddr + IO_PORT, nic->packet, ((rcv_size + 3) >> 1)); | 
|  | #if	0 | 
|  | for (i = 0; i < 48; i++) { | 
|  | printf("%hhX", nic->packet[i]); | 
|  | putchar(i % 16 == 15 ? '\n' : ' '); | 
|  | } | 
|  | #endif | 
|  | nic->packetlen = rcv_size; | 
|  | rcv_car = rx_start + RCV_HEADER + rcv_size; | 
|  | rx_start = rcv_next_frame; | 
|  | if (rcv_car == 0) | 
|  | rcv_car = ((RCV_UPPER_LIMIT << 8) | 0xff); | 
|  | outw(rcv_car - 1, ioaddr + RCV_STOP); | 
|  | return (1); | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | TRANSMIT - Transmit a frame | 
|  | ***************************************************************************/ | 
|  | static void eepro_transmit( | 
|  | struct nic *nic, | 
|  | const char *d,			/* Destination */ | 
|  | unsigned int t,			/* Type */ | 
|  | unsigned int s,			/* size */ | 
|  | const char *p)			/* Packet */ | 
|  | { | 
|  | unsigned int	status, tx_available, last, end, length; | 
|  | unsigned short	type; | 
|  | int		boguscount = 20; | 
|  |  | 
|  | length = s + ETH_HLEN; | 
|  | if (tx_end > tx_start) | 
|  | tx_available = XMT_RAM - (tx_end - tx_start); | 
|  | else if (tx_end < tx_start) | 
|  | tx_available = tx_start - tx_end; | 
|  | else | 
|  | tx_available = XMT_RAM; | 
|  | last = tx_end; | 
|  | end = last + (((length + 3) >> 1) << 1) + XMT_HEADER; | 
|  | if (end >= (XMT_UPPER_LIMIT << 8)) { | 
|  | last = (XMT_LOWER_LIMIT << 8); | 
|  | end = last + (((length + 3) >> 1) << 1) + XMT_HEADER; | 
|  | } | 
|  | outw(last, ioaddr + HOST_ADDRESS_REG); | 
|  | outw(XMT_CMD, ioaddr + IO_PORT); | 
|  | outw(0, ioaddr + IO_PORT); | 
|  | outw(end, ioaddr + IO_PORT); | 
|  | outw(length, ioaddr + IO_PORT); | 
|  | outsw(ioaddr + IO_PORT, d, ETH_ALEN / 2); | 
|  | outsw(ioaddr + IO_PORT, nic->node_addr, ETH_ALEN / 2); | 
|  | type = htons(t); | 
|  | outsw(ioaddr + IO_PORT, &type, sizeof(type) / 2); | 
|  | outsw(ioaddr + IO_PORT, p, (s + 3) >> 1); | 
|  | /* A dummy read to flush the DRAM write pipeline */ | 
|  | status = inw(ioaddr + IO_PORT); | 
|  | outw(last, ioaddr + xmt_bar); | 
|  | outb(XMT_CMD, ioaddr); | 
|  | tx_start = last; | 
|  | tx_last = last; | 
|  | tx_end = end; | 
|  | #if	0 | 
|  | printf("%d %d\n", tx_start, tx_end); | 
|  | #endif | 
|  | while (boguscount > 0) { | 
|  | if (((status = inw(ioaddr + IO_PORT)) & TX_DONE_BIT) == 0) { | 
|  | udelay(40); | 
|  | boguscount--; | 
|  | continue; | 
|  | } | 
|  | #if	DEBUG | 
|  | if ((status & 0x2000) == 0) | 
|  | printf("Transmit status %hX\n", status); | 
|  | #endif | 
|  | } | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | DISABLE - Turn off ethernet interface | 
|  | ***************************************************************************/ | 
|  | static void eepro_disable(struct nic *nic) | 
|  | { | 
|  | eepro_sw2bank0(ioaddr);	/* Switch to bank 0 */ | 
|  | /* Flush the Tx and disable Rx */ | 
|  | outb(STOP_RCV_CMD, ioaddr); | 
|  | tx_start = tx_end = (XMT_LOWER_LIMIT << 8); | 
|  | tx_last = 0; | 
|  | /* Reset the 82595 */ | 
|  | eepro_full_reset(ioaddr); | 
|  | } | 
|  |  | 
|  | static int read_eeprom(int location) | 
|  | { | 
|  | int		i; | 
|  | unsigned short	retval = 0; | 
|  | int		ee_addr = ioaddr + eeprom_reg; | 
|  | int		read_cmd = location | EE_READ_CMD; | 
|  | int		ctrl_val = EECS; | 
|  |  | 
|  | if (eepro == LAN595FX_10ISA) { | 
|  | eepro_sw2bank1(ioaddr); | 
|  | outb(0x00, ioaddr + STATUS_REG); | 
|  | } | 
|  | eepro_sw2bank2(ioaddr); | 
|  | 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 | EEDI : ctrl_val; | 
|  | outb(outval, ee_addr); | 
|  | outb(outval | EESK, ee_addr);	/* EEPROM clock tick */ | 
|  | eeprom_delay(); | 
|  | outb(outval, ee_addr);		/* finish EEPROM clock tick */ | 
|  | eeprom_delay(); | 
|  | } | 
|  | outb(ctrl_val, ee_addr); | 
|  | for (i = 16; i > 0; i--) { | 
|  | outb(ctrl_val | EESK, ee_addr); | 
|  | eeprom_delay(); | 
|  | retval = (retval << 1) | ((inb(ee_addr) & EEDO) ? 1 : 0); | 
|  | outb(ctrl_val, ee_addr); | 
|  | eeprom_delay(); | 
|  | } | 
|  | /* terminate the EEPROM access */ | 
|  | ctrl_val &= ~EECS; | 
|  | outb(ctrl_val | EESK, ee_addr); | 
|  | eeprom_delay(); | 
|  | outb(ctrl_val, ee_addr); | 
|  | eeprom_delay(); | 
|  | eepro_sw2bank0(ioaddr); | 
|  | return (retval); | 
|  | } | 
|  |  | 
|  | static int eepro_probe1(struct nic *nic) | 
|  | { | 
|  | int		i, id, counter, l_eepro = 0; | 
|  | union { | 
|  | unsigned char	caddr[ETH_ALEN]; | 
|  | unsigned short	saddr[ETH_ALEN/2]; | 
|  | } station_addr; | 
|  | char		*name; | 
|  |  | 
|  | id = inb(ioaddr + ID_REG); | 
|  | if ((id & ID_REG_MASK) != ID_REG_SIG) | 
|  | return (0); | 
|  | counter = id & R_ROBIN_BITS; | 
|  | if (((id = inb(ioaddr + ID_REG)) & R_ROBIN_BITS) != (counter + 0x40)) | 
|  | return (0); | 
|  | /* yes the 82595 has been found */ | 
|  | station_addr.saddr[2] = read_eeprom(2); | 
|  | if (station_addr.saddr[2] == 0x0000 || station_addr.saddr[2] == 0xFFFF) { | 
|  | l_eepro = 3; | 
|  | eepro = LAN595FX_10ISA; | 
|  | eeprom_reg= EEPROM_REG_10; | 
|  | rcv_start = RCV_START_10; | 
|  | xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_10; | 
|  | xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_10; | 
|  | station_addr.saddr[2] = read_eeprom(2); | 
|  | } | 
|  | station_addr.saddr[1] = read_eeprom(3); | 
|  | station_addr.saddr[0] = read_eeprom(4); | 
|  | if (l_eepro) | 
|  | name = "Intel EtherExpress 10 ISA"; | 
|  | else if (read_eeprom(7) == ee_FX_INT2IRQ) { | 
|  | name = "Intel EtherExpress Pro/10+ ISA"; | 
|  | l_eepro = 2; | 
|  | } else if (station_addr.saddr[0] == SA_ADDR1) { | 
|  | name = "Intel EtherExpress Pro/10 ISA"; | 
|  | l_eepro = 1; | 
|  | } else { | 
|  | l_eepro = 0; | 
|  | name = "Intel 82595-based LAN card"; | 
|  | } | 
|  | station_addr.saddr[0] = swap16(station_addr.saddr[0]); | 
|  | station_addr.saddr[1] = swap16(station_addr.saddr[1]); | 
|  | station_addr.saddr[2] = swap16(station_addr.saddr[2]); | 
|  | for (i = 0; i < ETH_ALEN; i++) { | 
|  | nic->node_addr[i] = station_addr.caddr[i]; | 
|  | } | 
|  | printf("\n%s ioaddr %#hX, addr %!", name, ioaddr, nic->node_addr); | 
|  | mem_start = RCV_LOWER_LIMIT << 8; | 
|  | if ((mem_end & 0x3F) < 3 || (mem_end & 0x3F) > 29) | 
|  | mem_end = RCV_UPPER_LIMIT << 8; | 
|  | else { | 
|  | mem_end = mem_end * 1024 + (RCV_LOWER_LIMIT << 8); | 
|  | rcv_ram = mem_end - (RCV_LOWER_LIMIT << 8); | 
|  | } | 
|  | printf(", Rx mem %dK, if %s\n", (mem_end - mem_start) >> 10, | 
|  | GetBit(read_eeprom(5), ee_BNC_TPE) ? "BNC" : "TP"); | 
|  | return (1); | 
|  | } | 
|  |  | 
|  | /************************************************************************** | 
|  | PROBE - Look for an adapter, this routine's visible to the outside | 
|  | ***************************************************************************/ | 
|  | struct nic *eepro_probe(struct nic *nic, unsigned short *probe_addrs) | 
|  | { | 
|  | unsigned short		*p; | 
|  | /* same probe list as the Linux driver */ | 
|  | static unsigned short	ioaddrs[] = { | 
|  | 0x300, 0x210, 0x240, 0x280, 0x2C0, 0x200, 0x320, 0x340, 0x360, 0}; | 
|  |  | 
|  | if (probe_addrs == 0 || probe_addrs[0] == 0) | 
|  | probe_addrs = ioaddrs; | 
|  | for (p = probe_addrs; (ioaddr = *p) != 0; p++) { | 
|  | if (eepro_probe1(nic)) | 
|  | break; | 
|  | } | 
|  | if (*p == 0) | 
|  | return (0); | 
|  | eepro_reset(nic); | 
|  | /* point to NIC specific routines */ | 
|  | nic->reset = eepro_reset; | 
|  | nic->poll = eepro_poll; | 
|  | nic->transmit = eepro_transmit; | 
|  | nic->disable = eepro_disable; | 
|  | return (nic); | 
|  | } |