Update of /cvsroot/gc-linux/linux/drivers/net
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20928/drivers/net
Added Files:
Kconfig Makefile exi.h gc-net.c
Log Message:
network driver. prints messages when pinged. orginal code by tmbinc,
linux driver by ionic, debugging by ionic, tmbinc, groepaz, costis, mist.
--- NEW FILE: Kconfig ---
#
# Network device configuration
#
config NETDEVICES
depends on NET
bool "Network device support"
---help---
You can say N here if you don't intend to connect your Linux box to
any other computer at all.
You'll have to say Y if your computer contains a network card that
you want to use under Linux. If you are going to run SLIP or PPP over
telephone line or null modem cable you need say Y here. Connecting
two machines with parallel ports using PLIP needs this, as well as
AX.25/KISS for sending Internet traffic over amateur radio links.
See also "The Linux Network Administrator's Guide" by Olaf Kirch and
[...2417 lines suppressed...]
<file:Documentation/networking/shaper.txt> for more information.
An alternative to this traffic shaper is the experimental
Class-Based Queueing (CBQ) scheduling support which you get if you
say Y to "QoS and/or fair queueing" above.
To set up and configure shaper devices, you need the shapecfg
program, available from <ftp://shadow.cabi.net/pub/Linux/> in the
shaper package.
To compile this driver as a module, choose M here: the module
will be called shaper. If unsure, say N.
source "drivers/net/wan/Kconfig"
source "drivers/net/pcmcia/Kconfig"
source "drivers/atm/Kconfig"
source "drivers/s390/net/Kconfig"
--- NEW FILE: Makefile ---
#
# Makefile for the Linux network (ethercard) device drivers.
#
rcpci-objs := rcpci45.o rclanmtl.o
ifeq ($(CONFIG_ISDN_PPP),y)
obj-$(CONFIG_ISDN) += slhc.o
endif
obj-$(CONFIG_E100) += e100/
obj-$(CONFIG_E1000) += e1000/
obj-$(CONFIG_IXGB) += ixgb/
obj-$(CONFIG_BONDING) += bonding/
#
# link order important here
#
obj-$(CONFIG_PLIP) += plip.o
obj-$(CONFIG_ROADRUNNER) += rrunner.o
obj-$(CONFIG_HAPPYMEAL) += sunhme.o
obj-$(CONFIG_SUNLANCE) += sunlance.o
obj-$(CONFIG_SUNQE) += sunqe.o
obj-$(CONFIG_SUNBMAC) += sunbmac.o
obj-$(CONFIG_MYRI_SBUS) += myri_sbus.o
obj-$(CONFIG_SUNGEM) += sungem.o sungem_phy.o
obj-$(CONFIG_MACE) += mace.o
obj-$(CONFIG_BMAC) += bmac.o
obj-$(CONFIG_OAKNET) += oaknet.o 8390.o
obj-$(CONFIG_DGRS) += dgrs.o
obj-$(CONFIG_RCPCI) += rcpci.o
obj-$(CONFIG_VORTEX) += 3c59x.o
obj-$(CONFIG_TYPHOON) += typhoon.o
obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
obj-$(CONFIG_PCNET32) += pcnet32.o
obj-$(CONFIG_EEPRO100) += eepro100.o
obj-$(CONFIG_TLAN) += tlan.o
obj-$(CONFIG_EPIC100) += epic100.o
obj-$(CONFIG_SIS190) += sis190.o
obj-$(CONFIG_SIS900) += sis900.o
obj-$(CONFIG_YELLOWFIN) += yellowfin.o
obj-$(CONFIG_ACENIC) += acenic.o
obj-$(CONFIG_VETH) += veth.o
obj-$(CONFIG_NATSEMI) += natsemi.o
obj-$(CONFIG_NS83820) += ns83820.o
obj-$(CONFIG_STNIC) += stnic.o 8390.o
obj-$(CONFIG_FEALNX) += fealnx.o
obj-$(CONFIG_TIGON3) += tg3.o
obj-$(CONFIG_TC35815) += tc35815.o
obj-$(CONFIG_SK98LIN) += sk98lin/
obj-$(CONFIG_SKFP) += skfp/
obj-$(CONFIG_VIA_RHINE) += via-rhine.o
obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
#
# end link order section
#
obj-$(CONFIG_MII) += mii.o
obj-$(CONFIG_SUNDANCE) += sundance.o
obj-$(CONFIG_HAMACHI) += hamachi.o
obj-$(CONFIG_NET) += Space.o net_init.o loopback.o
obj-$(CONFIG_SEEQ8005) += seeq8005.o
obj-$(CONFIG_ETHERTAP) += ethertap.o
obj-$(CONFIG_NET_SB1000) += sb1000.o
obj-$(CONFIG_MAC8390) += mac8390.o 8390.o
obj-$(CONFIG_APNE) += apne.o 8390.o
obj-$(CONFIG_PCMCIA_PCNET) += 8390.o
obj-$(CONFIG_SHAPER) += shaper.o
obj-$(CONFIG_SK_G16) += sk_g16.o
obj-$(CONFIG_HP100) += hp100.o
obj-$(CONFIG_SMC9194) += smc9194.o
obj-$(CONFIG_FEC) += fec.o
obj-$(CONFIG_68360_ENET) += 68360enet.o
obj-$(CONFIG_ARM_ETHERH) += 8390.o
obj-$(CONFIG_WD80x3) += wd.o 8390.o
obj-$(CONFIG_EL2) += 3c503.o 8390.o
obj-$(CONFIG_NE2000) += ne.o 8390.o
obj-$(CONFIG_NE2K_CBUS) += ne2k_cbus.o 8390.o
obj-$(CONFIG_NE2_MCA) += ne2.o 8390.o
obj-$(CONFIG_HPLAN) += hp.o 8390.o
obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390.o
obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o
obj-$(CONFIG_ULTRAMCA) += smc-mca.o 8390.o
obj-$(CONFIG_ULTRA32) += smc-ultra32.o 8390.o
obj-$(CONFIG_E2100) += e2100.o 8390.o
obj-$(CONFIG_ES3210) += es3210.o 8390.o
obj-$(CONFIG_LNE390) += lne390.o 8390.o
obj-$(CONFIG_NE3210) += ne3210.o 8390.o
obj-$(CONFIG_NET_SB1250_MAC) += sb1250-mac.o
obj-$(CONFIG_B44) += b44.o
obj-$(CONFIG_PPP) += ppp_generic.o slhc.o
obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o
obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o
obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o
obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
obj-$(CONFIG_SLIP) += slip.o
ifeq ($(CONFIG_SLIP_COMPRESSED),y)
obj-$(CONFIG_SLIP) += slhc.o
endif
obj-$(CONFIG_DUMMY) += dummy.o
obj-$(CONFIG_DE600) += de600.o
obj-$(CONFIG_DE620) += de620.o
obj-$(CONFIG_AT1500) += lance.o
obj-$(CONFIG_LANCE) += lance.o
obj-$(CONFIG_SUN3_82586) += sun3_82586.o
obj-$(CONFIG_SUN3LANCE) += sun3lance.o
obj-$(CONFIG_DEFXX) += defxx.o
obj-$(CONFIG_SGISEEQ) += sgiseeq.o
obj-$(CONFIG_SGI_O2MACE_ETH) += meth.o
obj-$(CONFIG_AT1700) += at1700.o
obj-$(CONFIG_FMV18X) += fmv18x.o
obj-$(CONFIG_EL1) += 3c501.o
obj-$(CONFIG_EL16) += 3c507.o
obj-$(CONFIG_ELMC) += 3c523.o
obj-$(CONFIG_SKMC) += sk_mca.o
obj-$(CONFIG_IBMLANA) += ibmlana.o
obj-$(CONFIG_ELMC_II) += 3c527.o
obj-$(CONFIG_EL3) += 3c509.o
obj-$(CONFIG_3C515) += 3c515.o
obj-$(CONFIG_EEXPRESS) += eexpress.o
obj-$(CONFIG_EEXPRESS_PRO) += eepro.o
obj-$(CONFIG_8139CP) += 8139cp.o
obj-$(CONFIG_8139TOO) += 8139too.o
obj-$(CONFIG_ZNET) += znet.o
obj-$(CONFIG_LAN_SAA9730) += saa9730.o
obj-$(CONFIG_DEPCA) += depca.o
obj-$(CONFIG_EWRK3) += ewrk3.o
obj-$(CONFIG_ATP) += atp.o
obj-$(CONFIG_NI5010) += ni5010.o
obj-$(CONFIG_NI52) += ni52.o
obj-$(CONFIG_NI65) += ni65.o
obj-$(CONFIG_ELPLUS) += 3c505.o
obj-$(CONFIG_AC3200) += ac3200.o 8390.o
obj-$(CONFIG_APRICOT) += 82596.o
obj-$(CONFIG_LASI_82596) += lasi_82596.o
obj-$(CONFIG_MVME16x_NET) += 82596.o
obj-$(CONFIG_BVME6000_NET) += 82596.o
# This is also a 82596 and should probably be merged
obj-$(CONFIG_LP486E) += lp486e.o
obj-$(CONFIG_ETH16I) += eth16i.o
obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o
obj-$(CONFIG_HPLANCE) += hplance.o 7990.o
obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o
obj-$(CONFIG_EQUALIZER) += eql.o
obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o
obj-$(CONFIG_MIPS_GT96100ETH) += gt96100eth.o
obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o
obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o
obj-$(CONFIG_BAGETLANCE) += bagetlance.o
obj-$(CONFIG_DECLANCE) += declance.o
obj-$(CONFIG_ATARILANCE) += atarilance.o
obj-$(CONFIG_ATARI_BIONET) += atari_bionet.o
obj-$(CONFIG_ATARI_PAMSNET) += atari_pamsnet.o
obj-$(CONFIG_A2065) += a2065.o
obj-$(CONFIG_HYDRA) += hydra.o 8390.o
obj-$(CONFIG_ARIADNE) += ariadne.o
obj-$(CONFIG_CS89x0) += cs89x0.o
obj-$(CONFIG_MACSONIC) += macsonic.o
obj-$(CONFIG_MACMACE) += macmace.o
obj-$(CONFIG_MAC89x0) += mac89x0.o
obj-$(CONFIG_TUN) += tun.o
obj-$(CONFIG_DL2K) += dl2k.o
obj-$(CONFIG_R8169) += r8169.o
obj-$(CONFIG_AMD8111_ETH) += amd8111e.o
obj-$(CONFIG_GAMECUBE_NET) += gc-net.o
obj-$(CONFIG_ARM) += arm/
obj-$(CONFIG_NET_FC) += fc/
obj-$(CONFIG_DEV_APPLETALK) += appletalk/
obj-$(CONFIG_TR) += tokenring/
obj-$(CONFIG_WAN) += wan/
obj-$(CONFIG_ARCNET) += arcnet/
obj-$(CONFIG_NET_PCMCIA) += pcmcia/
obj-$(CONFIG_NET_WIRELESS) += wireless/
obj-$(CONFIG_NET_TULIP) += tulip/
obj-$(CONFIG_HAMRADIO) += hamradio/
obj-$(CONFIG_IRDA) += irda/
--- NEW FILE: exi.h ---
#ifndef __exi_h
#define __exi_h
void exi_select(int channel, int device, int freq);
void exi_deselect(int channel);
#define EXI_READ 0
#define EXI_WRITE 1
void exi_imm(int channel, void *data, int len, int mode, int zero);
void exi_sync(int channel);
void exi_imm_ex(int channel, void *data, int len, int mode);
void exi_init(void);
#define EXI_EVENT_IRQ 0
#define EXI_EVENT_INSERT 1
#define EXI_EVENT_TC 2
typedef void (exi_irq_handler_t)(int channel, int event, void *context);
int exi_request_irq(int channel, int event, exi_irq_handler_t *handler, void *context);
int exi_free_irq(int channel, int event);
#endif
--- NEW FILE: gc-net.c ---
/* ------------------------------------------------------------------------- */
/* gc-bba.c GameCube BroadBand Adaptor Driver */
/* ------------------------------------------------------------------------- */
/* Copyright (C) 2004 Stefan Esser
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* ------------------------------------------------------------------------- */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/string.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <asm/system.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <asm/io.h>
#include "exi.h"
#define BBA_IRQ 4
#define IRQ_EXI 4
void gcif_irq_handler(int channel, int event, void *ct);
///////////////////////////////////////////////////////////////////////////////////////////////////////
// must be MOVED LATER
///////////////////////////////////////////////////////////////////////////////////////////////////////
/* exi_select: enable chip select, set speed */
void exi_select(int channel, int device, int freq)
{
volatile unsigned long *exi = (volatile unsigned long *)0xCC006800;
long d;
// exi_select
d = exi[channel * 5];
d &= 0x405;
d |= ((1<<device)<<7) | (freq << 4);
exi[channel*5] = d;
}
/* disable chipselect */
void exi_deselect(int channel)
{
volatile unsigned long *exi = (volatile unsigned long *)0xCC006800;
exi[channel * 5] &= 0x405;
}
/* dirty way for asynchronous reads */
static void *exi_last_addr;
static int exi_last_len;
/* mode?Read:Write len bytes to/from channel */
/* when read, data will be written back in exi_sync */
void exi_imm(int channel, void *data, int len, int mode, int zero)
{
volatile unsigned long *exi = (volatile unsigned long *)0xCC006800;
if (mode == EXI_WRITE)
exi[channel * 5 + 4] = *(unsigned long*)data;
exi[channel * 5 + 3] = ((len-1)<<4)|(mode<<2)|1;
if (mode == EXI_READ)
{
exi_last_addr = data;
exi_last_len = len;
} else
{
exi_last_addr = 0;
exi_last_len = 0;
}
}
/* Wait until transfer is done, write back data */
void exi_sync(int channel)
{
volatile unsigned long *exi = (volatile unsigned long *)0xCC006800;
while (exi[channel * 5 + 3] & 1);
if (exi_last_addr)
{
int i;
unsigned long d;
d = exi[channel * 5 + 4];
for (i=0; i<exi_last_len; ++i)
((unsigned char*)exi_last_addr)[i] = (d >> ((3-i)*8)) & 0xFF;
}
}
/* simple wrapper for transfers > 4bytes */
void exi_imm_ex(int channel, void *data, int len, int mode)
{
unsigned char *d = (unsigned char*)data;
while (len)
{
int tc = len;
if (tc > 4)
tc = 4;
exi_imm(channel, d, tc, mode, 0);
exi_sync(channel);
len-=tc;
d+=tc;
}
}
static exi_irq_handler_t *exi_handler[3 * 3]; // 3 channels, 3 events
static void *exi_handler_context[3 * 3];
static unsigned long exi_enable_mask[3];
void exi_refresh_enable(void)
{
int channel;
for (channel = 0; channel < 3; ++channel)
*(unsigned long*)(0xcc006800 + channel*0x14) |= 0x405; // exi_enable_mask[channel];
}
static inline int have_irq(int t)
{
if (exi_handler[t])
{
printk("CALL HANDLER\n");
exi_handler[t](t/3, t%3, exi_handler_context[t]);
return 1;
} else
{
printk("UNHANDLED EXI\n");
return 0;
}
}
void exi_interrupt_handler(int irq, void *c)
{
int ch;
for (ch = 0; ch < 3; ++ch)
{
unsigned long v = (*(unsigned long*)(0xcc006800 + ch * 0x14)); // & 0xC0F;
v &= v<<1;
if (v & 0x800)
have_irq(ch * 3 + EXI_EVENT_INSERT);
if (v & 8)
have_irq(ch * 3 + EXI_EVENT_TC);
if (v & 2)
have_irq(ch * 3 + EXI_EVENT_IRQ);
*(unsigned long*)(0xcc006800 + ch * 0x14) |= v;
}
}
void exi_interrupt_debug_handler(int irq, void *c)
{
int ch;
for (ch = 0; ch < 3; ++ch)
{
unsigned long v = (*(unsigned long*)(0xcc006800 + ch * 0x14)); // & 0xC0F;
v &= v<<1;
printk("ch %d c %08x\n", ch, (unsigned int)v);
if (v & 0x800)
if (!have_irq(ch * 3 + EXI_EVENT_INSERT))
; // v &= ~0x800;
if (v & 8)
if (!have_irq(ch * 3 + EXI_EVENT_TC))
; // v &= ~8;
if (v & 2)
if (!have_irq(ch * 3 + EXI_EVENT_IRQ))
; /// v &= ~2;
*(unsigned long*)(0xcc006800 + ch * 0x14) |= v;
}
}
void exi_init()
{
printk("EXI: init interrupts\n");
//request_irq(IRQ_EXI, exi_interrupt_handler, 0);
//request_debug_irq(IRQ_EXI, exi_interrupt_debug_handler, 0);
*(unsigned long*)(0xcc006814) |= 3<<10; // enable&clear irq for insertion
}
int exi_request_irq(int channel, int event, exi_irq_handler_t *handler, void *context)
{
if (exi_handler[channel * 3 + event])
{
printk("EXI: irq %d:%d already used!\n", channel, event);
return -1;
}
exi_handler[channel * 3 + event] = handler;
exi_handler_context[channel * 3 + event] = context;
switch (event)
{
case EXI_EVENT_TC:
*(unsigned long*)(0xcc006800 + channel*0x14) |= 3<<2; // enable&clear irq
exi_enable_mask[channel] |= 1 << 2;
break;
case EXI_EVENT_INSERT:
*(unsigned long*)(0xcc006800 + channel*0x14) |= 3<<10;
exi_enable_mask[channel] |= 1 << 10;
break;
case EXI_EVENT_IRQ:
*(unsigned long*)(0xcc006800 + channel*0x14) |= 3<<0;
exi_enable_mask[channel] |= 1 << 0;
break;
}
return 0;
}
int exi_free_irq(int channel, int event)
{
exi_handler[channel * 3 + event] = 0;
switch (event)
{
case EXI_EVENT_TC:
*(unsigned long*)(0xcc006800 + channel*0x14) &= ~(3<<2); // enable&clear irq
exi_enable_mask[channel] &= ~(1 << 2);
break;
case EXI_EVENT_INSERT:
*(unsigned long*)(0xcc006800 + channel*0x14) &= ~(3<<10);
exi_enable_mask[channel] &= ~(1 << 10);
break;
case EXI_EVENT_IRQ:
*(unsigned long*)(0xcc006800 + channel*0x14) &= ~(3<<0);
exi_enable_mask[channel] &= ~(1 << 0);
break;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
unsigned char eth_inb(int reg)
{
unsigned long val;
unsigned char res;
val = (reg << 8) | 0x80000000;
exi_select(0, 2, 5);
exi_imm(0, &val, 4, EXI_WRITE, 0);
exi_sync(0);
exi_imm(0, &res, 1, EXI_READ, 0);
exi_sync(0);
exi_deselect(0);
return res;
}
unsigned char eth_exi_inb_slow(int reg)
{
unsigned short val;
unsigned char res;
val = (reg << 8);
exi_select(0, 2, 5);
exi_imm(0, &val, 2, EXI_WRITE, 0);
exi_sync(0);
exi_imm(0, &res, 1, EXI_READ, 0);
exi_sync(0);
udelay(200);
exi_deselect(0);
return res;
}
void eth_outb(int reg, unsigned char byte)
{
unsigned long val;
val = (reg << 8)|0xC0000000;
exi_select(0, 2, 5);
exi_imm(0, &val, 4, EXI_WRITE, 0);
exi_sync(0);
exi_imm(0, &byte, 1, EXI_WRITE, 0);
exi_sync(0);
exi_deselect(0);
}
void eth_exi_outb(int reg, unsigned char byte)
{
unsigned short val;
val = (reg << 8)|0x4000;
exi_select(0, 2, 5);
exi_imm(0, &val, 2, EXI_WRITE, 0);
exi_sync(0);
exi_imm(0, &byte, 1, EXI_WRITE, 0);
exi_sync(0);
exi_deselect(0);
}
unsigned char eth_exi_inb(int reg)
{
unsigned short val;
unsigned char res;
val = reg << 8;
exi_select(0, 2, 5);
exi_imm(0, &val, 2, EXI_WRITE, 0);
exi_sync(0);
exi_imm(0, &res, 1, EXI_READ, 0);
exi_sync(0);
exi_deselect(0);
return res;
}
void eth_exi_ins(int reg, void *res, int len)
{
unsigned short val;
val = reg << 8;
exi_select(0, 2, 5);
exi_imm(0, &val, 2, EXI_WRITE, 0);
exi_sync(0);
exi_imm_ex(0, res, len, EXI_READ);
exi_sync(0);
exi_deselect(0);
}
void eth_exi_outs(int reg, void *res, int len)
{
unsigned short val;
val = (reg << 8)|0x4000;
exi_select(0, 2, 5);
exi_imm(0, &val, 2, EXI_WRITE, 0);
exi_sync(0);
exi_imm_ex(0, res, len, EXI_WRITE);
exi_sync(0);
exi_deselect(0);
}
void eth_ins(int reg, void *res, int len)
{
unsigned long val;
val = (reg << 8)|0x80000000;
exi_select(0, 2, 5);
exi_imm(0, &val, 4, EXI_WRITE, 0);
exi_sync(0);
exi_imm_ex(0, res, len, EXI_READ);
exi_sync(0);
exi_deselect(0);
}
void eth_outs(int reg, void *res, int len)
{
unsigned long val;
val = (reg << 8)|0xC0000000;
exi_select(0, 2, 5);
exi_imm(0, &val, 4, EXI_WRITE, 0);
exi_sync(0);
exi_imm_ex(0, res, len, EXI_WRITE);
exi_sync(0);
exi_deselect(0);
}
static spinlock_t gc_bba_lock;
#define RUNT 60 /* Too small Ethernet packet */
#define ETH_LEN 6
/*
* D-Link driver variables:
*/
static volatile int rx_page;
#define TX_PAGES 2
static volatile int tx_fifo[TX_PAGES];
static volatile int tx_fifo_in;
static volatile int tx_fifo_out;
static volatile int free_tx_pages = TX_PAGES;
static int was_down;
static irqreturn_t gc_bba_interrupt(int irq, void *dev_id, struct pt_regs * regs);
static int adapter_init(struct net_device *dev);
/*
static inline u8 de600_read_status(struct net_device *dev)
{
u8 status;
outb_p(STATUS, DATA_PORT);
status = inb(STATUS_PORT);
outb_p(NULL_COMMAND | HI_NIBBLE, DATA_PORT);
return status;
}
static inline u8 de600_read_byte(unsigned char type, struct net_device *dev)
{
// dev used by macros
u8 lo;
outb_p((type), DATA_PORT);
lo = ((unsigned char)inb(STATUS_PORT)) >> 4;
outb_p((type) | HI_NIBBLE, DATA_PORT);
return ((unsigned char)inb(STATUS_PORT) & (unsigned char)0xf0) | lo;
}
*/
/*
* Open/initialize the board. This is called (in the current kernel)
* after booting when 'ifconfig <dev->name> $IP_ADDR' is run (in rc.inet1).
*
* This routine should set everything up anew at each open, even
* registers that "should" only need to be set once at boot, so that
* there is a non-reboot way to recover if something goes wrong.
*/
static int gc_bba_open(struct net_device *dev)
{
unsigned long flags;
printk("gc_bba_open\n");
int ret = request_irq(BBA_IRQ, gc_bba_interrupt, 0, dev->name, dev);
if (ret) {
printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name, BBA_IRQ);
return ret;
}
spin_lock_irqsave(&gc_bba_lock, flags);
ret = adapter_init(dev);
spin_unlock_irqrestore(&gc_bba_lock, flags);
return ret;
}
/*
* The inverse routine to de600_open().
*/
static int gc_bba_close(struct net_device *dev)
{
printk("gc_bba_close\n");
// //select_nic();
rx_page = 0;
// de600_put_command(RESET);
// de600_put_command(STOP_RESET);
// de600_put_command(0);
// //select_prn();
free_irq(BBA_IRQ, dev);
return 0;
}
static struct net_device_stats *get_stats(struct net_device *dev)
{
return (struct net_device_stats *)(dev->priv);
}
static inline void trigger_interrupt(struct net_device *dev)
{
// de600_put_command(FLIP_IRQ);
// //select_prn();
// DE600_SLOW_DOWN;
// //select_nic();
// de600_put_command(0);
}
/*
* Copy a buffer to the adapter transmit page memory.
* Start sending.
*/
static int gc_bba_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
unsigned long flags;
int transmit_from;
int len;
int tickssofar;
u8 *buffer = skb->data;
int i;
if (free_tx_pages <= 0) { /* Do timeouts, to avoid hangs. */
tickssofar = jiffies - dev->trans_start;
if (tickssofar < 5)
return 1;
/* else */
printk(KERN_WARNING "%s: transmit timed out (%d), %s?\n", dev->name, tickssofar, "network cable problem");
/* Restart the adapter. */
spin_lock_irqsave(&gc_bba_lock, flags);
if (adapter_init(dev)) {
spin_unlock_irqrestore(&gc_bba_lock, flags);
return 1;
}
spin_unlock_irqrestore(&gc_bba_lock, flags);
}
/* Start real output */
printk("gc_bba_start_xmit:len=%d, page %d/%d\n", skb->len, tx_fifo_in, free_tx_pages);
if ((len = skb->len) < RUNT)
len = RUNT;
spin_lock_irqsave(&gc_bba_lock, flags);
spin_unlock_irqrestore(&gc_bba_lock, flags);
dev_kfree_skb(skb);
return 0;
}
char buffer[3500];
static char *gc_input(void *v)
{
// struct gcif *gcif=(struct gcif*)netif->state;
char *p, *q;
unsigned short len, p_read, p_write;
int i;
int ptr;
p_write = eth_inb(0x16);
p_write |= eth_inb(0x17) << 8;
p_read = eth_inb(0x18);
p_read |= eth_inb(0x19) << 8;
// printk("w %x r %x\n", p_write, p_read);
if (p_read == p_write)
{
printk("nothing left.\n");
return 0;
}
unsigned char descr[4];
eth_outb(0x3a, 2);
if (eth_inb(0x3a) & 2)
{
printk("NO DATA AVAILABLE!\n");
return 0;
}
len=0;
descr[0] = eth_inb((p_read<<8) + 0);
descr[1] = eth_inb((p_read<<8) + 1);
descr[2] = eth_inb((p_read<<8) + 2);
descr[3] = eth_inb((p_read<<8) + 3);
len = (descr[1] >> 4) | (descr[2]<<4);
ptr = (p_read << 8) + 4;
for (i=0; i<len; ++i)
{
if (ptr == 0x1000) // wrap around
ptr = 0x100;
buffer[i]=eth_inb(ptr++); // skip descriptor
}
eth_outb(0x18, descr[0] & 0xFF);
eth_outb(0x19, descr[1] & 0xFF);
// i=0;
// p = pbuf_alloc(PBUF_LINK, len, PBUF_POOL);
// if(p != NULL) {
/* We iterate over the pbuf chain until we have read the entire
packet into the pbuf. */
// for(q = p; q != NULL; q = q->next) {
/* Read enough bytes to fill this pbuf in the chain. The
avaliable data in the pbuf is given by the q->len
variable. */
/* read data into(q->payload, q->len); */
// memcpy(q->payload, buffer+i, q->len);
// i+=q->len;
// exi_imm_ex(0, q->payload, q->len, EXI_READ);
// }
// }
return p;
}
static void inline gcif_service(void *netif)
{
// struct gcif *gcif;
// gcif = netif->state;
unsigned short p_read, p_write;
int status = eth_inb(9) & eth_inb(8);
printk("gcif_service: status %08x\n", status);
if (!status)
printk("?? GC irq but no irq ??\n");
if (status & 2)
{
while (1)
{
p_write = eth_inb(0x16);
p_write |= eth_inb(0x17) << 8;
p_read = eth_inb(0x18);
p_read |= eth_inb(0x19) << 8;
if (p_write == p_read)
break;
gc_input(NULL);
printk("Break\n");
break;
}
eth_outb(9, 2);
}
if (status & 8)
{
printk("receive error :(\n");
eth_outb(9, 8);
}
if (status & ~(8|2))
{
printk("status %02x\n", status);
eth_outb(9, ~(8|2));
}
}
/*
* The typical workload of the driver:
* Handle the network interface interrupts.
*/
static irqreturn_t gc_bba_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
struct net_device *dev = dev_id;
u8 irq_status;
int retrig = 0;
int boguscount = 0;
/* This might just as well be deleted now, no crummy drivers present :-) */
if ((dev == NULL) || (BBA_IRQ != irq)) {
printk(KERN_ERR "%s: bogus interrupt %d\n", dev?dev->name:"GC_BBA", irq);
return IRQ_NONE;
}
spin_lock(&gc_bba_lock);
int ch;
for (ch = 0; ch < 3; ++ch)
{
unsigned long v = (*(unsigned long*)(0xcc006800 + ch * 0x14)); // & 0xC0F;
v &= v<<1;
if (v & 0x800)
have_irq(ch * 3 + EXI_EVENT_INSERT);
if (v & 8)
have_irq(ch * 3 + EXI_EVENT_TC);
if (v & 2)
have_irq(ch * 3 + EXI_EVENT_IRQ);
*(unsigned long*)(0xcc006800 + ch * 0x14) |= v;
}
if (retrig)
trigger_interrupt(dev);
spin_unlock(&gc_bba_lock);
return IRQ_HANDLED;
// struct netif *netif = (struct netif*)ct;
int s;
eth_exi_outb(2, 0);
s = eth_exi_inb(3);
if (s & 0x80)
{
eth_exi_outb(3, 0x80);
gcif_service(NULL);
eth_exi_outb(2, 0xF8);
return;
}
if (s & 0x40)
{
printk("GCIF - EXI - 0x40!\n");
eth_exi_outb(3, 0x40);
eth_exi_outb(2, 0xF8);
return;
}
if (s & 0x20)
{
printk("GCIF - EXI - CMDERR!\n");
eth_exi_outb(3, 0x20);
eth_exi_outb(2, 0xF8);
return;
}
if (s & 0x10)
{
printk("GCIF - EXI - patchtru!\n");
eth_exi_outb(3, 0x10);
eth_exi_outb(2, 0xF8);
return;
}
if (s & 0x08)
{
printk("GCIF - EXI - HASH function\n");
eth_exi_outb(3, 0x08);
eth_exi_outb(2, 0xF8);
return;
}
printk("GCIF - EXI - ?? %02x\n", s);
eth_exi_outb(2, 0xF8);
if (retrig)
trigger_interrupt(dev);
spin_unlock(&gc_bba_lock);
return IRQ_HANDLED;
}
int __init gc_bba_probe(struct net_device *dev)
{
int i;
static struct net_device_stats gc_bba_netstats;
short s=0;
long l;
/*dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);*/
printk("gc_bba_probe\n");
SET_MODULE_OWNER(dev);
printk(KERN_INFO "%s: Nintendo GameCube broadband adapter", dev->name);
/* probe for adapter */
rx_page = 0;
//select_nic();
exi_select(0, 2, 5);
exi_imm_ex(0, &s, 2, EXI_WRITE);
exi_imm_ex(0, &l, 4, EXI_READ);
exi_deselect(0);
printk(": %u\n", l);
if (l != 0x4020200) {
printk("BBA not found");
return -ENODEV;
}
printk("initializing BBA...\n");
eth_outb(0x60, 0); // unknown
udelay(10000);
eth_exi_inb_slow(0xF);
udelay(10000);
eth_outb(0, 1); // reset
udelay(10000);
eth_outb(0, 0); // /reset
eth_exi_outs(4, "\xd1\x07\x75\x75", 2);
eth_exi_outb(5, 0x4e);
printk("BBA %02x %02x %02x %02x %02x %02x %02x %02x\n",
eth_exi_inb(0), eth_exi_inb(1), eth_exi_inb(2), eth_exi_inb(3),
eth_exi_inb(4), eth_exi_inb(5), eth_exi_inb(6), eth_exi_inb(7));
eth_outb(0x5b, eth_inb(0x5b)&~(1<<7));
eth_outb(0x5e, 1);
eth_outb(0x5c, eth_inb(0x5c)|4);
eth_outb(1, 0x11);
// eth_outb(1, 0);
eth_outb(0x50, 0x80);
udelay(10000);
// recvinit
eth_outb(0xA, 0x1);
eth_outb(0xB, 0x0);
eth_outb(0x16, 0x1);
eth_outb(0x17, 0x0);
eth_outb(0x18, 0x1);
eth_outb(0x19, 0x0);
eth_outb(0x1a, 0xF);
eth_outb(0x1b, 0);
eth_outb(1, (eth_inb(1) & 0xFE) | 0x12);
eth_outb(0, 8);
eth_outb(0x32, 8);
eth_ins(0x20, dev->dev_addr, ETH_LEN);
printk("MAC ADDRESS %02x:%02x:%02x:%02x:%02x:%02x\n",
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
/* Get the adapter ethernet address from the ROM */
for (i = 0; i < ETH_ALEN; i++) {
dev->broadcast[i] = 0xff;
}
eth_exi_outb(0x2, 0xFF);
eth_exi_outb(0x3, 0xFF);
eth_outb(8, 0xFF); // enable all IRQs
eth_outb(9, 0xFF); // clear all irqs
printk("after all: irq mask %x %x\n", eth_inb(8), eth_inb(9));
/* Initialize the device structure. */
dev->priv = &gc_bba_netstats;
memset(dev->priv, 0, sizeof(struct net_device_stats));
dev->get_stats = get_stats;
dev->open = gc_bba_open;
dev->stop = gc_bba_close;
dev->hard_start_xmit = &gc_bba_start_xmit;
ether_setup(dev);
dev->flags&=~IFF_MULTICAST;
return 0;
}
static int adapter_init(struct net_device *dev)
{
int i;
//select_nic();
rx_page = 0; /* used by RESET */
printk("initializing BBA...\n");
eth_outb(0x60, 0); // unknown
udelay(10000);
eth_exi_inb_slow(0xF);
udelay(10000);
eth_outb(0, 1); // reset
udelay(10000);
eth_outb(0, 0); // /reset
eth_exi_outs(4, "\xd1\x07\x75\x75", 2);
eth_exi_outb(5, 0x4e);
printk("BBA %02x %02x %02x %02x %02x %02x %02x %02x\n",
eth_exi_inb(0), eth_exi_inb(1), eth_exi_inb(2), eth_exi_inb(3),
eth_exi_inb(4), eth_exi_inb(5), eth_exi_inb(6), eth_exi_inb(7));
eth_outb(0x5b, eth_inb(0x5b)&~(1<<7));
eth_outb(0x5e, 1);
eth_outb(0x5c, eth_inb(0x5c)|4);
eth_outb(1, 0x11);
// eth_outb(1, 0);
eth_outb(0x50, 0x80);
udelay(10000);
// recvinit
eth_outb(0xA, 0x1);
eth_outb(0xB, 0x0);
eth_outb(0x16, 0x1);
eth_outb(0x17, 0x0);
eth_outb(0x18, 0x1);
eth_outb(0x19, 0x0);
eth_outb(0x1a, 0xF);
eth_outb(0x1b, 0);
eth_outb(1, (eth_inb(1) & 0xFE) | 0x12);
eth_outb(0, 8);
eth_outb(0x32, 8);
eth_ins(0x20, dev->dev_addr, ETH_LEN);
printk("MAC ADDRESS %02x:%02x:%02x:%02x:%02x:%02x\n",
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
/* Get the adapter ethernet address from the ROM */
for (i = 0; i < ETH_ALEN; i++) {
dev->broadcast[i] = 0xff;
}
// eth_ins(0x20, dev->ethaddr->addr, 6);
// printk("MAC ADDRESS %02x:%02x:%02x:%02x:%02x:%02x\n",
// gcif->ethaddr->addr[0], gcif->ethaddr->addr[1], gcif->ethaddr->addr[2],
// gcif->ethaddr->addr[3], gcif->ethaddr->addr[4], gcif->ethaddr->addr[5]);
exi_request_irq(2, EXI_EVENT_IRQ, gcif_irq_handler, NULL);
eth_exi_outb(0x2, 0xFF);
eth_exi_outb(0x3, 0xFF);
eth_outb(8, 0xFF); // enable all IRQs
eth_outb(9, 0xFF); // clear all irqs
printk("after all: irq mask %x %x\n", eth_inb(8), eth_inb(9));
netif_start_queue(dev);
return 0; /* OK */
}
static struct net_device gc_bba_dev;
static int __init gc_bba_init(void)
{
printk("gc_bba_init\n");
spin_lock_init(&gc_bba_lock);
gc_bba_dev.init = gc_bba_probe;
if (register_netdev(&gc_bba_dev) != 0)
return -EIO;
return 0;
}
static void __exit gc_bba_exit(void)
{
printk("gc_bba_exit\n");
unregister_netdev(&gc_bba_dev);
}
void gcif_irq_handler(int channel, int event, void *ct)
{
// struct netif *netif = (struct netif*)ct;
int s;
eth_exi_outb(2, 0);
s = eth_exi_inb(3);
if (s & 0x80)
{
eth_exi_outb(3, 0x80);
gcif_service(NULL);
eth_exi_outb(2, 0xF8);
return;
}
if (s & 0x40)
{
printk("GCIF - EXI - 0x40!\n");
eth_exi_outb(3, 0x40);
eth_exi_outb(2, 0xF8);
return;
}
if (s & 0x20)
{
printk("GCIF - EXI - CMDERR!\n");
eth_exi_outb(3, 0x20);
eth_exi_outb(2, 0xF8);
return;
}
if (s & 0x10)
{
printk("GCIF - EXI - patchtru!\n");
eth_exi_outb(3, 0x10);
eth_exi_outb(2, 0xF8);
return;
}
if (s & 0x08)
{
printk("GCIF - EXI - HASH function\n");
eth_exi_outb(3, 0x08);
eth_exi_outb(2, 0xF8);
return;
}
printk("GCIF - EXI - ?? %02x\n", s);
eth_exi_outb(2, 0xF8);
}
module_init(gc_bba_init);
module_exit(gc_bba_exit);
MODULE_AUTHOR("Stefan Esser <se@...>");
MODULE_DESCRIPTION("Nintendo GameCube BBA Ethernet driver");
MODULE_LICENSE("GPL");
|