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

📄 if_snnew.c

📁 T-kernel Tcp/ip Protocol Stack Sample
💻 C
📖 第 1 页 / 共 5 页
字号:
/****************************************************************************
 * Copyright (C) 2001-2006 MITSUBISHI ELECTRIC CORPORATION and
 * RENESAS SOLUTIONS CORPORATION
 * All rights reserved.
 *
 ****************************************************************************
 * Copyright (c) 1996 Gardner Buchanan <gbuchanan@shl.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by Gardner Buchanan.
 * 4. The name of Gardner Buchanan may not be used to endorse or promote
 *    products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *   $Id if_sn.c,v 1.5 1996/10/30 13:22:50 gardner Exp $
 */

/*
 * This is a driver for SMC's 9000 series of Ethernet adapters.
 *
 * This FreeBSD driver is derived from the smc9194 Linux driver by
 * Erik Stahlman and is Copyright (C) 1996 by Erik Stahlman.
 * This driver also shamelessly borrows from the FreeBSD ep driver
 * which is Copyright (C) 1994 Herb Peyerl <hpeyerl@novatel.ca>
 * All rights reserved.
 *
 * It is set up for my SMC91C92 equipped Ampro LittleBoard embedded
 * PC.  It is adapted from Erik Stahlman's Linux driver which worked
 * with his EFA Info*Express SVC VLB adaptor.  According to SMC's databook,
 * it will work for the entire SMC 9xxx series. (Ha Ha)
 *
 * "Features" of the SMC chip:
 *   4608 byte packet memory. (for the 91C92.  Others have more)
 *   EEPROM for configuration
 *   AUI/TP selection
 *
 * Authors:
 *      Erik Stahlman                   erik@vt.edu
 *      Herb Peyerl                     hpeyerl@novatel.ca
 *      Andres Vega Garcia              avega@sophia.inria.fr
 *      Serge Babkin                    babkin@hq.icb.chel.su
 *      Gardner Buchanan                gbuchanan@shl.com
 *
 * Sources:
 *    o   SMC databook
 *    o   "smc9194.c:v0.10(FIXED) 02/15/96 by Erik Stahlman (erik@vt.edu)"
 *    o   "if_ep.c,v 1.19 1995/01/24 20:53:45 davidg Exp"
 *
 * Known Bugs:
 *    o   The hardware multicast filter isn't used yet.
 *    o   Setting of the hardware address isn't supported.
 *    o   Hardware padding isn't used.
 */

#if defined(_MIC_M32104_) || defined (_MIC_M32192_)
#define WAIT_UNIT 1000
// #define WAIT_UNIT 10000
// #define WAIT_UNIT 100000
#elif defined(_STD_SH7727_)
#define WAIT_UNIT 100000
#elif defined(_MIC_SH7145_)
#define WAIT_UNIT 2*1000*1000
#endif

#if defined(_MIC_M32192_)
#define IMJTICR3    (volatile unsigned char *)0x0080007D /* MJT Input Int Ctrl Reg */
#define TINIR6      (volatile unsigned char *)0x0080023E /* TIN Int Ctrl Reg-6 */
#define P10MOD      (volatile unsigned char *)0x0080074A /* P10 Operation Mode Reg */
#define P10SMOD     (volatile unsigned char *)0x0080076A /* P10 Peripheral Func Sel  Reg */
#define TIN2425CR   (volatile unsigned char *)0x008007E1 /* TIN24,25 Int Mask reg */
#define TIN2425IMA  (volatile unsigned char *)0x008007E2 /* TIN24,25 Int Mask reg */
#define TIN2627IMA  (volatile unsigned char *)0x00800BE2 /* TIN26,27 Int Mask reg */
#endif /* _MIC_M32192_ */
#if defined(T_KERNEL)
#include <tk/tkernel.h>
#endif

#include <sys/byte_order.h>
#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/file.h>
#include <sys/filedesc.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/ioctl.h>
#include <sys/errno.h>

#include <net/route.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>

#ifdef INET
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
#endif

