📄 if_fe.c
字号:
{ 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 + -