/*
* 3c595.c -- 3COM 3C595 Fast Etherlink III PCI driver for etherboot
*
* Copyright (C) 2000 Shusuke Nisiyama <shu@athena.qe.eng.hokudai.ac.jp>
* All rights reserved.
* Mar. 14, 2000
*
* This software may be used, modified, copied, distributed, and sold, in
* both source and binary form provided that the above copyright and these
* terms are retained. Under no circumstances are the authors responsible for
* the proper functioning of this software, nor do the authors assume any
* responsibility for damages incurred with its use.
*
* This code is based on Martin Renters' etherboot-4.4.3 3c509.c and
* Herb Peyerl's FreeBSD 3.4-RELEASE if_vx.c driver.
*
* Copyright (C) 1993-1994, David Greenman, Martin Renters.
* Copyright (C) 1993-1995, Andres Vega Garcia.
* Copyright (C) 1995, Serge Babkin.
*
* Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
*
* timlegge 08-24-2003 Add Multicast Support
*/
/* #define EDEBUG */
#include "etherboot.h"
#include "nic.h"
#include "pci.h"
#include "3c595.h"
#include "timer.h"
static unsigned short eth_nic_base;
static struct connector_entry {
int bit;
char *name;
#define CONNECTOR_UTP 0
{ 0x08, "utp"},
{ 0x20, "aui"},
/* dummy */
{ 0, "???"},
{ 0x10, "bnc"},
{ 0x02, "tx"},
{ 0x04, "fx"},
{ 0x40, "mii"},
{ 0, "???"}
};
static void vxgetlink(void);
static void vxsetlink(void);
/**************************************************************************
ETH_RESET - Reset adapter
***************************************************************************/
{
int i;
/***********************************************************
Reset 3Com 595 card
*************************************************************/
/* stop card */
udelay(8000);
/*
* initialize card
*/
GO_WINDOW(0);
/* Disable the card */
/* outw(0, BASE + VX_W0_CONFIG_CTRL); */
/* Configure IRQ to none */
/* outw(SET_IRQ(0), BASE + VX_W0_RESOURCE_CFG); */
/* Enable the card */
/* outw(ENABLE_DRQ_IRQ, BASE + VX_W0_CONFIG_CTRL); */
GO_WINDOW(2);
/* Reload the ether_addr. */
for (i = 0; i < ETH_ALEN; i++)
/* Window 1 is operating window */
GO_WINDOW(1);
for (i = 0; i < 31; i++)
/*
* Attempt to get rid of any stray interrupts that occured during
* configuration. On the i386 this isn't possible because one may
* already be queued. However, a single stray interrupt is
* unimportant.
*/
vxsetlink();
/*{
int i,j;
i = CONNECTOR_TX;
GO_WINDOW(3);
j = inl(BASE + VX_W3_INTERNAL_CFG) & ~INTERNAL_CONNECTOR_MASK;
outl(BASE + VX_W3_INTERNAL_CFG, j | (i <<INTERNAL_CONNECTOR_BITS));
GO_WINDOW(4);
outw(LINKBEAT_ENABLE, BASE + VX_W4_MEDIA_TYPE);
GO_WINDOW(1);
}*/
/* start tranciever and receiver */
}
/**************************************************************************
ETH_TRANSMIT - Transmit a frame
***************************************************************************/
static char padmap[] = {
0, 3, 2, 1};
static void t595_transmit(
const char *d, /* Destination */
unsigned int t, /* Type */
unsigned int s, /* size */
const char *p) /* Packet */
{
register int len;
int pad;
int status;
#ifdef EDEBUG
#endif
/* swap bytes of type */
t= htons(t);
/*
* The 3c595 automatically pads short packets to minimum ethernet length,
* but we drop packets that are too large. Perhaps we should truncate
* them instead?
*/
return;
}
/* drop acknowledgements */
}
}
/* no room in FIFO */
}
/* write packet */
if (s & 1)
while (pad--)
/* wait for Tx complete */
;
}
/**************************************************************************
ETH_POLL - Wait for a frame
***************************************************************************/
{
/* common variables */
/* variables for 3C595 */
register short rx_fifo;
#ifdef EDEBUG
if(cst & 0x1FFF)
#endif
if( (cst & S_RX_COMPLETE)==0 ) {
/* acknowledge everything */
return 0;
}
#ifdef EDEBUG
#endif
return 0;
}
if (rx_fifo==0)
return 0;
if ( ! retrieve ) return 1;
/* read packet */
#ifdef EDEBUG
#endif
if(rx_fifo & 1)
while(1) {
#ifdef EDEBUG
#endif
if(rx_fifo>0) {
if(rx_fifo & 1)
#ifdef EDEBUG
#endif
}
if(( status & RX_INCOMPLETE )==0) {
#ifdef EDEBUG
#endif
break;
}
udelay(1000);
}
/* acknowledge reception of packet */
#ifdef EDEBUG
{
else
}
#endif
return 1;
}
/*************************************************************************
3Com 595 - specific routines
**************************************************************************/
static int
{
int i;
udelay(1000);
if (i >= MAX_EEPROMBUSY) {
/* printf("3c595: eeprom failed to come ready.\n"); */
return (0);
}
return (1);
}
/*
* get_e: gets a 16 bits word from the EEPROM. we must have set the window
* before
*/
static int
int offset;
{
if (!eeprom_rdy())
return (0xffff);
if (!eeprom_rdy())
return (0xffff);
}
static void
vxgetlink(void)
{
int n, k;
GO_WINDOW(3);
for (n = 0, k = 0; k < VX_CONNECTORS; k++) {
if (n > 0) {
printf("/");
}
n++;
}
}
if (vx_connectors == 0) {
printf("no connectors!");
return;
}
GO_WINDOW(3);
if (vx_connector & 0x10) {
vx_connector &= 0x0f;
printf(": disable 'auto select' with DOS util!");
} else {
}
}
static void
vxsetlink(void)
{
int i, j;
if (prev_conn == -1) {
}
i = vx_connector; /* default in EEPROM */
reason = "default";
warning = 0;
warning = "strange connector type in EEPROM.";
reason = "forced";
i = CONNECTOR_UTP;
}
if (warning != 0) {
}
/* Set the selected connector. */
GO_WINDOW(3);
/* First, disable all. */
udelay(8000);
GO_WINDOW(4);
/* Second, enable the selected one. */
switch(i) {
case CONNECTOR_UTP:
GO_WINDOW(4);
break;
case CONNECTOR_BNC:
udelay(8000);
break;
case CONNECTOR_TX:
case CONNECTOR_FX:
GO_WINDOW(4);
break;
default: /* AUI and MII fall here */
break;
}
GO_WINDOW(1);
}
{
udelay(8000);
GO_WINDOW(4);
GO_WINDOW(1);
}
{
switch ( action ) {
case DISABLE :
break;
case ENABLE :
break;
case FORCE :
break;
}
}
/**************************************************************************
ETH_PROBE - Look for an adapter
***************************************************************************/
{
int i;
unsigned short *p;
return 0;
/* eth_nic_base = probeaddrs[0] & ~3; */
GO_WINDOW(0);
vxgetlink();
/*
printf("\nEEPROM:");
for (i = 0; i < (EEPROMSIZE/2); i++) {
printf("%hX:", get_e(i));
}
printf("\n");
*/
/*
* Read the station address from the eeprom
*/
for (i = 0; i < 3; i++) {
GO_WINDOW(0);
GO_WINDOW(2);
}
return 1;
}
};
.type = NIC_DRIVER,
.name = "3C595",
.probe = t595_probe,
.class = 0,
};
/*
* Local variables:
* c-basic-offset: 8
* End:
*/