#include <uif_ext.h>
#include "if_snreg.h"

#define BASE_ADDR_SET 0

volatile unsigned short bswap_w(volatile unsigned short);
volatile unsigned char inb(volatile unsigned int);
void insw(volatile unsigned int, volatile unsigned short *, int);
volatile unsigned short inw(volatile unsigned int);
volatile unsigned char outb(volatile unsigned int, volatile unsigned char);
void outsw(volatile unsigned int, volatile unsigned short *, int);
volatile unsigned short outw(volatile unsigned int, volatile unsigned short);

int sn_lan_init(void);
int snprobe(struct isa_device *);
static int snattach(struct isa_device *);
void sninit(void *);
void snstart(struct ifnet *);
static void snresume(struct ifnet *);

#if defined(T_KERNEL)
void snintr(UINT, VP);
#endif
void snintr_sc(void);
void snread(struct sn_softc *);
static int snioctl(struct ifnet *, unsigned int, caddr_t);
void snreset(void);
void snwatchdog(struct ifnet *);
void snstop(void);

static int smc_probe(int);
int phy_init(void);
int phy_ints(void);
unsigned short phy_access(u_char, u_char, u_char, unsigned short);
void clkmdio(unsigned short);

extern int kprintf(const char*, ...);

#ifdef PRINTON
#define printf kprintf
#endif

/* I (GB) have been unlucky getting the hardware padding
 * to work properly.
 */
#define SW_PAD

struct sn_softc sn_softc0;

/*** bswap_w: byte swap of half word ***/
volatile unsigned short
bswap_w(volatile unsigned short val)
{
	volatile unsigned char *p = (volatile unsigned char *)&val;
#if defined(_MIC_M32192_) || defined(_MIC_SH7145_) || defined(_MIC_M32104_)
	return ((p[1] << 8) | (p[0]));
#elif defined(_STD_SH7727_)
	return ((p[0] << 8) | (p[1]));
#endif
}

/*** inb: read byte from specified port ***/
volatile unsigned char
inb(volatile unsigned int port)
{
	return (*((volatile unsigned  char *)(port)));
}

/*** insw: read every half word from specified port ***/
void insw(volatile unsigned int port, volatile unsigned short *ptr, int len)
{
	volatile unsigned short *io_ptr = (volatile unsigned short *)port;
	while (len-- > 0)
	{
#if defined(_MIC_M32192_)||defined(_STD_SH7727_)||defined(_MIC_SH7145_)||(_MIC_M32104_)
		*ptr++ = *io_ptr;
#else
		*ptr++ = bswap_w(*io_ptr);
#endif
	}
}

/*** inw: read word from specified port ***/
volatile unsigned short
inw(volatile unsigned int port)
{
#if defined(_MIC_M32192_) || defined(_MIC_SH7145_) || defined(_MIC_M32104_)
	/* swap bytes because of
	   HIGH_BYTE is odd address and LOW_BYTE is even address */
	return (bswap_w(*(volatile unsigned short *)port));
#elif defined(_STD_SH7727_)
	return (*((volatile unsigned short *)port));
#endif
}

/*** outb: write byte to specified port ***/
volatile unsigned char
outb(volatile unsigned int port, volatile unsigned char val)
{
	*((volatile unsigned  char *)port) = val;
	return (val);
}

/*** outsw: write every half word to specified port ***/
void outsw(volatile unsigned int port, volatile unsigned short *ptr, int len)
{
	volatile unsigned short *io_ptr = (volatile unsigned short *)port;
	while (len-- > 0)
	{
#if defined(_MIC_M32192_) || defined(_STD_SH7727_) || defined(_MIC_SH7145_)
		*io_ptr = *ptr++;
#else
		*io_ptr = bswap_w(*ptr++);
#endif
	}
}

