⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 if_fe.c

📁 很好的一个嵌入式linux平台下的bootloader
💻 C
📖 第 1 页 / 共 5 页
字号:
	{ NULL, NULL }};/* * Determine if the device is present * *   on entry: * 	a pointer to an isa_device struct *   on exit: *	zero if device not found *	or number of i/o addresses used (if found) */intfe_probe ( struct isa_device * isa_dev ){	struct fe_softc * sc, * u;	int nports;	struct fe_probe_list const * list;	u_short const * addr;	u_short single [ 2 ];	/* Initialize "minimum" parts of our softc.  */	sc = &fe_softc[ isa_dev->id_unit ];	sc->sc_unit = isa_dev->id_unit;#if FE_DEBUG >= 2	log( LOG_INFO, "fe%d: %s\n", sc->sc_unit, fe_version );#endif#ifndef DEV_LKM	/* Fill the device config data and register it.  */	sc->kdc = fe_kdc_template;	sc->kdc.kdc_unit = sc->sc_unit;	sc->kdc.kdc_parentdata = isa_dev;	dev_attach( &sc->kdc );#endif	/* Probe each possibility, one at a time.  */	for ( list = fe_probe_list; list->probe != NULL; list++ ) {		if ( isa_dev->id_iobase != NO_IOADDR ) {			/* Probe one specific address.  */			single[ 0 ] = isa_dev->id_iobase;			single[ 1 ] = 0;			addr = single;		} else if ( list->addresses != NULL ) {			/* Auto detect.  */			addr = list->addresses;		} else {			/* We need a list of addresses to do auto detect.  */			continue;		}		/* Probe all possible addresses for the board.  */		while ( *addr != 0 ) {			/* Don't probe already used address.  */			for ( u = &fe_softc[0]; u < &fe_softc[NFE]; u++ ) {				if ( u->addr == *addr ) break;			}			if ( u < &fe_softc[NFE] ) continue;			/* Probe an address.  */			sc->addr = *addr;			nports = list->probe( isa_dev, sc );			if ( nports > 0 ) {				/* Found.  */				isa_dev->id_iobase = *addr;				return ( nports );			}			/* Try next.  */			sc->addr = 0;			addr++;		}	}	/* Probe failed.  */	return ( 0 );}/* * Check for specific bits in specific registers have specific values. */struct fe_simple_probe_struct{	u_char port;	/* Offset from the base I/O address.  */	u_char mask;	/* Bits to be checked.  */	u_char bits;	/* Values to be compared against.  */};static INLINE intfe_simple_probe ( u_short addr, struct fe_simple_probe_struct const * sp ){	struct fe_simple_probe_struct const * p;	for ( p = sp; p->mask != 0; p++ ) {		if ( ( INB( addr, p->port ) & p->mask ) != p->bits ) {			return ( 0 );		}	}	return ( 1 );}/* * Routines to read all bytes from the config EEPROM through MB86965A. * I'm not sure what exactly I'm doing here...  I was told just to follow * the steps, and it worked.  Could someone tell me why the following * code works?  (Or, why all similar codes I tried previously doesn't * work.)  FIXME. */static INLINE voidstrobe ( u_short bmpr16 ){	/*	 * Output same value twice.  To speed-down execution?	 */	outb( bmpr16, FE_B16_SELECT );	outb( bmpr16, FE_B16_SELECT );	outb( bmpr16, FE_B16_SELECT | FE_B16_CLOCK );	outb( bmpr16, FE_B16_SELECT | FE_B16_CLOCK );	outb( bmpr16, FE_B16_SELECT );	outb( bmpr16, FE_B16_SELECT );}static voidfe_read_eeprom ( struct fe_softc * sc, u_char * data ){	u_char n, val, bit;	u_char save16, save17;	/* Save old values of the registers.  */	save16 = INB( sc->addr, FE_BMPR16 );	save17 = INB( sc->addr, FE_BMPR17 );	/* Read bytes from EEPROM; two bytes per an iterration.  */	for ( n = 0; n < FE_EEPROM_SIZE / 2; n++ ) {		/* Reset the EEPROM interface.  */		OUTB( sc->addr, FE_BMPR16, 0x00 );		OUTB( sc->addr, FE_BMPR17, 0x00 );		OUTB( sc->addr, FE_BMPR16, FE_B16_SELECT );		/* Start EEPROM access.  */		OUTB( sc->addr, FE_BMPR17, FE_B17_DATA );		STROBE( sc->addr, FE_BMPR16 );		/* Pass the iterration count to the chip.  */		val = 0x80 | n;		for ( bit = 0x80; bit != 0x00; bit >>= 1 ) {			OUTB( sv->addr, FE_BMPR17, ( val & bit ) ? FE_B17_DATA : 0 );			STROBE( sc->addr, FE_BMPR16 );		}		OUTB( sc->addr, FE_BMPR17, 0x00 );		/* Read a byte.  */		val = 0;		for ( bit = 0x80; bit != 0x00; bit >>= 1 ) {			STROBE( sc->addr, FE_BMPR16 );			if ( INB( sc->addr, FE_BMPR17 ) & FE_B17_DATA ) {				val |= bit;			}		}		*data++ = val;		/* Read one more byte.  */		val = 0;		for ( bit = 0x80; bit != 0x00; bit >>= 1 ) {			STROBE( sc->addr, FE_BMPR16 );			if ( INB( sc->addr, FE_BMPR17 ) & FE_B17_DATA ) {				val |= bit;			}		}		*data++ = val;	}	/* Restore register values, in the case we had no 86965.  */	OUTB( sc->addr, FE_BMPR16, save16 );	OUTB( sc->addrm FE_BMPR17, save17 );#if FE_DEBUG >= 3	/* Report what we got.  */	data -= FE_EEPROM_SIZE;	log( LOG_INFO, "fe%d: EEPROM:"		" %02x%02x%02x%02x %02x%02x%02x%02x -"		" %02x%02x%02x%02x %02x%02x%02x%02x -"		" %02x%02x%02x%02x %02x%02x%02x%02x -"		" %02x%02x%02x%02x %02x%02x%02x%02x\n",		sc->sc_unit,		data[ 0], data[ 1], data[ 2], data[ 3],		data[ 4], data[ 5], data[ 6], data[ 7],		data[ 8], data[ 9], data[10], data[11],		data[12], data[13], data[14], data[15],		data[16], data[17], data[18], data[19],		data[20], data[21], data[22], data[23],		data[24], data[25], data[26], data[27],		data[28], data[29], data[30], data[31] );#endif}/* * Hardware (vendor) specific probe routines. *//* * Probe and initialization for Fujitsu FMV-180 series boards */static intfe_probe_fmv ( struct isa_device *isa_dev, struct fe_softc * sc ){	int i, n;	static u_short const ioaddr [ 8 ] =		{ 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x300, 0x340 };	static u_short const irqmap [ 4 ] =		{ IRQ3,  IRQ7,  IRQ10, IRQ15 };	static struct fe_simple_probe_struct const probe_table [] = {		{ FE_DLCR2, 0x70, 0x00 },		{ FE_DLCR4, 0x08, 0x00 },	    /*	{ FE_DLCR5, 0x80, 0x00 },	Doesn't work.  */		{ FE_FMV0, FE_FMV0_MAGIC_MASK,  FE_FMV0_MAGIC_VALUE },		{ FE_FMV1, FE_FMV1_CARDID_MASK, FE_FMV1_CARDID_ID   },		{ FE_FMV3, FE_FMV3_EXTRA_MASK,  FE_FMV3_EXTRA_VALUE },#if 1	/*	 * Test *vendor* part of the station address for Fujitsu.	 * The test will gain reliability of probe process, but	 * it rejects FMV-180 clone boards manufactured by other vendors.	 * We have to turn the test off when such cards are made available.	 */		{ FE_FMV4, 0xFF, 0x00 },		{ FE_FMV5, 0xFF, 0x00 },		{ FE_FMV6, 0xFF, 0x0E },#else	/*	 * We can always verify the *first* 2 bits (in Ehternet	 * bit order) are "no multicast" and "no local" even for	 * unknown vendors.	 */		{ FE_FMV4, 0x03, 0x00 },#endif		{ 0 }	};#if 0	/*	 * Dont probe at all if the config says we are PCMCIA...	 */	if ( isa_dev->id_flags & FE_FLAGS_PCMCIA ) return ( 0 );#endif	/*	 * See if the sepcified address is possible for FMV-180 series.	 */	for ( i = 0; i < 8; i++ ) {		if ( ioaddr[ i ] == sc->addr ) break;	}	if ( i == 8 ) return 0;	/* Simple probe.  */	if ( !fe_simple_probe( sc->addr, probe_table ) ) return 0;	/* Check if our I/O address matches config info on EEPROM.  */	n = ( INB( sc->addr, FE_FMV2 ) & FE_FMV2_ADDR ) >> FE_FMV2_ADDR_SHIFT;	if ( ioaddr[ n ] != sc->addr ) return 0;	/* Determine the card type.  */	switch ( INB( sc->addr, FE_FMV0 ) & FE_FMV0_MODEL ) {	  case FE_FMV0_MODEL_FMV181:		sc->type = FE_TYPE_FMV181;		sc->typestr = "FMV-181";		sc->sc_description = "Ethernet adapter: FMV-181";		break;	  case FE_FMV0_MODEL_FMV182:		sc->type = FE_TYPE_FMV182;		sc->typestr = "FMV-182";		sc->sc_description = "Ethernet adapter: FMV-182";		break;	  default:	  	/* Unknown card type: maybe a new model, but...  */		return 0;	}	/*	 * An FMV-180 has successfully been proved.	 * Determine which IRQ to be used.	 *	 * In this version, we always get an IRQ assignment from the	 * FMV-180's configuration EEPROM, ignoring that specified in	 * config file.	 */	n = ( INB( sc->addr, FE_FMV2 ) & FE_FMV2_IRQ ) >> FE_FMV2_IRQ_SHIFT;	isa_dev->id_irq = irqmap[ n ];	/*	 * Initialize constants in the per-line structure.	 */	/* Get our station address from EEPROM.  */	inblk( sc->addr, FE_FMV4, sc->sc_enaddr, ETHER_ADDR_LEN );	/* Make sure we got a valid station address.  */	if ( ( sc->sc_enaddr[ 0 ] & 0x03 ) != 0x00	  || ( sc->sc_enaddr[ 0 ] == 0x00	    && sc->sc_enaddr[ 1 ] == 0x00	    && sc->sc_enaddr[ 2 ] == 0x00 ) ) return 0;	/* Register values which depend on board design.  */	sc->proto_dlcr4 = FE_D4_LBC_DISABLE | FE_D4_CNTRL;	sc->proto_dlcr5 = 0;	sc->proto_dlcr7 = FE_D7_BYTSWP_LH | FE_D7_IDENT_EC;	/*	 * Program the 86960 as follows:	 *	SRAM: 32KB, 100ns, byte-wide access.	 *	Transmission buffer: 4KB x 2.	 *	System bus interface: 16 bits.	 * We cannot change these values but TXBSIZE, because they	 * are hard-wired on the board.  Modifying TXBSIZE will affect	 * the driver performance.	 */	sc->proto_dlcr6 = FE_D6_BUFSIZ_32KB | FE_D6_TXBSIZ_2x4KB		| FE_D6_BBW_BYTE | FE_D6_SBW_WORD | FE_D6_SRAM_100ns;	/*	 * Minimum initialization of the hardware.	 * We write into registers; hope I/O ports have no	 * overlap with other boards.	 */	/* Initialize ASIC.  */	OUTB( sc->addr, FE_FMV3, 0 );	OUTB( sc->addr, FE_FMV10, 0 );	/* Wait for a while.  I'm not sure this is necessary.  FIXME.  */	DELAY(200);	/* Initialize 86960.  */	OUTB( sc->addr, FE_DLCR6, sc->proto_dlcr6 | FE_D6_DLC_DISABLE );	DELAY(200);	/* Disable all interrupts.  */	OUTB( sc->addr, FE_DLCR2, 0 );	OUTB( sc->addr, FE_DLCR3, 0 );	/* Turn the "master interrupt control" flag of ASIC on.  */	OUTB( sc->addr, FE_FMV3, FE_FMV3_ENABLE_FLAG );	/*	 * That's all.  FMV-180 occupies 32 I/O addresses, by the way.	 */	return 32;}/* * Probe and initialization for Allied-Telesis AT1700/RE2000 series. */static intfe_probe_ati ( struct isa_device * isa_dev, struct fe_softc * sc ){	int i, n;	u_char eeprom [ FE_EEPROM_SIZE ];	static u_short const ioaddr [ 8 ] =		{ 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300 };	static u_short const irqmap_lo [ 4 ] =		{ IRQ3,  IRQ4,  IRQ5,  IRQ9 };	static u_short const irqmap_hi [ 4 ] =		{ IRQ10, IRQ11, IRQ12, IRQ15 };	static struct fe_simple_probe_struct const probe_table [] = {		{ FE_DLCR2,  0x70, 0x00 },		{ FE_DLCR4,  0x08, 0x00 },		{ FE_DLCR5,  0x80, 0x00 },#if 0		{ FE_BMPR16, 0x1B, 0x00 },		{ FE_BMPR17, 0x7F, 0x00 },#endif		{ 0 }	};#if 0	/*	 * Don't probe at all if the config says we are PCMCIA...	 */	if ( isa_dev->id_flags & FE_FLAGS_PCMCIA ) return ( 0 );#endif#if FE_DEBUG >= 3	log( LOG_INFO, "fe%d: probe (0x%x) for ATI\n", sc->sc_unit, sc->addr );	fe_dump( LOG_INFO, sc, NULL );#endif	/*	 * See if the sepcified address is possible for MB86965A JLI mode.	 */	for ( i = 0; i < 8; i++ ) {		if ( ioaddr[ i ] == sc->addr ) break;	}	if ( i == 8 ) return 0;	/*	 * We should test if MB86965A is on the base address now.	 * Unfortunately, it is very hard to probe it reliably, since	 * we have no way to reset the chip under software control.	 * On cold boot, we could check the "signature" bit patterns	 * described in the Fujitsu document.  On warm boot, however,	 * we can predict almost nothing about register values.	 */	if ( !fe_simple_probe( sc->addr, probe_table ) ) return 0;	/* Check if our I/O address matches config info on 86965.  */	n = ( INB( sc->addr, FE_BMPR19 ) & FE_B19_ADDR ) >> FE_B19_ADDR_SHIFT;	if ( ioaddr[ n ] != sc->addr ) return 0;	/*	 * We are now almost sure we have an AT1700 at the given	 * address.  So, read EEPROM through 86965.  We have to write	 * into LSI registers to read from EEPROM.  I want to avoid it	 * at this stage, but I cannot test the presense of the chip	 * any further without reading EEPROM.  FIXME.	 */	fe_read_eeprom( sc, eeprom );	/* Make sure that config info in EEPROM and 86965 agree.  */	if ( eeprom[ FE_EEPROM_CONF ] != INB( sc->addr, FE_BMPR19 ) ) {		return 0;	}	/*	 * Determine the card type.	 * There may be a way to identify various models.  FIXME.	 */	sc->type = FE_TYPE_AT1700;	sc->typestr = "AT1700/RE2000";	sc->sc_description = "Ethernet adapter: AT1700 or RE2000";	/*	 * I was told that RE2000 series has two variants on IRQ	 * selection.  They are 3/4/5/9 and 10/11/12/15.  I don't know	 * how we can distinguish which model is which.  For now, we	 * just trust irq setting in config.  FIXME.	 *	 * I've heard that ATI puts an identification between these	 * two models in the EEPROM.  Sounds reasonable.  I've also	 * heard that Linux driver for AT1700 tests it.  O.K.  Let's	 * try using it and see what happens.  Anyway, we will use an	 * IRQ value passed by config (i.e., user), if one is	 * available.  FIXME.	 */	n = ( INB( sc->addr, FE_BMPR19 ) & FE_B19_IRQ ) >> FE_B19_IRQ_SHIFT;	if ( isa_dev->id_irq == 0 ) {		/* Try to determine IRQ settings.  */		if ( eeprom[ FE_EEP_ATI_TYPE ] & FE_EEP_ATI_TYPE_HIGHIRQ ) {			isa_dev->id_irq = irqmap_hi[ n ];		} else {			isa_dev->id_irq = irqmap_lo[ n ];		}	}	/*	 * Initialize constants in the per-line structure.	 */	/* Get our station address from EEPROM.  */	bcopy( eeprom + FE_EEP_ATI_ADDR, sc->sc_enaddr, ETHER_ADDR_LEN );#if 1	/*	 * This test doesn't work well for AT1700 look-alike by	 * other vendors.	 */	/* Make sure the vendor part is for Allied-Telesis.  */	if ( sc->sc_enaddr[ 0 ] != 0x00	  || sc->sc_enaddr[ 1 ] != 0x00	  || sc->sc_enaddr[ 2 ] != 0xF4 ) return 0;#else	/* Make sure we got a valid station address.  */	if ( ( sc->sc_enaddr[ 0 ] & 0x03 ) != 0x00	  || ( sc->sc_enaddr[ 0 ] == 0x00	    && sc->sc_enaddr[ 1 ] == 0x00	    && sc->sc_enaddr[ 2 ] == 0x00 ) ) return 0;#endif	/* Should find all register prototypes here.  FIXME.  */	sc->proto_dlcr4 = FE_D4_LBC_DISABLE | FE_D4_CNTRL;  /* FIXME */	sc->proto_dlcr5 = 0;	sc->proto_dlcr7 = FE_D7_BYTSWP_LH | FE_D7_IDENT_EC;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -