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