/*** outw: write word to specified port ***/
volatile unsigned short
outw(volatile unsigned int port, volatile unsigned short val)
{
#if defined(_MIC_M32192_)||defined(_MIC_SH7145_)||defined(_MIC_M32104_)
	/* swap bytes because of
	   HIGH_BYTE is odd address and LOW_BYTE is even address */
	volatile unsigned short lval;
	lval = bswap_w(val);
	*((volatile unsigned  short *)port) = lval;
	return (lval);
#elif defined(_STD_SH7727_)
	*((volatile unsigned  short *)port) = val;
	return (val);
#endif
}

int
sn_lan_init(void)
{
	struct isa_device is;
	int ret, j;
	ER ercd;
	T_DINT pk_dint;

#if defined(_MIC_SH7145_)
	/* initialize PFC(Pin Function Controller) */
	out_h(PACRL2, (in_h(PACRL2) & ~(0xC000)) | 0x8000);   /* CS3 output */
	out_h(PBCR2, (in_h(PBCR2) & ~(0x0C00)) | 0x0400);   /* IRQ3 input */

	/* initialize BSC(Bus State Controller) */
	out_h(BCR1, (in_h(BCR1) & ~(0x0080)) | 0x0008);	/* CS3 = 16 bit */
	out_h(BCR2, (in_h(BCR2) & ~(0xC000)) | 0x8080);	/* CS3 = 2 cycle */
	out_h(WCR1, (in_h(WCR1) & ~(0xF000)) | 0x6000);	/* CS3 = 6 wait */
#elif defined(_STD_SH7727_)
	/* initialize PFC(Pin Function Controller) */
	out_h(PHCR, in_h(PHCR) & ~(0x00FF) );   /* IRL3-0=0101 input */
	out_h(PKCR, in_h(PKCR) & ~(0x0030) );   /* CS4 output */

	/* initialize BSC(Bus State Controller) */
	out_h(BCR2, (in_h(BCR2) & ~(0x0100)) | 0x0200);	/* CS4 = 16 bit */
	out_h(WCR1, (in_h(WCR1) & ~(0x0100)) | 0x0200);	/* CS4 = 2 cycle */
	out_h(WCR2, (in_h(WCR2) & ~(0x0100)) | 0x0280);	/* CS4 = 6 wait */
#endif

	is.id_iobase = SMC_LAN_BASEADDR;
	is.id_irq = SMC_LAN_IRQ;
	is.id_unit = SMC_LAN_0;

	/* structure initialize */
	bzero((char *)&sn_softc0, sizeof(sn_softc0));

	/* probe device */
	ret = snprobe(&is);
	if (ret < 0) {
		return(-1);
	}

	/* interface attach */
	ret = snattach(&is);
	if (ret < 0) {
		return(-1);
	}

	/* Set interrupt handler */
	pk_dint.intatr = TA_HLNG;
	pk_dint.inthdr = (FP)snintr;
#if defined(T_KERNEL)
	ercd = tk_def_int(is.id_irq, &pk_dint);
#endif
	if (ercd != E_OK) {
		return(-1);
	}

#if defined(_MIC_SH7145_)
	/* initialize INTC(INTerrupt Controller) */
	out_h(ICR1, in_h(ICR1) | 0x0010 );	/* IRQ3 = edge */
	out_h(ICR2, in_h(ICR2) & ~(0x0300) );	/* IRQ3 = down edge */
	out_h(ISR, in_h(ISR) & ~(0x0010) );	/* IRQ3 request clear */
	out_h(IPRA, (in_h(IPRA) & ~(0x000F)) | 0x0008);	/* IRQ3 = level 8 */
#elif defined(_STD_SH7727_)
	/* initialize INTC(INTerrupt Controller) */
	out_h(ICR1, in_h(ICR1) | 0x4000 );	/* IRL3-0 select */
#elif defined(_MIC_M32104_)
	/* initialize ICU1: IEN=enable, ISMOD="H"level, ILEVEL=3 */
	ICUCR1 = 0x1033;
#elif defined(_MIC_M32192_)
	*TINIR6 = 0x0F;
	*TIN2425IMA = 0x01;
	*TIN2627IMA = 0x03;

	*TIN2425CR = 0x03;
	*IMJTICR3   = 0x03;
	*P10MOD    = 0x10;
	*P10SMOD   = 0x10;	
#endif

	return(0);
}

