📄 smc91x.c
字号:
do { status = SMC_inb( INT_REG ); if ( status & IM_ALLOC_INT ) { /* acknowledge the interrupt */ SMC_outb( IM_ALLOC_INT, INT_REG ); break; } } while ( -- time_out ); if ( !time_out ) { PRINTK2("%s: memory allocation, try %d failed, Reset MMU ...\n", SMC_DEV_NAME, try); /* Reset the MMU */ SMC_SELECT_BANK( 2 ); SMC_outw( MC_RESET, MMU_CMD_REG ); while ( SMC_inw( MMU_CMD_REG ) & MC_BUSY ) msleep(1); // Wait until not busy if (try < SMC_ALLOC_MAX_TRY) goto again; else return 0; } PRINTK2("%s: memory allocation, try %d succeeded ...\n", SMC_DEV_NAME, try); /* I can send the packet now.. */ ioaddr = SMC_BASE_ADDRESS; buf = (byte *)packet; /* If I get here, I _know_ there is a packet slot waiting for me */ packet_no = SMC_inb( AR_REG ); if ( packet_no & AR_FAILED ) { /* or isn't there? BAD CHIP! */ printf("%s: Memory allocation failed. \n", SMC_DEV_NAME); return 0; } /* we have a packet address, so tell the card to use it */ SMC_outb( packet_no, PN_REG ); /* point to the beginning of the packet */ SMC_outw( PTR_AUTOINC , PTR_REG ); PRINTK3("%s: Trying to xmit packet of length %x\n", SMC_DEV_NAME, length);#if SMC_DEBUG > 2 printf("Transmitting Packet\n"); print_packet( buf, length );#endif /* send the packet length ( +6 for status, length and ctl byte ) and the status word ( set to zeros ) */#ifdef USE_32_BIT SMC_outl( (length +6 ) << 16 , DATA_REG );#else SMC_outw( 0, DATA_REG ); /* send the packet length ( +6 for status words, length, and ctl*/ SMC_outw( (length+6), DATA_REG );#endif /* send the actual data . I _think_ it's faster to send the longs first, and then . mop up by sending the last word. It depends heavily . on alignment, at least on the 486. Maybe it would be . a good idea to check which is optimal? But that could take . almost as much time as is saved? */#ifdef USE_32_BIT SMC_outsl(DATA_REG, buf, length >> 2 ); if ( length & 0x2 ) SMC_outw(*((word *)(buf + (length & 0xFFFFFFFC))), DATA_REG);#else SMC_outsw(DATA_REG , buf, (length ) >> 1);#endif // USE_32_BIT /* Send the last byte, if there is one. */ if ( (length & 1) == 0 ) { SMC_outw( 0, DATA_REG ); } else { SMC_outw( buf[length -1 ] | 0x2000, DATA_REG ); } /* and let the chipset deal with it */ SMC_outw( MC_ENQUEUE , MMU_CMD_REG ); while ( !(status = SMC_inb(INT_REG)) & IM_TX_EMPTY_INT) ; if ( status & IM_TX_EMPTY_INT) { // Ack TX_EMPTY SMC_outb( IM_TX_EMPTY_INT, INT_REG); } if ( status & IM_TX_INT ) { PRINTK("TX error occurs\n"); // ACK TX_INT, something goes wrong SMC_outb( IM_TX_INT, INT_REG); SMC_outw( SMC_inw(TCR_REG) | TCR_ENABLE, TCR_REG ); } return length;}/*------------------------------------------------------------------------- | | smc_destructor( struct net_device * dev ) | Input parameters: | dev, pointer to the device structure | | Output: | None. | ---------------------------------------------------------------------------*/void smc_destructor(){ PRINTK2(CARDNAME ":smc_destructor\n");}/* * Open and Initialize the board * * Set up everything, reset the card, etc .. * */static int smc_open(){ int i; /* used to set hw ethernet address */ u8 ver; testpoint[11] = 1; PRINTK2("%s:smc_open\n", SMC_DEV_NAME); /* reset the hardware */ smc_reset(); smc_enable(); SMC_outw(3, BANK_SELECT); ver = SMC_inw(REV_REG) & 0xff; if ( ver >= 0x70 ) { //#ifndef CONFIG_SMC91111_EXT_PHY /* Configure the PHY */ smc_phy_configure();//#endif } /* conservative setting (10Mbps, HalfDuplex, no AutoNeg.) */// SMC_SELECT_BANK(0);// SMC_outw(0, RPC_REG); /* According to Becker, I have to set the hardware address at this point, because the (l)user can set it with an ioctl. Easily done... */ SMC_SELECT_BANK( 1 );#ifdef USE_32_BIT for ( i = 0; i < 6; i += 2 ) { word address; address = eth_mac_addr[ i + 1 ] << 8 ; address |= eth_mac_addr[ i ]; SMC_outw( address, ADDR0_REG + i ); }#else for ( i = 0; i < 6; i ++ ) SMC_outb( eth_mac_addr[i], ADDR0_REG + i );#endif testpoint[12] = 1; return 0;}#ifdef USE_32_BITvoidinsl32(r,b,l) { int __i ; dword *__b2; __b2 = (dword *) b; for (__i = 0; __i < l; __i++) { *(__b2 + __i) = *(dword *)(r+0x10000300); } }#endif/*------------------------------------------------------------- . . smc_rcv - receive a packet from the card . . There is ( at least ) a packet waiting to be read from . chip-memory. . . o Read the status . o If an error, record it . o otherwise, read in the packet --------------------------------------------------------------*/static int smc_rcv(){ int packet_number; word status; word packet_length; int is_error = 0; struct mybuf *packet;#ifdef USE_32_BIT dword stat_len;#endif SMC_SELECT_BANK(2); packet_number = SMC_inw( RXFIFO_REG ); if ( packet_number & RXFIFO_REMPTY ) { return 0; } packet = bget(0); PRINTK3("%s:smc_rcv\n", SMC_DEV_NAME); /* start reading from the start of the packet */ SMC_outw( PTR_READ | PTR_RCV | PTR_AUTOINC, PTR_REG ); /* First two words are status and packet_length */#ifdef USE_32_BIT stat_len = SMC_inl(DATA_REG); status = stat_len & 0xffff; packet_length = stat_len >> 16;#else status = SMC_inw( DATA_REG ); packet_length = SMC_inw( DATA_REG );#endif packet_length &= 0x07ff; /* mask off top bits */ packet->len = packet_length; PRINTK2("RCV: STATUS %4x LENGTH %4x\n", status, packet_length ); if ( !(status & RS_ERRORS ) ){ /* Adjust for having already read the first two words */ packet_length -= 4; //4; // set odd length for bug in LAN91C111, // which never sets RS_ODDFRAME /* TODO ? */#ifdef USE_32_BIT PRINTK3(" Reading %d dwords (and %d bytes) \n", packet_length >> 2, packet_length & 3 ); /* QUESTION: Like in the TX routine, do I want to send the DWORDs or the bytes first, or some mixture. A mixture might improve already slow PIO performance */ SMC_insl( DATA_REG , packet->buf, packet_length >> 2 ); /* read the left over bytes */ if (packet_length & 3) { int i; byte *tail = packet->buf + (packet_length & ~3); dword leftover = SMC_inl(DATA_REG); for (i=0; i<(packet_length & 3); i++) *tail++ = (byte) (leftover >> (8*i)) & 0xff; } #else PRINTK3(" Reading %d words and %d byte(s) \n", (packet_length >> 1 ), packet_length & 1 ); SMC_insw(DATA_REG , packet->buf, packet_length >> 1);#endif // USE_32_BIT#if SMC_DEBUG > 2 printf("Receiving Packet\n"); print_packet( packet->buf, packet_length );#endif } else { /* error ... */ /* TODO ? */ is_error = 1; } while ( SMC_inw( MMU_CMD_REG ) & MC_BUSY ) msleep(1); // Wait until not busy /* error or good, tell the card to get rid of this packet */ SMC_outw( MC_RELEASE, MMU_CMD_REG ); while ( SMC_inw( MMU_CMD_REG ) & MC_BUSY ) msleep(1); // Wait until not busy if (!is_error) { /* Pass the packet up to the protocol layers. */ net_rx(); return packet_length; } else { return 0; }}/*---------------------------------------------------- . smc_close . . this makes the board clean up everything that it can . and not talk to the outside world. Caused by . an 'ifconfig ethX down' . -----------------------------------------------------*/static int smc_close(){ PRINTK2("%s:smc_close\n", SMC_DEV_NAME); /* clear everything */ smc_shutdown(); return 0;}#if 0/*------------------------------------------------------------ . Modify a bit in the LAN91C111 register set .-------------------------------------------------------------*/static word smc_modify_regbit(int bank, int ioaddr, int reg, unsigned int bit, int val){ word regval; SMC_SELECT_BANK( bank ); regval = SMC_inw( reg ); if (val) regval |= bit; else regval &= ~bit; SMC_outw( regval, 0 ); return(regval);}/*------------------------------------------------------------ . Retrieve a bit in the LAN91C111 register set .-------------------------------------------------------------*/static int smc_get_regbit(int bank, int ioaddr, int reg, unsigned int bit){ SMC_SELECT_BANK( bank ); if ( SMC_inw( reg ) & bit) return(1); else return(0);}/*------------------------------------------------------------ . Modify a LAN91C111 register (word access only) .-------------------------------------------------------------*/static void smc_modify_reg(int bank, int ioaddr, int reg, word val){ SMC_SELECT_BANK( bank ); SMC_outw( val, reg );}/*------------------------------------------------------------ . Retrieve a LAN91C111 register (word access only) .-------------------------------------------------------------*/static int smc_get_reg(int bank, int ioaddr, int reg){ SMC_SELECT_BANK( bank ); return(SMC_inw( reg ));}#endif /* 0 *///---PHY CONTROL AND CONFIGURATION-----------------------------------------#if (SMC_DEBUG > 2 )/*------------------------------------------------------------ . Debugging function for viewing MII Management serial bitstream .-------------------------------------------------------------*/static void smc_dump_mii_stream(byte* bits, int size){ int i; printf("BIT#:"); for (i = 0; i < size; ++i) { printf("%d", i%10); } printf("\nMDOE:"); for (i = 0; i < size; ++i) { if (bits[i] & MII_MDOE) printf("1"); else printf("0"); } printf("\nMDO :"); for (i = 0; i < size; ++i) { if (bits[i] & MII_MDO) printf("1"); else printf("0"); } printf("\nMDI :"); for (i = 0; i < size; ++i) { if (bits[i] & MII_MDI) printf("1"); else printf("0"); } printf("\n");}#endif/*------------------------------------------------------------ . Reads a register from the MII Management serial interface .-------------------------------------------------------------*/static word smc_read_phy_register(byte phyreg){ int oldBank; int i; byte mask; word mii_reg; byte bits[64]; int clk_idx = 0; int input_idx; word phydata; byte phyaddr = SMC_PHY_ADDR; // 32 consecutive ones on MDO to establish sync for (i = 0; i < 32; ++i) bits[clk_idx++] = MII_MDOE | MII_MDO;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -