From: <mi...@pr...> - 2004-01-31 02:48:46
|
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...@no...>"); MODULE_DESCRIPTION("Nintendo GameCube BBA Ethernet driver"); MODULE_LICENSE("GPL"); |