int
snprobe(struct isa_device *is)
{
	/*  Device was configured with 'port ?' In this case we complain
	 */
	if (is->id_iobase == -1) { /* port? */
	    return(-1);
	}

	/*  Device was configured with 'irq ?' In this case we complain
	 */
	if (is->id_irq < 0) {
	    return(-1);
	}

	/* Device was configured with 'port xxx', 'irq xx'
	 * In this case we search for the card with that address
	 */
	if (smc_probe(is->id_iobase) != 0) {
	   return(-1);
	}

	return(0);
}

static int
snattach(struct isa_device *is)
{
	struct sn_softc *sc = &sn_softc0;
	struct ifnet *ifp = &sc->arpcom.ac_if;
	u_short i;
	u_char *p;
	struct ifaddr *ifa;
	struct sockaddr_dl *sdl;
	u_short address=0;
	int mac_ok=0;

	/* This is the value used for BASE
	 */
	sc->sn_io_addr = is->id_iobase;

	sc->pages_wanted = -1;

#ifdef PRINTON
	SMC_SELECT_BANK( 3 );
	rev = inw( BASE + REVISION_REG_W );

	if (chip_ids[(rev >> 4) & 0xF])
	   printf("%s\n", chip_ids[(rev >> 4) & 0xF]);
#endif

	/* Stop for configuration reg setup */
	snstop();

#if !defined(LAN91C111)
	/* set MII SELECT */
	SMC_SELECT_BANK( 1 );
	i = inw( BASE + CONFIG_REG_W );
	outw( BASE + CONFIG_REG_W, i|0x8000 );
#endif

#ifdef PRINTON
	printf(i & CR_AUI_SELECT ? "AUI\n" : "UTP\n");
#endif

	/*
	 * Read the station address from the chip.
	 * The MAC address is bank 1, regs 4 - 9
	 */
	SMC_SELECT_BANK( 1 );
	p = (u_char *) & sc->arpcom.ac_enaddr;

	for (i=0; i < 6; i += 2) {
		switch (i) {
		case (0):
			address = inw( BASE + IAR_ADDR0_REG_W );
			break;
		case (2):
			address = inw( BASE + IAR_ADDR1_REG_W );
			break;
		case (4):
			address = inw( BASE + IAR_ADDR2_REG_W );
			break;
		}
		p[ i ] = address & 0xFF;
		p[ i + 1 ] = address >> 8;
	}

	/* MAC address check ! If MAC isn't set,We set temporary value */
	for (i=0; i < 6; i++) {
#if defined(LAN91C111)
		/* When the EEPROM is an initial state (when not to set nothing), 
		   all of loaded bits is '1' */
		if (p[ i ] != 0xFF) {
#else
		if (p[ i ] != 0x0) {
#endif
			mac_ok = 1;
			break;
		}
	}

	if (mac_ok != 1) {
		/* set temporary MAC address (= 00:60:97:f8:16:01) to chip.
		   NOTE: not modify the EEPROM contents */
		outw( BASE+IAR_ADDR0_REG_W, 0x6000);	/* byte swap */
		outw( BASE+IAR_ADDR1_REG_W, 0xf897);
		outw( BASE+IAR_ADDR2_REG_W, 0x0116);

		/* read MAC address from chip */
		for (i = 0; i < 6; i += 2) {
			switch (i) {
			case (0):
				address = inw( BASE + IAR_ADDR0_REG_W );
				break;
			case (2):
				address = inw( BASE + IAR_ADDR1_REG_W );
				break;
			case (4):
				address = inw( BASE + IAR_ADDR2_REG_W );
				break;
   			}
			p[ i ] = address & 0xFF;
			p[ i + 1 ] = address >> 8;
		}
	}

#ifdef PRINTON
	printf(" MAC address 0x%08x\n", sc->arpcom.ac_enaddr);

⌨️ 快捷键说明

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