📄 if_snnew.c
字号:
/****************************************************************************
* 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 + -