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

📄 smc9000.c

📁 i386的bootloader源码grub
💻 C
📖 第 1 页 / 共 2 页
字号:
 /*------------------------------------------------------------------------ * smc9000.c * This is a Etherboot driver for SMC's 9000 series of Ethernet cards. * * Copyright (C) 1998 Daniel Engstr鰉 <daniel.engstrom@riksnett.no> * Based on the Linux SMC9000 driver, smc9194.c by Eric Stahlman * Copyright (C) 1996 by Erik Stahlman <eric@vt.edu> * * This software may be used and distributed according to the terms * of the GNU Public License, incorporated herein by reference. * * "Features" of the SMC chip: *   4608 byte packet memory. ( for the 91C92/4.  Others have more ) *   EEPROM for configuration *   AUI/TP selection * * Authors *	Erik Stahlman				<erik@vt.edu> *      Daniel Engstr鰉                         <daniel.engstrom@riksnett.no> * * History * 98-09-25              Daniel Engstr鰉 Etherboot driver crated from Eric's *                                       Linux driver. * *---------------------------------------------------------------------------*/#define LINUX_OUT_MACROS 1#define SMC9000_VERBOSE  1#define SMC9000_DEBUG    0#include "etherboot.h"#include "nic.h"#include "cards.h"#include "smc9000.h"# define _outb outb# define _outw outwstatic const char       smc9000_version[] = "Version 0.99 98-09-30";static unsigned int	smc9000_base=0;static const char       *interfaces[ 2 ] = { "TP", "AUI" };static const char       *chip_ids[ 15 ] =  {   NULL, NULL, NULL,   /* 3 */ "SMC91C90/91C92",   /* 4 */ "SMC91C94",   /* 5 */ "SMC91C95",   NULL,   /* 7 */ "SMC91C100",   /* 8 */ "SMC91C100FD",   NULL, NULL, NULL,   NULL, NULL, NULL};static const char      smc91c96_id[] = "SMC91C96";/* * Function: smc_reset( int ioaddr ) * Purpose: *	This sets the SMC91xx chip to its normal state, hopefully from whatever *	mess that any other DOS driver has put it in. * * Maybe I should reset more registers to defaults in here?  SOFTRESET  should * do that for me. * * Method: *	1.  send a SOFT RESET *	2.  wait for it to finish *	3.  reset the memory management unit *      4.  clear all interrupts **/static void smc_reset(int ioaddr){   /* This resets the registers mostly to defaults, but doesn't    * affect EEPROM.  That seems unnecessary */   SMC_SELECT_BANK(ioaddr, 0);   _outw( RCR_SOFTRESET, ioaddr + RCR );   /* this should pause enough for the chip to be happy */   SMC_DELAY(ioaddr);   /* Set the transmit and receive configuration registers to    * default values */   _outw(RCR_CLEAR, ioaddr + RCR);   _outw(TCR_CLEAR, ioaddr + TCR);   /* Reset the MMU */   SMC_SELECT_BANK(ioaddr, 2);   _outw( MC_RESET, ioaddr + MMU_CMD );   /* Note:  It doesn't seem that waiting for the MMU busy is needed here,    * but this is a place where future chipsets _COULD_ break.  Be wary    * of issuing another MMU command right after this */   _outb(0, ioaddr + INT_MASK);}/*---------------------------------------------------------------------- * Function: smc_probe( int ioaddr ) * * Purpose: *	Tests to see if a given ioaddr points to an SMC9xxx chip. *	Returns a 0 on success * * Algorithm: *	(1) see if the high byte of BANK_SELECT is 0x33 *	(2) compare the ioaddr with the base register's address *	(3) see if I recognize the chip ID in the appropriate register * * --------------------------------------------------------------------- */static int smc_probe( int ioaddr ){   word bank;   word	revision_register;   word base_address_register;   /* First, see if the high byte is 0x33 */   bank = inw(ioaddr + BANK_SELECT);   if ((bank & 0xFF00) != 0x3300) {      return -1;   }   /* The above MIGHT indicate a device, but I need to write to further    *	test this.  */   _outw(0x0, ioaddr + BANK_SELECT);   bank = inw(ioaddr + BANK_SELECT);   if ((bank & 0xFF00) != 0x3300) {      return -1;   }   /* well, we've already written once, so hopefully another time won't    *  hurt.  This time, I need to switch the bank register to bank 1,    *  so I can access the base address register */   SMC_SELECT_BANK(ioaddr, 1);   base_address_register = inw(ioaddr + BASE);   if (ioaddr != (base_address_register >> 3 & 0x3E0))  {#ifdef	SMC9000_VERBOSE      printf("SMC9000: IOADDR %hX doesn't match configuration (%hX)."	     "Probably not a SMC chip\n",	     ioaddr, base_address_register >> 3 & 0x3E0);#endif      /* well, the base address register didn't match.  Must not have       * been a SMC chip after all. */      return -1;   }   /* check if the revision register is something that I recognize.    * These might need to be added to later, as future revisions    * could be added.  */   SMC_SELECT_BANK(ioaddr, 3);   revision_register  = inw(ioaddr + REVISION);   if (!chip_ids[(revision_register >> 4) & 0xF]) {      /* I don't recognize this chip, so... */#ifdef	SMC9000_VERBOSE      printf("SMC9000: IO %hX: Unrecognized revision register:"	     " %hX, Contact author.\n", ioaddr, revision_register);#endif      return -1;   }   /* at this point I'll assume that the chip is an SMC9xxx.    * It might be prudent to check a listing of MAC addresses    * against the hardware address, or do some other tests. */   return 0;}/************************************************************************** * ETH_RESET - Reset adapter ***************************************************************************/static void smc9000_reset(struct nic *nic){   smc_reset(smc9000_base);}/************************************************************************** * ETH_TRANSMIT - Transmit a frame ***************************************************************************/static void smc9000_transmit(	struct nic *nic,	const char *d,			/* Destination */	unsigned int t,			/* Type */	unsigned int s,			/* size */	const char *p)			/* Packet */{   word length; /* real, length incl. header */   word numPages;   unsigned long time_out;   byte	packet_no;   word status;   int i;   /* We dont pad here since we can have the hardware doing it for us */   length = (s + ETH_HLEN + 1)&~1;   /* convert to MMU pages */   numPages = length / 256;   if (numPages > 7 ) {#ifdef	SMC9000_VERBOSE      printf("SMC9000: Far too big packet error. \n");#endif      return;   }   /* dont try more than, say 30 times */   for (i=0;i<30;i++) {      /* now, try to allocate the memory */      SMC_SELECT_BANK(smc9000_base, 2);      _outw(MC_ALLOC | numPages, smc9000_base + MMU_CMD);      status = 0;      /* wait for the memory allocation to finnish */      for (time_out = currticks() + 5*TICKS_PER_SEC; currticks() < time_out; ) {	 status = inb(smc9000_base + INTERRUPT);	 if ( status & IM_ALLOC_INT ) {	    /* acknowledge the interrupt */	    _outb(IM_ALLOC_INT, smc9000_base + INTERRUPT);	    break;	 }      }      if ((status & IM_ALLOC_INT) != 0 ) {	 /* We've got the memory */	 break;      } else {	 printf("SMC9000: Memory allocation timed out, resetting MMU.\n");	 _outw(MC_RESET, smc9000_base + MMU_CMD);      }   }   /* If I get here, I _know_ there is a packet slot waiting for me */   packet_no = inb(smc9000_base + PNR_ARR + 1);   if (packet_no & 0x80) {      /* or isn't there?  BAD CHIP! */      printf("SMC9000: Memory allocation failed. \n");      return;   }   /* we have a packet address, so tell the card to use it */   _outb(packet_no, smc9000_base + PNR_ARR);   /* point to the beginning of the packet */   _outw(PTR_AUTOINC, smc9000_base + POINTER);#if	SMC9000_DEBUG > 2   printf("Trying to xmit packet of length %hX\n", length );#endif   /* send the packet length ( +6 for status, length and ctl byte )    * and the status word ( set to zeros ) */   _outw(0, smc9000_base + DATA_1 );   /* send the packet length ( +6 for status words, length, and ctl) */   _outb((length+6) & 0xFF,  smc9000_base + DATA_1);   _outb((length+6) >> 8 ,   smc9000_base + DATA_1);   /* Write the contents of the packet */   /* The ethernet header first... */   outsw(smc9000_base + DATA_1, d, ETH_ALEN >> 1);

⌨️ 快捷键说明

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