15b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /*------------------------------------------------------------------------ 25b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * smc9000.c 35b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * This is a Etherboot driver for SMC's 9000 series of Ethernet cards. 45b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * 55b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * Copyright (C) 1998 Daniel Engstr�m <daniel.engstrom@riksnett.no> 65b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * Based on the Linux SMC9000 driver, smc9194.c by Eric Stahlman 75b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * Copyright (C) 1996 by Erik Stahlman <eric@vt.edu> 85b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * 95b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * This software may be used and distributed according to the terms 105b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * of the GNU Public License, incorporated herein by reference. 115b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * 125b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * "Features" of the SMC chip: 135b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * 4608 byte packet memory. ( for the 91C92/4. Others have more ) 145b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * EEPROM for configuration 155b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * AUI/TP selection 165b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * 175b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * Authors 185b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * Erik Stahlman <erik@vt.edu> 195b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * Daniel Engstr�m <daniel.engstrom@riksnett.no> 205b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * 215b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * History 225b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * 98-09-25 Daniel Engstr�m Etherboot driver crated from Eric's 235b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * Linux driver. 245b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * 255b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project *---------------------------------------------------------------------------*/ 265b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define LINUX_OUT_MACROS 1 275b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define SMC9000_VERBOSE 1 285b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#define SMC9000_DEBUG 0 295b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 305b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#include "etherboot.h" 315b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#include "nic.h" 325b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#include "cards.h" 335b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#include "smc9000.h" 345b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 355b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project# define _outb outb 365b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project# define _outw outw 375b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 385b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic const char smc9000_version[] = "Version 0.99 98-09-30"; 395b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic unsigned int smc9000_base=0; 405b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic const char *interfaces[ 2 ] = { "TP", "AUI" }; 415b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic const char *chip_ids[ 15 ] = { 425b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project NULL, NULL, NULL, 435b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* 3 */ "SMC91C90/91C92", 445b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* 4 */ "SMC91C94", 455b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* 5 */ "SMC91C95", 465b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project NULL, 475b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* 7 */ "SMC91C100", 485b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* 8 */ "SMC91C100FD", 495b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project NULL, NULL, NULL, 505b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project NULL, NULL, NULL 515b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project}; 525b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic const char smc91c96_id[] = "SMC91C96"; 535b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 545b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/* 555b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * Function: smc_reset( int ioaddr ) 565b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * Purpose: 575b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * This sets the SMC91xx chip to its normal state, hopefully from whatever 585b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * mess that any other DOS driver has put it in. 595b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * 605b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * Maybe I should reset more registers to defaults in here? SOFTRESET should 615b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * do that for me. 625b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * 635b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * Method: 645b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * 1. send a SOFT RESET 655b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * 2. wait for it to finish 665b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * 3. reset the memory management unit 675b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * 4. clear all interrupts 685b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * 695b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project*/ 705b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic void smc_reset(int ioaddr) 715b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{ 725b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* This resets the registers mostly to defaults, but doesn't 735b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * affect EEPROM. That seems unnecessary */ 745b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project SMC_SELECT_BANK(ioaddr, 0); 755b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outw( RCR_SOFTRESET, ioaddr + RCR ); 765b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 775b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* this should pause enough for the chip to be happy */ 785b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project SMC_DELAY(ioaddr); 795b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 805b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* Set the transmit and receive configuration registers to 815b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * default values */ 825b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outw(RCR_CLEAR, ioaddr + RCR); 835b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outw(TCR_CLEAR, ioaddr + TCR); 845b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 855b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* Reset the MMU */ 865b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project SMC_SELECT_BANK(ioaddr, 2); 875b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outw( MC_RESET, ioaddr + MMU_CMD ); 885b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 895b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* Note: It doesn't seem that waiting for the MMU busy is needed here, 905b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * but this is a place where future chipsets _COULD_ break. Be wary 915b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * of issuing another MMU command right after this */ 925b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outb(0, ioaddr + INT_MASK); 935b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project} 945b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 955b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 965b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/*---------------------------------------------------------------------- 975b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * Function: smc_probe( int ioaddr ) 985b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * 995b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * Purpose: 1005b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * Tests to see if a given ioaddr points to an SMC9xxx chip. 1015b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * Returns a 0 on success 1025b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * 1035b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * Algorithm: 1045b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * (1) see if the high byte of BANK_SELECT is 0x33 1055b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * (2) compare the ioaddr with the base register's address 1065b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * (3) see if I recognize the chip ID in the appropriate register 1075b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * 1085b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * --------------------------------------------------------------------- 1095b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project */ 1105b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic int smc_probe( int ioaddr ) 1115b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{ 1125b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project word bank; 1135b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project word revision_register; 1145b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project word base_address_register; 1155b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1165b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* First, see if the high byte is 0x33 */ 1175b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project bank = inw(ioaddr + BANK_SELECT); 1185b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if ((bank & 0xFF00) != 0x3300) { 1195b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project return -1; 1205b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 1215b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* The above MIGHT indicate a device, but I need to write to further 1225b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * test this. */ 1235b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outw(0x0, ioaddr + BANK_SELECT); 1245b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project bank = inw(ioaddr + BANK_SELECT); 1255b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if ((bank & 0xFF00) != 0x3300) { 1265b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project return -1; 1275b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 1285b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1295b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* well, we've already written once, so hopefully another time won't 1305b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * hurt. This time, I need to switch the bank register to bank 1, 1315b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * so I can access the base address register */ 1325b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project SMC_SELECT_BANK(ioaddr, 1); 1335b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project base_address_register = inw(ioaddr + BASE); 1345b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1355b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if (ioaddr != (base_address_register >> 3 & 0x3E0)) { 1365b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#ifdef SMC9000_VERBOSE 1375b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("SMC9000: IOADDR %hX doesn't match configuration (%hX)." 1385b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project "Probably not a SMC chip\n", 1395b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project ioaddr, base_address_register >> 3 & 0x3E0); 1405b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#endif 1415b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* well, the base address register didn't match. Must not have 1425b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * been a SMC chip after all. */ 1435b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project return -1; 1445b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 1455b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1465b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1475b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* check if the revision register is something that I recognize. 1485b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * These might need to be added to later, as future revisions 1495b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * could be added. */ 1505b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project SMC_SELECT_BANK(ioaddr, 3); 1515b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project revision_register = inw(ioaddr + REVISION); 1525b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if (!chip_ids[(revision_register >> 4) & 0xF]) { 1535b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* I don't recognize this chip, so... */ 1545b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#ifdef SMC9000_VERBOSE 1555b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("SMC9000: IO %hX: Unrecognized revision register:" 1565b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project " %hX, Contact author.\n", ioaddr, revision_register); 1575b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#endif 1585b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project return -1; 1595b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 1605b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1615b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* at this point I'll assume that the chip is an SMC9xxx. 1625b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * It might be prudent to check a listing of MAC addresses 1635b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * against the hardware address, or do some other tests. */ 1645b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project return 0; 1655b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project} 1665b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1675b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1685b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/************************************************************************** 1695b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * ETH_RESET - Reset adapter 1705b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project ***************************************************************************/ 1715b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1725b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic void smc9000_reset(struct nic *nic) 1735b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{ 1745b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project smc_reset(smc9000_base); 1755b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project} 1765b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1775b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/************************************************************************** 1785b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * ETH_TRANSMIT - Transmit a frame 1795b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project ***************************************************************************/ 1805b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic void smc9000_transmit( 1815b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project struct nic *nic, 1825b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project const char *d, /* Destination */ 1835b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project unsigned int t, /* Type */ 1845b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project unsigned int s, /* size */ 1855b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project const char *p) /* Packet */ 1865b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{ 1875b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project word length; /* real, length incl. header */ 1885b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project word numPages; 1895b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project unsigned long time_out; 1905b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project byte packet_no; 1915b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project word status; 1925b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project int i; 1935b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1945b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* We dont pad here since we can have the hardware doing it for us */ 1955b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project length = (s + ETH_HLEN + 1)&~1; 1965b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 1975b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* convert to MMU pages */ 1985b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project numPages = length / 256; 1995b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2005b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if (numPages > 7 ) { 2015b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#ifdef SMC9000_VERBOSE 2025b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("SMC9000: Far too big packet error. \n"); 2035b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#endif 2045b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project return; 2055b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 2065b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2075b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* dont try more than, say 30 times */ 2085b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project for (i=0;i<30;i++) { 2095b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* now, try to allocate the memory */ 2105b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project SMC_SELECT_BANK(smc9000_base, 2); 2115b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outw(MC_ALLOC | numPages, smc9000_base + MMU_CMD); 2125b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2135b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project status = 0; 2145b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* wait for the memory allocation to finnish */ 2155b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project for (time_out = currticks() + 5*TICKS_PER_SEC; currticks() < time_out; ) { 2165b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project status = inb(smc9000_base + INTERRUPT); 2175b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if ( status & IM_ALLOC_INT ) { 2185b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* acknowledge the interrupt */ 2195b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outb(IM_ALLOC_INT, smc9000_base + INTERRUPT); 2205b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project break; 2215b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 2225b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 2235b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2245b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if ((status & IM_ALLOC_INT) != 0 ) { 2255b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* We've got the memory */ 2265b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project break; 2275b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } else { 2285b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("SMC9000: Memory allocation timed out, resetting MMU.\n"); 2295b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outw(MC_RESET, smc9000_base + MMU_CMD); 2305b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 2315b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 2325b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2335b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* If I get here, I _know_ there is a packet slot waiting for me */ 2345b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project packet_no = inb(smc9000_base + PNR_ARR + 1); 2355b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if (packet_no & 0x80) { 2365b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* or isn't there? BAD CHIP! */ 2375b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("SMC9000: Memory allocation failed. \n"); 2385b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project return; 2395b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 2405b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2415b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* we have a packet address, so tell the card to use it */ 2425b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outb(packet_no, smc9000_base + PNR_ARR); 2435b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2445b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* point to the beginning of the packet */ 2455b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outw(PTR_AUTOINC, smc9000_base + POINTER); 2465b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2475b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#if SMC9000_DEBUG > 2 2485b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("Trying to xmit packet of length %hX\n", length ); 2495b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#endif 2505b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2515b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* send the packet length ( +6 for status, length and ctl byte ) 2525b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * and the status word ( set to zeros ) */ 2535b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outw(0, smc9000_base + DATA_1 ); 2545b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2555b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* send the packet length ( +6 for status words, length, and ctl) */ 2565b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outb((length+6) & 0xFF, smc9000_base + DATA_1); 2575b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outb((length+6) >> 8 , smc9000_base + DATA_1); 2585b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2595b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* Write the contents of the packet */ 2605b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2615b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* The ethernet header first... */ 2625b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outsw(smc9000_base + DATA_1, d, ETH_ALEN >> 1); 2635b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outsw(smc9000_base + DATA_1, nic->node_addr, ETH_ALEN >> 1); 2645b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outw(htons(t), smc9000_base + DATA_1); 2655b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2665b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* ... the data ... */ 2675b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project outsw(smc9000_base + DATA_1 , p, s >> 1); 2685b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2695b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* ... and the last byte, if there is one. */ 2705b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if ((s & 1) == 0) { 2715b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outw(0, smc9000_base + DATA_1); 2725b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } else { 2735b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outb(p[s-1], smc9000_base + DATA_1); 2745b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outb(0x20, smc9000_base + DATA_1); 2755b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 2765b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2775b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* and let the chipset deal with it */ 2785b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outw(MC_ENQUEUE , smc9000_base + MMU_CMD); 2795b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2805b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project status = 0; time_out = currticks() + 5*TICKS_PER_SEC; 2815b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project do { 2825b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project status = inb(smc9000_base + INTERRUPT); 2835b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2845b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if ((status & IM_TX_INT ) != 0) { 2855b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project word tx_status; 2865b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2875b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* ack interrupt */ 2885b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outb(IM_TX_INT, smc9000_base + INTERRUPT); 2895b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2905b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project packet_no = inw(smc9000_base + FIFO_PORTS); 2915b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project packet_no &= 0x7F; 2925b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2935b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* select this as the packet to read from */ 2945b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outb( packet_no, smc9000_base + PNR_ARR ); 2955b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2965b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* read the first word from this packet */ 2975b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outw( PTR_AUTOINC | PTR_READ, smc9000_base + POINTER ); 2985b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 2995b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project tx_status = inw( smc9000_base + DATA_1 ); 3005b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3015b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if (0 == (tx_status & TS_SUCCESS)) { 3025b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#ifdef SMC9000_VERBOSE 3035b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("SMC9000: TX FAIL STATUS: %hX \n", tx_status); 3045b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#endif 3055b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* re-enable transmit */ 3065b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project SMC_SELECT_BANK(smc9000_base, 0); 3075b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outw(inw(smc9000_base + TCR ) | TCR_ENABLE, smc9000_base + TCR ); 3085b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 3095b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3105b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* kill the packet */ 3115b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project SMC_SELECT_BANK(smc9000_base, 2); 3125b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outw(MC_FREEPKT, smc9000_base + MMU_CMD); 3135b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3145b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project return; 3155b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 3165b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project }while(currticks() < time_out); 3175b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3185b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("SMC9000: Waring TX timed out, resetting board\n"); 3195b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project smc_reset(smc9000_base); 3205b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project return; 3215b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project} 3225b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3235b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/************************************************************************** 3245b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * ETH_POLL - Wait for a frame 3255b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project ***************************************************************************/ 3265b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic int smc9000_poll(struct nic *nic) 3275b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{ 3285b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if(!smc9000_base) 3295b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project return 0; 3305b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3315b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project SMC_SELECT_BANK(smc9000_base, 2); 3325b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if (inw(smc9000_base + FIFO_PORTS) & FP_RXEMPTY) 3335b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project return 0; 3345b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3355b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* start reading from the start of the packet */ 3365b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outw(PTR_READ | PTR_RCV | PTR_AUTOINC, smc9000_base + POINTER); 3375b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3385b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* First read the status and check that we're ok */ 3395b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if (!(inw(smc9000_base + DATA_1) & RS_ERRORS)) { 3405b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* Next: read the packet length and mask off the top bits */ 3415b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project nic->packetlen = (inw(smc9000_base + DATA_1) & 0x07ff); 3425b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3435b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* the packet length includes the 3 extra words */ 3445b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project nic->packetlen -= 6; 3455b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#if SMC9000_DEBUG > 2 3465b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf(" Reading %d words (and %d byte(s))\n", 3475b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project (nic->packetlen >> 1), nic->packetlen & 1); 3485b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#endif 3495b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* read the packet (and the last "extra" word) */ 3505b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project insw(smc9000_base + DATA_1, nic->packet, (nic->packetlen+2) >> 1); 3515b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* is there an odd last byte ? */ 3525b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if (nic->packet[nic->packetlen+1] & 0x20) 3535b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project nic->packetlen++; 3545b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3555b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* error or good, tell the card to get rid of this packet */ 3565b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outw(MC_RELEASE, smc9000_base + MMU_CMD); 3575b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project return 1; 3585b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 3595b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3605b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("SMC9000: RX error\n"); 3615b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* error or good, tell the card to get rid of this packet */ 3625b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outw(MC_RELEASE, smc9000_base + MMU_CMD); 3635b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project return 0; 3645b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project} 3655b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3665b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstatic void smc9000_disable(struct nic *nic) 3675b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{ 3685b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if(!smc9000_base) 3695b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project return; 3705b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3715b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* no more interrupts for me */ 3725b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project SMC_SELECT_BANK(smc9000_base, 2); 3735b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outb( 0, smc9000_base + INT_MASK); 3745b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3755b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* and tell the card to stay away from that nasty outside world */ 3765b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project SMC_SELECT_BANK(smc9000_base, 0); 3775b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outb( RCR_CLEAR, smc9000_base + RCR ); 3785b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outb( TCR_CLEAR, smc9000_base + TCR ); 3795b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project} 3805b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3815b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project/************************************************************************** 3825b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * ETH_PROBE - Look for an adapter 3835b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project ***************************************************************************/ 3845b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3855b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectstruct nic *smc9000_probe(struct nic *nic, unsigned short *probe_addrs) 3865b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project{ 3875b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project unsigned short revision; 3885b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project int memory; 3895b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project int media; 3905b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project const char * version_string; 3915b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project const char * if_string; 3925b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project int i; 3935b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 3945b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* 3955b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * the SMC9000 can be at any of the following port addresses. To change, 3965b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * for a slightly different card, you can add it to the array. Keep in 3975b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * mind that the array must end in zero. 3985b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project */ 3995b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project static unsigned short portlist[] = { 4005b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#ifdef SMC9000_SCAN 4015b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project SMC9000_SCAN, 4025b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#else 4035b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, 4045b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 4055b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#endif 4065b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 0 }; 4075b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4085b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("\nSMC9000 %s\n", smc9000_version); 4095b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#ifdef SMC9000_VERBOSE 4105b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("Copyright (C) 1998 Daniel Engstr\x94m\n"); 4115b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("Copyright (C) 1996 Eric Stahlman\n"); 4125b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#endif 4135b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* if no addresses supplied, fall back on defaults */ 4145b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if (probe_addrs == 0 || probe_addrs[0] == 0) 4155b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project probe_addrs = portlist; 4165b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4175b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* check every ethernet address */ 4185b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project for (i = 0; probe_addrs[i]; i++) { 4195b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* check this specific address */ 4205b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if (smc_probe(probe_addrs[i]) == 0) 4215b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project smc9000_base = probe_addrs[i]; 4225b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 4235b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4245b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* couldn't find anything */ 4255b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if(0 == smc9000_base) 4265b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project goto out; 4275b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4285b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* 4295b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * Get the MAC address ( bank 1, regs 4 - 9 ) 4305b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project */ 4315b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project SMC_SELECT_BANK(smc9000_base, 1); 4325b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project for ( i = 0; i < 6; i += 2 ) { 4335b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project word address; 4345b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4355b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project address = inw(smc9000_base + ADDR0 + i); 4365b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project nic->node_addr[i+1] = address >> 8; 4375b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project nic->node_addr[i] = address & 0xFF; 4385b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 4395b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4405b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4415b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* get the memory information */ 4425b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project SMC_SELECT_BANK(smc9000_base, 0); 4435b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project memory = ( inw(smc9000_base + MCR) >> 9 ) & 0x7; /* multiplier */ 4445b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project memory *= 256 * (inw(smc9000_base + MIR) & 0xFF); 4455b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4465b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* 4475b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * Now, I want to find out more about the chip. This is sort of 4485b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * redundant, but it's cleaner to have it in both, rather than having 4495b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * one VERY long probe procedure. 4505b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project */ 4515b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project SMC_SELECT_BANK(smc9000_base, 3); 4525b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project revision = inw(smc9000_base + REVISION); 4535b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project version_string = chip_ids[(revision >> 4) & 0xF]; 4545b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4555b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if (((revision & 0xF0) >> 4 == CHIP_9196) && 4565b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project ((revision & 0x0F) >= REV_9196)) { 4575b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* This is a 91c96. 'c96 has the same chip id as 'c94 (4) but 4585b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * a revision starting at 6 */ 4595b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project version_string = smc91c96_id; 4605b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 4615b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4625b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if ( !version_string ) { 4635b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* I shouldn't get here because this call was done before.... */ 4645b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project goto out; 4655b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 4665b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4675b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* is it using AUI or 10BaseT ? */ 4685b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project SMC_SELECT_BANK(smc9000_base, 1); 4695b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if (inw(smc9000_base + CONFIG) & CFG_AUI_SELECT) 4705b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project media = 2; 4715b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project else 4725b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project media = 1; 4735b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4745b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if_string = interfaces[media - 1]; 4755b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4765b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* now, reset the chip, and put it into a known state */ 4775b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project smc_reset(smc9000_base); 4785b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4795b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("%s rev:%d I/O port:%hX Interface:%s RAM:%d bytes \n", 4805b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project version_string, revision & 0xF, 4815b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project smc9000_base, if_string, memory ); 4825b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* 4835b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project * Print the Ethernet address 4845b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project */ 4855b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("Ethernet MAC address: %!\n", nic->node_addr); 4865b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4875b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project SMC_SELECT_BANK(smc9000_base, 0); 4885b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4895b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* see the header file for options in TCR/RCR NORMAL*/ 4905b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outw(TCR_NORMAL, smc9000_base + TCR); 4915b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outw(RCR_NORMAL, smc9000_base + RCR); 4925b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 4935b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project /* Select which interface to use */ 4945b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project SMC_SELECT_BANK(smc9000_base, 1); 4955b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project if ( media == 1 ) { 4965b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outw( inw( smc9000_base + CONFIG ) & ~CFG_AUI_SELECT, 4975b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project smc9000_base + CONFIG ); 4985b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 4995b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project else if ( media == 2 ) { 5005b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project _outw( inw( smc9000_base + CONFIG ) | CFG_AUI_SELECT, 5015b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project smc9000_base + CONFIG ); 5025b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project } 5035b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 5045b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project nic->reset = smc9000_reset; 5055b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project nic->poll = smc9000_poll; 5065b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project nic->transmit = smc9000_transmit; 5075b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project nic->disable = smc9000_disable; 5085b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 5095b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 5105b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project return nic; 5115b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 5125b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Projectout: 5135b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#ifdef SMC9000_VERBOSE 5145b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project printf("No SMC9000 adapters found\n"); 5155b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project#endif 5165b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project smc9000_base = 0; 5175b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 5185b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project return (0); 5195b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project} 5205b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 5215b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 5225b1eb061628a97aae48a9c0bcaa96eb0bfa07aa4The Android Open Source Project 523