diff --git a/debian/patches/bugfix/m68k/2.6.24/133-arch.diff b/debian/patches/bugfix/m68k/2.6.24/133-arch.diff deleted file mode 100644 index 3a885d37f..000000000 --- a/debian/patches/bugfix/m68k/2.6.24/133-arch.diff +++ /dev/null @@ -1,23 +0,0 @@ -Subject: [PATCH] Local m68k changes - -Local m68k changes, _NEVER_ to be submitted upstream: - - Force ARCH to be m68k - - Append `-m68k' to EXTRAVERSION - -Signed-off-by: Geert Uytterhoeven for m68k CVS only ---- - Makefile | 2 +- - localversion.m68k | 1 + - 2 files changed, 2 insertions(+), 1 deletion(-) - ---- a/Makefile -+++ b/Makefile -@@ -190,7 +190,7 @@ SUBARCH := $(shell uname -m | sed -e s/i - # Default value for CROSS_COMPILE is not to prefix executables - # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile - --ARCH ?= $(SUBARCH) -+ARCH ?= m68k - CROSS_COMPILE ?= - - # Architecture as present in compile.h diff --git a/debian/patches/bugfix/m68k/2.6.24/143-ioext.diff b/debian/patches/bugfix/m68k/2.6.24/143-ioext.diff new file mode 100644 index 000000000..561552247 --- /dev/null +++ b/debian/patches/bugfix/m68k/2.6.24/143-ioext.diff @@ -0,0 +1,1351 @@ +To: linus, alan +Cc: lkml +Subject: [PATCH] Amiga GVP I/O Extender PLIP + +From: Linux/m68k legacy + +Add a PLIP driver for the Amiga GVP I/O Extender's parallel port +--- + drivers/char/16c552.h | 165 +++++++ + drivers/char/ioext.h | 107 ++++ + drivers/char/plip_ioext.c | 1057 ++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 1329 insertions(+) + +--- /dev/null ++++ b/drivers/char/16c552.h +@@ -0,0 +1,165 @@ ++/* ++ * Definitions for the 16c552 DACE ++ * (dual-asynchronous-communications-element) used on the GVP ++ * IO-Extender. ++ * ++ * Basically this is two 16c550 uarts's and a parallel port, which is ++ * why the serial definitions should be valid for the 16c550 uart ++ * aswell. ++ * ++ * Data was taken from National Semiconductors duart 16c552 ++ * data-sheets and the Texas Instruments DACE 16c552 data-sheets (the ++ * NS version of the chip is _non_ standard and their data-sheets did ++ * cost me several wasted hours of work). ++ * ++ * This file is (C) 1995 Jes Sorensen (jds@kom.auc.dk) ++ * ++ * Moved from drivers/char/ to include/linux/, because it's useful ++ * on more than just the one card. I'm using it on the hp300 DCA ++ * serial driver, for example. ++ * -- Peter Maydell 05/1998 ++ */ ++ ++#ifndef _16C552_H_ ++#define _16C552_H_ ++ ++/* Serial stuff */ ++ ++struct uart_16c550 { ++ volatile u_char skip0; ++ volatile u_char RBR; ++ volatile u_char skip1; ++ volatile u_char IER; ++ volatile u_char skip2; ++ volatile u_char IIR; ++ volatile u_char skip3; ++ volatile u_char LCR; ++ volatile u_char skip4; ++ volatile u_char MCR; ++ volatile u_char skip5; ++ volatile u_char LSR; ++ volatile u_char skip6; ++ volatile u_char MSR; ++ volatile u_char skip7; ++ volatile u_char SCR; ++}; ++ ++#define THR RBR ++#define FCR IIR ++#define DLL RBR ++#define DLM IER ++#define AFR IIR ++ ++/* ++ * Bit-defines for the various registers. ++ */ ++ ++ ++/* IER */ ++ ++#define ERDAI (1<<0) ++#define ETHREI (1<<1) ++#define ELSI (1<<2) ++#define EMSI (1<<3) ++ ++/* IIR - Interrupt Ident. Register */ ++ ++#define IRQ_PEND (1<<0) /* NOTE: IRQ_PEND=0 implies irq pending */ ++#define IRQ_ID1 (1<<1) ++#define IRQ_ID2 (1<<2) ++#define IRQ_ID3 (1<<3) ++#define FIFO_ENA0 (1<<6) /* Both these are set when FCR(1<<0)=1 */ ++#define FIFO_ENA1 (1<<7) ++ ++#define IRQ_RLS (IRQ_ID1 | IRQ_ID2) ++#define IRQ_RDA (IRQ_ID2) ++#define IRQ_CTI (IRQ_ID2 | IRQ_ID3) ++#define IRQ_THRE (IRQ_ID1) ++#define IRQ_MS 0 ++ ++/* FCR - FIFO Control Register */ ++ ++#define FIFO_ENA (1<<0) ++#define RCVR_FIFO_RES (1<<1) ++#define XMIT_FIFO_RES (1<<2) ++#define DMA_MODE_SEL (1<<3) ++#define RCVR_TRIG_LSB (1<<6) ++#define RCVR_TRIG_MSB (1<<7) ++ ++#define FIFO_TRIG_1 0x00 ++#define FIFO_TRIG_4 RCVR_TRIG_LSB ++#define FIFO_TRIG_8 RCVR_TRIG_MSB ++#define FIFO_TRIG_14 RCVR_TRIG_LSB|RCVR_TRIG_MSB ++ ++/* LCR - Line Control Register */ ++ ++#define WLS0 (1<<0) ++#define WLS1 (1<<1) ++#define STB (1<<2) ++#define PEN (1<<3) ++#define EPS (1<<4) ++#define STICK_PARITY (1<<5) ++#define SET_BREAK (1<<6) ++#define DLAB (1<<7) ++ ++#define data_5bit 0x00 ++#define data_6bit 0x01 ++#define data_7bit 0x02 ++#define data_8bit 0x03 ++ ++ ++/* MCR - Modem Control Register */ ++ ++#define DTR (1<<0) ++#define RTS (1<<1) ++#define OUT1 (1<<2) ++#define OUT2 (1<<3) ++#define LOOP (1<<4) ++ ++/* LSR - Line Status Register */ ++ ++#define DR (1<<0) ++#define OE (1<<1) ++#define PE (1<<2) ++#define FE (1<<3) ++#define BI (1<<4) ++#define THRE (1<<5) ++#define TEMT (1<<6) ++#define RCVR_FIFO_ERR (1<<7) ++ ++/* MSR - Modem Status Register */ ++ ++#define DCTS (1<<0) ++#define DDSR (1<<1) ++#define TERI (1<<2) ++#define DDCD (1<<3) ++#define CTS (1<<4) ++#define DSR (1<<5) ++#define RING_I (1<<6) ++#define DCD (1<<7) ++ ++/* AFR - Alternate Function Register */ ++ ++#define CONCUR_WRITE (1<<0) ++#define BAUDOUT (1<<1) ++#define RXRDY (1<<2) ++ ++/* Parallel stuff */ ++ ++/* ++ * Unfortunately National Semiconductors did not supply the ++ * specifications for the parallel port in the chip :-( ++ * TI succed though, so here they are :-) ++ * ++ * Defines for the bits can be found by including ++ */ ++struct IOEXT_par { ++ volatile u_char skip0; ++ volatile u_char DATA; ++ volatile u_char skip1; ++ volatile u_char STATUS; ++ volatile u_char skip2; ++ volatile u_char CTRL; ++}; ++ ++#endif +--- /dev/null ++++ b/drivers/char/ioext.h +@@ -0,0 +1,107 @@ ++/* ++ * Shared data structure for GVP IO-Extender support. ++ * ++ * Merge of ioext.h and ser_ioext.h ++ */ ++#ifndef _IOEXT_H_ ++#define _IOEXT_H_ ++ ++#include ++ ++#include "16c552.h" ++ ++#define MAX_IOEXT 5 /* ++ * The maximum number of io-extenders is 5, as you ++ * can't have more than 5 ZII boards in any Amiga. ++ */ ++ ++#define UART_CLK 7372800 ++ ++#define IOEXT_BAUD_BASE (UART_CLK / 16) ++ ++#define IOEXT_MAX_LINES 2 ++ ++#define IOEXT_PAR_PLIP 0x0001 ++#define IOEXT_PAR_LP 0x0002 ++ ++ ++/* ++ * Macros for the serial driver. ++ */ ++#define curruart(info) ((struct uart_16c550 *)(info->port)) ++ ++#define ser_DTRon(info) curruart(info)->MCR |= DTR ++#define ser_RTSon(info) curruart(info)->MCR |= RTS ++#define ser_DTRoff(info) curruart(info)->MCR &= ~DTR ++#define ser_RTSoff(info) curruart(info)->MCR &= ~RTS ++ ++ ++/* ++ * CNTR defines (copied from the GVP SCSI-driver file gvp11.h ++ */ ++#define GVP_BUSY (1<<0) ++#define GVP_IRQ_PEND (1<<1) ++#define GVP_IRQ_ENA (1<<3) ++#define GVP_DIR_WRITE (1<<4) ++ ++ ++/* ++ * CTRL defines ++ */ ++#define PORT0_MIDI (1<<0) /* CLR = DRIVERS SET = MIDI */ ++#define PORT1_MIDI (1<<1) /* CLR = DRIVERS SET = MIDI */ ++#define PORT0_DRIVER (1<<2) /* CLR = RS232, SET = MIDI */ ++#define PORT1_DRIVER (1<<3) /* CLR = RS232, SET = MIDI */ ++#define IRQ_SEL (1<<4) /* CLR = INT2, SET = INT6 */ ++#define ROM_BANK_SEL (1<<5) /* CLR = LOW 32K, SET = HIGH 32K */ ++#define PORT0_CTRL (1<<6) /* CLR = RTSx or RXRDYx, SET = RTSx ONLY */ ++#define PORT1_CTRL (1<<7) /* CLR = RTSx or RXRDYx, SET = RTSx ONLY */ ++ ++ ++/* ++ * This is the struct describing the registers on the IO-Extender. ++ * NOTE: The board uses a dual uart (16c552), which should be equal to ++ * two 16c550 uarts. ++ */ ++typedef struct { ++ char gap0[0x41]; ++ volatile unsigned char CNTR; /* GVP DMAC CNTR (status register) */ ++ char gap1[0x11e]; ++ struct uart_16c550 uart0; /* The first uart */ ++ char gap2[0xf0]; ++ struct uart_16c550 uart1; /* The second uart */ ++ char gap3[0xf0]; ++ struct IOEXT_par par; /* The parallel port */ ++ char gap4[0xfb]; ++ volatile unsigned char CTRL; /* The control-register on the board */ ++} IOEXT_struct; ++ ++ ++typedef struct { ++ int num_uarts; ++ int line[IOEXT_MAX_LINES]; ++ volatile struct uart_16c550 *uart[IOEXT_MAX_LINES]; ++ IOEXT_struct *board; ++ int spurious_count; ++ unsigned char par_use; /* IOEXT_PAR_xxx */ ++#if defined(CONFIG_GVPIOEXT_PLIP) || defined(CONFIG_GVPIOEXT_PLIP_MODULE) ++ struct nt_device *dev; ++#endif ++#if defined(CONFIG_GVPIOEXT_LP) || defined(CONFIG_GVPIOEXT_LP_MODULE) ++ struct lp_struct *lp_table; ++ int lp_dev; ++ int lp_interrupt; ++#endif ++} IOExtInfoType; ++ ++/* Number of detected boards. */ ++extern int ioext_num; ++extern IOExtInfoType ioext_info[MAX_IOEXT]; ++ ++void ioext_plip_interrupt(struct net_device *dev, int *spurious_count); ++void ioext_lp_interrupt(int dev, int *spurious_count); ++ ++extern struct net_device ioext_dev_plip[3]; ++extern struct lp_struct ioext_lp_table[1]; ++ ++#endif +--- /dev/null ++++ b/drivers/char/plip_ioext.c +@@ -0,0 +1,1057 @@ ++/* ++ * plip_ioext: A parallel port "network" driver for GVP IO-Extender. ++ * ++ * Authors: See drivers/net/plip.c ++ * IO-Extender version by Steve Bennett, ++ * ++ * This driver is for use with a 5-bit cable (LapLink (R) cable). ++ */ ++ ++static const char *version = "NET3 PLIP version 2.2/m68k"; ++ ++#define __NO_VERSION__ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++/*#include */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "ioext.h" ++ ++#define DEBUG 0 ++ ++/* Map 'struct device *' to our control structure */ ++#define PLIP_DEV(DEV) (&ioext_info[(DEV)->irq]) ++ ++/************************************************************************ ++** ++** PLIP definitions ++** ++************************************************************************* ++*/ ++ ++/* Use 0 for production, 1 for verification, >2 for debug */ ++#ifndef NET_DEBUG ++#define NET_DEBUG 2 ++#endif ++static unsigned int net_debug = NET_DEBUG; ++ ++/* In micro second */ ++#define PLIP_DELAY_UNIT 1 ++ ++/* Connection time out = PLIP_TRIGGER_WAIT * PLIP_DELAY_UNIT usec */ ++#define PLIP_TRIGGER_WAIT 500 ++ ++/* Nibble time out = PLIP_NIBBLE_WAIT * PLIP_DELAY_UNIT usec */ ++#define PLIP_NIBBLE_WAIT 3000 ++ ++#define PAR_DATA(dev) ((dev)->base_addr+0) ++#define PAR_STATUS(dev) ((dev)->base_addr+2) ++#define PAR_CONTROL(dev) ((dev)->base_addr+4) ++ ++static void enable_par_irq(struct device *dev, int on); ++static int plip_init(struct device *dev); ++ ++/* Bottom halfs */ ++static void plip_kick_bh(struct device *dev); ++static void plip_bh(struct device *dev); ++ ++/* Functions for DEV methods */ ++static int plip_rebuild_header(struct sk_buff *skb); ++static int plip_tx_packet(struct sk_buff *skb, struct device *dev); ++static int plip_open(struct device *dev); ++static int plip_close(struct device *dev); ++static struct enet_statistics *plip_get_stats(struct device *dev); ++static int plip_config(struct device *dev, struct ifmap *map); ++static int plip_ioctl(struct device *dev, struct ifreq *ifr, int cmd); ++ ++enum plip_connection_state { ++ PLIP_CN_NONE=0, ++ PLIP_CN_RECEIVE, ++ PLIP_CN_SEND, ++ PLIP_CN_CLOSING, ++ PLIP_CN_ERROR ++}; ++ ++enum plip_packet_state { ++ PLIP_PK_DONE=0, ++ PLIP_PK_TRIGGER, ++ PLIP_PK_LENGTH_LSB, ++ PLIP_PK_LENGTH_MSB, ++ PLIP_PK_DATA, ++ PLIP_PK_CHECKSUM ++}; ++ ++enum plip_nibble_state { ++ PLIP_NB_BEGIN, ++ PLIP_NB_1, ++ PLIP_NB_2, ++}; ++ ++struct plip_local { ++ enum plip_packet_state state; ++ enum plip_nibble_state nibble; ++ union { ++ struct { ++#if defined(__LITTLE_ENDIAN) ++ unsigned char lsb; ++ unsigned char msb; ++#elif defined(__BIG_ENDIAN) ++ unsigned char msb; ++ unsigned char lsb; ++#else ++#error "Please fix the endianness defines in " ++#endif ++ } b; ++ unsigned short h; ++ } length; ++ unsigned short byte; ++ unsigned char checksum; ++ unsigned char data; ++ struct sk_buff *skb; ++}; ++ ++struct net_local { ++ struct enet_statistics enet_stats; ++ struct tq_struct immediate; ++ struct tq_struct deferred; ++ struct plip_local snd_data; ++ struct plip_local rcv_data; ++ unsigned long trigger; ++ unsigned long nibble; ++ enum plip_connection_state connection; ++ unsigned short timeout_count; ++ char is_deferred; ++ int (*orig_rebuild_header)(struct sk_buff *skb); ++}; ++ ++struct device ioext_dev_plip[] = { ++ { ++ "plip0", ++ 0, 0, 0, 0, /* memory */ ++ 0, 0, /* base, irq */ ++ 0, 0, 0, NULL, plip_init ++ }, ++ { ++ "plip1", ++ 0, 0, 0, 0, /* memory */ ++ 0, 0, /* base, irq */ ++ 0, 0, 0, NULL, plip_init ++ }, ++ { ++ "plip2", ++ 0, 0, 0, 0, /* memory */ ++ 0, 0, /* base, irq */ ++ 0, 0, 0, NULL, plip_init ++ } ++}; ++ ++/* ++ * Check for and handle an interrupt for this PLIP device. ++ * ++ */ ++void ioext_plip_interrupt(struct device *dev, int *spurious_count) ++{ ++ struct net_local *nl; ++ struct plip_local *rcv; ++ unsigned char c0; ++ unsigned long flags; ++ ++ nl = (struct net_local *)dev->priv; ++ rcv = &nl->rcv_data; ++ ++ c0 = z_readb(PAR_STATUS(dev)); ++ ++ if (dev->interrupt) { ++ return; ++ } ++ ++ if ((c0 & 0xf8) != 0xc0) { ++ /* Not for us */ ++ ++*spurious_count; ++ return; ++ } ++ ++ *spurious_count = 0; ++ dev->interrupt = 1; ++ ++ local_irq_save(flags); ++ ++ switch (nl->connection) { ++ case PLIP_CN_CLOSING: ++ dev->tbusy = 0; ++ case PLIP_CN_NONE: ++ case PLIP_CN_SEND: ++ dev->last_rx = jiffies; ++ rcv->state = PLIP_PK_TRIGGER; ++ nl->connection = PLIP_CN_RECEIVE; ++ nl->timeout_count = 0; ++ queue_task(&nl->immediate, &tq_immediate); ++ mark_bh(IMMEDIATE_BH); ++ local_irq_restore(flags); ++#if 0 ++ printk("%s: receive irq in SEND/NONE/CLOSING (%d) ok\n", ++ dev->name, nl->connection); ++#endif ++ break; ++ ++ case PLIP_CN_RECEIVE: ++ local_irq_restore(flags); ++ printk("%s: receive interrupt when receiving packet\n", ++ dev->name); ++ break; ++ ++ case PLIP_CN_ERROR: ++ local_irq_restore(flags); ++ printk("%s: receive interrupt in error state\n", dev->name); ++ break; ++ } ++} ++ ++ ++/* Bottom half handler for the delayed request. ++ This routine is kicked by do_timer(). ++ Request `plip_bh' to be invoked. */ ++static void ++plip_kick_bh(struct device *dev) ++{ ++ struct net_local *nl = (struct net_local *)dev->priv; ++ ++ if (nl->is_deferred) { ++ queue_task(&nl->immediate, &tq_immediate); ++ mark_bh(IMMEDIATE_BH); ++ } ++} ++ ++/* Forward declarations of internal routines */ ++static int plip_none(struct device *, struct net_local *, ++ struct plip_local *, struct plip_local *); ++static int plip_receive_packet(struct device *, struct net_local *, ++ struct plip_local *, struct plip_local *); ++static int plip_send_packet(struct device *, struct net_local *, ++ struct plip_local *, struct plip_local *); ++static int plip_connection_close(struct device *, struct net_local *, ++ struct plip_local *, struct plip_local *); ++static int plip_error(struct device *, struct net_local *, ++ struct plip_local *, struct plip_local *); ++static int plip_bh_timeout_error(struct device *dev, struct net_local *nl, ++ struct plip_local *snd, ++ struct plip_local *rcv, ++ int error); ++ ++#define OK 0 ++#define TIMEOUT 1 ++#define ERROR 2 ++ ++typedef int (*plip_func)(struct device *dev, struct net_local *nl, ++ struct plip_local *snd, struct plip_local *rcv); ++ ++static plip_func connection_state_table[] = ++{ ++ plip_none, ++ plip_receive_packet, ++ plip_send_packet, ++ plip_connection_close, ++ plip_error ++}; ++ ++/* ++** enable_par_irq() ++** ++** Enable or disable parallel irq for 'dev' according to 'on'. ++** ++** It is NOT possible to disable only the parallel irq. ++** So we disable the board interrupt instead. This means that ++** during reception of a PLIP packet, no serial interrupts can ++** happen. Sorry. ++*/ ++static void enable_par_irq(struct device *dev, int on) ++{ ++ if (on) { ++ PLIP_DEV(dev)->board->CNTR |= GVP_IRQ_ENA; ++ } ++ else { ++ PLIP_DEV(dev)->board->CNTR &= ~GVP_IRQ_ENA; ++ } ++} ++ ++/* Bottom half handler of PLIP. */ ++static void ++plip_bh(struct device *dev) ++{ ++ struct net_local *nl = (struct net_local *)dev->priv; ++ struct plip_local *snd = &nl->snd_data; ++ struct plip_local *rcv = &nl->rcv_data; ++ plip_func f; ++ int r; ++ ++ nl->is_deferred = 0; ++ f = connection_state_table[nl->connection]; ++ if ((r = (*f)(dev, nl, snd, rcv)) != OK ++ && (r = plip_bh_timeout_error(dev, nl, snd, rcv, r)) != OK) { ++ nl->is_deferred = 1; ++ queue_task(&nl->deferred, &tq_timer); ++ } ++} ++ ++static int ++plip_bh_timeout_error(struct device *dev, struct net_local *nl, ++ struct plip_local *snd, struct plip_local *rcv, ++ int error) ++{ ++ unsigned char c0; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ if (nl->connection == PLIP_CN_SEND) { ++ ++ if (error != ERROR) { /* Timeout */ ++ nl->timeout_count++; ++ if ((snd->state == PLIP_PK_TRIGGER ++ && nl->timeout_count <= 10) ++ || nl->timeout_count <= 3) { ++ local_irq_restore(flags); ++ /* Try again later */ ++ return TIMEOUT; ++ } ++ c0 = z_readb(PAR_STATUS(dev)); ++ printk(KERN_INFO "%s: transmit timeout(%d,%02x)\n", ++ dev->name, snd->state, c0); ++ } ++ nl->enet_stats.tx_errors++; ++ nl->enet_stats.tx_aborted_errors++; ++ } else if (nl->connection == PLIP_CN_RECEIVE) { ++ if (rcv->state == PLIP_PK_TRIGGER) { ++ /* Transmission was interrupted. */ ++ local_irq_restore(flags); ++ return OK; ++ } ++ if (error != ERROR) { /* Timeout */ ++ if (++nl->timeout_count <= 3) { ++ local_irq_restore(flags); ++ /* Try again later */ ++ return TIMEOUT; ++ } ++ c0 = z_readb(PAR_STATUS(dev)); ++ printk(KERN_INFO "%s: receive timeout(%d,%02x)\n", ++ dev->name, rcv->state, c0); ++ } ++ nl->enet_stats.rx_dropped++; ++ } ++ rcv->state = PLIP_PK_DONE; ++ if (rcv->skb) { ++ kfree_skb(rcv->skb); ++ rcv->skb = NULL; ++ } ++ snd->state = PLIP_PK_DONE; ++ if (snd->skb) { ++ dev_kfree_skb(snd->skb); ++ snd->skb = NULL; ++ } ++ enable_par_irq(dev, 0); ++ dev->tbusy = 1; ++ nl->connection = PLIP_CN_ERROR; ++ z_writeb(0x00, PAR_DATA(dev)); ++ local_irq_restore(flags); ++ ++ return TIMEOUT; ++} ++ ++static int ++plip_none(struct device *dev, struct net_local *nl, ++ struct plip_local *snd, struct plip_local *rcv) ++{ ++ return OK; ++} ++ ++/* PLIP_RECEIVE --- receive a byte(two nibbles) ++ Returns OK on success, TIMEOUT on timeout */ ++inline static int ++plip_receive(struct device *dev, unsigned short nibble_timeout, ++ enum plip_nibble_state *ns_p, unsigned char *data_p) ++{ ++ unsigned char c0, c1; ++ unsigned int cx; ++ ++ switch (*ns_p) { ++ case PLIP_NB_BEGIN: ++ cx = nibble_timeout; ++ while (1) { ++ c0 = z_readb(PAR_STATUS(dev)); ++ udelay(PLIP_DELAY_UNIT); ++ if ((c0 & 0x80) == 0) { ++ c1 = z_readb(PAR_STATUS(dev)); ++ if (c0 == c1) ++ break; ++ } ++ if (--cx == 0) ++ return TIMEOUT; ++ } ++#if 0 ++ printk("received first nybble: %02X -> %02X\n", ++ c0, (c0 >> 3) & 0x0F); ++#endif ++ *data_p = (c0 >> 3) & 0x0f; ++ z_writeb(0x10, PAR_DATA(dev)); /* send ACK */ ++ *ns_p = PLIP_NB_1; ++ ++ case PLIP_NB_1: ++ cx = nibble_timeout; ++ while (1) { ++ c0 = z_readb(PAR_STATUS(dev)); ++ udelay(PLIP_DELAY_UNIT); ++ if (c0 & 0x80) { ++ c1 = z_readb(PAR_STATUS(dev)); ++ if (c0 == c1) ++ break; ++ } ++ if (--cx == 0) ++ return TIMEOUT; ++ } ++#if 0 ++ printk("received second nybble: %02X -> %02X\n", ++ c0, (c0 << 1) & 0xF0); ++#endif ++ *data_p |= (c0 << 1) & 0xf0; ++ z_writeb(0x00, PAR_DATA(dev)); /* send ACK */ ++ *ns_p = PLIP_NB_BEGIN; ++ case PLIP_NB_2: ++ break; ++ } ++ return OK; ++} ++ ++/* PLIP_RECEIVE_PACKET --- receive a packet */ ++static int ++plip_receive_packet(struct device *dev, struct net_local *nl, ++ struct plip_local *snd, struct plip_local *rcv) ++{ ++ unsigned short nibble_timeout = nl->nibble; ++ unsigned char *lbuf; ++ unsigned long flags; ++ ++ switch (rcv->state) { ++ case PLIP_PK_TRIGGER: ++ enable_par_irq(dev, 0); ++ dev->interrupt = 0; ++ z_writeb(0x01, PAR_DATA(dev)); /* send ACK */ ++ if (net_debug > 2) ++ printk(KERN_DEBUG "%s: receive start\n", dev->name); ++ rcv->state = PLIP_PK_LENGTH_LSB; ++ rcv->nibble = PLIP_NB_BEGIN; ++ ++ case PLIP_PK_LENGTH_LSB: ++ if (snd->state != PLIP_PK_DONE) { ++ if (plip_receive(dev, nl->trigger, ++ &rcv->nibble, &rcv->length.b.lsb)) { ++ /* collision, here dev->tbusy == 1 */ ++ rcv->state = PLIP_PK_DONE; ++ nl->is_deferred = 1; ++ nl->connection = PLIP_CN_SEND; ++ queue_task(&nl->deferred, &tq_timer); ++ enable_par_irq(dev, 1); ++ return OK; ++ } ++ } else { ++ if (plip_receive(dev, nibble_timeout, ++ &rcv->nibble, &rcv->length.b.lsb)) ++ return TIMEOUT; ++ } ++ rcv->state = PLIP_PK_LENGTH_MSB; ++ ++ case PLIP_PK_LENGTH_MSB: ++ if (plip_receive(dev, nibble_timeout, ++ &rcv->nibble, &rcv->length.b.msb)) ++ return TIMEOUT; ++ if (rcv->length.h > dev->mtu + dev->hard_header_len ++ || rcv->length.h < 8) { ++ printk(KERN_INFO "%s: bogus packet size %d.\n", ++ dev->name, rcv->length.h); ++ return ERROR; ++ } ++ /* Malloc up new buffer. */ ++ rcv->skb = dev_alloc_skb(rcv->length.h); ++ if (rcv->skb == NULL) { ++ printk(KERN_INFO "%s: Memory squeeze.\n", dev->name); ++ return ERROR; ++ } ++ skb_put(rcv->skb,rcv->length.h); ++ rcv->skb->dev = dev; ++ rcv->state = PLIP_PK_DATA; ++ rcv->byte = 0; ++ rcv->checksum = 0; ++ ++ case PLIP_PK_DATA: ++ lbuf = rcv->skb->data; ++ do ++ if (plip_receive(dev, nibble_timeout, ++ &rcv->nibble, &lbuf[rcv->byte])) ++ return TIMEOUT; ++ while (++rcv->byte < rcv->length.h); ++ do ++ rcv->checksum += lbuf[--rcv->byte]; ++ while (rcv->byte); ++ rcv->state = PLIP_PK_CHECKSUM; ++ ++ case PLIP_PK_CHECKSUM: ++ if (plip_receive(dev, nibble_timeout, ++ &rcv->nibble, &rcv->data)) ++ return TIMEOUT; ++ if (rcv->data != rcv->checksum) { ++ nl->enet_stats.rx_crc_errors++; ++ if (net_debug) ++ printk(KERN_INFO "%s: checksum error\n", ++ dev->name); ++ return ERROR; ++ } ++ rcv->state = PLIP_PK_DONE; ++ ++ case PLIP_PK_DONE: ++ /* Inform the upper layer for the arrival of a packet. */ ++ rcv->skb->protocol=eth_type_trans(rcv->skb, dev); ++ netif_rx(rcv->skb); ++ nl->enet_stats.rx_packets++; ++ rcv->skb = NULL; ++ if (net_debug > 2) ++ printk(KERN_DEBUG "%s: receive end\n", dev->name); ++ ++ /* Close the connection. */ ++ z_writeb (0x00, PAR_DATA(dev)); ++ ++ local_irq_save(flags); ++ if (snd->state != PLIP_PK_DONE) { ++ nl->connection = PLIP_CN_SEND; ++ local_irq_restore(flags); ++ queue_task(&nl->immediate, &tq_immediate); ++ mark_bh(IMMEDIATE_BH); ++ enable_par_irq(dev, 1); ++ return OK; ++ } else { ++ nl->connection = PLIP_CN_NONE; ++ local_irq_restore(flags); ++ enable_par_irq(dev, 1); ++ return OK; ++ } ++ } ++ return OK; ++} ++ ++/* PLIP_SEND --- send a byte (two nibbles) ++ Returns OK on success, TIMEOUT when timeout */ ++inline static int ++plip_send(struct device *dev, unsigned short nibble_timeout, ++ enum plip_nibble_state *ns_p, unsigned char data) ++{ ++ unsigned char c0; ++ unsigned int cx; ++ ++ switch (*ns_p) { ++ case PLIP_NB_BEGIN: ++ z_writeb((data & 0x0f), PAR_DATA(dev)); ++ *ns_p = PLIP_NB_1; ++ ++ case PLIP_NB_1: ++ z_writeb(0x10 | (data & 0x0f), PAR_DATA(dev)); ++ cx = nibble_timeout; ++ while (1) { ++ c0 = z_readb(PAR_STATUS(dev)); ++ if ((c0 & 0x80) == 0) ++ break; ++ if (--cx == 0) ++ return TIMEOUT; ++ udelay(PLIP_DELAY_UNIT); ++ } ++ z_writeb(0x10 | (data >> 4), PAR_DATA(dev)); ++ *ns_p = PLIP_NB_2; ++ ++ case PLIP_NB_2: ++ z_writeb((data >> 4), PAR_DATA(dev)); ++ cx = nibble_timeout; ++ while (1) { ++ c0 = z_readb(PAR_STATUS(dev)); ++ if (c0 & 0x80) ++ break; ++ if (--cx == 0) ++ return TIMEOUT; ++ udelay(PLIP_DELAY_UNIT); ++ } ++ *ns_p = PLIP_NB_BEGIN; ++ return OK; ++ } ++ return OK; ++} ++ ++/* PLIP_SEND_PACKET --- send a packet */ ++static int ++plip_send_packet(struct device *dev, struct net_local *nl, ++ struct plip_local *snd, struct plip_local *rcv) ++{ ++ unsigned short nibble_timeout = nl->nibble; ++ unsigned char *lbuf; ++ unsigned char c0; ++ unsigned int cx; ++ unsigned long flags; ++ ++ if (snd->skb == NULL || (lbuf = snd->skb->data) == NULL) { ++ printk(KERN_INFO "%s: send skb lost\n", dev->name); ++ snd->state = PLIP_PK_DONE; ++ snd->skb = NULL; ++ return ERROR; ++ } ++ ++ if (snd->length.h == 0) { ++ return OK; ++ } ++ ++ switch (snd->state) { ++ case PLIP_PK_TRIGGER: ++ if ((z_readb(PAR_STATUS(dev)) & 0xf8) != 0x80) ++ return TIMEOUT; ++ ++ /* Trigger remote rx interrupt. */ ++ z_writeb(0x08, PAR_DATA(dev)); ++ cx = nl->trigger; ++ while (1) { ++ udelay(PLIP_DELAY_UNIT); ++ local_irq_save(flags); ++ if (nl->connection == PLIP_CN_RECEIVE) { ++ local_irq_restore(flags); ++ /* interrupted */ ++ nl->enet_stats.collisions++; ++ if (net_debug > 1) ++ printk(KERN_INFO "%s: collision.\n", ++ dev->name); ++ return OK; ++ } ++ c0 = z_readb(PAR_STATUS(dev)); ++ if (c0 & 0x08) { ++ enable_par_irq(dev, 0); ++ if (net_debug > 2) ++ printk(KERN_DEBUG "%s: send start\n", ++ dev->name); ++ snd->state = PLIP_PK_LENGTH_LSB; ++ snd->nibble = PLIP_NB_BEGIN; ++ nl->timeout_count = 0; ++ local_irq_restore(flags); ++ break; ++ } ++ local_irq_restore(flags); ++ if (--cx == 0) { ++ z_writeb(0x00, PAR_DATA(dev)); ++ return TIMEOUT; ++ } ++ } ++ ++ case PLIP_PK_LENGTH_LSB: ++ if (plip_send(dev, nibble_timeout, ++ &snd->nibble, snd->length.b.lsb)) ++ return TIMEOUT; ++ snd->state = PLIP_PK_LENGTH_MSB; ++ ++ case PLIP_PK_LENGTH_MSB: ++ if (plip_send(dev, nibble_timeout, ++ &snd->nibble, snd->length.b.msb)) ++ return TIMEOUT; ++ snd->state = PLIP_PK_DATA; ++ snd->byte = 0; ++ snd->checksum = 0; ++ ++ case PLIP_PK_DATA: ++ do ++ if (plip_send(dev, nibble_timeout, ++ &snd->nibble, lbuf[snd->byte])) ++ return TIMEOUT; ++ while (++snd->byte < snd->length.h); ++ do ++ snd->checksum += lbuf[--snd->byte]; ++ while (snd->byte); ++ snd->state = PLIP_PK_CHECKSUM; ++ ++ case PLIP_PK_CHECKSUM: ++ if (plip_send(dev, nibble_timeout, ++ &snd->nibble, snd->checksum)) ++ return TIMEOUT; ++ ++ dev_kfree_skb(snd->skb); ++ nl->enet_stats.tx_packets++; ++ snd->state = PLIP_PK_DONE; ++ ++ case PLIP_PK_DONE: ++ /* Close the connection */ ++ z_writeb (0x00, PAR_DATA(dev)); ++ snd->skb = NULL; ++ if (net_debug > 2) ++ printk(KERN_DEBUG "%s: send end\n", dev->name); ++ nl->connection = PLIP_CN_CLOSING; ++ nl->is_deferred = 1; ++ queue_task(&nl->deferred, &tq_timer); ++ enable_par_irq(dev, 1); ++ return OK; ++ } ++ return OK; ++} ++ ++static int ++plip_connection_close(struct device *dev, struct net_local *nl, ++ struct plip_local *snd, struct plip_local *rcv) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ if (nl->connection == PLIP_CN_CLOSING) { ++ nl->connection = PLIP_CN_NONE; ++ dev->tbusy = 0; ++ mark_bh(NET_BH); ++ } ++ local_irq_restore(flags); ++ return OK; ++} ++ ++/* PLIP_ERROR --- wait till other end settled */ ++static int ++plip_error(struct device *dev, struct net_local *nl, ++ struct plip_local *snd, struct plip_local *rcv) ++{ ++ unsigned char status; ++ ++ status = z_readb(PAR_STATUS(dev)); ++ if ((status & 0xf8) == 0x80) { ++ if (net_debug > 2) ++ printk(KERN_DEBUG "%s: reset interface.\n", dev->name); ++ nl->connection = PLIP_CN_NONE; ++ dev->tbusy = 0; ++ dev->interrupt = 0; ++ enable_par_irq(dev, 1); ++ mark_bh(NET_BH); ++ } else { ++ nl->is_deferred = 1; ++ queue_task(&nl->deferred, &tq_timer); ++ } ++ ++ return OK; ++} ++ ++/* We don't need to send arp, for plip is point-to-point. */ ++static int ++plip_rebuild_header(struct sk_buff *skb) ++{ ++ struct device *dev = skb->dev; ++ struct net_local *nl = (struct net_local *)dev->priv; ++ struct ethhdr *eth = (struct ethhdr *)skb->data; ++ int i; ++ ++ if ((dev->flags & IFF_NOARP)==0) ++ return nl->orig_rebuild_header(skb); ++ ++ if (eth->h_proto != __constant_htons(ETH_P_IP) ++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) ++ && eth->h_proto != __constant_htons(ETH_P_IPV6) ++#endif ++ ) { ++ printk(KERN_ERR "plip_rebuild_header: Don't know how to resolve type %d addresses?\n", (int)eth->h_proto); ++ memcpy(eth->h_source, dev->dev_addr, dev->addr_len); ++ return 0; ++ } ++ ++ for (i=0; i < ETH_ALEN - sizeof(u32); i++) ++ eth->h_dest[i] = 0xfc; ++#if 0 ++ *(u32 *)(eth->h_dest+i) = dst; ++#else ++ /* Do not want to include net/route.h here. ++ * In any case, it is TOP of silliness to emulate ++ * hardware addresses on PtP link. --ANK ++ */ ++ *(u32 *)(eth->h_dest+i) = 0; ++#endif ++ return 0; ++} ++ ++static int ++plip_tx_packet(struct sk_buff *skb, struct device *dev) ++{ ++ struct net_local *nl = (struct net_local *)dev->priv; ++ struct plip_local *snd = &nl->snd_data; ++ unsigned long flags; ++ ++ if (dev->tbusy) ++ return 1; ++ ++ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { ++ printk(KERN_ERR "%s: Transmitter access conflict.\n", ++ dev->name); ++ return 1; ++ } ++ ++ if (skb->len > dev->mtu + dev->hard_header_len) { ++ printk(KERN_ERR "%s: packet too big, %d.\n", ++ dev->name, (int)skb->len); ++ dev->tbusy = 0; ++ return 0; ++ } ++ ++ if (net_debug > 2) ++ printk(KERN_DEBUG "%s: send request\n", dev->name); ++ ++ local_irq_save(flags); ++ dev->trans_start = jiffies; ++ snd->skb = skb; ++ snd->length.h = skb->len; ++ snd->state = PLIP_PK_TRIGGER; ++ if (nl->connection == PLIP_CN_NONE) { ++ nl->connection = PLIP_CN_SEND; ++ nl->timeout_count = 0; ++ } ++ queue_task(&nl->immediate, &tq_immediate); ++ mark_bh(IMMEDIATE_BH); ++ local_irq_restore(flags); ++ ++ return 0; ++} ++ ++/* Open/initialize the board. This is called (in the current kernel) ++ sometime after booting when the 'ifconfig' program is run. ++ ++ */ ++static int ++plip_open(struct device *dev) ++{ ++ struct net_local *nl = (struct net_local *)dev->priv; ++ struct in_device *in_dev; ++ ++#if defined(CONFIG_GVPIOEXT_LP) || defined(CONFIG_GVPIOEXT_LP_MODULE) ++ /* Yes, there is a race condition here. Fix it later */ ++ if (PLIP_DEV(dev)->par_use & IOEXT_PAR_LP) { ++ /* Can't open if lp is in use */ ++#if DEBUG ++ printk("par is in use by lp\n"); ++#endif ++ return(-EBUSY); ++ } ++#endif ++ PLIP_DEV(dev)->par_use |= IOEXT_PAR_PLIP; ++ ++#if DEBUG ++ printk("plip_open(): sending 00 to data port\n"); ++#endif ++ ++ /* Clear the data port. */ ++ z_writeb (0x00, PAR_DATA(dev)); ++ ++#if DEBUG ++ printk("plip_open(): sent\n"); ++#endif ++ ++ /* Initialize the state machine. */ ++ nl->rcv_data.state = nl->snd_data.state = PLIP_PK_DONE; ++ nl->rcv_data.skb = nl->snd_data.skb = NULL; ++ nl->connection = PLIP_CN_NONE; ++ nl->is_deferred = 0; ++ ++ /* Fill in the MAC-level header. ++ (ab)Use "dev->broadcast" to store point-to-point MAC address. ++ ++ PLIP doesn't have a real mac address, but we need to create one ++ to be DOS compatible. */ ++ memset(dev->dev_addr, 0xfc, ETH_ALEN); ++ memset(dev->broadcast, 0xfc, ETH_ALEN); ++ ++ if ((in_dev=dev->ip_ptr) != NULL) { ++ /* ++ * Any address will do - we take the first ++ */ ++ struct in_ifaddr *ifa=in_dev->ifa_list; ++ if (ifa != NULL) { ++ memcpy(dev->dev_addr+2, &ifa->ifa_local, 4); ++ memcpy(dev->broadcast+2, &ifa->ifa_address, 4); ++ } ++ } ++ ++ dev->interrupt = 0; ++ dev->start = 1; ++ dev->tbusy = 0; ++ ++ MOD_INC_USE_COUNT; ++ ++ /* Enable rx interrupt. */ ++ enable_par_irq(dev, 1); ++ ++ return 0; ++} ++ ++/* The inverse routine to plip_open (). */ ++static int ++plip_close(struct device *dev) ++{ ++ struct net_local *nl = (struct net_local *)dev->priv; ++ struct plip_local *snd = &nl->snd_data; ++ struct plip_local *rcv = &nl->rcv_data; ++ unsigned long flags; ++ ++ dev->tbusy = 1; ++ dev->start = 0; ++ local_irq_save(flags); ++ nl->is_deferred = 0; ++ nl->connection = PLIP_CN_NONE; ++ local_irq_restore(flags); ++ z_writeb(0x00, PAR_DATA(dev)); ++ ++ snd->state = PLIP_PK_DONE; ++ if (snd->skb) { ++ dev_kfree_skb(snd->skb); ++ snd->skb = NULL; ++ } ++ rcv->state = PLIP_PK_DONE; ++ if (rcv->skb) { ++ kfree_skb(rcv->skb); ++ rcv->skb = NULL; ++ } ++ ++ PLIP_DEV(dev)->par_use &= ~IOEXT_PAR_PLIP; ++ ++ MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++static struct enet_statistics * ++plip_get_stats(struct device *dev) ++{ ++ struct net_local *nl = (struct net_local *)dev->priv; ++ struct enet_statistics *r = &nl->enet_stats; ++ ++ return r; ++} ++ ++static int ++plip_config(struct device *dev, struct ifmap *map) ++{ ++ if (dev->flags & IFF_UP) ++ return -EBUSY; ++ ++ printk(KERN_INFO "%s: This interface is autodetected (ignored).\n", ++ dev->name); ++ ++ return 0; ++} ++ ++static int ++plip_ioctl(struct device *dev, struct ifreq *rq, int cmd) ++{ ++ struct net_local *nl = (struct net_local *) dev->priv; ++ struct plipconf *pc = (struct plipconf *) &rq->ifr_data; ++ ++ switch(pc->pcmd) { ++ case PLIP_GET_TIMEOUT: ++ pc->trigger = nl->trigger; ++ pc->nibble = nl->nibble; ++ break; ++ case PLIP_SET_TIMEOUT: ++ nl->trigger = pc->trigger; ++ nl->nibble = pc->nibble; ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ return 0; ++} ++ ++/* ++ * Detect and initialize all IO-Extenders in this system. ++ * ++ * Both PLIP and serial devices are configured. ++ */ ++int plip_init(struct device *dev) ++{ ++ IOEXT_struct *board; ++ struct net_local *nl; ++ ++ if (ioext_num == 0) { ++ printk(KERN_INFO "%s\n", version); ++ } ++ ++ board = PLIP_DEV(dev)->board; ++ dev->base_addr = (unsigned long)&board->par.DATA; ++ ++ /* Cheat and use irq to index into our table */ ++ dev->irq = ioext_num; ++ ++ printk(KERN_INFO "%s: IO-Extender parallel port at 0x%08lX\n", dev->name, dev->base_addr); ++ ++ /* Fill in the generic fields of the device structure. */ ++ ether_setup(dev); ++ ++ /* Then, override parts of it */ ++ dev->hard_start_xmit = plip_tx_packet; ++ dev->open = plip_open; ++ dev->stop = plip_close; ++ dev->get_stats = plip_get_stats; ++ dev->set_config = plip_config; ++ dev->do_ioctl = plip_ioctl; ++ dev->tx_queue_len = 10; ++ dev->flags = IFF_POINTOPOINT|IFF_NOARP; ++ ++ /* Set the private structure */ ++ dev->priv = kmalloc(sizeof (struct net_local), GFP_KERNEL); ++ if (dev->priv == NULL) { ++ printk(KERN_ERR "%s: out of memory\n", dev->name); ++ return -ENOMEM; ++ } ++ memset(dev->priv, 0, sizeof(struct net_local)); ++ nl = (struct net_local *) dev->priv; ++ ++ nl->orig_rebuild_header = dev->rebuild_header; ++ dev->rebuild_header = plip_rebuild_header; ++ ++ /* Initialize constants */ ++ nl->trigger = PLIP_TRIGGER_WAIT; ++ nl->nibble = PLIP_NIBBLE_WAIT; ++ ++ /* Initialize task queue structures */ ++ nl->immediate.next = NULL; ++ nl->immediate.sync = 0; ++ nl->immediate.routine = (void *)(void *)plip_bh; ++ nl->immediate.data = dev; ++ ++ nl->deferred.next = NULL; ++ nl->deferred.sync = 0; ++ nl->deferred.routine = (void *)(void *)plip_kick_bh; ++ nl->deferred.data = dev; ++ ++ /* Don't enable interrupts yet */ ++ ++ return 0; ++} diff --git a/debian/patches/bugfix/m68k/2.6.24/149-mc68681.diff b/debian/patches/bugfix/m68k/2.6.24/149-mc68681.diff new file mode 100644 index 000000000..5e4d6125a --- /dev/null +++ b/debian/patches/bugfix/m68k/2.6.24/149-mc68681.diff @@ -0,0 +1,145 @@ +To: linus, alan +Cc: lkml +Subject: [PATCH] MC68681 DUART + +From: Linux/m68k legacy + +MC68681 DUART register definitions for the Amiga MultiFace III serial driver. +--- + drivers/char/mc68681.h | 131 +++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 131 insertions(+) + +--- /dev/null ++++ b/drivers/char/mc68681.h +@@ -0,0 +1,131 @@ ++#ifndef _MC68681_H_ ++#define _MC68681_H_ ++ ++/* ++ * This describes an MC68681 DUART. It has almost only overlayed registers, which ++ * the structure very ugly. ++ * Note that the ri-register isn't really a register of the duart but a kludge of bsc ++ * to make the ring indicator available. ++ * ++ * The data came from the MFC-31-Developer Kit (from Ralph Seidel, ++ * zodiac@darkness.gun.de) and the data sheet of Phillip's clone device (SCN68681) ++ * (from Richard Hirst, srh@gpt.co.uk) ++ * ++ * 11.11.95 copyright Joerg Dorchain (dorchain@mpi-sb.mpg.de) ++ * ++ */ ++ ++struct duarthalf { ++union { ++volatile u_char mr1; /* rw */ ++volatile u_char mr2; /* rw */ ++} mr; ++volatile u_char ri; /* special, read */ ++union { ++volatile u_char sr; /* read */ ++volatile u_char csr; /* write */ ++} sr_csr; ++u_char pad1; ++volatile u_char cr; /* write */ ++u_char pad2; ++union { ++volatile u_char rhr; /* read */ ++volatile u_char thr; /* write */ ++} hr; ++u_char pad3; ++}; ++ ++struct duart { ++struct duarthalf pa; ++union { ++volatile u_char ipcr; /* read */ ++volatile u_char acr; /* write */ ++} ipcr_acr; ++u_char pad1; ++union { ++volatile u_char isr; /* read */ ++volatile u_char imr; /* write */ ++} ir; ++u_char pad2; ++volatile u_char ctu; ++u_char pad3; ++volatile u_char ctl; ++u_char pad4; ++struct duarthalf pb; ++volatile u_char ivr; ++u_char pad5; ++union { ++volatile u_char ipr; /* read */ ++volatile u_char opcr; /* write */ ++} ipr_opcr; ++u_char pad6; ++union { ++volatile u_char start; /* read */ ++volatile u_char sopc; /* write */ ++} start_sopc; ++u_char pad7; ++union { ++volatile u_char stop; /* read */ ++volatile u_char ropc; /* write */ ++} stop_ropc; ++u_char pad8; ++}; ++ ++#define MR1_BITS 3 ++#define MR1_5BITS 0 ++#define MR1_6BITS 1 ++#define MR1_7BITS 2 ++#define MR1_8BITS 3 ++ ++#define MR1_PARITY_ODD 4 ++ ++#define MR1_PARITY 24 ++#define MR1_PARITY_WITH 0 ++#define MR1_PARITY_FORCE 8 ++#define MR1_PARITY_NO 16 ++#define MR1_PARITY_MULTIDROP 24 ++ ++#define MR1_ERROR_BLOCK 32 ++#define MR1_FFULL_IRQ 64 ++#define MR1_RxRTS_ON 128 ++ ++#define MR2_STOPS 15 ++#define MR2_1STOP 7 ++#define MR2_2STOP 15 ++ ++#define MR2_CTS_ON 16 ++#define MR2_TxRTS_ON 32 ++ ++#define MR2_MODE 192 ++#define MR2_NORMAL 0 ++#define MR2_ECHO 64 ++#define MR2_LOCALLOOP 128 ++#define MR2_REMOTELOOP 192 ++ ++#define CR_RXCOMMAND 3 ++#define CR_NONE 0 ++#define CR_RX_ON 1 ++#define CR_RX_OFF 2 ++#define CR_TXCOMMAND 12 ++#define CR_TX_ON 4 ++#define CR_TX_OFF 8 ++#define CR_MISC 112 ++#define CR_RESET_MR 16 ++#define CR_RESET_RX 32 ++#define CR_RESET_TX 48 ++#define CR_RESET_ERR 64 ++#define CR_RESET_BREAK 80 ++#define CR_START_BREAK 96 ++#define CR_STOP_BREAK 112 ++ ++#define SR_RXRDY 1 ++#define SR_FFULL 2 ++#define SR_TXRDY 4 ++#define SR_TXEMPT 8 ++#define SR_OVERRUN 16 ++#define SR_PARITY 32 ++#define SR_FRAMING 64 ++#define SR_BREAK 128 ++ ++ ++#endif diff --git a/debian/patches/bugfix/m68k/2.6.24/152-pci.diff b/debian/patches/bugfix/m68k/2.6.24/152-pci.diff new file mode 100644 index 000000000..69597cedb --- /dev/null +++ b/debian/patches/bugfix/m68k/2.6.24/152-pci.diff @@ -0,0 +1,20 @@ +To: linus, alan +Cc: lkml +Subject: [PATCH] M68k PCI + +First steps in making m68k PCI support compilable again +--- + arch/m68k/kernel/bios32.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/m68k/kernel/bios32.c ++++ b/arch/m68k/kernel/bios32.c +@@ -284,7 +284,7 @@ static void __init layout_bus(struct pci + + DBG_DEVS(("layout_bus: starting bus %d\n", bus->number)); + +- if (!bus->devices && !bus->children) ++ if (list_empty(&bus->devices) && list_empty(&bus->children)) + return; + + /* diff --git a/debian/patches/bugfix/m68k/2.6.24/448-ide.diff b/debian/patches/bugfix/m68k/2.6.24/448-ide.diff new file mode 100644 index 000000000..83e3bea10 --- /dev/null +++ b/debian/patches/bugfix/m68k/2.6.24/448-ide.diff @@ -0,0 +1,22 @@ +To: linus, akpm, B.Zolnierkiewicz@elka.pw.edu.pl +Cc: lkml +Subject: [PATCH] m68k IDE compiler bug + +From: Roman Zippel + +IDE: Avoid compiler bug in gcc 3.2 (from Roman Zippel) +--- + include/linux/ide.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/include/linux/ide.h ++++ b/include/linux/ide.h +@@ -502,7 +502,7 @@ typedef union { + * sense_key : Sense key of the last failed packet command + */ + typedef union { +- unsigned all :8; ++ u8 all; + struct { + #if defined(__LITTLE_ENDIAN_BITFIELD) + unsigned ili :1; diff --git a/debian/patches/bugfix/m68k/2.6.24/478-serial.diff b/debian/patches/bugfix/m68k/2.6.24/478-serial.diff new file mode 100644 index 000000000..b7df95c74 --- /dev/null +++ b/debian/patches/bugfix/m68k/2.6.24/478-serial.diff @@ -0,0 +1,29 @@ +To: linus, akpm +Cc: lkml +Subject: [PATCH] M68k SERIAL_PORT_DFNS only if CONFIG_ISA + +From: Kars de Jong + +M68k serial: Only define SERIAL_PORT_DFNS when CONFIG_ISA is defined. Otherwise +the first 4 slots in the 8250 driver are unavailable on non-ISA machines. + +Signed-off-by: Kars de Jong +Signed-off-by: Geert Uytterhoeven +--- + include/asm-m68k/serial.h | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/include/asm-m68k/serial.h ++++ b/include/asm-m68k/serial.h +@@ -25,9 +25,11 @@ + #define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF + #endif + ++#ifdef CONFIG_ISA + #define SERIAL_PORT_DFNS \ + /* UART CLK PORT IRQ FLAGS */ \ + { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \ + { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */ \ + { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \ + { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */ ++#endif diff --git a/debian/patches/bugfix/m68k/2.6.24/amiga-debug=mem.diff b/debian/patches/bugfix/m68k/2.6.24/amiga-debug=mem.diff new file mode 100644 index 000000000..343ea3077 --- /dev/null +++ b/debian/patches/bugfix/m68k/2.6.24/amiga-debug=mem.diff @@ -0,0 +1,74 @@ +--- + arch/m68k/amiga/config.c | 30 +++++++++++++++++++++--------- + 1 file changed, 21 insertions(+), 9 deletions(-) + +--- a/arch/m68k/amiga/config.c ++++ b/arch/m68k/amiga/config.c +@@ -109,6 +109,7 @@ static void amiga_mem_console_write(stru + unsigned int count); + void amiga_serial_console_write(struct console *co, const char *s, + unsigned int count); ++static void __init amiga_savekmsg_init(void); + #ifdef CONFIG_HEARTBEAT + static void amiga_heartbeat(int on); + #endif +@@ -119,6 +120,8 @@ static struct console amiga_console_driv + .index = -1, + }; + ++static int __initdata amiga_enable_debug_mem; ++ + + /* + * Motherboard Resources present in all Amiga models +@@ -465,6 +468,9 @@ void __init config_amiga(void) + /* initialize chipram allocator */ + amiga_chip_init(); + ++ if (amiga_enable_debug_mem && AMIGAHW_PRESENT(CHIP_RAM)) ++ amiga_savekmsg_init(); ++ + /* our beloved beeper */ + if (AMIGAHW_PRESENT(AMI_AUDIO)) + amiga_init_sound(); +@@ -783,18 +789,10 @@ static void amiga_mem_console_write(stru + } + } + +-static int __init amiga_savekmsg_setup(char *arg) ++static void __init amiga_savekmsg_init(void) + { + static struct resource debug_res = { .name = "Debug" }; + +- if (!MACH_IS_AMIGA || strcmp(arg, "mem")) +- goto done; +- +- if (!AMIGAHW_PRESENT(CHIP_RAM)) { +- printk("Warning: no chipram present for debugging\n"); +- goto done; +- } +- + savekmsg = amiga_chip_alloc_res(SAVEKMSG_MAXMEM, &debug_res); + savekmsg->magic1 = SAVEKMSG_MAGIC1; + savekmsg->magic2 = SAVEKMSG_MAGIC2; +@@ -803,6 +801,20 @@ static int __init amiga_savekmsg_setup(c + + amiga_console_driver.write = amiga_mem_console_write; + register_console(&amiga_console_driver); ++} ++ ++static int __init amiga_savekmsg_setup(char *arg) ++{ ++ if (!MACH_IS_AMIGA || strcmp(arg, "mem")) ++ goto done; ++ ++ if (!AMIGAHW_PRESENT(CHIP_RAM)) { ++ printk("Warning: no chipram present for debugging\n"); ++ amiga_enable_debug_mem = 1; ++ goto done; ++ } ++ ++ amiga_savekmsg_init(); + + done: + return 0; diff --git a/debian/patches/bugfix/m68k/2.6.24/amiga-platform-device.diff b/debian/patches/bugfix/m68k/2.6.24/amiga-platform-device.diff new file mode 100644 index 000000000..fc57dd0a8 --- /dev/null +++ b/debian/patches/bugfix/m68k/2.6.24/amiga-platform-device.diff @@ -0,0 +1,191 @@ + +static int __init xxx_probe(struct platform_device *pdev) +{ + regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID); + fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID); + if (!regs || !fifo) + return -ENXIO; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + + + + + platform_set_drvdata(pdev, xxx); + + + + + + + + +} + +static int __exit xxx_remove(struct platform_device *pdev) +{ + xxx = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + + + return 0; +} + +static struct platform_driver xxx_driver = { + .remove = __exit_p(xxx_remove), + .driver = { + .name = "xxx", + }, +}; + +static int __init xxx_init(void) +{ + return platform_driver_probe(&xxx_driver, xxx_probe); +} +module_init(xxx_init); + +static void __exit xxx_exit(void) +{ + platform_driver_unregister(&xxx_driver); +} +module_exit(xxx_exit); + +arch/m68k/amiga/amiints.c: if (AMIGAHW_PRESENT(PCMCIA)) +arch/m68k/amiga/chipram.c: if (!AMIGAHW_PRESENT(CHIP_RAM)) +arch/m68k/amiga/config.c: if (AMIGAHW_PRESENT(name)) \ +arch/m68k/amiga/config.c: if (AMIGAHW_PRESENT(ZORRO)) +arch/m68k/amiga/config.c: printk("ZORRO%s ", AMIGAHW_PRESENT(ZORRO3) ? "3" : ""); +arch/m68k/amiga/config.c: if (AMIGAHW_PRESENT(A3000_CLK)) { +arch/m68k/amiga/config.c: } else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ { +arch/m68k/amiga/config.c: if (AMIGAHW_PRESENT(ZORRO3)) { +arch/m68k/amiga/config.c: if (amiga_enable_debug_mem && AMIGAHW_PRESENT(CHIP_RAM)) +arch/m68k/amiga/config.c: if (AMIGAHW_PRESENT(AMI_AUDIO)) +arch/m68k/amiga/config.c: if (AMIGAHW_PRESENT(MAGIC_REKICK)) +arch/m68k/amiga/config.c: if (AMIGAHW_PRESENT(A3000_CLK)) { +arch/m68k/amiga/config.c: } else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ { +arch/m68k/amiga/config.c: if (AMIGAHW_PRESENT(A3000_CLK)) { +arch/m68k/amiga/config.c: } else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ { +arch/m68k/amiga/config.c: if (!AMIGAHW_PRESENT(CHIP_RAM)) { +arch/m68k/amiga/config.c: if (AMIGAHW_PRESENT(CHIP_RAM)) +arch/m68k/amiga/config.c: if (AMIGAHW_PRESENT(AMI_VIDEO)) { +arch/m68k/amiga/config.c: if (AMIGAHW_PRESENT(name)) \ +arch/m68k/amiga/config.c: if (AMIGAHW_PRESENT(ZORRO)) +arch/m68k/amiga/config.c: AMIGAHW_PRESENT(ZORRO3) ? "I" : "", +arch/m68k/kernel/setup.c: if (MACH_IS_AMIGA && AMIGAHW_PRESENT(GG2_ISA)) { +arch/m68k/kernel/setup.c: if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)) { +drivers/block/amiflop.c: if (!AMIGAHW_PRESENT(AMI_FLOPPY)) +drivers/char/amiserial.c: if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_SERIAL)) +drivers/ide/legacy/gayle.c: if ((a4000 = AMIGAHW_PRESENT(A4000_IDE)) || AMIGAHW_PRESENT(A1200_IDE)) +drivers/input/keyboard/amikbd.c: if (!AMIGAHW_PRESENT(AMI_KEYBOARD)) +drivers/input/mouse/amimouse.c: if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_MOUSE)) +drivers/net/apne.c: if ( !(AMIGAHW_PRESENT(PCMCIA)) ) +drivers/parport/parport_amiga.c: if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_PARALLEL)) +drivers/scsi/a3000.c: if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(A3000_SCSI)) +drivers/scsi/a4000t.c: if (!(MACH_IS_AMIGA && AMIGAHW_PRESENT(A4000_SCSI))) +drivers/video/amifb.c: if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_VIDEO)) +drivers/video/amifb.c: if (AMIGAHW_PRESENT(AMBER_FF)) +drivers/video/amifb.c: } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || +drivers/video/amifb.c: AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { +drivers/video/amifb.c: } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || +drivers/video/amifb.c: AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { +drivers/zorro/proc.c: if (MACH_IS_AMIGA && AMIGAHW_PRESENT(ZORRO)) { +drivers/zorro/zorro.c: if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO)) +drivers/zorro/zorro.c: if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO)) +drivers/zorro/zorro.c: zorro_bus.num_resources = AMIGAHW_PRESENT(ZORRO3) ? 4 : 2; +include/asm-m68k/amigahw.h:#define AMIGAHW_PRESENT(name) (amiga_hw_present.name) +sound/oss/dmasound/dmasound_paula.c: if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_AUDIO)) { +--- + arch/m68k/amiga/Makefile | 2 - + arch/m68k/amiga/platform.c | 73 +++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 74 insertions(+), 1 deletion(-) + +--- a/arch/m68k/amiga/Makefile ++++ b/arch/m68k/amiga/Makefile +@@ -2,6 +2,6 @@ + # Makefile for Linux arch/m68k/amiga source directory + # + +-obj-y := config.o amiints.o cia.o chipram.o amisound.o ++obj-y := config.o amiints.o cia.o chipram.o amisound.o platform.o + + obj-$(CONFIG_AMIGA_PCMCIA) += pcmcia.o +--- /dev/null ++++ b/arch/m68k/amiga/platform.c +@@ -0,0 +1,73 @@ ++/* ++ * Copyright (C) 2007 Geert Uytterhoeven ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive ++ * for more details. ++ */ ++ ++#include ++#include // FIXME show_mem() ++ ++#include ++ ++ ++static struct platform_device amiga_serial = { ++ .name = "amiga-serial", ++ .id = -1, ++}; ++ ++static int __init amiga_init_devices(void) ++{ ++ if (AMIGAHW_PRESENT(AMI_FLOPPY)) ++ platform_device_register_simple("amiga-floppy", -1, NULL, 0); ++ ++ if (AMIGAHW_PRESENT(AMI_SERIAL)) ++ platform_device_register(&amiga_serial); ++ ++#if 0 ++ /* video hardware */ ++[ ] AMIGAHW_PRESENT(AMI_VIDEO); /* Amiga Video */ ++[ ] AMIGAHW_PRESENT(AMI_BLITTER); /* Amiga Blitter */ ++[ ] AMIGAHW_PRESENT(AMBER_FF); /* Amber Flicker Fixer */ ++ /* sound hardware */ ++[ ] AMIGAHW_PRESENT(AMI_AUDIO); /* Amiga Audio */ ++ /* disk storage interfaces */ ++[ ] AMIGAHW_PRESENT(AMI_FLOPPY); /* Amiga Floppy */ ++[ ] AMIGAHW_PRESENT(A3000_SCSI); /* SCSI (wd33c93, A3000 alike) */ ++[ ] AMIGAHW_PRESENT(A4000_SCSI); /* SCSI (ncr53c710, A4000T alike) */ ++[ ] AMIGAHW_PRESENT(A1200_IDE); /* IDE (A1200 alike) */ ++[ ] AMIGAHW_PRESENT(A4000_IDE); /* IDE (A4000 alike) */ ++[ ] AMIGAHW_PRESENT(CD_ROM); /* CD ROM drive */ ++ /* other I/O hardware */ ++[ ] AMIGAHW_PRESENT(AMI_KEYBOARD); /* Amiga Keyboard */ ++[ ] AMIGAHW_PRESENT(AMI_MOUSE); /* Amiga Mouse */ ++[ ] AMIGAHW_PRESENT(AMI_SERIAL); /* Amiga Serial */ ++[ ] AMIGAHW_PRESENT(AMI_PARALLEL); /* Amiga Parallel */ ++ /* real time clocks */ ++[ ] AMIGAHW_PRESENT(A2000_CLK); /* Hardware Clock (A2000 alike) */ ++[ ] AMIGAHW_PRESENT(A3000_CLK); /* Hardware Clock (A3000 alike) */ ++ /* supporting hardware */ ++[ ] AMIGAHW_PRESENT(CHIP_RAM); /* Chip RAM */ ++[ ] AMIGAHW_PRESENT(PAULA); /* Paula (8364) */ ++[ ] AMIGAHW_PRESENT(DENISE); /* Denise (8362) */ ++[ ] AMIGAHW_PRESENT(DENISE_HR); /* Denise (8373) */ ++[ ] AMIGAHW_PRESENT(LISA); /* Lisa (8375) */ ++[ ] AMIGAHW_PRESENT(AGNUS_PAL); /* Normal/Fat PAL Agnus (8367/8371) */ ++[ ] AMIGAHW_PRESENT(AGNUS_NTSC); /* Normal/Fat NTSC Agnus (8361/8370) */ ++[ ] AMIGAHW_PRESENT(AGNUS_HR_PAL); /* Fat Hires PAL Agnus (8372) */ ++[ ] AMIGAHW_PRESENT(AGNUS_HR_NTSC); /* Fat Hires NTSC Agnus (8372) */ ++[ ] AMIGAHW_PRESENT(ALICE_PAL); /* PAL Alice (8374) */ ++[ ] AMIGAHW_PRESENT(ALICE_NTSC); /* NTSC Alice (8374) */ ++[ ] AMIGAHW_PRESENT(MAGIC_REKICK); /* A3000 Magic Hard Rekick */ ++[ ] AMIGAHW_PRESENT(PCMCIA); /* PCMCIA Slot */ ++[ ] AMIGAHW_PRESENT(GG2_ISA); /* GG2 Zorro2ISA Bridge */ ++[ ] AMIGAHW_PRESENT(ZORRO); /* Zorro AutoConfig */ ++[ ] AMIGAHW_PRESENT(ZORRO3); /* Zorro III */ ++#endif ++ ++ return 0; ++} ++ ++device_initcall(amiga_init_devices); ++ diff --git a/debian/patches/bugfix/m68k/2.6.24/amiga-platform-device2.diff b/debian/patches/bugfix/m68k/2.6.24/amiga-platform-device2.diff new file mode 100644 index 000000000..84816ba88 --- /dev/null +++ b/debian/patches/bugfix/m68k/2.6.24/amiga-platform-device2.diff @@ -0,0 +1,32 @@ +--- + arch/m68k/amiga/platform.c | 18 ++++++++++++++++-- + 1 file changed, 16 insertions(+), 2 deletions(-) + +--- a/arch/m68k/amiga/platform.c ++++ b/arch/m68k/amiga/platform.c +@@ -12,9 +12,23 @@ + #include + + ++static struct resource amiga_serial_resources[] = { ++ { ++ /* ++ * We request SERDAT and SERPER only, because the serial ++ * registers are too spread over the custom register space ++ */ ++ .start = CUSTOM_PHYSADDR+0x30, ++ .end = CUSTOM_PHYSADDR+0x33, ++ .flags = IORESOURCE_MEM, ++ } ++}; ++ + static struct platform_device amiga_serial = { +- .name = "amiga-serial", +- .id = -1, ++ .name = "amiga-serial", ++ .id = -1, ++ .num_resources = ARRAY_SIZE(amiga_serial_resources), ++ .resource = amiga_serial_resources, + }; + + static int __init amiga_init_devices(void) diff --git a/debian/patches/bugfix/m68k/2.6.24/atari-aranym.diff b/debian/patches/bugfix/m68k/2.6.24/atari-aranym.diff new file mode 100644 index 000000000..8405f44a5 --- /dev/null +++ b/debian/patches/bugfix/m68k/2.6.24/atari-aranym.diff @@ -0,0 +1,534 @@ +Subject: [PATCH] m68k: Atari ARAnyM support + +From: Michael Schmitz + +This isn't really my kettle of fish, but I post it anyway unless Petr +complains :-) + +This is what makes it possible for me to test 2.6 builds on the +emulator... + +Should be signed off by Petr, really. + +Signed-off-by: Geert Uytterhoeven +--- + arch/m68k/Kconfig | 15 ++ + arch/m68k/Makefile | 1 + arch/m68k/emu/Makefile | 7 + + arch/m68k/emu/natfeat.c | 113 +++++++++++++++++ + arch/m68k/emu/nfeth.c | 284 +++++++++++++++++++++++++++++++++++++++++++++ + arch/m68k/kernel/setup.c | 5 + drivers/net/Kconfig | 8 + + include/asm-m68k/natfeat.h | 22 +++ + 8 files changed, 455 insertions(+) + +--- a/arch/m68k/Kconfig ++++ b/arch/m68k/Kconfig +@@ -267,6 +267,21 @@ config Q40 + Q60. Select your CPU below. For 68LC060 don't forget to enable FPU + emulation. + ++config NATFEAT ++ bool "ARAnyM emulator support" ++ depends on ATARI ++ help ++ This option enables support for ARAnyM native features, such as ++ access to a disk image as /dev/hda. Useful with the ARANYM option. ++ ++config NFETH ++ tristate "NatFeat Ethernet support" ++ depends on NET_ETHERNET && NATFEAT ++ help ++ Say Y to include support for the ARAnyM NatFeat network device ++ which will emulate a regular ethernet device while presenting an ++ ethertap device to the host system. ++ + comment "Processor type" + + config M68020 +--- a/arch/m68k/Makefile ++++ b/arch/m68k/Makefile +@@ -74,6 +74,7 @@ core-$(CONFIG_MVME16x) += arch/m68k/mvm + core-$(CONFIG_BVME6000) += arch/m68k/bvme6000/ + core-$(CONFIG_SUN3X) += arch/m68k/sun3x/ arch/m68k/sun3/ + core-$(CONFIG_SUN3) += arch/m68k/sun3/ arch/m68k/sun3/prom/ ++core-$(CONFIG_NATFEAT) += arch/m68k/emu/ + core-$(CONFIG_M68040) += arch/m68k/fpsp040/ + core-$(CONFIG_M68060) += arch/m68k/ifpsp060/ + core-$(CONFIG_M68KFPU_EMU) += arch/m68k/math-emu/ +--- /dev/null ++++ b/arch/m68k/emu/Makefile +@@ -0,0 +1,7 @@ ++# ++# Makefile for Linux arch/m68k/emu source directory ++# ++ ++obj-y += natfeat.o ++ ++obj-$(CONFIG_NFETH) += nfeth.o +--- /dev/null ++++ b/arch/m68k/emu/natfeat.c +@@ -0,0 +1,113 @@ ++/* ++ * natfeat.c - ARAnyM hardware support via Native Features (natfeats) ++ * ++ * Copyright (c) 2005 Petr Stehlik of ARAnyM dev team ++ * ++ * Reworked for Linux by Roman Zippel ++ * ++ * This software may be used and distributed according to the terms of ++ * the GNU General Public License (GPL), incorporated herein by reference. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++asm("\n" ++" .global nf_get_id,nf_call\n" ++"nf_get_id:\n" ++" .short 0x7300\n" ++" rts\n" ++"nf_call:\n" ++" .short 0x7301\n" ++" rts\n" ++"1: moveq.l #0,%d0\n" ++" rts\n" ++" .section __ex_table,\"a\"\n" ++" .long nf_get_id,1b\n" ++" .long nf_call,1b\n" ++" .previous"); ++ ++static int stderr_id; ++ ++static void nf_write(struct console *co, const char *str, unsigned int count) ++{ ++ char buf[68]; ++ ++ buf[64] = 0; ++ while (count > 64) { ++ memcpy(buf, str, 64); ++ nf_call(stderr_id, buf); ++ str += 64; ++ count -= 64; ++ } ++ memcpy(buf, str, count); ++ buf[count] = 0; ++ nf_call(stderr_id, buf); ++} ++ ++void nfprint(const char *fmt, ...) ++{ ++ static char buf[256]; ++ va_list ap; ++ int n; ++ ++ va_start(ap, fmt); ++ n = vsnprintf(buf, 256, fmt, ap); ++ nf_call(nf_get_id("NF_STDERR"), buf); ++ va_end(ap); ++} ++ ++static struct console nf_console_driver = { ++ .name = "debug", ++ .write = nf_write, ++ .flags = CON_PRINTBUFFER, ++ .index = -1, ++}; ++ ++static int __init nf_debug_setup(char *arg) ++{ ++ if (strcmp(arg, "emu")) ++ return 0; ++ ++ stderr_id = nf_get_id("NF_STDERR"); ++ if (stderr_id) ++ register_console(&nf_console_driver); ++ return 0; ++} ++ ++early_param("debug", nf_debug_setup); ++ ++static void nf_poweroff(void) ++{ ++ long id = nf_get_id("NF_SHUTDOWN"); ++ ++ if (id) ++ nf_call(id); ++} ++ ++void nf_init(void) ++{ ++ unsigned long id, version; ++ char buf[256]; ++ ++ id = nf_get_id("NF_VERSION"); ++ if (!id) ++ return; ++ version = nf_call(id); ++ ++ id = nf_get_id("NF_NAME"); ++ if (!id) ++ return; ++ nf_call(id, buf, 256); ++ buf[255] = 0; ++ ++ pr_info("NatFeats found (%s, %lu.%lu)\n", buf, version >> 16, ++ version & 0xffff); ++ ++ mach_power_off = nf_poweroff; ++} +--- /dev/null ++++ b/arch/m68k/emu/nfeth.c +@@ -0,0 +1,284 @@ ++/* ++ * atari_nfeth.c - ARAnyM ethernet card driver for GNU/Linux ++ * ++ * Copyright (c) 2005 Milan Jurik, Petr Stehlik of ARAnyM dev team ++ * ++ * Based on ARAnyM driver for FreeMiNT written by Standa Opichal ++ * ++ * This software may be used and distributed according to the terms of ++ * the GNU General Public License (GPL), incorporated herein by reference. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++enum { ++ GET_VERSION = 0, /* no parameters, return NFAPI_VERSION in d0 */ ++ XIF_INTLEVEL, /* no parameters, return Interrupt Level in d0 */ ++ XIF_IRQ, /* acknowledge interrupt from host */ ++ XIF_START, /* (ethX), called on 'ifup', start receiver thread */ ++ XIF_STOP, /* (ethX), called on 'ifdown', stop the thread */ ++ XIF_READLENGTH, /* (ethX), return size of network data block to read */ ++ XIF_READBLOCK, /* (ethX, buffer, size), read block of network data */ ++ XIF_WRITEBLOCK, /* (ethX, buffer, size), write block of network data */ ++ XIF_GET_MAC, /* (ethX, buffer, size), return MAC HW addr in buffer */ ++ XIF_GET_IPHOST, /* (ethX, buffer, size), return IP address of host */ ++ XIF_GET_IPATARI, /* (ethX, buffer, size), return IP address of atari */ ++ XIF_GET_NETMASK /* (ethX, buffer, size), return IP netmask */ ++}; ++ ++#define DRV_NAME "nfeth" ++#define DRV_VERSION "0.3" ++#define DRV_RELDATE "10/12/2005" ++ ++#define MAX_UNIT 8 ++ ++/* These identify the driver base version and may not be removed. */ ++static char version[] __devinitdata = ++KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " S.Opichal, M.Jurik, P.Stehlik\n" ++KERN_INFO " http://aranym.atari.org/\n"; ++ ++MODULE_AUTHOR("Milan Jurik"); ++MODULE_DESCRIPTION("Atari NFeth driver"); ++MODULE_LICENSE("GPL"); ++/* ++MODULE_PARM(nfeth_debug, "i"); ++MODULE_PARM_DESC(nfeth_debug, "nfeth_debug level (1-2)"); ++*/ ++ ++ ++static long nfEtherID; ++static int nfEtherIRQ; ++ ++struct nfeth_private { ++ int ethX; ++ struct net_device_stats stats; ++}; ++ ++static struct net_device *nfeth_dev[MAX_UNIT]; ++ ++int nfeth_open(struct net_device *dev); ++int nfeth_stop(struct net_device *dev); ++irqreturn_t nfeth_interrupt(int irq, void *dev_id); ++int nfeth_xmit(struct sk_buff *skb, struct net_device *dev); ++ ++int nfeth_open(struct net_device *dev) ++{ ++ struct nfeth_private *priv = netdev_priv(dev); ++ int res; ++ ++ res = nf_call(nfEtherID + XIF_START, priv->ethX); ++ ++ /* Clean statistics */ ++ memset(&priv->stats, 0, sizeof(struct net_device_stats)); ++ ++ pr_debug(DRV_NAME ": open %d\n", res); ++ ++ /* Ready for data */ ++ netif_start_queue(dev); ++ ++ return 0; ++} ++ ++int nfeth_stop(struct net_device *dev) ++{ ++ struct nfeth_private *priv = netdev_priv(dev); ++ ++ /* No more data */ ++ netif_stop_queue(dev); ++ ++ nf_call(nfEtherID + XIF_STOP, priv->ethX); ++ ++ return 0; ++} ++ ++/* ++ * Read a packet out of the adapter and pass it to the upper layers ++ */ ++static inline void recv_packet(struct net_device *dev) ++{ ++ struct nfeth_private *priv = netdev_priv(dev); ++ int handled = 0; ++ unsigned short pktlen; ++ struct sk_buff *skb; ++ ++ /* read packet length (excluding 32 bit crc) */ ++ pktlen = nf_call(nfEtherID + XIF_READLENGTH, priv->ethX); ++ ++ pr_debug(DRV_NAME ": recv_packet: %i\n", pktlen); ++ ++ if (!pktlen) { ++ pr_debug(DRV_NAME ": recv_packet: pktlen == 0\n"); ++ priv->stats.rx_errors++; ++ return; ++ } ++ ++ skb = dev_alloc_skb(pktlen + 2); ++ if (!skb) { ++ pr_debug(DRV_NAME ++ ": recv_packet: out of mem (buf_alloc failed)\n"); ++ priv->stats.rx_dropped++; ++ return; ++ } ++ ++ skb->dev = dev; ++ skb_reserve(skb, 2); /* 16 Byte align */ ++ skb_put(skb, pktlen); /* make room */ ++ nf_call(nfEtherID + XIF_READBLOCK, priv->ethX, virt_to_phys(skb->data), ++ pktlen); ++ ++ skb->protocol = eth_type_trans(skb, dev); ++ netif_rx(skb); ++ dev->last_rx = jiffies; ++ priv->stats.rx_packets++; ++ priv->stats.rx_bytes += pktlen; ++ ++ /* and enqueue packet */ ++ handled = 1; ++ return; ++} ++ ++irqreturn_t nfeth_interrupt(int irq, void *dev_id) ++{ ++ int i, m, mask; ++ ++ mask = nf_call(nfEtherID + XIF_IRQ, 0); ++ for (i = 0, m = 1; i < MAX_UNIT; m <<= 1, i++) { ++ if (mask & m && nfeth_dev[i]) { ++ recv_packet(nfeth_dev[i]); ++ nf_call(nfEtherID + XIF_IRQ, m); ++ } ++ } ++ return IRQ_HANDLED; ++} ++ ++int nfeth_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ int len; ++ char *data, shortpkt[ETH_ZLEN]; ++ struct nfeth_private *priv = netdev_priv(dev); ++ ++ data = skb->data; ++ len = skb->len; ++ if (len < ETH_ZLEN) { ++ memset(shortpkt, 0, ETH_ZLEN); ++ memcpy(shortpkt, data, len); ++ data = shortpkt; ++ len = ETH_ZLEN; ++ } ++ ++ dev->trans_start = jiffies; ++ ++ pr_debug(DRV_NAME ": send %d bytes\n", len); ++ nf_call(nfEtherID + XIF_WRITEBLOCK, priv->ethX, virt_to_phys(data), ++ len); ++ ++ priv->stats.tx_packets++; ++ priv->stats.tx_bytes += len; ++ ++ dev_kfree_skb(skb); ++ return 0; ++} ++ ++static void nfeth_tx_timeout(struct net_device *dev) ++{ ++ struct nfeth_private *priv = netdev_priv(dev); ++ priv->stats.tx_errors++; ++ netif_wake_queue(dev); ++} ++ ++static struct net_device_stats *nfeth_get_stats(struct net_device *dev) ++{ ++ struct nfeth_private *priv = netdev_priv(dev); ++ return &priv->stats; ++} ++ ++struct net_device * __init nfeth_probe(int unit) ++{ ++ struct net_device *dev; ++ struct nfeth_private *priv; ++ char mac[ETH_ALEN], host_ip[32], local_ip[32]; ++ DECLARE_MAC_BUF(macfmt); ++ int err; ++ ++ if (!nf_call(nfEtherID + XIF_GET_MAC, unit, mac, ETH_ALEN)) ++ return NULL; ++ ++ dev = alloc_etherdev(sizeof(struct nfeth_private)); ++ if (!dev) ++ return NULL; ++ ++ dev->irq = nfEtherIRQ; ++ dev->open = nfeth_open; ++ dev->stop = nfeth_stop; ++ dev->hard_start_xmit = nfeth_xmit; ++ dev->tx_timeout = nfeth_tx_timeout; ++ dev->get_stats = nfeth_get_stats; ++ dev->flags |= NETIF_F_NO_CSUM; ++ memcpy(dev->dev_addr, mac, ETH_ALEN); ++ ++ priv = netdev_priv(dev); ++ priv->ethX = unit; ++ ++ err = register_netdev(dev); ++ if (err) { ++ free_netdev(dev); ++ return NULL; ++ } ++ ++ nf_call(nfEtherID + XIF_GET_IPHOST, unit, ++ host_ip, sizeof(host_ip)); ++ nf_call(nfEtherID + XIF_GET_IPATARI, unit, ++ local_ip, sizeof(local_ip)); ++ ++ pr_info("%s: nfeth addr:%s (%s) HWaddr:%s\n", dev->name, host_ip, ++ local_ip, print_mac(macfmt, mac)); ++ ++ return dev; ++} ++ ++int __init nfeth_init(void) ++{ ++ long ver; ++ int i; ++ ++ nfEtherID = nf_get_id("ETHERNET"); ++ if (!nfEtherID) ++ return -ENODEV; ++ ++ ver = nf_call(nfEtherID + GET_VERSION); ++ pr_info("nfeth API %lu\n", ver); ++ ++ nfEtherIRQ = nf_call(nfEtherID + XIF_INTLEVEL); ++ if (request_irq(nfEtherIRQ, nfeth_interrupt, IRQF_SHARED, ++ "eth emu", nfeth_interrupt)) { ++ printk(KERN_ERR "nfeth: request for irq %d failed", ++ nfEtherIRQ); ++ return -ENODEV; ++ } ++ ++ for (i = 0; i < MAX_UNIT; i++) ++ nfeth_dev[i] = nfeth_probe(i); ++ ++ return 0; ++} ++ ++void __exit nfeth_cleanup(void) ++{ ++ int i; ++ ++ for (i = 0; i < MAX_UNIT; i++) { ++ if (nfeth_dev[i]) { ++ unregister_netdev(nfeth_dev[0]); ++ free_netdev(nfeth_dev[0]); ++ } ++ } ++ free_irq(nfEtherIRQ, nfeth_interrupt); ++} ++ ++module_init(nfeth_init); ++module_exit(nfeth_cleanup); +--- a/arch/m68k/kernel/setup.c ++++ b/arch/m68k/kernel/setup.c +@@ -39,6 +39,7 @@ + #ifdef CONFIG_SUN3X + #include + #endif ++#include + + unsigned long m68k_machtype; + unsigned long m68k_cputype; +@@ -314,6 +315,10 @@ void __init setup_arch(char **cmdline_p) + panic("No configuration setup"); + } + ++#ifdef CONFIG_NATFEAT ++ nf_init(); ++#endif ++ + paging_init(); + + #ifndef CONFIG_SUN3 +--- a/drivers/net/Kconfig ++++ b/drivers/net/Kconfig +@@ -428,6 +428,14 @@ config ATARILANCE + on the AMD Lance chipset: RieblCard (with or without battery), or + PAMCard VME (also the version by Rhotron, with different addresses). + ++config ATARI_ETHERNEC ++ tristate "Atari EtherNEC Ethernet support" ++ depends on NET_ETHERNET && ATARI && ATARI_ROM_ISA ++ help ++ Say Y to include support for the EtherNEC network adapter for the ++ ROM port. The driver works by polling instead of interrupts, so it ++ is quite slow. ++ + config SUN3LANCE + tristate "Sun3/Sun3x on-board LANCE support" + depends on SUN3 || SUN3X +--- /dev/null ++++ b/include/asm-m68k/natfeat.h +@@ -0,0 +1,22 @@ ++/* ++ * ARAnyM hardware support via Native Features (natfeats) ++ * ++ * Copyright (c) 2005 Petr Stehlik of ARAnyM dev team ++ * ++ * This software may be used and distributed according to the terms of ++ * the GNU General Public License (GPL), incorporated herein by reference. ++ */ ++ ++#ifndef _NATFEAT_H ++#define _NATFEAT_H ++ ++long nf_get_id(const char *feature_name); ++long nf_call(long id, ...); ++ ++void nf_init(void); ++void nf_shutdown(void); ++ ++void nfprint(const char *fmt, ...) ++ __attribute__ ((format (printf, 1, 2))); ++ ++# endif /* _NATFEAT_H */ diff --git a/debian/patches/bugfix/m68k/2.6.24/atari-ethernat.diff b/debian/patches/bugfix/m68k/2.6.24/atari-ethernat.diff new file mode 100644 index 000000000..724437717 --- /dev/null +++ b/debian/patches/bugfix/m68k/2.6.24/atari-ethernat.diff @@ -0,0 +1,2581 @@ +From schmitz@opal.biophys.uni-duesseldorf.de Mon Oct 22 10:03:40 2007 +Date: Mon, 22 Oct 2007 09:27:52 +0200 (CEST) +From: Michael Schmitz +To: Geert Uytterhoeven +Cc: Michael Schmitz , linux-m68k@vger.kernel.org, cts@debian.org +Subject: [PATCH] Atari EtherNAT (SMC91C111) driver + +Hi Geert, + +> On Sun, 21 Oct 2007, Michael Schmitz wrote: +> > this patch is needed to make the Atari EtherNEC driver with the associated +> > ROM port ISA I/O stuff compile again. This is relative to your quilt patch +> > queue and git 2.6 as of yesterday. Please apply. +> +> Thanks, applied. + +Thanks - I'll have a few updates to this shortly, just noticed the +multi-byte IO emulation (inw, inl etc.) that we discussed months ago had +gone missing from the patch. That's what you get for keeping too many +trees around. + +But first things first - I finally had enough time to work on the platform +driver code I need for the SMC91C111 driver aka EtherNAT driver for the +Falcon. Here's the patch - I could only test it so far on ARAnyM, meaning +the driver correctly fails to load because the hardware cannot be found. +Christian may be able to build the driver and test on his Falcon before I +get mine set up. + +One thing that I am not entirely happy about is having the driver resource +registered unconditionally in atari/config.c, regardless whether the +driver is built or not. May I incude autoconf.h in the arch code? The +other one is a kconfig issue - I need to select MMIO either as module or +builtin, depending on how the EtherNAT driver is built. That does not +appear to be automatic yet. + +Aside from that, at least something that can be tested. + +Signed-off-by: Michael Schmitz + +--- + arch/m68k/atari/config.c | 41 + drivers/net/Kconfig | 10 + drivers/net/Makefile | 1 + drivers/net/atari_91C111.c | 2437 +++++++++++++++++++++++++++++++++++++++++++++ + include/asm-m68k/io.h | 2 + 5 files changed, 2491 insertions(+) + +--- a/arch/m68k/atari/config.c ++++ b/arch/m68k/atari/config.c +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -670,3 +671,43 @@ static int atari_get_hardware_list(char + + return len; + } ++ ++/* ++ * MSch: initial platform device support for Atari, required for EtherNAT ++ */ ++ ++#define ATARI_ETHERNAT_PHYS_ADDR 0x80000000 ++#define ATARI_ETHERNAT_IRQ 0xc3 ++ ++static struct resource smc91x_resources[] = { ++ [0] = { ++ .name = "smc91x-regs", ++ .start = ATARI_ETHERNAT_PHYS_ADDR, ++ .end = ATARI_ETHERNAT_PHYS_ADDR + 0xfffff, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .name = "smc91x-irq", ++ .start = ATARI_ETHERNAT_IRQ, ++ .end = ATARI_ETHERNAT_IRQ, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device smc91x_device = { ++ .name = "smc91x", ++ .id = -1, ++ .num_resources = ARRAY_SIZE(smc91x_resources), ++ .resource = smc91x_resources, ++}; ++ ++static struct platform_device *atari_platform_devices[] __initdata = { ++ &smc91x_device ++}; ++ ++int __init atari_platform_init(void) ++{ ++ return platform_add_devices(atari_platform_devices, ARRAY_SIZE(atari_platform_devices)); ++} ++ ++arch_initcall(atari_platform_init); +--- a/drivers/net/Kconfig ++++ b/drivers/net/Kconfig +@@ -436,6 +436,16 @@ config ATARI_ETHERNEC + ROM port. The driver works by polling instead of interrupts, so it + is quite slow. + ++config ATARI_ETHERNAT ++ tristate "Atari EtherNAT Ethernet support" ++ select CRC32 ++ select MII ++ depends on NET_ETHERNET && ATARI ++ help ++ Say Y to include support for the EtherNAT network adapter for the ++ CT/60 extension port. The driver works by polling instead of ++ interrupts, so it is quite slow. ++ + config SUN3LANCE + tristate "Sun3/Sun3x on-board LANCE support" + depends on SUN3 || SUN3X +--- a/drivers/net/Makefile ++++ b/drivers/net/Makefile +@@ -194,6 +194,7 @@ obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o + obj-$(CONFIG_DECLANCE) += declance.o + obj-$(CONFIG_ATARILANCE) += atarilance.o + obj-$(CONFIG_ATARI_ETHERNEC) += atari_ethernec.o 8390.o ++obj-$(CONFIG_ATARI_ETHERNAT) += atari_91C111.o + obj-$(CONFIG_A2065) += a2065.o + obj-$(CONFIG_HYDRA) += hydra.o + obj-$(CONFIG_ARIADNE) += ariadne.o +--- /dev/null ++++ b/drivers/net/atari_91C111.c +@@ -0,0 +1,2437 @@ ++/* ++ * smc91x.c ++ * This is a driver for SMSC's 91C9x/91C1xx single-chip Ethernet devices. ++ * ++ * Copyright (C) 1996 by Erik Stahlman ++ * Copyright (C) 2001 Standard Microsystems Corporation ++ * Developed by Simple Network Magic Corporation ++ * Copyright (C) 2003 Monta Vista Software, Inc. ++ * Unified SMC91x driver by Nicolas Pitre ++ * ++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * Arguments: ++ * io = for the base address ++ * irq = for the IRQ ++ * nowait = 0 for normal wait states, 1 eliminates additional wait states ++ * ++ * original author: ++ * Erik Stahlman ++ * ++ * hardware multicast code: ++ * Peter Cammaert ++ * ++ * contributors: ++ * Daris A Nevil ++ * Nicolas Pitre ++ * Russell King ++ * ++ * History: ++ * 08/20/00 Arnaldo Melo fix kfree(skb) in smc_hardware_send_packet ++ * 12/15/00 Christian Jullien fix "Warning: kfree_skb on hard IRQ" ++ * 03/16/01 Daris A Nevil modified smc9194.c for use with LAN91C111 ++ * 08/22/01 Scott Anderson merge changes from smc9194 to smc91111 ++ * 08/21/01 Pramod B Bhardwaj added support for RevB of LAN91C111 ++ * 12/20/01 Jeff Sutherland initial port to Xscale PXA with DMA support ++ * 04/07/03 Nicolas Pitre unified SMC91x driver, killed irq races, ++ * more bus abstraction, big cleanup, etc. ++ * 29/09/03 Russell King - add driver model support ++ * - ethtool support ++ * - convert to use generic MII interface ++ * - add link up/down notification ++ * - don't try to handle full negotiation in ++ * smc_phy_configure ++ * - clean up (and fix stack overrun) in PHY ++ * MII read/write functions ++ * 22/09/04 Nicolas Pitre big update (see commit log for details) ++ */ ++static const char version[] = ++ "smc91x.c: v1.1, sep 22 2004 by Nicolas Pitre \n"; ++ ++#define SMC_DEBUG 2 ++ ++/* Debugging level */ ++#ifndef SMC_DEBUG ++#define SMC_DEBUG 0 ++#endif ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "smc91x.h" ++ ++#ifdef CONFIG_ISA ++/* ++ * the LAN91C111 can be at any of the following port addresses. To change, ++ * for a slightly different card, you can add it to the array. Keep in ++ * mind that the array must end in zero. ++ */ ++static unsigned int smc_portlist[] __initdata = { ++ 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, ++ 0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0 ++}; ++ ++#endif /* CONFIG_ISA */ ++ ++#ifndef SMC_IOADDR ++# define SMC_IOADDR -1 ++#endif ++static unsigned long io = SMC_IOADDR; ++module_param(io, ulong, 0400); ++MODULE_PARM_DESC(io, "I/O base address"); ++ ++#ifndef SMC_IRQ ++# define SMC_IRQ -1 ++#endif ++static int irq = SMC_IRQ; ++module_param(irq, int, 0400); ++MODULE_PARM_DESC(irq, "IRQ number"); ++ ++ ++#ifndef SMC_NOWAIT ++# define SMC_NOWAIT 0 ++#endif ++static int nowait = SMC_NOWAIT; ++module_param(nowait, int, 0400); ++MODULE_PARM_DESC(nowait, "set to 1 for no wait state"); ++ ++/* ++ * Transmit timeout, default 5 seconds. ++ */ ++static int watchdog = 1000; ++module_param(watchdog, int, 0400); ++MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds"); ++ ++MODULE_LICENSE("GPL"); ++ ++/* ++ * The internal workings of the driver. If you are changing anything ++ * here with the SMC stuff, you should have the datasheet and know ++ * what you are doing. ++ */ ++#define CARDNAME "smc91x" ++ ++/* ++ * Use power-down feature of the chip ++ */ ++#define POWER_DOWN 1 ++ ++/* ++ * Wait time for memory to be free. This probably shouldn't be ++ * tuned that much, as waiting for this means nothing else happens ++ * in the system ++ */ ++#define MEMORY_WAIT_TIME 16 ++ ++/* ++ * The maximum number of processing loops allowed for each call to the ++ * IRQ handler. ++ */ ++#define MAX_IRQ_LOOPS 8 ++ ++/* ++ * This selects whether TX packets are sent one by one to the SMC91x internal ++ * memory and throttled until transmission completes. This may prevent ++ * RX overruns a litle by keeping much of the memory free for RX packets ++ * but to the expense of reduced TX throughput and increased IRQ overhead. ++ * Note this is not a cure for a too slow data bus or too high IRQ latency. ++ */ ++#define THROTTLE_TX_PKTS 0 ++ ++/* ++ * The MII clock high/low times. 2x this number gives the MII clock period ++ * in microseconds. (was 50, but this gives 6.4ms for each MII transaction!) ++ */ ++#define MII_DELAY 1 ++ ++#if SMC_DEBUG > 0 ++#define DBG(n, args...) \ ++ do { \ ++ if (SMC_DEBUG >= (n)) \ ++ printk(args); \ ++ } while (0) ++ ++#define PRINTK(args...) printk(args) ++#else ++#define DBG(n, args...) do { } while(0) ++#define PRINTK(args...) printk(KERN_DEBUG args) ++#endif ++ ++#if SMC_DEBUG > 3 ++static void PRINT_PKT(u_char *buf, int length) ++{ ++ int i; ++ int remainder; ++ int lines; ++ ++ lines = length / 16; ++ remainder = length % 16; ++ ++ for (i = 0; i < lines ; i ++) { ++ int cur; ++ for (cur = 0; cur < 8; cur++) { ++ u_char a, b; ++ a = *buf++; ++ b = *buf++; ++ printk("%02x%02x ", a, b); ++ } ++ printk("\n"); ++ } ++ for (i = 0; i < remainder/2 ; i++) { ++ u_char a, b; ++ a = *buf++; ++ b = *buf++; ++ printk("%02x%02x ", a, b); ++ } ++ printk("\n"); ++} ++#else ++#define PRINT_PKT(x...) do { } while(0) ++#endif ++ ++ ++/* this enables an interrupt in the interrupt mask register */ ++#define SMC_ENABLE_INT(x) do { \ ++ unsigned char mask; \ ++ spin_lock_irq(&lp->lock); \ ++ mask = SMC_GET_INT_MASK(); \ ++ mask |= (x); \ ++ SMC_SET_INT_MASK(mask); \ ++ spin_unlock_irq(&lp->lock); \ ++} while (0) ++ ++/* this disables an interrupt from the interrupt mask register */ ++#define SMC_DISABLE_INT(x) do { \ ++ unsigned char mask; \ ++ spin_lock_irq(&lp->lock); \ ++ mask = SMC_GET_INT_MASK(); \ ++ mask &= ~(x); \ ++ SMC_SET_INT_MASK(mask); \ ++ spin_unlock_irq(&lp->lock); \ ++} while (0) ++ ++/* ++ * Wait while MMU is busy. This is usually in the order of a few nanosecs ++ * if at all, but let's avoid deadlocking the system if the hardware ++ * decides to go south. ++ */ ++#define SMC_WAIT_MMU_BUSY() do { \ ++ if (unlikely(SMC_GET_MMU_CMD() & MC_BUSY)) { \ ++ unsigned long timeout = jiffies + 2; \ ++ while (SMC_GET_MMU_CMD() & MC_BUSY) { \ ++ if (time_after(jiffies, timeout)) { \ ++ printk("%s: timeout %s line %d\n", \ ++ dev->name, __FILE__, __LINE__); \ ++ break; \ ++ } \ ++ cpu_relax(); \ ++ } \ ++ } \ ++} while (0) ++ ++/* ++ * Timer based operation on Atari ++ */ ++static irqreturn_t smc_interrupt(int irq, void *dev_id); ++ ++static int use_poll = 0; ++module_param(use_poll, int, 0); ++MODULE_PARM_DESC(use_poll, "Use timer interrupt to poll driver"); ++ ++/* This is used by cleanup, to prevent the module from being unloaded while ++ * intrpt_routine is still in the task queue ++ */ ++static wait_queue_head_t WaitQ; ++ ++static struct delayed_work tqueue; ++ ++static struct net_device *poll_dev = NULL; ++ ++static void atari_ethernat_int(struct work_struct *work) ++{ ++ struct net_device *dev = poll_dev; ++ ++ if(!dev) { ++ /* If cleanup wants us to die */ ++ if (waitqueue_active(&WaitQ)) ++ wake_up(&WaitQ); /* Now cleanup_module can return */ ++ else ++ /* Put ourselves back in the task queue */ ++ schedule_delayed_work(&tqueue, 1); ++ return; ++ } ++ ++ if (netif_running(dev)) { ++ smc_interrupt(dev->irq, dev); ++ } ++ ++ /* If cleanup wants us to die */ ++ if (waitqueue_active(&WaitQ)) ++ wake_up(&WaitQ); /* Now cleanup_module can return */ ++ else ++ /* Put ourselves back in the task queue */ ++ schedule_delayed_work(&tqueue, 0); /* reduced delay from 1 */ ++} ++ ++static void atari_ethernat_start_poll(struct net_device *dev) ++{ ++ poll_dev = dev; ++ ++ init_waitqueue_head(&WaitQ); ++ ++ /* MSch: need to insert dev into work struct?? */ ++ ++ INIT_DELAYED_WORK(&tqueue, atari_ethernat_int); ++ schedule_delayed_work(&tqueue, 1); ++} ++ ++static void atari_ethernat_stop_poll(struct net_device *dev) ++{ ++ poll_dev = NULL; ++ ++ if (dev) { ++ sleep_on(&WaitQ); ++ } ++} ++ ++ ++ ++/* ++ * this does a soft reset on the device ++ */ ++static void smc_reset(struct net_device *dev) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ void __iomem *ioaddr = lp->base; ++ unsigned int ctl, cfg; ++ struct sk_buff *pending_skb; ++ ++ DBG(2, "%s: %s\n", dev->name, __FUNCTION__); ++ ++ /* Disable all interrupts, block TX tasklet */ ++ spin_lock_irq(&lp->lock); ++ SMC_SELECT_BANK(2); ++ SMC_SET_INT_MASK(0); ++ pending_skb = lp->pending_tx_skb; ++ lp->pending_tx_skb = NULL; ++ spin_unlock_irq(&lp->lock); ++ ++ /* free any pending tx skb */ ++ if (pending_skb) { ++ dev_kfree_skb(pending_skb); ++ dev->stats.tx_errors++; ++ dev->stats.tx_aborted_errors++; ++ } ++ ++ /* ++ * This resets the registers mostly to defaults, but doesn't ++ * affect EEPROM. That seems unnecessary ++ */ ++ SMC_SELECT_BANK(0); ++ SMC_SET_RCR(RCR_SOFTRST); ++ ++ /* ++ * Setup the Configuration Register ++ * This is necessary because the CONFIG_REG is not affected ++ * by a soft reset ++ */ ++ SMC_SELECT_BANK(1); ++ ++ cfg = CONFIG_DEFAULT; ++ ++ /* ++ * Setup for fast accesses if requested. If the card/system ++ * can't handle it then there will be no recovery except for ++ * a hard reset or power cycle ++ */ ++ if (nowait) ++ cfg |= CONFIG_NO_WAIT; ++ ++ /* ++ * Release from possible power-down state ++ * Configuration register is not affected by Soft Reset ++ */ ++ cfg |= CONFIG_EPH_POWER_EN; ++ ++ SMC_SET_CONFIG(cfg); ++ ++ /* this should pause enough for the chip to be happy */ ++ /* ++ * elaborate? What does the chip _need_? --jgarzik ++ * ++ * This seems to be undocumented, but something the original ++ * driver(s) have always done. Suspect undocumented timing ++ * info/determined empirically. --rmk ++ */ ++ udelay(1); ++ ++ /* Disable transmit and receive functionality */ ++ SMC_SELECT_BANK(0); ++ SMC_SET_RCR(RCR_CLEAR); ++ SMC_SET_TCR(TCR_CLEAR); ++ ++ SMC_SELECT_BANK(1); ++ ctl = SMC_GET_CTL() | CTL_LE_ENABLE; ++ ++ /* ++ * Set the control register to automatically release successfully ++ * transmitted packets, to make the best use out of our limited ++ * memory ++ */ ++ if(!THROTTLE_TX_PKTS) ++ ctl |= CTL_AUTO_RELEASE; ++ else ++ ctl &= ~CTL_AUTO_RELEASE; ++ SMC_SET_CTL(ctl); ++ ++ /* Reset the MMU */ ++ SMC_SELECT_BANK(2); ++ SMC_SET_MMU_CMD(MC_RESET); ++ SMC_WAIT_MMU_BUSY(); ++} ++ ++/* ++ * Enable Interrupts, Receive, and Transmit ++ */ ++static void smc_enable(struct net_device *dev) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ void __iomem *ioaddr = lp->base; ++ int mask; ++ ++ DBG(2, "%s: %s\n", dev->name, __FUNCTION__); ++ ++ /* see the header file for options in TCR/RCR DEFAULT */ ++ SMC_SELECT_BANK(0); ++ SMC_SET_TCR(lp->tcr_cur_mode); ++ SMC_SET_RCR(lp->rcr_cur_mode); ++ ++ SMC_SELECT_BANK(1); ++ SMC_SET_MAC_ADDR(dev->dev_addr); ++ ++ /* now, enable interrupts */ ++ mask = IM_EPH_INT|IM_RX_OVRN_INT|IM_RCV_INT; ++ if (lp->version >= (CHIP_91100 << 4)) ++ mask |= IM_MDINT; ++ SMC_SELECT_BANK(2); ++ SMC_SET_INT_MASK(mask); ++ ++ /* ++ * From this point the register bank must _NOT_ be switched away ++ * to something else than bank 2 without proper locking against ++ * races with any tasklet or interrupt handlers until smc_shutdown() ++ * or smc_reset() is called. ++ */ ++} ++ ++/* ++ * this puts the device in an inactive state ++ */ ++static void smc_shutdown(struct net_device *dev) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ void __iomem *ioaddr = lp->base; ++ struct sk_buff *pending_skb; ++ ++ DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__); ++ ++ /* no more interrupts for me */ ++ spin_lock_irq(&lp->lock); ++ SMC_SELECT_BANK(2); ++ SMC_SET_INT_MASK(0); ++ pending_skb = lp->pending_tx_skb; ++ lp->pending_tx_skb = NULL; ++ spin_unlock_irq(&lp->lock); ++ if (pending_skb) ++ dev_kfree_skb(pending_skb); ++ ++ /* and tell the card to stay away from that nasty outside world */ ++ SMC_SELECT_BANK(0); ++ SMC_SET_RCR(RCR_CLEAR); ++ SMC_SET_TCR(TCR_CLEAR); ++ ++#ifdef POWER_DOWN ++ /* finally, shut the chip down */ ++ SMC_SELECT_BANK(1); ++ SMC_SET_CONFIG(SMC_GET_CONFIG() & ~CONFIG_EPH_POWER_EN); ++#endif ++} ++ ++/* ++ * This is the procedure to handle the receipt of a packet. ++ */ ++static inline void smc_rcv(struct net_device *dev) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ void __iomem *ioaddr = lp->base; ++ unsigned int packet_number, status, packet_len; ++ ++ DBG(3, "%s: %s\n", dev->name, __FUNCTION__); ++ ++ packet_number = SMC_GET_RXFIFO(); ++ if (unlikely(packet_number & RXFIFO_REMPTY)) { ++ PRINTK("%s: smc_rcv with nothing on FIFO.\n", dev->name); ++ return; ++ } ++ ++ /* read from start of packet */ ++ SMC_SET_PTR(PTR_READ | PTR_RCV | PTR_AUTOINC); ++ ++ /* First two words are status and packet length */ ++ SMC_GET_PKT_HDR(status, packet_len); ++ packet_len &= 0x07ff; /* mask off top bits */ ++ DBG(2, "%s: RX PNR 0x%x STATUS 0x%04x LENGTH 0x%04x (%d)\n", ++ dev->name, packet_number, status, ++ packet_len, packet_len); ++ ++ back: ++ if (unlikely(packet_len < 6 || status & RS_ERRORS)) { ++ if (status & RS_TOOLONG && packet_len <= (1514 + 4 + 6)) { ++ /* accept VLAN packets */ ++ status &= ~RS_TOOLONG; ++ goto back; ++ } ++ if (packet_len < 6) { ++ /* bloody hardware */ ++ printk(KERN_ERR "%s: fubar (rxlen %u status %x\n", ++ dev->name, packet_len, status); ++ status |= RS_TOOSHORT; ++ } ++ SMC_WAIT_MMU_BUSY(); ++ SMC_SET_MMU_CMD(MC_RELEASE); ++ dev->stats.rx_errors++; ++ if (status & RS_ALGNERR) ++ dev->stats.rx_frame_errors++; ++ if (status & (RS_TOOSHORT | RS_TOOLONG)) ++ dev->stats.rx_length_errors++; ++ if (status & RS_BADCRC) ++ dev->stats.rx_crc_errors++; ++ } else { ++ struct sk_buff *skb; ++ unsigned char *data; ++ unsigned int data_len; ++ ++ /* set multicast stats */ ++ if (status & RS_MULTICAST) ++ dev->stats.multicast++; ++ ++ /* ++ * Actual payload is packet_len - 6 (or 5 if odd byte). ++ * We want skb_reserve(2) and the final ctrl word ++ * (2 bytes, possibly containing the payload odd byte). ++ * Furthermore, we add 2 bytes to allow rounding up to ++ * multiple of 4 bytes on 32 bit buses. ++ * Hence packet_len - 6 + 2 + 2 + 2. ++ */ ++ skb = dev_alloc_skb(packet_len); ++ if (unlikely(skb == NULL)) { ++ printk(KERN_NOTICE "%s: Low memory, packet dropped.\n", ++ dev->name); ++ SMC_WAIT_MMU_BUSY(); ++ SMC_SET_MMU_CMD(MC_RELEASE); ++ dev->stats.rx_dropped++; ++ return; ++ } ++ ++ /* Align IP header to 32 bits */ ++ skb_reserve(skb, 2); ++ ++ /* BUG: the LAN91C111 rev A never sets this bit. Force it. */ ++ if (lp->version == 0x90) ++ status |= RS_ODDFRAME; ++ ++ /* ++ * If odd length: packet_len - 5, ++ * otherwise packet_len - 6. ++ * With the trailing ctrl byte it's packet_len - 4. ++ */ ++ data_len = packet_len - ((status & RS_ODDFRAME) ? 5 : 6); ++ data = skb_put(skb, data_len); ++ SMC_PULL_DATA(data, packet_len - 4); ++ ++ SMC_WAIT_MMU_BUSY(); ++ SMC_SET_MMU_CMD(MC_RELEASE); ++ ++ PRINT_PKT(data, packet_len - 4); ++ ++ dev->last_rx = jiffies; ++ skb->protocol = eth_type_trans(skb, dev); ++ netif_rx(skb); ++ dev->stats.rx_packets++; ++ dev->stats.rx_bytes += data_len; ++ } ++} ++ ++#ifdef CONFIG_SMP ++/* ++ * On SMP we have the following problem: ++ * ++ * A = smc_hardware_send_pkt() ++ * B = smc_hard_start_xmit() ++ * C = smc_interrupt() ++ * ++ * A and B can never be executed simultaneously. However, at least on UP, ++ * it is possible (and even desirable) for C to interrupt execution of ++ * A or B in order to have better RX reliability and avoid overruns. ++ * C, just like A and B, must have exclusive access to the chip and ++ * each of them must lock against any other concurrent access. ++ * Unfortunately this is not possible to have C suspend execution of A or ++ * B taking place on another CPU. On UP this is no an issue since A and B ++ * are run from softirq context and C from hard IRQ context, and there is ++ * no other CPU where concurrent access can happen. ++ * If ever there is a way to force at least B and C to always be executed ++ * on the same CPU then we could use read/write locks to protect against ++ * any other concurrent access and C would always interrupt B. But life ++ * isn't that easy in a SMP world... ++ */ ++#define smc_special_trylock(lock) \ ++({ \ ++ int __ret; \ ++ local_irq_disable(); \ ++ __ret = spin_trylock(lock); \ ++ if (!__ret) \ ++ local_irq_enable(); \ ++ __ret; \ ++}) ++#define smc_special_lock(lock) spin_lock_irq(lock) ++#define smc_special_unlock(lock) spin_unlock_irq(lock) ++#else ++#define smc_special_trylock(lock) (1) ++#define smc_special_lock(lock) do { } while (0) ++#define smc_special_unlock(lock) do { } while (0) ++#endif ++ ++/* ++ * This is called to actually send a packet to the chip. ++ */ ++static void smc_hardware_send_pkt(unsigned long data) ++{ ++ struct net_device *dev = (struct net_device *)data; ++ struct smc_local *lp = netdev_priv(dev); ++ void __iomem *ioaddr = lp->base; ++ struct sk_buff *skb; ++ unsigned int packet_no, len; ++ unsigned char *buf; ++ ++ DBG(3, "%s: %s\n", dev->name, __FUNCTION__); ++ ++ if (!smc_special_trylock(&lp->lock)) { ++ netif_stop_queue(dev); ++ tasklet_schedule(&lp->tx_task); ++ return; ++ } ++ ++ skb = lp->pending_tx_skb; ++ if (unlikely(!skb)) { ++ smc_special_unlock(&lp->lock); ++ return; ++ } ++ lp->pending_tx_skb = NULL; ++ ++ packet_no = SMC_GET_AR(); ++ if (unlikely(packet_no & AR_FAILED)) { ++ printk("%s: Memory allocation failed.\n", dev->name); ++ dev->stats.tx_errors++; ++ dev->stats.tx_fifo_errors++; ++ smc_special_unlock(&lp->lock); ++ goto done; ++ } ++ ++ /* point to the beginning of the packet */ ++ SMC_SET_PN(packet_no); ++ SMC_SET_PTR(PTR_AUTOINC); ++ ++ buf = skb->data; ++ len = skb->len; ++ DBG(2, "%s: TX PNR 0x%x LENGTH 0x%04x (%d) BUF 0x%p\n", ++ dev->name, packet_no, len, len, buf); ++ PRINT_PKT(buf, len); ++ ++ /* ++ * Send the packet length (+6 for status words, length, and ctl. ++ * The card will pad to 64 bytes with zeroes if packet is too small. ++ */ ++ SMC_PUT_PKT_HDR(0, len + 6); ++ ++ /* send the actual data */ ++ SMC_PUSH_DATA(buf, len & ~1); ++ ++ /* Send final ctl word with the last byte if there is one */ ++ SMC_outw(((len & 1) ? (0x2000 | buf[len-1]) : 0), ioaddr, DATA_REG); ++ ++ /* ++ * If THROTTLE_TX_PKTS is set, we stop the queue here. This will ++ * have the effect of having at most one packet queued for TX ++ * in the chip's memory at all time. ++ * ++ * If THROTTLE_TX_PKTS is not set then the queue is stopped only ++ * when memory allocation (MC_ALLOC) does not succeed right away. ++ */ ++ if (THROTTLE_TX_PKTS) ++ netif_stop_queue(dev); ++ ++ /* queue the packet for TX */ ++ SMC_SET_MMU_CMD(MC_ENQUEUE); ++ smc_special_unlock(&lp->lock); ++ ++ dev->trans_start = jiffies; ++ dev->stats.tx_packets++; ++ dev->stats.tx_bytes += len; ++ ++ SMC_ENABLE_INT(IM_TX_INT | IM_TX_EMPTY_INT); ++ ++done: if (!THROTTLE_TX_PKTS) ++ netif_wake_queue(dev); ++ ++ dev_kfree_skb(skb); ++} ++ ++/* ++ * Since I am not sure if I will have enough room in the chip's ram ++ * to store the packet, I call this routine which either sends it ++ * now, or set the card to generates an interrupt when ready ++ * for the packet. ++ */ ++static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ void __iomem *ioaddr = lp->base; ++ unsigned int numPages, poll_count, status; ++ ++ DBG(3, "%s: %s\n", dev->name, __FUNCTION__); ++ ++ BUG_ON(lp->pending_tx_skb != NULL); ++ ++ /* ++ * The MMU wants the number of pages to be the number of 256 bytes ++ * 'pages', minus 1 (since a packet can't ever have 0 pages :)) ++ * ++ * The 91C111 ignores the size bits, but earlier models don't. ++ * ++ * Pkt size for allocating is data length +6 (for additional status ++ * words, length and ctl) ++ * ++ * If odd size then last byte is included in ctl word. ++ */ ++ numPages = ((skb->len & ~1) + (6 - 1)) >> 8; ++ if (unlikely(numPages > 7)) { ++ printk("%s: Far too big packet error.\n", dev->name); ++ dev->stats.tx_errors++; ++ dev->stats.tx_dropped++; ++ dev_kfree_skb(skb); ++ return 0; ++ } ++ ++ smc_special_lock(&lp->lock); ++ ++ /* now, try to allocate the memory */ ++ SMC_SET_MMU_CMD(MC_ALLOC | numPages); ++ ++ /* ++ * Poll the chip for a short amount of time in case the ++ * allocation succeeds quickly. ++ */ ++ poll_count = MEMORY_WAIT_TIME; ++ do { ++ status = SMC_GET_INT(); ++ if (status & IM_ALLOC_INT) { ++ SMC_ACK_INT(IM_ALLOC_INT); ++ break; ++ } ++ } while (--poll_count); ++ ++ smc_special_unlock(&lp->lock); ++ ++ lp->pending_tx_skb = skb; ++ if (!poll_count) { ++ /* oh well, wait until the chip finds memory later */ ++ netif_stop_queue(dev); ++ DBG(2, "%s: TX memory allocation deferred.\n", dev->name); ++ SMC_ENABLE_INT(IM_ALLOC_INT); ++ } else { ++ /* ++ * Allocation succeeded: push packet to the chip's own memory ++ * immediately. ++ */ ++ smc_hardware_send_pkt((unsigned long)dev); ++ } ++ ++ return 0; ++} ++ ++/* ++ * This handles a TX interrupt, which is only called when: ++ * - a TX error occurred, or ++ * - CTL_AUTO_RELEASE is not set and TX of a packet completed. ++ */ ++static void smc_tx(struct net_device *dev) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ void __iomem *ioaddr = lp->base; ++ unsigned int saved_packet, packet_no, tx_status, pkt_len; ++ ++ DBG(3, "%s: %s\n", dev->name, __FUNCTION__); ++ ++ /* If the TX FIFO is empty then nothing to do */ ++ packet_no = SMC_GET_TXFIFO(); ++ if (unlikely(packet_no & TXFIFO_TEMPTY)) { ++ PRINTK("%s: smc_tx with nothing on FIFO.\n", dev->name); ++ return; ++ } ++ ++ /* select packet to read from */ ++ saved_packet = SMC_GET_PN(); ++ SMC_SET_PN(packet_no); ++ ++ /* read the first word (status word) from this packet */ ++ SMC_SET_PTR(PTR_AUTOINC | PTR_READ); ++ SMC_GET_PKT_HDR(tx_status, pkt_len); ++ DBG(2, "%s: TX STATUS 0x%04x PNR 0x%02x\n", ++ dev->name, tx_status, packet_no); ++ ++ if (!(tx_status & ES_TX_SUC)) ++ dev->stats.tx_errors++; ++ ++ if (tx_status & ES_LOSTCARR) ++ dev->stats.tx_carrier_errors++; ++ ++ if (tx_status & (ES_LATCOL | ES_16COL)) { ++ PRINTK("%s: %s occurred on last xmit\n", dev->name, ++ (tx_status & ES_LATCOL) ? ++ "late collision" : "too many collisions"); ++ dev->stats.tx_window_errors++; ++ if (!(dev->stats.tx_window_errors & 63) && net_ratelimit()) { ++ printk(KERN_INFO "%s: unexpectedly large number of " ++ "bad collisions. Please check duplex " ++ "setting.\n", dev->name); ++ } ++ } ++ ++ /* kill the packet */ ++ SMC_WAIT_MMU_BUSY(); ++ SMC_SET_MMU_CMD(MC_FREEPKT); ++ ++ /* Don't restore Packet Number Reg until busy bit is cleared */ ++ SMC_WAIT_MMU_BUSY(); ++ SMC_SET_PN(saved_packet); ++ ++ /* re-enable transmit */ ++ SMC_SELECT_BANK(0); ++ SMC_SET_TCR(lp->tcr_cur_mode); ++ SMC_SELECT_BANK(2); ++} ++ ++ ++/*---PHY CONTROL AND CONFIGURATION-----------------------------------------*/ ++ ++static void smc_mii_out(struct net_device *dev, unsigned int val, int bits) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ void __iomem *ioaddr = lp->base; ++ unsigned int mii_reg, mask; ++ ++ mii_reg = SMC_GET_MII() & ~(MII_MCLK | MII_MDOE | MII_MDO); ++ mii_reg |= MII_MDOE; ++ ++ for (mask = 1 << (bits - 1); mask; mask >>= 1) { ++ if (val & mask) ++ mii_reg |= MII_MDO; ++ else ++ mii_reg &= ~MII_MDO; ++ ++ SMC_SET_MII(mii_reg); ++ udelay(MII_DELAY); ++ SMC_SET_MII(mii_reg | MII_MCLK); ++ udelay(MII_DELAY); ++ } ++} ++ ++static unsigned int smc_mii_in(struct net_device *dev, int bits) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ void __iomem *ioaddr = lp->base; ++ unsigned int mii_reg, mask, val; ++ ++ mii_reg = SMC_GET_MII() & ~(MII_MCLK | MII_MDOE | MII_MDO); ++ SMC_SET_MII(mii_reg); ++ ++ for (mask = 1 << (bits - 1), val = 0; mask; mask >>= 1) { ++ if (SMC_GET_MII() & MII_MDI) ++ val |= mask; ++ ++ SMC_SET_MII(mii_reg); ++ udelay(MII_DELAY); ++ SMC_SET_MII(mii_reg | MII_MCLK); ++ udelay(MII_DELAY); ++ } ++ ++ return val; ++} ++ ++/* ++ * Reads a register from the MII Management serial interface ++ */ ++static int smc_phy_read(struct net_device *dev, int phyaddr, int phyreg) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ void __iomem *ioaddr = lp->base; ++ unsigned int phydata; ++ ++ SMC_SELECT_BANK(3); ++ ++ /* Idle - 32 ones */ ++ smc_mii_out(dev, 0xffffffff, 32); ++ ++ /* Start code (01) + read (10) + phyaddr + phyreg */ ++ smc_mii_out(dev, 6 << 10 | phyaddr << 5 | phyreg, 14); ++ ++ /* Turnaround (2bits) + phydata */ ++ phydata = smc_mii_in(dev, 18); ++ ++ /* Return to idle state */ ++ SMC_SET_MII(SMC_GET_MII() & ~(MII_MCLK|MII_MDOE|MII_MDO)); ++ ++ DBG(3, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n", ++ __FUNCTION__, phyaddr, phyreg, phydata); ++ ++ SMC_SELECT_BANK(2); ++ return phydata; ++} ++ ++/* ++ * Writes a register to the MII Management serial interface ++ */ ++static void smc_phy_write(struct net_device *dev, int phyaddr, int phyreg, ++ int phydata) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ void __iomem *ioaddr = lp->base; ++ ++ SMC_SELECT_BANK(3); ++ ++ /* Idle - 32 ones */ ++ smc_mii_out(dev, 0xffffffff, 32); ++ ++ /* Start code (01) + write (01) + phyaddr + phyreg + turnaround + phydata */ ++ smc_mii_out(dev, 5 << 28 | phyaddr << 23 | phyreg << 18 | 2 << 16 | phydata, 32); ++ ++ /* Return to idle state */ ++ SMC_SET_MII(SMC_GET_MII() & ~(MII_MCLK|MII_MDOE|MII_MDO)); ++ ++ DBG(3, "%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n", ++ __FUNCTION__, phyaddr, phyreg, phydata); ++ ++ SMC_SELECT_BANK(2); ++} ++ ++/* ++ * Finds and reports the PHY address ++ */ ++static void smc_phy_detect(struct net_device *dev) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ int phyaddr; ++ ++ DBG(2, "%s: %s\n", dev->name, __FUNCTION__); ++ ++ lp->phy_type = 0; ++ ++ /* ++ * Scan all 32 PHY addresses if necessary, starting at ++ * PHY#1 to PHY#31, and then PHY#0 last. ++ */ ++ for (phyaddr = 1; phyaddr < 33; ++phyaddr) { ++ unsigned int id1, id2; ++ ++ /* Read the PHY identifiers */ ++ id1 = smc_phy_read(dev, phyaddr & 31, MII_PHYSID1); ++ id2 = smc_phy_read(dev, phyaddr & 31, MII_PHYSID2); ++ ++ DBG(3, "%s: phy_id1=0x%x, phy_id2=0x%x\n", ++ dev->name, id1, id2); ++ ++ /* Make sure it is a valid identifier */ ++ if (id1 != 0x0000 && id1 != 0xffff && id1 != 0x8000 && ++ id2 != 0x0000 && id2 != 0xffff && id2 != 0x8000) { ++ /* Save the PHY's address */ ++ lp->mii.phy_id = phyaddr & 31; ++ lp->phy_type = id1 << 16 | id2; ++ break; ++ } ++ } ++} ++ ++/* ++ * Sets the PHY to a configuration as determined by the user ++ */ ++static int smc_phy_fixed(struct net_device *dev) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ void __iomem *ioaddr = lp->base; ++ int phyaddr = lp->mii.phy_id; ++ int bmcr, cfg1; ++ ++ DBG(3, "%s: %s\n", dev->name, __FUNCTION__); ++ ++ /* Enter Link Disable state */ ++ cfg1 = smc_phy_read(dev, phyaddr, PHY_CFG1_REG); ++ cfg1 |= PHY_CFG1_LNKDIS; ++ smc_phy_write(dev, phyaddr, PHY_CFG1_REG, cfg1); ++ ++ /* ++ * Set our fixed capabilities ++ * Disable auto-negotiation ++ */ ++ bmcr = 0; ++ ++ if (lp->ctl_rfduplx) ++ bmcr |= BMCR_FULLDPLX; ++ ++ if (lp->ctl_rspeed == 100) ++ bmcr |= BMCR_SPEED100; ++ ++ /* Write our capabilities to the phy control register */ ++ smc_phy_write(dev, phyaddr, MII_BMCR, bmcr); ++ ++ /* Re-Configure the Receive/Phy Control register */ ++ SMC_SELECT_BANK(0); ++ SMC_SET_RPC(lp->rpc_cur_mode); ++ SMC_SELECT_BANK(2); ++ ++ return 1; ++} ++ ++/* ++ * smc_phy_reset - reset the phy ++ * @dev: net device ++ * @phy: phy address ++ * ++ * Issue a software reset for the specified PHY and ++ * wait up to 100ms for the reset to complete. We should ++ * not access the PHY for 50ms after issuing the reset. ++ * ++ * The time to wait appears to be dependent on the PHY. ++ * ++ * Must be called with lp->lock locked. ++ */ ++static int smc_phy_reset(struct net_device *dev, int phy) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ unsigned int bmcr; ++ int timeout; ++ ++ smc_phy_write(dev, phy, MII_BMCR, BMCR_RESET); ++ ++ for (timeout = 2; timeout; timeout--) { ++ spin_unlock_irq(&lp->lock); ++ msleep(50); ++ spin_lock_irq(&lp->lock); ++ ++ bmcr = smc_phy_read(dev, phy, MII_BMCR); ++ if (!(bmcr & BMCR_RESET)) ++ break; ++ } ++ ++ return bmcr & BMCR_RESET; ++} ++ ++/* ++ * smc_phy_powerdown - powerdown phy ++ * @dev: net device ++ * ++ * Power down the specified PHY ++ */ ++static void smc_phy_powerdown(struct net_device *dev) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ unsigned int bmcr; ++ int phy = lp->mii.phy_id; ++ ++ if (lp->phy_type == 0) ++ return; ++ ++ /* We need to ensure that no calls to smc_phy_configure are ++ pending. ++ ++ flush_scheduled_work() cannot be called because we are ++ running with the netlink semaphore held (from ++ devinet_ioctl()) and the pending work queue contains ++ linkwatch_event() (scheduled by netif_carrier_off() ++ above). linkwatch_event() also wants the netlink semaphore. ++ */ ++ while(lp->work_pending) ++ yield(); ++ ++ bmcr = smc_phy_read(dev, phy, MII_BMCR); ++ smc_phy_write(dev, phy, MII_BMCR, bmcr | BMCR_PDOWN); ++} ++ ++/* ++ * smc_phy_check_media - check the media status and adjust TCR ++ * @dev: net device ++ * @init: set true for initialisation ++ * ++ * Select duplex mode depending on negotiation state. This ++ * also updates our carrier state. ++ */ ++static void smc_phy_check_media(struct net_device *dev, int init) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ void __iomem *ioaddr = lp->base; ++ ++ if (mii_check_media(&lp->mii, netif_msg_link(lp), init)) { ++ /* duplex state has changed */ ++ if (lp->mii.full_duplex) { ++ lp->tcr_cur_mode |= TCR_SWFDUP; ++ } else { ++ lp->tcr_cur_mode &= ~TCR_SWFDUP; ++ } ++ ++ SMC_SELECT_BANK(0); ++ SMC_SET_TCR(lp->tcr_cur_mode); ++ } ++} ++ ++/* ++ * Configures the specified PHY through the MII management interface ++ * using Autonegotiation. ++ * Calls smc_phy_fixed() if the user has requested a certain config. ++ * If RPC ANEG bit is set, the media selection is dependent purely on ++ * the selection by the MII (either in the MII BMCR reg or the result ++ * of autonegotiation.) If the RPC ANEG bit is cleared, the selection ++ * is controlled by the RPC SPEED and RPC DPLX bits. ++ */ ++static void smc_phy_configure(struct work_struct *work) ++{ ++ struct smc_local *lp = ++ container_of(work, struct smc_local, phy_configure); ++ struct net_device *dev = lp->dev; ++ void __iomem *ioaddr = lp->base; ++ int phyaddr = lp->mii.phy_id; ++ int my_phy_caps; /* My PHY capabilities */ ++ int my_ad_caps; /* My Advertised capabilities */ ++ int status; ++ ++ DBG(3, "%s:smc_program_phy()\n", dev->name); ++ ++ spin_lock_irq(&lp->lock); ++ ++ /* ++ * We should not be called if phy_type is zero. ++ */ ++ if (lp->phy_type == 0) ++ goto smc_phy_configure_exit; ++ ++ if (smc_phy_reset(dev, phyaddr)) { ++ printk("%s: PHY reset timed out\n", dev->name); ++ goto smc_phy_configure_exit; ++ } ++ ++ /* ++ * Enable PHY Interrupts (for register 18) ++ * Interrupts listed here are disabled ++ */ ++ smc_phy_write(dev, phyaddr, PHY_MASK_REG, ++ PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD | ++ PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB | ++ PHY_INT_SPDDET | PHY_INT_DPLXDET); ++ ++ /* Configure the Receive/Phy Control register */ ++ SMC_SELECT_BANK(0); ++ SMC_SET_RPC(lp->rpc_cur_mode); ++ ++ /* If the user requested no auto neg, then go set his request */ ++ if (lp->mii.force_media) { ++ smc_phy_fixed(dev); ++ goto smc_phy_configure_exit; ++ } ++ ++ /* Copy our capabilities from MII_BMSR to MII_ADVERTISE */ ++ my_phy_caps = smc_phy_read(dev, phyaddr, MII_BMSR); ++ ++ if (!(my_phy_caps & BMSR_ANEGCAPABLE)) { ++ printk(KERN_INFO "Auto negotiation NOT supported\n"); ++ smc_phy_fixed(dev); ++ goto smc_phy_configure_exit; ++ } ++ ++ my_ad_caps = ADVERTISE_CSMA; /* I am CSMA capable */ ++ ++ if (my_phy_caps & BMSR_100BASE4) ++ my_ad_caps |= ADVERTISE_100BASE4; ++ if (my_phy_caps & BMSR_100FULL) ++ my_ad_caps |= ADVERTISE_100FULL; ++ if (my_phy_caps & BMSR_100HALF) ++ my_ad_caps |= ADVERTISE_100HALF; ++ if (my_phy_caps & BMSR_10FULL) ++ my_ad_caps |= ADVERTISE_10FULL; ++ if (my_phy_caps & BMSR_10HALF) ++ my_ad_caps |= ADVERTISE_10HALF; ++ ++ /* Disable capabilities not selected by our user */ ++ if (lp->ctl_rspeed != 100) ++ my_ad_caps &= ~(ADVERTISE_100BASE4|ADVERTISE_100FULL|ADVERTISE_100HALF); ++ ++ if (!lp->ctl_rfduplx) ++ my_ad_caps &= ~(ADVERTISE_100FULL|ADVERTISE_10FULL); ++ ++ /* Update our Auto-Neg Advertisement Register */ ++ smc_phy_write(dev, phyaddr, MII_ADVERTISE, my_ad_caps); ++ lp->mii.advertising = my_ad_caps; ++ ++ /* ++ * Read the register back. Without this, it appears that when ++ * auto-negotiation is restarted, sometimes it isn't ready and ++ * the link does not come up. ++ */ ++ status = smc_phy_read(dev, phyaddr, MII_ADVERTISE); ++ ++ DBG(2, "%s: phy caps=%x\n", dev->name, my_phy_caps); ++ DBG(2, "%s: phy advertised caps=%x\n", dev->name, my_ad_caps); ++ ++ /* Restart auto-negotiation process in order to advertise my caps */ ++ smc_phy_write(dev, phyaddr, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART); ++ ++ smc_phy_check_media(dev, 1); ++ ++smc_phy_configure_exit: ++ SMC_SELECT_BANK(2); ++ spin_unlock_irq(&lp->lock); ++ lp->work_pending = 0; ++} ++ ++/* ++ * smc_phy_interrupt ++ * ++ * Purpose: Handle interrupts relating to PHY register 18. This is ++ * called from the "hard" interrupt handler under our private spinlock. ++ */ ++static void smc_phy_interrupt(struct net_device *dev) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ int phyaddr = lp->mii.phy_id; ++ int phy18; ++ ++ DBG(2, "%s: %s\n", dev->name, __FUNCTION__); ++ ++ if (lp->phy_type == 0) ++ return; ++ ++ for(;;) { ++ smc_phy_check_media(dev, 0); ++ ++ /* Read PHY Register 18, Status Output */ ++ phy18 = smc_phy_read(dev, phyaddr, PHY_INT_REG); ++ if ((phy18 & PHY_INT_INT) == 0) ++ break; ++ } ++} ++ ++/*--- END PHY CONTROL AND CONFIGURATION-------------------------------------*/ ++ ++static void smc_10bt_check_media(struct net_device *dev, int init) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ void __iomem *ioaddr = lp->base; ++ unsigned int old_carrier, new_carrier; ++ ++ old_carrier = netif_carrier_ok(dev) ? 1 : 0; ++ ++ SMC_SELECT_BANK(0); ++ new_carrier = (SMC_GET_EPH_STATUS() & ES_LINK_OK) ? 1 : 0; ++ SMC_SELECT_BANK(2); ++ ++ if (init || (old_carrier != new_carrier)) { ++ if (!new_carrier) { ++ netif_carrier_off(dev); ++ } else { ++ netif_carrier_on(dev); ++ } ++ if (netif_msg_link(lp)) ++ printk(KERN_INFO "%s: link %s\n", dev->name, ++ new_carrier ? "up" : "down"); ++ } ++} ++ ++static void smc_eph_interrupt(struct net_device *dev) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ void __iomem *ioaddr = lp->base; ++ unsigned int ctl; ++ ++ smc_10bt_check_media(dev, 0); ++ ++ SMC_SELECT_BANK(1); ++ ctl = SMC_GET_CTL(); ++ SMC_SET_CTL(ctl & ~CTL_LE_ENABLE); ++ SMC_SET_CTL(ctl); ++ SMC_SELECT_BANK(2); ++} ++ ++/* ++ * This is the main routine of the driver, to handle the device when ++ * it needs some attention. ++ */ ++static irqreturn_t smc_interrupt(int irq, void *dev_id) ++{ ++ struct net_device *dev = dev_id; ++ struct smc_local *lp = netdev_priv(dev); ++ void __iomem *ioaddr = lp->base; ++ int status, mask, timeout, card_stats; ++ int saved_pointer; ++ ++ DBG(3, "%s: %s\n", dev->name, __FUNCTION__); ++ ++ spin_lock(&lp->lock); ++ ++ /* A preamble may be used when there is a potential race ++ * between the interruptible transmit functions and this ++ * ISR. */ ++ SMC_INTERRUPT_PREAMBLE; ++ ++ saved_pointer = SMC_GET_PTR(); ++ mask = SMC_GET_INT_MASK(); ++ SMC_SET_INT_MASK(0); ++ ++ /* set a timeout value, so I don't stay here forever */ ++ timeout = MAX_IRQ_LOOPS; ++ ++ do { ++ status = SMC_GET_INT(); ++ ++ DBG(2, "%s: INT 0x%02x MASK 0x%02x MEM 0x%04x FIFO 0x%04x\n", ++ dev->name, status, mask, ++ ({ int meminfo; SMC_SELECT_BANK(0); ++ meminfo = SMC_GET_MIR(); ++ SMC_SELECT_BANK(2); meminfo; }), ++ SMC_GET_FIFO()); ++ ++ status &= mask; ++ if (!status) ++ break; ++ ++ if (status & IM_TX_INT) { ++ /* do this before RX as it will free memory quickly */ ++ DBG(3, "%s: TX int\n", dev->name); ++ smc_tx(dev); ++ SMC_ACK_INT(IM_TX_INT); ++ if (THROTTLE_TX_PKTS) ++ netif_wake_queue(dev); ++ } else if (status & IM_RCV_INT) { ++ DBG(3, "%s: RX irq\n", dev->name); ++ smc_rcv(dev); ++ } else if (status & IM_ALLOC_INT) { ++ DBG(3, "%s: Allocation irq\n", dev->name); ++ tasklet_hi_schedule(&lp->tx_task); ++ mask &= ~IM_ALLOC_INT; ++ } else if (status & IM_TX_EMPTY_INT) { ++ DBG(3, "%s: TX empty\n", dev->name); ++ mask &= ~IM_TX_EMPTY_INT; ++ ++ /* update stats */ ++ SMC_SELECT_BANK(0); ++ card_stats = SMC_GET_COUNTER(); ++ SMC_SELECT_BANK(2); ++ ++ /* single collisions */ ++ dev->stats.collisions += card_stats & 0xF; ++ card_stats >>= 4; ++ ++ /* multiple collisions */ ++ dev->stats.collisions += card_stats & 0xF; ++ } else if (status & IM_RX_OVRN_INT) { ++ DBG(1, "%s: RX overrun (EPH_ST 0x%04x)\n", dev->name, ++ ({ int eph_st; SMC_SELECT_BANK(0); ++ eph_st = SMC_GET_EPH_STATUS(); ++ SMC_SELECT_BANK(2); eph_st; }) ); ++ SMC_ACK_INT(IM_RX_OVRN_INT); ++ dev->stats.rx_errors++; ++ dev->stats.rx_fifo_errors++; ++ } else if (status & IM_EPH_INT) { ++ smc_eph_interrupt(dev); ++ } else if (status & IM_MDINT) { ++ SMC_ACK_INT(IM_MDINT); ++ smc_phy_interrupt(dev); ++ } else if (status & IM_ERCV_INT) { ++ SMC_ACK_INT(IM_ERCV_INT); ++ PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT \n", dev->name); ++ } ++ } while (--timeout); ++ ++ /* restore register states */ ++ SMC_SET_PTR(saved_pointer); ++ SMC_SET_INT_MASK(mask); ++ spin_unlock(&lp->lock); ++ ++ if (timeout == MAX_IRQ_LOOPS) ++ PRINTK("%s: spurious interrupt (mask = 0x%02x)\n", ++ dev->name, mask); ++ DBG(3, "%s: Interrupt done (%d loops)\n", ++ dev->name, MAX_IRQ_LOOPS - timeout); ++ ++ /* ++ * We return IRQ_HANDLED unconditionally here even if there was ++ * nothing to do. There is a possibility that a packet might ++ * get enqueued into the chip right after TX_EMPTY_INT is raised ++ * but just before the CPU acknowledges the IRQ. ++ * Better take an unneeded IRQ in some occasions than complexifying ++ * the code for all cases. ++ */ ++ return IRQ_HANDLED; ++} ++ ++#ifdef CONFIG_NET_POLL_CONTROLLER ++/* ++ * Polling receive - used by netconsole and other diagnostic tools ++ * to allow network i/o with interrupts disabled. ++ */ ++static void smc_poll_controller(struct net_device *dev) ++{ ++ disable_irq(dev->irq); ++ smc_interrupt(dev->irq, dev); ++ enable_irq(dev->irq); ++} ++#endif ++ ++/* Our watchdog timed out. Called by the networking layer */ ++static void smc_timeout(struct net_device *dev) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ void __iomem *ioaddr = lp->base; ++ int status, mask, eph_st, meminfo, fifo; ++ ++ DBG(2, "%s: %s\n", dev->name, __FUNCTION__); ++ ++ spin_lock_irq(&lp->lock); ++ status = SMC_GET_INT(); ++ mask = SMC_GET_INT_MASK(); ++ fifo = SMC_GET_FIFO(); ++ SMC_SELECT_BANK(0); ++ eph_st = SMC_GET_EPH_STATUS(); ++ meminfo = SMC_GET_MIR(); ++ SMC_SELECT_BANK(2); ++ spin_unlock_irq(&lp->lock); ++ PRINTK( "%s: TX timeout (INT 0x%02x INTMASK 0x%02x " ++ "MEM 0x%04x FIFO 0x%04x EPH_ST 0x%04x)\n", ++ dev->name, status, mask, meminfo, fifo, eph_st ); ++ ++ smc_reset(dev); ++ smc_enable(dev); ++ ++ /* ++ * Reconfiguring the PHY doesn't seem like a bad idea here, but ++ * smc_phy_configure() calls msleep() which calls schedule_timeout() ++ * which calls schedule(). Hence we use a work queue. ++ */ ++ if (lp->phy_type != 0) { ++ if (schedule_work(&lp->phy_configure)) { ++ lp->work_pending = 1; ++ } ++ } ++ ++ /* We can accept TX packets again */ ++ dev->trans_start = jiffies; ++ netif_wake_queue(dev); ++} ++ ++/* ++ * This routine will, depending on the values passed to it, ++ * either make it accept multicast packets, go into ++ * promiscuous mode (for TCPDUMP and cousins) or accept ++ * a select set of multicast packets ++ */ ++static void smc_set_multicast_list(struct net_device *dev) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ void __iomem *ioaddr = lp->base; ++ unsigned char multicast_table[8]; ++ int update_multicast = 0; ++ ++ DBG(2, "%s: %s\n", dev->name, __FUNCTION__); ++ ++ if (dev->flags & IFF_PROMISC) { ++ DBG(2, "%s: RCR_PRMS\n", dev->name); ++ lp->rcr_cur_mode |= RCR_PRMS; ++ } ++ ++/* BUG? I never disable promiscuous mode if multicasting was turned on. ++ Now, I turn off promiscuous mode, but I don't do anything to multicasting ++ when promiscuous mode is turned on. ++*/ ++ ++ /* ++ * Here, I am setting this to accept all multicast packets. ++ * I don't need to zero the multicast table, because the flag is ++ * checked before the table is ++ */ ++ else if (dev->flags & IFF_ALLMULTI || dev->mc_count > 16) { ++ DBG(2, "%s: RCR_ALMUL\n", dev->name); ++ lp->rcr_cur_mode |= RCR_ALMUL; ++ } ++ ++ /* ++ * This sets the internal hardware table to filter out unwanted ++ * multicast packets before they take up memory. ++ * ++ * The SMC chip uses a hash table where the high 6 bits of the CRC of ++ * address are the offset into the table. If that bit is 1, then the ++ * multicast packet is accepted. Otherwise, it's dropped silently. ++ * ++ * To use the 6 bits as an offset into the table, the high 3 bits are ++ * the number of the 8 bit register, while the low 3 bits are the bit ++ * within that register. ++ */ ++ else if (dev->mc_count) { ++ int i; ++ struct dev_mc_list *cur_addr; ++ ++ /* table for flipping the order of 3 bits */ ++ static const unsigned char invert3[] = {0, 4, 2, 6, 1, 5, 3, 7}; ++ ++ /* start with a table of all zeros: reject all */ ++ memset(multicast_table, 0, sizeof(multicast_table)); ++ ++ cur_addr = dev->mc_list; ++ for (i = 0; i < dev->mc_count; i++, cur_addr = cur_addr->next) { ++ int position; ++ ++ /* do we have a pointer here? */ ++ if (!cur_addr) ++ break; ++ /* make sure this is a multicast address - ++ shouldn't this be a given if we have it here ? */ ++ if (!(*cur_addr->dmi_addr & 1)) ++ continue; ++ ++ /* only use the low order bits */ ++ position = crc32_le(~0, cur_addr->dmi_addr, 6) & 0x3f; ++ ++ /* do some messy swapping to put the bit in the right spot */ ++ multicast_table[invert3[position&7]] |= ++ (1<>3)&7]); ++ } ++ ++ /* be sure I get rid of flags I might have set */ ++ lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL); ++ ++ /* now, the table can be loaded into the chipset */ ++ update_multicast = 1; ++ } else { ++ DBG(2, "%s: ~(RCR_PRMS|RCR_ALMUL)\n", dev->name); ++ lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL); ++ ++ /* ++ * since I'm disabling all multicast entirely, I need to ++ * clear the multicast list ++ */ ++ memset(multicast_table, 0, sizeof(multicast_table)); ++ update_multicast = 1; ++ } ++ ++ spin_lock_irq(&lp->lock); ++ SMC_SELECT_BANK(0); ++ SMC_SET_RCR(lp->rcr_cur_mode); ++ if (update_multicast) { ++ SMC_SELECT_BANK(3); ++ SMC_SET_MCAST(multicast_table); ++ } ++ SMC_SELECT_BANK(2); ++ spin_unlock_irq(&lp->lock); ++} ++ ++ ++/* ++ * Open and Initialize the board ++ * ++ * Set up everything, reset the card, etc.. ++ */ ++static int ++smc_open(struct net_device *dev) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ ++ DBG(2, "%s: %s\n", dev->name, __FUNCTION__); ++ ++ /* ++ * Check that the address is valid. If its not, refuse ++ * to bring the device up. The user must specify an ++ * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx ++ */ ++ if (!is_valid_ether_addr(dev->dev_addr)) { ++ PRINTK("%s: no valid ethernet hw addr\n", __FUNCTION__); ++ return -EINVAL; ++ } ++ ++ /* Setup the default Register Modes */ ++ lp->tcr_cur_mode = TCR_DEFAULT; ++ lp->rcr_cur_mode = RCR_DEFAULT; ++ lp->rpc_cur_mode = RPC_DEFAULT; ++ ++ /* ++ * If we are not using a MII interface, we need to ++ * monitor our own carrier signal to detect faults. ++ */ ++ if (lp->phy_type == 0) ++ lp->tcr_cur_mode |= TCR_MON_CSN; ++ ++ /* reset the hardware */ ++ smc_reset(dev); ++ smc_enable(dev); ++ ++ /* Configure the PHY, initialize the link state */ ++ if (lp->phy_type != 0) ++ smc_phy_configure(&lp->phy_configure); ++ else { ++ spin_lock_irq(&lp->lock); ++ smc_10bt_check_media(dev, 1); ++ spin_unlock_irq(&lp->lock); ++ } ++ ++ netif_start_queue(dev); ++ return 0; ++} ++ ++/* ++ * smc_close ++ * ++ * this makes the board clean up everything that it can ++ * and not talk to the outside world. Caused by ++ * an 'ifconfig ethX down' ++ */ ++static int smc_close(struct net_device *dev) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ ++ DBG(2, "%s: %s\n", dev->name, __FUNCTION__); ++ ++ netif_stop_queue(dev); ++ netif_carrier_off(dev); ++ ++ /* clear everything */ ++ smc_shutdown(dev); ++ tasklet_kill(&lp->tx_task); ++ smc_phy_powerdown(dev); ++ return 0; ++} ++ ++/* ++ * Ethtool support ++ */ ++static int ++smc_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ int ret; ++ ++ cmd->maxtxpkt = 1; ++ cmd->maxrxpkt = 1; ++ ++ if (lp->phy_type != 0) { ++ spin_lock_irq(&lp->lock); ++ ret = mii_ethtool_gset(&lp->mii, cmd); ++ spin_unlock_irq(&lp->lock); ++ } else { ++ cmd->supported = SUPPORTED_10baseT_Half | ++ SUPPORTED_10baseT_Full | ++ SUPPORTED_TP | SUPPORTED_AUI; ++ ++ if (lp->ctl_rspeed == 10) ++ cmd->speed = SPEED_10; ++ else if (lp->ctl_rspeed == 100) ++ cmd->speed = SPEED_100; ++ ++ cmd->autoneg = AUTONEG_DISABLE; ++ cmd->transceiver = XCVR_INTERNAL; ++ cmd->port = 0; ++ cmd->duplex = lp->tcr_cur_mode & TCR_SWFDUP ? DUPLEX_FULL : DUPLEX_HALF; ++ ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++static int ++smc_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ int ret; ++ ++ if (lp->phy_type != 0) { ++ spin_lock_irq(&lp->lock); ++ ret = mii_ethtool_sset(&lp->mii, cmd); ++ spin_unlock_irq(&lp->lock); ++ } else { ++ if (cmd->autoneg != AUTONEG_DISABLE || ++ cmd->speed != SPEED_10 || ++ (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL) || ++ (cmd->port != PORT_TP && cmd->port != PORT_AUI)) ++ return -EINVAL; ++ ++// lp->port = cmd->port; ++ lp->ctl_rfduplx = cmd->duplex == DUPLEX_FULL; ++ ++// if (netif_running(dev)) ++// smc_set_port(dev); ++ ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++static void ++smc_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info) ++{ ++ strncpy(info->driver, CARDNAME, sizeof(info->driver)); ++ strncpy(info->version, version, sizeof(info->version)); ++ strncpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info)); ++} ++ ++static int smc_ethtool_nwayreset(struct net_device *dev) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ int ret = -EINVAL; ++ ++ if (lp->phy_type != 0) { ++ spin_lock_irq(&lp->lock); ++ ret = mii_nway_restart(&lp->mii); ++ spin_unlock_irq(&lp->lock); ++ } ++ ++ return ret; ++} ++ ++static u32 smc_ethtool_getmsglevel(struct net_device *dev) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ return lp->msg_enable; ++} ++ ++static void smc_ethtool_setmsglevel(struct net_device *dev, u32 level) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ lp->msg_enable = level; ++} ++ ++static struct ethtool_ops smc_ethtool_ops = { ++ .get_settings = smc_ethtool_getsettings, ++ .set_settings = smc_ethtool_setsettings, ++ .get_drvinfo = smc_ethtool_getdrvinfo, ++ ++ .get_msglevel = smc_ethtool_getmsglevel, ++ .set_msglevel = smc_ethtool_setmsglevel, ++ .nway_reset = smc_ethtool_nwayreset, ++ .get_link = ethtool_op_get_link, ++// .get_eeprom = smc_ethtool_geteeprom, ++// .set_eeprom = smc_ethtool_seteeprom, ++}; ++ ++/* ++ * smc_findirq ++ * ++ * This routine has a simple purpose -- make the SMC chip generate an ++ * interrupt, so an auto-detect routine can detect it, and find the IRQ, ++ */ ++/* ++ * does this still work? ++ * ++ * I just deleted auto_irq.c, since it was never built... ++ * --jgarzik ++ */ ++static int __init smc_findirq(void __iomem *ioaddr) ++{ ++ int timeout = 20; ++ unsigned long cookie; ++ ++ DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__); ++ ++ cookie = probe_irq_on(); ++ ++ /* ++ * What I try to do here is trigger an ALLOC_INT. This is done ++ * by allocating a small chunk of memory, which will give an interrupt ++ * when done. ++ */ ++ /* enable ALLOCation interrupts ONLY */ ++ SMC_SELECT_BANK(2); ++ SMC_SET_INT_MASK(IM_ALLOC_INT); ++ ++ /* ++ * Allocate 512 bytes of memory. Note that the chip was just ++ * reset so all the memory is available ++ */ ++ SMC_SET_MMU_CMD(MC_ALLOC | 1); ++ ++ /* ++ * Wait until positive that the interrupt has been generated ++ */ ++ do { ++ int int_status; ++ udelay(10); ++ int_status = SMC_GET_INT(); ++ if (int_status & IM_ALLOC_INT) ++ break; /* got the interrupt */ ++ } while (--timeout); ++ ++ /* ++ * there is really nothing that I can do here if timeout fails, ++ * as autoirq_report will return a 0 anyway, which is what I ++ * want in this case. Plus, the clean up is needed in both ++ * cases. ++ */ ++ ++ /* and disable all interrupts again */ ++ SMC_SET_INT_MASK(0); ++ ++ /* and return what I found */ ++ return probe_irq_off(cookie); ++} ++ ++/* ++ * Function: smc_probe(unsigned long ioaddr) ++ * ++ * Purpose: ++ * Tests to see if a given ioaddr points to an SMC91x chip. ++ * Returns a 0 on success ++ * ++ * Algorithm: ++ * (1) see if the high byte of BANK_SELECT is 0x33 ++ * (2) compare the ioaddr with the base register's address ++ * (3) see if I recognize the chip ID in the appropriate register ++ * ++ * Here I do typical initialization tasks. ++ * ++ * o Initialize the structure if needed ++ * o print out my vanity message if not done so already ++ * o print out what type of hardware is detected ++ * o print out the ethernet address ++ * o find the IRQ ++ * o set up my private data ++ * o configure the dev structure with my subroutines ++ * o actually GRAB the irq. ++ * o GRAB the region ++ */ ++static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr) ++{ ++ struct smc_local *lp = netdev_priv(dev); ++ static int version_printed = 0; ++ int retval; ++ unsigned int val, revision_register; ++ const char *version_string; ++ DECLARE_MAC_BUF(mac); ++ ++ DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__); ++ ++ if (!hwreg_present( ioaddr + BANK_SELECT )) { ++ retval = -ENODEV; ++ goto err_out; ++ } ++ ++ /* First, see if the high byte is 0x33 */ ++ val = SMC_CURRENT_BANK(); ++ DBG(2, "%s: bank signature probe returned 0x%04x\n", CARDNAME, val); ++ if ((val & 0xFF00) != 0x3300) { ++ if ((val & 0xFF) == 0x33) { ++ printk(KERN_WARNING ++ "%s: Detected possible byte-swapped interface" ++ " at IOADDR %p\n", CARDNAME, ioaddr); ++ } ++ retval = -ENODEV; ++ goto err_out; ++ } ++ ++ /* ++ * The above MIGHT indicate a device, but I need to write to ++ * further test this. ++ */ ++ SMC_SELECT_BANK(0); ++ val = SMC_CURRENT_BANK(); ++ if ((val & 0xFF00) != 0x3300) { ++ retval = -ENODEV; ++ goto err_out; ++ } ++ ++ /* ++ * well, we've already written once, so hopefully another ++ * time won't hurt. This time, I need to switch the bank ++ * register to bank 1, so I can access the base address ++ * register ++ */ ++ SMC_SELECT_BANK(1); ++ val = SMC_GET_BASE(); ++ val = ((val & 0x1F00) >> 3) << SMC_IO_SHIFT; ++ if (((unsigned int)ioaddr & (0x3e0 << SMC_IO_SHIFT)) != val) { ++ printk("%s: IOADDR %p doesn't match configuration (%x).\n", ++ CARDNAME, ioaddr, val); ++ } ++ ++ /* ++ * check if the revision register is something that I ++ * recognize. These might need to be added to later, ++ * as future revisions could be added. ++ */ ++ SMC_SELECT_BANK(3); ++ revision_register = SMC_GET_REV(); ++ DBG(2, "%s: revision = 0x%04x\n", CARDNAME, revision_register); ++ version_string = chip_ids[ (revision_register >> 4) & 0xF]; ++ if (!version_string || (revision_register & 0xff00) != 0x3300) { ++ /* I don't recognize this chip, so... */ ++ printk("%s: IO %p: Unrecognized revision register 0x%04x" ++ ", Contact author.\n", CARDNAME, ++ ioaddr, revision_register); ++ ++ retval = -ENODEV; ++ goto err_out; ++ } ++ ++ /* At this point I'll assume that the chip is an SMC91x. */ ++ if (version_printed++ == 0) ++ printk("%s", version); ++ ++ /* fill in some of the fields */ ++ dev->base_addr = (unsigned long)ioaddr; ++ lp->base = ioaddr; ++ lp->version = revision_register & 0xff; ++ spin_lock_init(&lp->lock); ++ ++ /* Get the MAC address */ ++ SMC_SELECT_BANK(1); ++ SMC_GET_MAC_ADDR(dev->dev_addr); ++ ++ /* now, reset the chip, and put it into a known state */ ++ smc_reset(dev); ++ ++ /* ++ * If dev->irq is 0, then the device has to be banged on to see ++ * what the IRQ is. ++ * ++ * This banging doesn't always detect the IRQ, for unknown reasons. ++ * a workaround is to reset the chip and try again. ++ * ++ * Interestingly, the DOS packet driver *SETS* the IRQ on the card to ++ * be what is requested on the command line. I don't do that, mostly ++ * because the card that I have uses a non-standard method of accessing ++ * the IRQs, and because this _should_ work in most configurations. ++ * ++ * Specifying an IRQ is done with the assumption that the user knows ++ * what (s)he is doing. No checking is done!!!! ++ */ ++ if (dev->irq < 1) { ++ int trials; ++ ++ trials = 3; ++ while (trials--) { ++ dev->irq = smc_findirq(ioaddr); ++ if (dev->irq) ++ break; ++ /* kick the card and try again */ ++ smc_reset(dev); ++ } ++ } ++ if (dev->irq == 0) { ++ printk("%s: Couldn't autodetect your IRQ. Use irq=xx.\n", ++ dev->name); ++ retval = -ENODEV; ++ goto err_out; ++ } ++ dev->irq = irq_canonicalize(dev->irq); ++ ++ /* Fill in the fields of the device structure with ethernet values. */ ++ ether_setup(dev); ++ ++ dev->open = smc_open; ++ dev->stop = smc_close; ++ dev->hard_start_xmit = smc_hard_start_xmit; ++ dev->tx_timeout = smc_timeout; ++ dev->watchdog_timeo = msecs_to_jiffies(watchdog); ++ dev->set_multicast_list = smc_set_multicast_list; ++ dev->ethtool_ops = &smc_ethtool_ops; ++#ifdef CONFIG_NET_POLL_CONTROLLER ++ dev->poll_controller = smc_poll_controller; ++#endif ++ ++ tasklet_init(&lp->tx_task, smc_hardware_send_pkt, (unsigned long)dev); ++ INIT_WORK(&lp->phy_configure, smc_phy_configure); ++ lp->dev = dev; ++ lp->mii.phy_id_mask = 0x1f; ++ lp->mii.reg_num_mask = 0x1f; ++ lp->mii.force_media = 0; ++ lp->mii.full_duplex = 0; ++ lp->mii.dev = dev; ++ lp->mii.mdio_read = smc_phy_read; ++ lp->mii.mdio_write = smc_phy_write; ++ ++ /* ++ * Locate the phy, if any. ++ */ ++ if (lp->version >= (CHIP_91100 << 4)) ++ smc_phy_detect(dev); ++ ++ /* then shut everything down to save power */ ++ smc_shutdown(dev); ++ smc_phy_powerdown(dev); ++ ++ /* Set default parameters */ ++ lp->msg_enable = NETIF_MSG_LINK; ++ lp->ctl_rfduplx = 0; ++ lp->ctl_rspeed = 10; ++ ++ if (lp->version >= (CHIP_91100 << 4)) { ++ lp->ctl_rfduplx = 1; ++ lp->ctl_rspeed = 100; ++ } ++ ++ /* Grab the IRQ */ ++ retval = request_irq(dev->irq, &smc_interrupt, SMC_IRQ_FLAGS, dev->name, dev); ++ if (retval) { ++ use_poll = 1; ++ //goto err_out; ++ } ++ ++#ifdef SMC_USE_PXA_DMA ++ { ++ int dma = pxa_request_dma(dev->name, DMA_PRIO_LOW, ++ smc_pxa_dma_irq, NULL); ++ if (dma >= 0) ++ dev->dma = dma; ++ } ++#endif ++ ++ retval = register_netdev(dev); ++ if (retval == 0) { ++ /* now, print out the card info, in a short format.. */ ++ printk("%s: %s (rev %d) at %p IRQ %d", ++ dev->name, version_string, revision_register & 0x0f, ++ lp->base, dev->irq); ++ ++ if (dev->dma != (unsigned char)-1) ++ printk(" DMA %d", dev->dma); ++ ++ printk("%s%s\n", nowait ? " [nowait]" : "", ++ THROTTLE_TX_PKTS ? " [throttle_tx]" : ""); ++ ++ if (!is_valid_ether_addr(dev->dev_addr)) { ++ printk("%s: Invalid ethernet MAC address. Please " ++ "set using ifconfig\n", dev->name); ++ } else { ++ /* Print the Ethernet address */ ++ printk("%s: Ethernet addr: %s\n", ++ dev->name, print_mac(mac, dev->dev_addr)); ++ } ++ ++ if (lp->phy_type == 0) { ++ PRINTK("%s: No PHY found\n", dev->name); ++ } else if ((lp->phy_type & 0xfffffff0) == 0x0016f840) { ++ PRINTK("%s: PHY LAN83C183 (LAN91C111 Internal)\n", dev->name); ++ } else if ((lp->phy_type & 0xfffffff0) == 0x02821c50) { ++ PRINTK("%s: PHY LAN83C180\n", dev->name); ++ } ++ } ++ ++err_out: ++#ifdef SMC_USE_PXA_DMA ++ if (retval && dev->dma != (unsigned char)-1) ++ pxa_free_dma(dev->dma); ++#endif ++ return retval; ++} ++ ++static int smc_enable_device(struct platform_device *pdev) ++{ ++ unsigned long flags; ++ unsigned char ecor, ecsr; ++ void __iomem *addr; ++ struct resource * res; ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib"); ++ if (!res) ++ return 0; ++ ++ printk("smc91x-attrib resource found, start=%x !\n", res->start); ++ ++ /* ++ * Map the attribute space. This is overkill, but clean. ++ */ ++ addr = ioremap(res->start, ATTRIB_SIZE); ++ if (!addr) ++ return -ENOMEM; ++ ++ printk("smc91x-attrib resource remapped, start=%p !\n", addr); ++ ++ /* ++ * Reset the device. We must disable IRQs around this ++ * since a reset causes the IRQ line become active. ++ */ ++ local_irq_save(flags); ++ ecor = readb(addr + (ECOR << SMC_IO_SHIFT)) & ~ECOR_RESET; ++ writeb(ecor | ECOR_RESET, addr + (ECOR << SMC_IO_SHIFT)); ++ readb(addr + (ECOR << SMC_IO_SHIFT)); ++ ++ /* ++ * Wait 100us for the chip to reset. ++ */ ++ udelay(100); ++ ++ /* ++ * The device will ignore all writes to the enable bit while ++ * reset is asserted, even if the reset bit is cleared in the ++ * same write. Must clear reset first, then enable the device. ++ */ ++ writeb(ecor, addr + (ECOR << SMC_IO_SHIFT)); ++ writeb(ecor | ECOR_ENABLE, addr + (ECOR << SMC_IO_SHIFT)); ++ ++ /* ++ * Set the appropriate byte/word mode. ++ */ ++ ecsr = readb(addr + (ECSR << SMC_IO_SHIFT)) & ~ECSR_IOIS8; ++ if (!SMC_CAN_USE_16BIT) ++ ecsr |= ECSR_IOIS8; ++ writeb(ecsr, addr + (ECSR << SMC_IO_SHIFT)); ++ local_irq_restore(flags); ++ ++ iounmap(addr); ++ ++ /* ++ * Wait for the chip to wake up. We could poll the control ++ * register in the main register space, but that isn't mapped ++ * yet. We know this is going to take 750us. ++ */ ++ msleep(1); ++ ++ return 0; ++} ++ ++static int smc_request_attrib(struct platform_device *pdev) ++{ ++ struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib"); ++ ++ if (!res) ++ return 0; ++ ++ if (!request_mem_region(res->start, ATTRIB_SIZE, CARDNAME)) ++ return -EBUSY; ++ ++ return 0; ++} ++ ++static void smc_release_attrib(struct platform_device *pdev) ++{ ++ struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib"); ++ ++ if (res) ++ release_mem_region(res->start, ATTRIB_SIZE); ++} ++ ++static inline void smc_request_datacs(struct platform_device *pdev, struct net_device *ndev) ++{ ++ if (SMC_CAN_USE_DATACS) { ++ struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-data32"); ++ struct smc_local *lp = netdev_priv(ndev); ++ ++ if (!res) ++ return; ++ ++ if(!request_mem_region(res->start, SMC_DATA_EXTENT, CARDNAME)) { ++ printk(KERN_INFO "%s: failed to request datacs memory region.\n", CARDNAME); ++ return; ++ } ++ ++ lp->datacs = ioremap(res->start, SMC_DATA_EXTENT); ++ } ++} ++ ++static void smc_release_datacs(struct platform_device *pdev, struct net_device *ndev) ++{ ++ if (SMC_CAN_USE_DATACS) { ++ struct smc_local *lp = netdev_priv(ndev); ++ struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-data32"); ++ ++ if (lp->datacs) ++ iounmap(lp->datacs); ++ ++ lp->datacs = NULL; ++ ++ if (res) ++ release_mem_region(res->start, SMC_DATA_EXTENT); ++ } ++} ++ ++/* ++ * Resources defined and added to platform data in arch/m68k/atari/config.c ++ * These are left here for reference only! ++ */ ++ ++struct resource ethernat_attr = { ++ .start = 0x80000000, ++ .end = 0x800000FF, ++ .name = "smc91x-attrib", ++ .flags = IORESOURCE_MEM ++}; ++ ++struct resource ethernat_datacs = { ++ .start = 0, ++ .end = 0, ++ .name = "smc91x-data32", ++ .flags = IORESOURCE_MEM ++}; ++ ++/* ++ * smc_init(void) ++ * Input parameters: ++ * dev->base_addr == 0, try to find all possible locations ++ * dev->base_addr > 0x1ff, this is the address to check ++ * dev->base_addr == , return failure code ++ * ++ * Output: ++ * 0 --> there is a device ++ * anything else, error ++ */ ++ ++static int __init atari_ethernat_pdev_probe(struct platform_device *pdev) ++{ ++ struct net_device *ndev; ++ struct resource *res; ++ unsigned int __iomem *addr; ++ int ret; ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs"); ++ if (!res) ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) { ++ printk("smc91x-regs resource not found!\n"); ++ ret = -ENODEV; ++ goto out; ++ } ++ ++ printk("smc91x-regs resource found, start=%x !\n", res->start); ++ ++ if (!request_mem_region(res->start, SMC_IO_EXTENT, CARDNAME)) { ++ printk("could not request smc91x-regs resource at %ul!\n", res->start); ++ ret = -EBUSY; ++ goto out; ++ } ++ ++ ndev = alloc_etherdev(sizeof(struct smc_local)); ++ if (!ndev) { ++ printk("%s: could not allocate device.\n", CARDNAME); ++ ret = -ENOMEM; ++ goto out_release_io; ++ } ++ SET_NETDEV_DEV(ndev, &pdev->dev); ++ ++ ndev->dma = (unsigned char)-1; ++ ndev->irq = platform_get_irq(pdev, 0); ++ if (ndev->irq < 0) { ++ printk("atari_91C111: cannot determine interrupt! Using timer D poll...\n"); ++ ndev->irq = IRQ_MFP_TIMD; ++ /* timer actually set up later */ ++ } ++ ++ ret = smc_request_attrib(pdev); ++ if (ret) ++ goto out_free_netdev; ++#if defined(CONFIG_SA1100_ASSABET) ++ NCR_0 |= NCR_ENET_OSC_EN; ++#endif ++ ret = smc_enable_device(pdev); ++ if (ret) ++ goto out_release_attrib; ++ ++ addr = ioremap(res->start, SMC_IO_EXTENT); ++ if (!addr) { ++ ret = -ENOMEM; ++ goto out_release_attrib; ++ } ++ ++ /* ++ * Maybe postpone, see below? ++ */ ++#ifdef SMC_USE_PXA_DMA ++ { ++ struct smc_local *lp = netdev_priv(ndev); ++ lp->device = &pdev->dev; ++ lp->physaddr = res->start; ++ } ++#endif ++ ++ printk("smc91x-regs resource remapped, start=%p!\n", addr); ++ ++ // about to probe for device; need to enable net IRQ here! ++ // probe for base address + 0x23 or 0x20 ++ ++ platform_set_drvdata(pdev, ndev); ++ ret = smc_probe(ndev, addr); ++ if (ret != 0) ++ goto out_iounmap; ++ /* ++ * allocation of lp and setting of device and physaddr maybe here instead? ++ */ ++#ifdef SMC_USE_PXA_DMA ++ else { ++ struct smc_local *lp = netdev_priv(ndev); ++ lp->physaddr = res->start; ++ } ++#endif ++ ++ ++ if (ndev->irq < 0) { ++ if (use_poll) ++ atari_ethernat_start_poll(ndev); ++ } else if (ndev->irq == IRQ_MFP_TIMD) { ++ // init timer if not already running ++ /* set Timer D data Register */ ++ mfp.tim_dt_d = 123; /* 200 Hz */ ++ /* start timer D, div = 1:100 */ ++ mfp.tim_ct_cd = (mfp.tim_ct_cd & 0xf0) | 0x6; ++ } ++ ++ smc_request_datacs(pdev, ndev); ++ ++ return 0; ++ ++ out_iounmap: ++ platform_set_drvdata(pdev, NULL); ++ iounmap(addr); ++ out_release_attrib: ++ smc_release_attrib(pdev); ++ out_free_netdev: ++ free_netdev(ndev); ++ out_release_io: ++ release_mem_region(res->start, SMC_IO_EXTENT); ++ out: ++ printk("%s: not found (%d).\n", CARDNAME, ret); ++ ++ return ret; ++} ++ ++static int smc_drv_remove(struct platform_device *pdev) ++{ ++ struct net_device *ndev = platform_get_drvdata(pdev); ++ struct smc_local *lp = netdev_priv(ndev); ++ struct resource *res; ++ ++ platform_set_drvdata(pdev, NULL); ++ ++ if (use_poll) ++ atari_ethernat_stop_poll(ndev); ++ ++ unregister_netdev(ndev); ++ ++ free_irq(ndev->irq, ndev); ++ ++#ifdef SMC_USE_PXA_DMA ++ if (ndev->dma != (unsigned char)-1) ++ pxa_free_dma(ndev->dma); ++#endif ++ iounmap(lp->base); ++ ++ smc_release_datacs(pdev,ndev); ++ smc_release_attrib(pdev); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs"); ++ if (!res) ++ platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ release_mem_region(res->start, SMC_IO_EXTENT); ++ ++ free_netdev(ndev); ++ ++ return 0; ++} ++ ++static int smc_drv_suspend(struct platform_device *dev, pm_message_t state) ++{ ++ struct net_device *ndev = platform_get_drvdata(dev); ++ ++ if (ndev) { ++ if (netif_running(ndev)) { ++ netif_device_detach(ndev); ++ smc_shutdown(ndev); ++ smc_phy_powerdown(ndev); ++ } ++ } ++ return 0; ++} ++ ++static int smc_drv_resume(struct platform_device *dev) ++{ ++ struct net_device *ndev = platform_get_drvdata(dev); ++ ++ if (ndev) { ++ struct smc_local *lp = netdev_priv(ndev); ++ smc_enable_device(dev); ++ if (netif_running(ndev)) { ++ smc_reset(ndev); ++ smc_enable(ndev); ++ if (lp->phy_type != 0) ++ smc_phy_configure(&lp->phy_configure); ++ netif_device_attach(ndev); ++ } ++ } ++ return 0; ++} ++ ++static struct platform_driver smc_driver = { ++ .probe = atari_ethernat_pdev_probe, ++ .remove = smc_drv_remove, ++ .suspend = smc_drv_suspend, ++ .resume = smc_drv_resume, ++ .driver = { ++ .name = CARDNAME, ++ }, ++}; ++ ++static int __init smc_init(void) ++{ ++#ifdef MODULE ++ if (io == -1) ++ printk(KERN_WARNING ++ "%s: You shouldn't use auto-probing with insmod!\n", ++ CARDNAME); ++#endif ++ ++ return platform_driver_register(&smc_driver); ++} ++ ++static void __exit smc_cleanup(void) ++{ ++ platform_driver_unregister(&smc_driver); ++} ++ ++module_init(smc_init); ++module_exit(smc_cleanup); +--- a/include/asm-m68k/io.h ++++ b/include/asm-m68k/io.h +@@ -457,6 +457,8 @@ static inline void isa_delay(void) + #define readw isa_readw + #define writeb isa_writeb + #define writew isa_writew ++#define readsl raw_insl ++#define writesl raw_outsl + #endif + + #if !defined(CONFIG_ISA) && !defined(CONFIG_PCI) && !defined(CONFIG_ATARI_ROM_ISA) diff --git a/debian/patches/bugfix/m68k/2.6.24/atari-ethernec.diff b/debian/patches/bugfix/m68k/2.6.24/atari-ethernec.diff new file mode 100644 index 000000000..3b9d7a349 --- /dev/null +++ b/debian/patches/bugfix/m68k/2.6.24/atari-ethernec.diff @@ -0,0 +1,1063 @@ +Subject: [PATCH] m68k: Atari EtherNEC driver +Cc: Jeff Garzik , netdev@vger.kernel.org + +From: Michael Schmitz + +Atari EtherNEC driver + +Signed-off-by: Michael Schmitz +Signed-off-by: Roman Zippel +Signed-off-by: Geert Uytterhoeven +--- + drivers/net/Makefile | 1 + drivers/net/Space.c | 4 + drivers/net/atari_ethernec.c | 1014 +++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 1019 insertions(+) + +--- a/drivers/net/Makefile ++++ b/drivers/net/Makefile +@@ -193,6 +193,7 @@ obj-$(CONFIG_MIPS_SIM_NET) += mipsnet.o + obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o + obj-$(CONFIG_DECLANCE) += declance.o + obj-$(CONFIG_ATARILANCE) += atarilance.o ++obj-$(CONFIG_ATARI_ETHERNEC) += atari_ethernec.o 8390.o + obj-$(CONFIG_A2065) += a2065.o + obj-$(CONFIG_HYDRA) += hydra.o + obj-$(CONFIG_ARIADNE) += ariadne.o +--- a/drivers/net/Space.c ++++ b/drivers/net/Space.c +@@ -72,6 +72,7 @@ extern struct net_device *SK_init(int un + extern struct net_device *seeq8005_probe(int unit); + extern struct net_device *smc_init(int unit); + extern struct net_device *atarilance_probe(int unit); ++extern struct net_device *atari_ethernec_probe(int unit); + extern struct net_device *sun3lance_probe(int unit); + extern struct net_device *sun3_82586_probe(int unit); + extern struct net_device *apne_probe(int unit); +@@ -253,6 +254,9 @@ static struct devprobe2 m68k_probes[] __ + #ifdef CONFIG_ATARILANCE /* Lance-based Atari ethernet boards */ + {atarilance_probe, 0}, + #endif ++#ifdef CONFIG_ATARI_ETHERNEC /* NE2000 based ROM port ethernet cards */ ++ {atari_ethernec_probe, 0}, ++#endif + #ifdef CONFIG_SUN3LANCE /* sun3 onboard Lance chip */ + {sun3lance_probe, 0}, + #endif +--- /dev/null ++++ b/drivers/net/atari_ethernec.c +@@ -0,0 +1,1014 @@ ++/* ++ * atari_ethernec.c: Atari cartridge port ethernet adapter ++ * (C) 2006 Michael Schmitz ++ * ++ * Modified after: ++ */ ++ ++/* ne.c: A general non-shared-memory NS8390 ethernet driver for linux. */ ++/* ++ Written 1992-94 by Donald Becker. ++ ++ Copyright 1993 United States Government as represented by the ++ Director, National Security Agency. ++ ++ This software may be used and distributed according to the terms ++ of the GNU General Public License, incorporated herein by reference. ++ ++ The author may be reached as becker@scyld.com, or C/O ++ Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403 ++ ++ This driver should work with many programmed-I/O 8390-based ethernet ++ boards. Currently it supports the NE1000, NE2000, many clones, ++ and some Cabletron products. ++ ++ Changelog: ++ ++ Paul Gortmaker : use ENISR_RDC to monitor Tx PIO uploads, made ++ sanity checks and bad clone support optional. ++ Paul Gortmaker : new reset code, reset card after probe at boot. ++ Paul Gortmaker : multiple card support for module users. ++ Paul Gortmaker : Support for PCI ne2k clones, similar to lance.c ++ Paul Gortmaker : Allow users with bad cards to avoid full probe. ++ Paul Gortmaker : PCI probe changes, more PCI cards supported. ++ rjohnson@analogic.com : Changed init order so an interrupt will only ++ occur after memory is allocated for dev->priv. Deallocated memory ++ last in cleanup_modue() ++ Richard Guenther : Added support for ISAPnP cards ++ Paul Gortmaker : Discontinued PCI support - use ne2k-pci.c instead. ++ Hayato Fujiwara : Add m32r support. ++ ++*/ ++ ++/* ++ * From the driver distribution kit by Thomas Redelberger: ++ * ++ * Hardware circuit description (see directory ETHERNEC for schematics) ++ * ++ * As there is no reset line on the CP, a resistor and a capacitor are ++ * used to reset the NE card on power up. ++ * ++ * Reading from the NE card is done by a read cycle on the CP at address ++ * /ROM4 + 512*ISA address as the ISA address lines A0-A4 are connected ++ * to CP A9-A13. /ROM4 going low will start the ISA read cycle, enable ++ * the ISA bus buffers of the NE card and start decoding of the ISA IO ++ * address by the NE card. /ROM4 going high ends the cycle and the ++ * processor latches the data. ++ * ++ * Because the CP is read only writing to the NE card must be done with ++ * the trick to read from addresses that stand for the data. Dummy reads ++ * at /ROM3 base address + data*2 + ISA address*512 effect this. You ++ * might wonder why everything appears to be shifted up one bit. There is ++ * no CP "A0" address line. There are the signals /UDS and /LDS instead ++ * typical for the 68000 family. The original design which generated an ++ * "A0" worked on an ST and an STE but did not on a Falcon. ++ * ++ * The falling edge of /ROM3 enables the CP address lines A1-A8 onto the ++ * data bus and starts the ISA write cycle. The rising edge will end the ++ * ISA write cycle and the NE latches the data. The processor will also ++ * see and just read this same data but that is harmless. ++ * Elmar Hilgart reported that the bus buffer IC shall be an TTL F-type ++ * to keep up with the fast cycles on the Falcon. ++ * ++ * Base addresses: ++ * rom4 EQU $00fa0000 ; ROM4 base address ++ * rom3 EQU $00fb0000 ; ROM3 base address ++ * ++ */ ++ ++/* Routines for the NatSemi-based designs (NE[12]000). */ ++ ++static const char version1[] = ++"ne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com)\n"; ++static const char version2[] = ++"atari_ethernec.c 11/10/06 Michael Schmitz (schmitz@debian.org)\n"; ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "8390.h" ++ ++#define DRV_NAME "ethernec" ++ ++/* Some defines that people can play with if so inclined. */ ++ ++/* Do we support clones that don't adhere to 14,15 of the SAprom ? */ ++#define SUPPORT_NE_BAD_CLONES ++ ++/* Do we perform extra sanity checks on stuff ? */ ++/* #define NE_SANITY_CHECK */ ++ ++/* Do we implement the read before write bugfix ? */ ++/* #define NE_RW_BUGFIX */ ++ ++/* Do we have a non std. amount of memory? (in units of 256 byte pages) */ ++/* #define PACKETBUF_MEMSIZE 0x40 */ ++ ++/* A zero-terminated list of I/O addresses to be probed at boot. */ ++#ifndef MODULE ++static unsigned int netcard_portlist[] __initdata = { ++ 0x300, 0x280, 0x320, 0x340, 0x360, 0x380, 0 ++}; ++#endif ++ ++static struct isapnp_device_id isapnp_clone_list[] __initdata = { ++ { ISAPNP_CARD_ID('A','X','E',0x2011), ++ ISAPNP_VENDOR('A','X','E'), ISAPNP_FUNCTION(0x2011), ++ (long) "NetGear EA201" }, ++ { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ++ ISAPNP_VENDOR('E','D','I'), ISAPNP_FUNCTION(0x0216), ++ (long) "NN NE2000" }, ++ { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ++ ISAPNP_VENDOR('P','N','P'), ISAPNP_FUNCTION(0x80d6), ++ (long) "Generic PNP" }, ++ { } /* terminate list */ ++}; ++ ++MODULE_DEVICE_TABLE(isapnp, isapnp_clone_list); ++ ++#ifdef SUPPORT_NE_BAD_CLONES ++/* A list of bad clones that we none-the-less recognize. */ ++static struct { const char *name8, *name16; unsigned char SAprefix[4];} ++bad_clone_list[] __initdata = { ++ {"DE100", "DE200", {0x00, 0xDE, 0x01,}}, ++ {"DE120", "DE220", {0x00, 0x80, 0xc8,}}, ++ {"DFI1000", "DFI2000", {'D', 'F', 'I',}}, /* Original, eh? */ ++ {"EtherNext UTP8", "EtherNext UTP16", {0x00, 0x00, 0x79}}, ++ {"NE1000","NE2000-invalid", {0x00, 0x00, 0xd8}}, /* Ancient real NE1000. */ ++ {"NN1000", "NN2000", {0x08, 0x03, 0x08}}, /* Outlaw no-name clone. */ ++ {"4-DIM8","4-DIM16", {0x00,0x00,0x4d,}}, /* Outlaw 4-Dimension cards. */ ++ {"Con-Intl_8", "Con-Intl_16", {0x00, 0x00, 0x24}}, /* Connect Int'nl */ ++ {"ET-100","ET-200", {0x00, 0x45, 0x54}}, /* YANG and YA clone */ ++ {"COMPEX","COMPEX16",{0x00,0x80,0x48}}, /* Broken ISA Compex cards */ ++ {"E-LAN100", "E-LAN200", {0x00, 0x00, 0x5d}}, /* Broken ne1000 clones */ ++ {"PCM-4823", "PCM-4823", {0x00, 0xc0, 0x6c}}, /* Broken Advantech MoBo */ ++ {"REALTEK", "RTL8019", {0x00, 0x00, 0xe8}}, /* no-name with Realtek chip */ ++#if defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938) ++ {"RBHMA4X00-RTL8019", "RBHMA4X00/RTL8019", {0x00, 0x60, 0x0a}}, /* Toshiba built-in */ ++#endif ++ {"LCS-8834", "LCS-8836", {0x04, 0x04, 0x37}}, /* ShinyNet (SET) */ ++ {NULL,} ++}; ++#endif ++ ++/* ---- No user-serviceable parts below ---- */ ++ ++#define NE_BASE (dev->base_addr) ++#define NE_CMD 0x00 ++#define NE_DATAPORT 0x10 /* NatSemi-defined port window offset. */ ++#define NE_RESET 0x1f /* Issue a read to reset, a write to clear. */ ++#define NE_IO_EXTENT 0x20 ++ ++#define NE1SM_START_PG 0x20 /* First page of TX buffer */ ++#define NE1SM_STOP_PG 0x40 /* Last page +1 of RX ring */ ++#define NESM_START_PG 0x40 /* First page of TX buffer */ ++#define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ ++ ++#if defined(CONFIG_PLAT_MAPPI) ++# define DCR_VAL 0x4b ++#elif defined(CONFIG_PLAT_OAKS32R) || \ ++ defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938) || \ ++ defined(CONFIG_ATARI_ETHERNEC) || defined(CONFIG_ATARI_ETHERNEC_MODULE) ++# define DCR_VAL 0x48 /* 8-bit mode */ ++#else ++# define DCR_VAL 0x49 ++#endif ++ ++#if defined(CONFIG_ATARI_ETHERNEC) || defined(CONFIG_ATARI_ETHERNEC_MODULE) ++# define ETHERNEC_RTL_8019_BASE 0x300 ++# define ETHERNEC_RTL_8019_IRQ IRQ_MFP_TIMD ++#endif ++ ++static int ne_probe1(struct net_device *dev, int ioaddr); ++static int ne_probe_isapnp(struct net_device *dev); ++ ++static int ne_open(struct net_device *dev); ++static int ne_close(struct net_device *dev); ++ ++static void ne_reset_8390(struct net_device *dev); ++static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, ++ int ring_page); ++static void ne_block_input(struct net_device *dev, int count, ++ struct sk_buff *skb, int ring_offset); ++static void ne_block_output(struct net_device *dev, const int count, ++ const unsigned char *buf, const int start_page); ++ ++ ++/* ++ * The Atari ROM port has no interrupt line, so we poll the card instead. ++ */ ++ ++static int use_poll; ++ ++/* ++ * This is used by cleanup, to prevent the module from being unloaded while ++ * intrpt_routine is still in the task queue ++ */ ++static wait_queue_head_t WaitQ; ++ ++static struct delayed_work tqueue; ++ ++static struct net_device *poll_dev = NULL; ++ ++static void atari_ethernec_int(struct work_struct *work) ++{ ++ struct net_device *dev = poll_dev; ++ ++ if (!dev) { ++ /* If cleanup wants us to die */ ++ if (waitqueue_active(&WaitQ)) ++ wake_up(&WaitQ); /* Now cleanup_module can return */ ++ else ++ /* Put ourselves back in the task queue */ ++ schedule_delayed_work(&tqueue, 1); ++ return; ++ } ++ ++ if (netif_running(dev)) ++ ei_interrupt(dev->irq, dev); ++ ++ /* If cleanup wants us to die */ ++ if (waitqueue_active(&WaitQ)) ++ wake_up(&WaitQ); /* Now cleanup_module can return */ ++ else ++ /* Put ourselves back in the task queue */ ++ schedule_delayed_work(&tqueue, 0); /* reduced delay from 1 */ ++} ++ ++static void atari_ethernec_start_poll(struct net_device *dev) ++{ ++ poll_dev = dev; ++ ++ init_waitqueue_head(&WaitQ); ++ ++ INIT_DELAYED_WORK(&tqueue, atari_ethernec_int); ++ schedule_delayed_work(&tqueue, 1); ++} ++ ++static void atari_ethernec_stop_poll(struct net_device *dev) ++{ ++ poll_dev = NULL; ++ ++ if (dev) ++ sleep_on(&WaitQ); ++} ++ ++ ++/* Probe for various non-shared-memory ethercards. ++ ++ NEx000-clone boards have a Station Address PROM (SAPROM) in the packet ++ buffer memory space. NE2000 clones have 0x57,0x57 in bytes 0x0e,0x0f of ++ the SAPROM, while other supposed NE2000 clones must be detected by their ++ SA prefix. ++ ++ Reading the SAPROM from a word-wide card with the 8390 set in byte-wide ++ mode results in doubled values, which can be detected and compensated for. ++ ++ The probe is also responsible for initializing the card and filling ++ in the 'dev' and 'ei_status' structures. ++ ++ We use the minimum memory size for some ethercard product lines, iff we can't ++ distinguish models. You can increase the packet buffer size by setting ++ PACKETBUF_MEMSIZE. Reported Cabletron packet buffer locations are: ++ E1010 starts at 0x100 and ends at 0x2000. ++ E1010-x starts at 0x100 and ends at 0x8000. ("-x" means "more memory") ++ E2010 starts at 0x100 and ends at 0x4000. ++ E2010-x starts at 0x100 and ends at 0xffff. ++*/ ++ ++static int __init do_ne_probe(struct net_device *dev) ++{ ++ unsigned int base_addr = dev->base_addr; ++ int rv; ++#ifndef MODULE ++ int orig_irq = dev->irq; ++#endif ++ ++ /* First check any supplied i/o locations. User knows best. */ ++ if (base_addr > 0x1ff) { /* Check a single specified location. */ ++ rv = ne_probe1(dev, base_addr); ++ if (!rv && use_poll) { ++ /* Seems we have a valid device here; set up polling routine */ ++ poll_dev = dev; ++ atari_ethernec_start_poll(dev); ++ } ++ return rv; ++ } else if (base_addr != 0) /* Don't probe at all. */ ++ return -ENXIO; ++ ++ /* Then look for any installed ISAPnP clones */ ++ if (isapnp_present() && (ne_probe_isapnp(dev) == 0)) ++ return 0; ++ ++#ifndef MODULE ++ /* Last resort. The semi-risky ISA auto-probe. */ ++ for (base_addr = 0; netcard_portlist[base_addr] != 0; base_addr++) { ++ int ioaddr = netcard_portlist[base_addr]; ++ dev->irq = orig_irq; ++ rv = ne_probe1(dev, ioaddr); ++ if (rv == 0) { ++ if (use_poll) { ++ poll_dev = dev; ++ atari_ethernec_start_poll(dev); ++ } ++ return 0; ++ } ++ } ++#endif ++ ++ return -ENODEV; ++} ++ ++#ifndef MODULE ++struct net_device * __init atari_ethernec_probe(int unit) ++{ ++ struct net_device *dev = alloc_ei_netdev(); ++ int err; ++ ++ if (!dev) ++ return ERR_PTR(-ENOMEM); ++ ++ sprintf(dev->name, "eth%d", unit); ++ netdev_boot_setup_check(dev); ++ ++#if defined(CONFIG_ATARI_ETHERNEC) ++ dev->base_addr = ETHERNEC_RTL_8019_BASE; ++ dev->irq = ETHERNEC_RTL_8019_IRQ; ++#endif ++ err = do_ne_probe(dev); ++ if (err) ++ goto out; ++ ++ /* Seems we have a valid device here; set up polling routine */ ++ return dev; ++out: ++ free_netdev(dev); ++ return ERR_PTR(err); ++} ++#endif ++ ++static int __init ne_probe_isapnp(struct net_device *dev) ++{ ++ int i; ++ ++ for (i = 0; isapnp_clone_list[i].vendor != 0; i++) { ++ struct pnp_dev *idev = NULL; ++ ++ while ((idev = pnp_find_dev(NULL, ++ isapnp_clone_list[i].vendor, ++ isapnp_clone_list[i].function, ++ idev))) { ++ /* Avoid already found cards from previous calls */ ++ if (pnp_device_attach(idev) < 0) ++ continue; ++ if (pnp_activate_dev(idev) < 0) { ++ pnp_device_detach(idev); ++ continue; ++ } ++ /* if no io and irq, search for next */ ++ if (!pnp_port_valid(idev, 0) || !pnp_irq_valid(idev, 0)) { ++ pnp_device_detach(idev); ++ continue; ++ } ++ /* found it */ ++ dev->base_addr = pnp_port_start(idev, 0); ++ dev->irq = pnp_irq(idev, 0); ++ printk(KERN_INFO "atari_ethernec.c: ISAPnP reports %s at i/o %#lx, irq %d.\n", ++ (char *) isapnp_clone_list[i].driver_data, ++ dev->base_addr, dev->irq); ++ if (ne_probe1(dev, dev->base_addr) != 0) { /* Shouldn't happen. */ ++ printk(KERN_ERR "atari_ethernec.c: Probe of ISAPnP card at %#lx failed.\n", ++ dev->base_addr); ++ pnp_device_detach(idev); ++ return -ENXIO; ++ } ++ ei_status.priv = (unsigned long)idev; ++ break; ++ } ++ if (!idev) ++ continue; ++ return 0; ++ } ++ ++ return -ENODEV; ++} ++ ++static int __init ne_probe1(struct net_device *dev, int ioaddr) ++{ ++ int i; ++ unsigned char SA_prom[32]; ++ int wordlength = 2; ++ const char *name = NULL; ++ int start_page, stop_page; ++ int neX000, ctron, copam, bad_card; ++ int reg0, ret; ++ static unsigned version_printed; ++ ++ if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME)) ++ return -EBUSY; ++ ++ reg0 = inb_p(ioaddr); ++ if (reg0 == 0xFF) { ++ ret = -ENODEV; ++ goto err_out; ++ } ++ ++ /* Do a preliminary verification that we have a 8390. */ ++ { ++ int regd; ++ outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD); ++ regd = inb_p(ioaddr + 0x0d); ++ outb_p(0xff, ioaddr + 0x0d); ++ outb_p(E8390_NODMA+E8390_PAGE0, ioaddr + E8390_CMD); ++ inb_p(ioaddr + EN0_COUNTER0); /* Clear the counter by reading. */ ++ if (inb_p(ioaddr + EN0_COUNTER0) != 0) { ++ outb_p(reg0, ioaddr); ++ outb_p(regd, ioaddr + 0x0d); /* Restore the old values. */ ++ ret = -ENODEV; ++ goto err_out; ++ } ++ } ++ ++ if (ei_debug && version_printed++ == 0) ++ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2); ++ ++ /* A user with a poor card that fails to ack the reset, or that ++ does not have a valid 0x57,0x57 signature can still use this ++ without having to recompile. Specifying an i/o address along ++ with an otherwise unused dev->mem_end value of "0xBAD" will ++ cause the driver to skip these parts of the probe. */ ++ ++ bad_card = ((dev->base_addr != 0) && (dev->mem_end == 0xbad)); ++ ++ /* Reset card. Who knows what dain-bramaged state it was left in. */ ++ ++ { ++ unsigned long reset_start_time = jiffies; ++ ++ /* DON'T change these to inb_p/outb_p or reset will fail on clones. */ ++ outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET); ++ ++ while ((inb_p(ioaddr + EN0_ISR) & ENISR_RESET) == 0) { ++ if (time_after(jiffies, reset_start_time + 2 * HZ / 100)) { ++ if (bad_card) { ++ printk(" (warning: no reset ack)"); ++ break; ++ } else { ++ // MSch: ARAnyM exits here ++ printk(" not found (no reset ack).\n"); ++ ret = -ENODEV; ++ goto err_out; ++ } ++ } ++ } ++ ++ outb_p(0xff, ioaddr + EN0_ISR); /* Ack all intr. */ ++ } ++ ++ /* Read the 16 bytes of station address PROM. ++ We must first initialize registers, similar to NS8390_init(eifdev, 0). ++ We can't reliably read the SAPROM address without this. ++ (I learned the hard way!). */ ++ { ++ struct {unsigned char value, offset; } program_seq[] = ++ { ++ {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/ ++ {0x48, EN0_DCFG}, /* Set byte-wide (0x48) access. */ ++ {0x00, EN0_RCNTLO}, /* Clear the count regs. */ ++ {0x00, EN0_RCNTHI}, ++ {0x00, EN0_IMR}, /* Mask completion irq. */ ++ {0xFF, EN0_ISR}, ++ {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */ ++ {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */ ++ {32, EN0_RCNTLO}, ++ {0x00, EN0_RCNTHI}, ++ {0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */ ++ {0x00, EN0_RSARHI}, ++ {E8390_RREAD+E8390_START, E8390_CMD}, ++ }; ++ ++ for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) ++ outb_p(program_seq[i].value, ioaddr + program_seq[i].offset); ++ ++ } ++ for (i = 0; i < 32 /*sizeof(SA_prom)*/; i += 2) { ++ SA_prom[i] = inb(ioaddr + NE_DATAPORT); ++ SA_prom[i+1] = inb(ioaddr + NE_DATAPORT); ++ if (SA_prom[i] != SA_prom[i+1]) ++ wordlength = 1; ++ } ++ ++ if (wordlength == 2) { ++ for (i = 0; i < 16; i++) ++ SA_prom[i] = SA_prom[i+i]; ++ /* We must set the 8390 for word mode. */ ++ outb_p(DCR_VAL, ioaddr + EN0_DCFG); ++ start_page = NESM_START_PG; ++ ++ /* ++ * Realtek RTL8019AS datasheet says that the PSTOP register ++ * shouldn't exceed 0x60 in 8-bit mode. ++ * This chip can be identified by reading the signature from ++ * the remote byte count registers (otherwise write-only)... ++ */ ++ if ((DCR_VAL & 0x01) == 0 && /* 8-bit mode */ ++ inb(ioaddr + EN0_RCNTLO) == 0x50 && ++ inb(ioaddr + EN0_RCNTHI) == 0x70) ++ stop_page = 0x60; ++ else ++ stop_page = NESM_STOP_PG; ++ } else { ++ start_page = NE1SM_START_PG; ++ stop_page = NE1SM_STOP_PG; ++ } ++ ++#if defined(CONFIG_PLAT_MAPPI) || defined(CONFIG_PLAT_OAKS32R) ++ neX000 = ((SA_prom[14] == 0x57 && SA_prom[15] == 0x57) ++ || (SA_prom[14] == 0x42 && SA_prom[15] == 0x42)); ++#else ++ neX000 = (SA_prom[14] == 0x57 && SA_prom[15] == 0x57); ++#endif ++ ctron = (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d); ++ copam = (SA_prom[14] == 0x49 && SA_prom[15] == 0x00); ++ ++ /* Set up the rest of the parameters. */ ++ if (neX000 || bad_card || copam) { ++ name = (wordlength == 2) ? "NE2000" : "NE1000"; ++ } else if (ctron) { ++ name = (wordlength == 2) ? "Ctron-8" : "Ctron-16"; ++ start_page = 0x01; ++ stop_page = (wordlength == 2) ? 0x40 : 0x20; ++ } else { ++#ifdef SUPPORT_NE_BAD_CLONES ++ /* Ack! Well, there might be a *bad* NE*000 clone there. ++ Check for total bogus addresses. */ ++ for (i = 0; bad_clone_list[i].name8; i++) { ++ if (SA_prom[0] == bad_clone_list[i].SAprefix[0] && ++ SA_prom[1] == bad_clone_list[i].SAprefix[1] && ++ SA_prom[2] == bad_clone_list[i].SAprefix[2]) { ++ if (wordlength == 2) { ++ name = bad_clone_list[i].name16; ++ } else { ++ name = bad_clone_list[i].name8; ++ } ++ break; ++ } ++ } ++ if (bad_clone_list[i].name8 == NULL) { ++ printk(" not found (invalid signature %2.2x %2.2x).\n", ++ SA_prom[14], SA_prom[15]); ++ ret = -ENXIO; ++ goto err_out; ++ } ++#else ++ printk(" not found.\n"); ++ ret = -ENXIO; ++ goto err_out; ++#endif ++ } ++ ++ if (dev->irq < 2) { ++ unsigned long cookie = probe_irq_on(); ++ outb_p(0x50, ioaddr + EN0_IMR); /* Enable one interrupt. */ ++ outb_p(0x00, ioaddr + EN0_RCNTLO); ++ outb_p(0x00, ioaddr + EN0_RCNTHI); ++ outb_p(E8390_RREAD+E8390_START, ioaddr); /* Trigger it... */ ++ mdelay(10); /* wait 10ms for interrupt to propagate */ ++ outb_p(0x00, ioaddr + EN0_IMR); /* Mask it again. */ ++ dev->irq = probe_irq_off(cookie); ++ if (ei_debug > 2) ++ printk(" autoirq is %d\n", dev->irq); ++ } else if (dev->irq == 2) ++ /* Fixup for users that don't know that IRQ 2 is really IRQ 9, ++ or don't know which one to set. */ ++ dev->irq = 9; ++ ++ /* ++ * use timer based polling! ++ */ ++ if (! dev->irq) { ++ printk(" failed to detect IRQ line. Assuming irq %d\n", ++ ETHERNEC_RTL_8019_IRQ); ++ dev->irq = ETHERNEC_RTL_8019_IRQ; ++ /* timer routine set up in atari_ethernec_probe() */ ++ if (dev->irq == IRQ_MFP_TIMD) { ++ /* set Timer D data Register */ ++ mfp.tim_dt_d = 123; /* 200 Hz */ ++ /* start timer D, div = 1:100 */ ++ mfp.tim_ct_cd = (mfp.tim_ct_cd & 0xf0) | 0x6; ++ } ++ ret = request_irq(dev->irq, ei_interrupt, 0, name, dev); ++ if (ret) { ++ printk(" unable to get IRQ %d (errno=%d), polling instead.\n", ++ dev->irq, ret); ++ use_poll = 1; ++ } ++ } else { ++ ++ /* Snarf the interrupt now. There's no point in waiting since we cannot ++ share and the board will usually be enabled. */ ++ ret = request_irq(dev->irq, ei_interrupt, 0, name, dev); ++ if (ret) { ++ printk(" unable to get IRQ %d (errno=%d).\n", dev->irq, ret); ++ goto err_out; ++ } ++ } ++ dev->base_addr = ioaddr; ++ ++#ifdef CONFIG_PLAT_MAPPI ++ outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, ++ ioaddr + E8390_CMD); /* 0x61 */ ++ for (i = 0; i < ETHER_ADDR_LEN; i++) { ++ dev->dev_addr[i] = SA_prom[i] = inb_p(ioaddr + EN1_PHYS_SHIFT(i)); ++ printk(" %2.2x", SA_prom[i]); ++ } ++#else ++ for (i = 0; i < ETHER_ADDR_LEN; i++) { ++ printk(" %2.2x", SA_prom[i]); ++ dev->dev_addr[i] = SA_prom[i]; ++ } ++#endif ++ ++ printk("\n%s: %s found at %#x, using IRQ %d.\n", ++ dev->name, name, ioaddr, dev->irq); ++ ++ ei_status.name = name; ++ ei_status.tx_start_page = start_page; ++ ei_status.stop_page = stop_page; ++ ++ /* Use 16-bit mode only if this wasn't overridden by DCR_VAL */ ++ ei_status.word16 = (wordlength == 2 && (DCR_VAL & 0x01)); ++ ++ ei_status.rx_start_page = start_page + TX_PAGES; ++#ifdef PACKETBUF_MEMSIZE ++ /* Allow the packet buffer size to be overridden by know-it-alls. */ ++ ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE; ++#endif ++ ++ ei_status.reset_8390 = &ne_reset_8390; ++ ei_status.block_input = &ne_block_input; ++ ei_status.block_output = &ne_block_output; ++ ei_status.get_8390_hdr = &ne_get_8390_hdr; ++ ei_status.priv = 0; ++ dev->open = &ne_open; ++ dev->stop = &ne_close; ++#ifdef CONFIG_NET_POLL_CONTROLLER ++ dev->poll_controller = ei_poll; ++#endif ++ NS8390_init(dev, 0); ++ ++ ret = register_netdev(dev); ++ if (ret) ++ goto out_irq; ++ return 0; ++ ++out_irq: ++ free_irq(dev->irq, dev); ++err_out: ++ release_region(ioaddr, NE_IO_EXTENT); ++ return ret; ++} ++ ++static int ne_open(struct net_device *dev) ++{ ++ ei_open(dev); ++ return 0; ++} ++ ++static int ne_close(struct net_device *dev) ++{ ++ if (ei_debug > 1) ++ printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name); ++ ei_close(dev); ++ return 0; ++} ++ ++/* Hard reset the card. This used to pause for the same period that a ++ 8390 reset command required, but that shouldn't be necessary. */ ++ ++static void ne_reset_8390(struct net_device *dev) ++{ ++ unsigned long reset_start_time = jiffies; ++ ++ if (ei_debug > 1) ++ printk(KERN_DEBUG "resetting the 8390 t=%ld...", jiffies); ++ ++ /* DON'T change these to inb_p/outb_p or reset will fail on clones. */ ++ outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET); ++ ++ ei_status.txing = 0; ++ ei_status.dmaing = 0; ++ ++ /* This check _should_not_ be necessary, omit eventually. */ ++ while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0) { ++ if (time_after(jiffies, reset_start_time + 2*HZ/100)) { ++ printk(KERN_WARNING "%s: ne_reset_8390() did not complete.\n", ++ dev->name); ++ break; ++ } ++ } ++ outb_p(ENISR_RESET, NE_BASE + EN0_ISR); /* Ack intr. */ ++} ++ ++/* Grab the 8390 specific header. Similar to the block_input routine, but ++ we don't need to be concerned with ring wrap as the header will be at ++ the start of a page, so we optimize accordingly. */ ++ ++static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) ++{ ++ int nic_base = dev->base_addr; ++ ++ /* This *shouldn't* happen. If it does, it's the last thing you'll see */ ++ ++ if (ei_status.dmaing) ++ { ++ printk(KERN_EMERG "%s: DMAing conflict in ne_get_8390_hdr " ++ "[DMAstat:%d][irqlock:%d].\n", ++ dev->name, ei_status.dmaing, ei_status.irqlock); ++ return; ++ } ++ ++ ei_status.dmaing |= 0x01; ++ outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); ++ outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO); ++ outb_p(0, nic_base + EN0_RCNTHI); ++ outb_p(0, nic_base + EN0_RSARLO); /* On page boundary */ ++ outb_p(ring_page, nic_base + EN0_RSARHI); ++ outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD); ++ ++ if (ei_status.word16) ++ insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1); ++ else ++ insb(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)); ++ ++ outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ ++ ei_status.dmaing &= ~0x01; ++ ++ le16_to_cpus(&hdr->count); ++} ++ ++/* Block input and output, similar to the Crynwr packet driver. If you ++ are porting to a new ethercard, look at the packet driver source for hints. ++ The NEx000 doesn't share the on-board packet memory -- you have to put ++ the packet out through the "remote DMA" dataport using outb. */ ++ ++static void ne_block_input(struct net_device *dev, int count, ++ struct sk_buff *skb, int ring_offset) ++{ ++#ifdef NE_SANITY_CHECK ++ int xfer_count = count; ++#endif ++ int nic_base = dev->base_addr; ++ char *buf = skb->data; ++ ++ /* This *shouldn't* happen. If it does, it's the last thing you'll see */ ++ if (ei_status.dmaing) { ++ printk(KERN_EMERG "%s: DMAing conflict in ne_block_input " ++ "[DMAstat:%d][irqlock:%d].\n", ++ dev->name, ei_status.dmaing, ei_status.irqlock); ++ return; ++ } ++ ei_status.dmaing |= 0x01; ++ outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); ++ outb_p(count & 0xff, nic_base + EN0_RCNTLO); ++ outb_p(count >> 8, nic_base + EN0_RCNTHI); ++ outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO); ++ outb_p(ring_offset >> 8, nic_base + EN0_RSARHI); ++ outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD); ++ ++ if (ei_status.word16) { ++ insw(NE_BASE + NE_DATAPORT,buf,count>>1); ++ if (count & 0x01) { ++ buf[count-1] = inb(NE_BASE + NE_DATAPORT); ++#ifdef NE_SANITY_CHECK ++ xfer_count++; ++#endif ++ } ++ } else { ++ insb(NE_BASE + NE_DATAPORT, buf, count); ++ } ++ ++#ifdef NE_SANITY_CHECK ++ /* This was for the ALPHA version only, but enough people have ++ been encountering problems so it is still here. If you see ++ this message you either 1) have a slightly incompatible clone ++ or 2) have noise/speed problems with your bus. */ ++ ++ if (ei_debug > 1) { ++ /* DMA termination address check... */ ++ int addr, tries = 20; ++ do { ++ /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here ++ -- it's broken for Rx on some cards! */ ++ int high = inb_p(nic_base + EN0_RSARHI); ++ int low = inb_p(nic_base + EN0_RSARLO); ++ addr = (high << 8) + low; ++ if (((ring_offset + xfer_count) & 0xff) == low) ++ break; ++ } while (--tries > 0); ++ if (tries <= 0) ++ printk(KERN_WARNING "%s: RX transfer address mismatch," ++ "%#4.4x (expected) vs. %#4.4x (actual).\n", ++ dev->name, ring_offset + xfer_count, addr); ++ } ++#endif ++ outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ ++ ei_status.dmaing &= ~0x01; ++} ++ ++static void ne_block_output(struct net_device *dev, int count, ++ const unsigned char *buf, const int start_page) ++{ ++ int nic_base = NE_BASE; ++ unsigned long dma_start; ++#ifdef NE_SANITY_CHECK ++ int retries = 0; ++#endif ++ ++ /* Round the count up for word writes. Do we need to do this? ++ What effect will an odd byte count have on the 8390? ++ I should check someday. */ ++ ++ if (ei_status.word16 && (count & 0x01)) ++ count++; ++ ++ /* This *shouldn't* happen. If it does, it's the last thing you'll see */ ++ if (ei_status.dmaing) { ++ printk(KERN_EMERG "%s: DMAing conflict in ne_block_output." ++ "[DMAstat:%d][irqlock:%d]\n", ++ dev->name, ei_status.dmaing, ei_status.irqlock); ++ return; ++ } ++ ei_status.dmaing |= 0x01; ++ /* We should already be in page 0, but to be safe... */ ++ outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD); ++ ++#ifdef NE_SANITY_CHECK ++retry: ++#endif ++ ++#ifdef NE8390_RW_BUGFIX ++ /* Handle the read-before-write bug the same way as the ++ Crynwr packet driver -- the NatSemi method doesn't work. ++ Actually this doesn't always work either, but if you have ++ problems with your NEx000 this is better than nothing! */ ++ ++ outb_p(0x42, nic_base + EN0_RCNTLO); ++ outb_p(0x00, nic_base + EN0_RCNTHI); ++ outb_p(0x42, nic_base + EN0_RSARLO); ++ outb_p(0x00, nic_base + EN0_RSARHI); ++ outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD); ++ /* Make certain that the dummy read has occurred. */ ++ udelay(6); ++#endif ++ ++ outb_p(ENISR_RDC, nic_base + EN0_ISR); ++ ++ /* Now the normal output. */ ++ outb_p(count & 0xff, nic_base + EN0_RCNTLO); ++ outb_p(count >> 8, nic_base + EN0_RCNTHI); ++ outb_p(0x00, nic_base + EN0_RSARLO); ++ outb_p(start_page, nic_base + EN0_RSARHI); ++ ++ outb_p(E8390_RWRITE+E8390_START, nic_base + NE_CMD); ++ if (ei_status.word16) ++ outsw(NE_BASE + NE_DATAPORT, buf, count>>1); ++ else ++ outsb(NE_BASE + NE_DATAPORT, buf, count); ++ ++ dma_start = jiffies; ++ ++#ifdef NE_SANITY_CHECK ++ /* This was for the ALPHA version only, but enough people have ++ been encountering problems so it is still here. */ ++ ++ if (ei_debug > 1) { ++ /* DMA termination address check... */ ++ int addr, tries = 20; ++ do { ++ int high = inb_p(nic_base + EN0_RSARHI); ++ int low = inb_p(nic_base + EN0_RSARLO); ++ addr = (high << 8) + low; ++ if ((start_page << 8) + count == addr) ++ break; ++ } while (--tries > 0); ++ ++ if (tries <= 0) { ++ printk(KERN_WARNING "%s: Tx packet transfer address mismatch," ++ "%#4.4x (expected) vs. %#4.4x (actual).\n", ++ dev->name, (start_page << 8) + count, addr); ++ if (retries++ == 0) ++ goto retry; ++ } ++ } ++#endif ++ ++ while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0) { ++ if (time_after(jiffies, dma_start + 2*HZ/100)) { /* 20ms */ ++ printk(KERN_WARNING "%s: timeout waiting for Tx RDC.\n", dev->name); ++ ne_reset_8390(dev); ++ NS8390_init(dev, 1); ++ break; ++ } ++ } ++ ++ outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ ++ ei_status.dmaing &= ~0x01; ++ return; ++} ++ ++ ++#ifdef MODULE ++#define MAX_NE_CARDS 4 /* Max number of NE cards per module */ ++static struct net_device *dev_ne[MAX_NE_CARDS]; ++static int io[MAX_NE_CARDS]; ++static int irq[MAX_NE_CARDS]; ++static int bad[MAX_NE_CARDS]; /* 0xbad = bad sig or no reset ack */ ++ ++module_param_array(io, int, NULL, 0); ++module_param_array(irq, int, NULL, 0); ++module_param_array(bad, int, NULL, 0); ++module_param(use_poll, int, 0); ++MODULE_PARM_DESC(io, "I/O base address(es),required"); ++MODULE_PARM_DESC(irq, "IRQ number(s)"); ++MODULE_PARM_DESC(bad, "Accept card(s) with bad signatures"); ++MODULE_PARM_DESC(use_poll, "Use timer interrupt to poll driver"); ++MODULE_DESCRIPTION("NE1000/NE2000 ISA/PnP Ethernet driver"); ++MODULE_LICENSE("GPL"); ++ ++/* This is set up so that no ISA autoprobe takes place. We can't guarantee ++that the ne2k probe is the last 8390 based probe to take place (as it ++is at boot) and so the probe will get confused by any other 8390 cards. ++ISA device autoprobes on a running machine are not recommended anyway. */ ++ ++int __init init_module(void) ++{ ++ int this_dev, found = 0; ++ ++ for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { ++ struct net_device *dev = alloc_ei_netdev(); ++ if (!dev) ++ break; ++ dev->irq = irq[this_dev]; ++ dev->mem_end = bad[this_dev]; ++ dev->base_addr = io[this_dev]; ++ if (do_ne_probe(dev) == 0) { ++ dev_ne[found++] = dev; ++ continue; ++ } ++ free_netdev(dev); ++ if (found) ++ break; ++ if (io[this_dev] != 0) ++ printk(KERN_WARNING "atari_ethernec.c: No NE*000 card found at i/o = %#x\n", io[this_dev]); ++ else ++ printk(KERN_NOTICE "atari_ethernec.c: You must supply \"io=0xNNN\" value(s) for ISA cards.\n"); ++ return -ENXIO; ++ } ++ if (found) ++ return 0; ++ return -ENODEV; ++} ++ ++static void cleanup_card(struct net_device *dev) ++{ ++ struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; ++ if (idev) ++ pnp_device_detach(idev); ++ free_irq(dev->irq, dev); ++ release_region(dev->base_addr, NE_IO_EXTENT); ++} ++ ++void cleanup_module(void) ++{ ++ int this_dev; ++ ++ for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { ++ struct net_device *dev = dev_ne[this_dev]; ++ if (dev) { ++ if (use_poll) ++ atari_ethernec_stop_poll(dev); ++ unregister_netdev(dev); ++ cleanup_card(dev); ++ free_netdev(dev); ++ } ++ } ++} ++#endif /* MODULE */ diff --git a/debian/patches/bugfix/m68k/2.6.24/atari-platform-device.diff b/debian/patches/bugfix/m68k/2.6.24/atari-platform-device.diff new file mode 100644 index 000000000..32d260e0b --- /dev/null +++ b/debian/patches/bugfix/m68k/2.6.24/atari-platform-device.diff @@ -0,0 +1,73 @@ +arch/m68k/atari/ataints.c: ATARIHW_PRESENT(TT_MFP)) || \ +arch/m68k/atari/ataints.c: !((n) & 1) && ATARIHW_PRESENT(SCC)) || \ +arch/m68k/atari/ataints.c: if (ATARIHW_PRESENT(TT_MFP)) { +arch/m68k/atari/ataints.c: if (ATARIHW_PRESENT(SCC) && !atari_SCC_reset_done) { +arch/m68k/atari/ataints.c: if (ATARIHW_PRESENT(SCU)) { +arch/m68k/atari/ataints.c: if (ATARIHW_PRESENT(PCM_8BIT) && ATARIHW_PRESENT(MICROWIRE)) { +arch/m68k/atari/config.c: if (!MACH_IS_HADES && !ATARIHW_PRESENT(ST_SCSI)) { +arch/m68k/atari/config.c: if (ATARIHW_PRESENT(MSTE_CLK)) +arch/m68k/atari/config.c: if (ATARIHW_PRESENT(name)) \ +arch/m68k/atari/debug.c: if (ATARIHW_PRESENT(TT_MFP) && baud >= 6) { +drivers/block/ataflop.c: if (ATARIHW_PRESENT(FDCSPEED)) +drivers/block/ataflop.c: if (ATARIHW_PRESENT(FDCSPEED)) +drivers/block/ataflop.c: if (ATARIHW_PRESENT(FDCSPEED)) +drivers/block/ataflop.c: if (ATARIHW_PRESENT(FDCSPEED)) { +drivers/block/ataflop.c: if (ATARIHW_PRESENT(FDCSPEED)) +drivers/block/ataflop.c: if (ATARIHW_PRESENT(EXTD_DMA)) { +drivers/block/ataflop.c: paddr = ATARIHW_PRESENT(EXTD_DMA) ? +drivers/block/ataflop.c: if (ATARIHW_PRESENT(EXTD_DMA)) +drivers/block/ataflop.c: if (ATARIHW_PRESENT( EXTD_DMA )) +drivers/block/ataflop.c: if (ATARIHW_PRESENT(FDCSPEED)) { +drivers/block/ataflop.c: addr = ATARIHW_PRESENT( EXTD_DMA ) ? ReqData : DMABuffer; +drivers/block/ataflop.c: if (!ATARIHW_PRESENT( EXTD_DMA )) +drivers/block/ataflop.c: if (ATARIHW_PRESENT( EXTD_DMA )) +drivers/block/ataflop.c: if (ATARIHW_PRESENT( FDCSPEED ) || MACH_IS_MEDUSA) +drivers/block/ataflop.c: if (ATARIHW_PRESENT(FDCSPEED)) +drivers/char/dsp56k.c: if(!MACH_IS_ATARI || !ATARIHW_PRESENT(DSP56K)) { +drivers/char/nvram.c:#define CHECK_DRIVER_INIT() (MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK)) +drivers/ide/legacy/falconide.c: if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) { +drivers/input/keyboard/atakbd.c: if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP)) +drivers/input/mouse/atarimouse.c: if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP)) +drivers/scsi/atari_scsi.c:#define IS_A_TT() ATARIHW_PRESENT(TT_SCSI) +drivers/scsi/atari_scsi.c: (!ATARIHW_PRESENT(ST_SCSI) && !ATARIHW_PRESENT(TT_SCSI)) || +drivers/scsi/atari_scsi.c: if (ATARIHW_PRESENT(TT_CLK) && nvram_check_checksum()) { +drivers/scsi/atari_scsi.c: if (MACH_IS_ATARI && ATARIHW_PRESENT(ST_SCSI) && +drivers/scsi/atari_scsi.c: !ATARIHW_PRESENT(EXTD_DMA) && m68k_num_memory > 1) { +drivers/scsi/atari_scsi.c: atari_dma_stram_mask = (ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000 +drivers/video/atafb.c: if (ATARIHW_PRESENT(PCM_8BIT)) { +drivers/video/atafb.c: if (ATARIHW_PRESENT(EXTD_SHIFTER)) { +drivers/video/atafb.c: var->red.length = ATARIHW_PRESENT(EXTD_SHIFTER) ? 4 : 3; +drivers/video/atafb.c: if (ATARIHW_PRESENT(EXTD_SHIFTER)) +drivers/video/atafb.c: if (ATARIHW_PRESENT(EXTD_SHIFTER)) +drivers/video/atafb.c: if (ATARIHW_PRESENT(PCM_8BIT)) { +drivers/video/atafb.c: if (!ATARIHW_PRESENT(EXTD_SHIFTER)) +drivers/video/atafb.c: if (ATARIHW_PRESENT(EXTD_SHIFTER)) +drivers/video/atafb.c: (!ATARIHW_PRESENT(EXTD_SHIFTER) && var->xoffset)) +drivers/video/atafb.c: if (ATARIHW_PRESENT(TT_SHIFTER)) { +drivers/video/atafb.c: if (ATARIHW_PRESENT(VIDEL_SHIFTER)) { +drivers/video/atafb.c: if (ATARIHW_PRESENT(STND_SHIFTER) || +drivers/video/atafb.c: ATARIHW_PRESENT(EXTD_SHIFTER)) { +include/asm-m68k/atarihw.h:#define ATARIHW_PRESENT(name) (atari_hw_present.name) +sound/oss/dmasound/dmasound_atari.c: if (MACH_IS_ATARI && ATARIHW_PRESENT(PCM_8BIT)) { +sound/oss/dmasound/dmasound_atari.c: if (ATARIHW_PRESENT(CODEC)) { +sound/oss/dmasound/dmasound_atari.c: } else if (ATARIHW_PRESENT(MICROWIRE)) { +drivers/char/atari_scc.c: int escc = ATARIHW_PRESENT(ST_ESCC); +drivers/char/atari_scc.c: if (!(ATARIHW_PRESENT(SCC) || ATARIHW_PRESENT(ST_ESCC))) +drivers/char/atari_scc.c: if (ATARIHW_PRESENT(TT_MFP) && baud >= 6) { +--- + arch/m68k/atari/platform.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- /dev/null ++++ b/arch/m68k/atari/platform.c +@@ -0,0 +1,10 @@ ++/* ++ * Copyright (C) 2007 Geert Uytterhoeven ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive ++ * for more details. ++ */ ++ ++#include ++ diff --git a/debian/patches/bugfix/m68k/2.6.24/atari-rom-isa.diff b/debian/patches/bugfix/m68k/2.6.24/atari-rom-isa.diff new file mode 100644 index 000000000..446bef486 --- /dev/null +++ b/debian/patches/bugfix/m68k/2.6.24/atari-rom-isa.diff @@ -0,0 +1,401 @@ +Subject: [PATCH] m68k: Atari ROM port ISA adapter support + +From: Michael Schmitz + +Atari ROM port ISA adapter support + +Signed-off-by: Michael Schmitz +Signed-off-by: Roman Zippel +Signed-off-by: Geert Uytterhoeven +--- + arch/m68k/Kconfig | 10 +++ + include/asm-m68k/io.h | 137 ++++++++++++++++++++++++++++++++++++++++++++-- + include/asm-m68k/raw_io.h | 116 ++++++++++++++++++++++++++++++++++++++ + 3 files changed, 258 insertions(+), 5 deletions(-) + +--- a/arch/m68k/Kconfig ++++ b/arch/m68k/Kconfig +@@ -150,6 +150,16 @@ config PCI + information about which PCI hardware does work under Linux and which + doesn't. + ++config ATARI_ROM_ISA ++ bool "Atari ROM port ISA adapter support" ++ depends on ATARI ++ help ++ This option enables support for the ROM port ISA adapter used to ++ operate ISA cards on Atari. Only 8 bit cards are supported, and ++ no interrupt lines are connected. ++ The only driver currently using this adapter is the EtherNEC ++ driver for RTL8019AS based NE2000 compatible network cards. ++ + config MAC + bool "Macintosh support" + depends on !MMU_SUN3 +--- a/include/asm-m68k/io.h ++++ b/include/asm-m68k/io.h +@@ -83,9 +83,26 @@ extern unsigned long gg2_isa_base; + #endif + #endif /* AMIGA_PCMCIA */ + ++#ifdef CONFIG_ATARI_ROM_ISA + ++#define enec_isa_read_base 0xfffa0000 ++#define enec_isa_write_base 0xfffb0000 + +-#ifdef CONFIG_ISA ++#define ENEC_ISA_IO_B(ioaddr) (enec_isa_read_base+((((unsigned long)(ioaddr))&0x1F)<<9)) ++#define ENEC_ISA_IO_W(ioaddr) (enec_isa_read_base+((((unsigned long)(ioaddr))&0x1F)<<9)) ++#define ENEC_ISA_MEM_B(madr) (enec_isa_read_base+((((unsigned long)(madr))&0x1F)<<9)) ++#define ENEC_ISA_MEM_W(madr) (enec_isa_read_base+((((unsigned long)(madr))&0x1F)<<9)) ++ ++#ifndef MULTI_ISA ++#define MULTI_ISA 0 ++#else ++#undef MULTI_ISA ++#define MULTI_ISA 1 ++#endif ++#endif /* ATARI */ ++ ++ ++#if defined(CONFIG_ISA) || defined(CONFIG_ATARI_ROM_ISA) + + #if MULTI_ISA == 0 + #undef MULTI_ISA +@@ -94,6 +111,7 @@ extern unsigned long gg2_isa_base; + #define Q40_ISA (1) + #define GG2_ISA (2) + #define AG_ISA (3) ++#define ENEC_ISA (4) + + #if defined(CONFIG_Q40) && !defined(MULTI_ISA) + #define ISA_TYPE Q40_ISA +@@ -107,6 +125,10 @@ extern unsigned long gg2_isa_base; + #define ISA_TYPE GG2_ISA + #define ISA_SEX 0 + #endif ++#if defined(CONFIG_ATARI_ROM_ISA) && !defined(MULTI_ISA) ++#define ISA_TYPE ENEC_ISA ++#define ISA_SEX 0 ++#endif + + #ifdef MULTI_ISA + extern int isa_type; +@@ -134,6 +156,9 @@ static inline u8 __iomem *isa_itb(unsign + #ifdef CONFIG_AMIGA_PCMCIA + case AG_ISA: return (u8 __iomem *)AG_ISA_IO_B(addr); + #endif ++#ifdef CONFIG_ATARI_ROM_ISA ++ case ENEC_ISA: return (u8 __iomem *)ENEC_ISA_IO_B(addr); ++#endif + default: return NULL; /* avoid warnings, just in case */ + } + } +@@ -150,6 +175,9 @@ static inline u16 __iomem *isa_itw(unsig + #ifdef CONFIG_AMIGA_PCMCIA + case AG_ISA: return (u16 __iomem *)AG_ISA_IO_W(addr); + #endif ++#ifdef CONFIG_ATARI_ROM_ISA ++ case ENEC_ISA: return (u16 __iomem *)ENEC_ISA_IO_W(addr); ++#endif + default: return NULL; /* avoid warnings, just in case */ + } + } +@@ -160,7 +188,7 @@ static inline u32 __iomem *isa_itl(unsig + #ifdef CONFIG_AMIGA_PCMCIA + case AG_ISA: return (u32 __iomem *)AG_ISA_IO_W(addr); + #endif +- default: return 0; /* avoid warnings, just in case */ ++ default: return NULL; /* avoid warnings, just in case */ + } + } + static inline u8 __iomem *isa_mtb(unsigned long addr) +@@ -176,6 +204,9 @@ static inline u8 __iomem *isa_mtb(unsign + #ifdef CONFIG_AMIGA_PCMCIA + case AG_ISA: return (u8 __iomem *)addr; + #endif ++#ifdef CONFIG_ATARI_ROM_ISA ++ case ENEC_ISA: return (u8 __iomem *)ENEC_ISA_MEM_B(addr); ++#endif + default: return NULL; /* avoid warnings, just in case */ + } + } +@@ -192,6 +223,9 @@ static inline u16 __iomem *isa_mtw(unsig + #ifdef CONFIG_AMIGA_PCMCIA + case AG_ISA: return (u16 __iomem *)addr; + #endif ++#ifdef CONFIG_ATARI_ROM_ISA ++ case ENEC_ISA: return (u16 __iomem *)ENEC_ISA_MEM_W(addr); ++#endif + default: return NULL; /* avoid warnings, just in case */ + } + } +@@ -213,6 +247,34 @@ static inline u16 __iomem *isa_mtw(unsig + (ISA_SEX ? out_be16(isa_mtw((unsigned long)(p)),(val)) \ + : out_le16(isa_mtw((unsigned long)(p)),(val))) + ++#if defined(CONFIG_ATARI_ROM_ISA) ++#define isa_rom_inb(port) rom_in_8(isa_itb(port)) ++#define isa_rom_inw(port) \ ++ (ISA_SEX ? rom_in_be16(isa_itw(port)) \ ++ : rom_in_le16(isa_itw(port))) ++#define isa_rom_inl(port) \ ++ (ISA_SEX ? rom_in_be32(isa_itw(port)) \ ++ : rom_in_le32(isa_itw(port))) ++ ++#define isa_rom_outb(val, port) rom_out_8(isa_itb(port), (val)) ++#define isa_rom_outw(val, port) \ ++ (ISA_SEX ? rom_out_be16(isa_itw(port), (val)) \ ++ : rom_out_le16(isa_itw(port), (val))) ++#define isa_rom_outl(val, port) \ ++ (ISA_SEX ? rom_out_be32(isa_itw(port), (val)) \ ++ : rom_out_le32(isa_itw(port), (val))) ++ ++#define isa_rom_readb(p) rom_in_8(isa_mtb((unsigned long)(p))) ++#define isa_rom_readw(p) \ ++ (ISA_SEX ? rom_in_be16(isa_mtw((unsigned long)(p))) \ ++ : rom_in_le16(isa_mtw((unsigned long)(p)))) ++ ++#define isa_rom_writeb(val, p) rom_out_8(isa_mtb((unsigned long)(p)), (val)) ++#define isa_rom_writew(val, p) \ ++ (ISA_SEX ? rom_out_be16(isa_mtw((unsigned long)(p)), (val)) \ ++ : rom_out_le16(isa_mtw((unsigned long)(p)), (val))) ++#endif ++ + static inline void isa_delay(void) + { + switch(ISA_TYPE) +@@ -226,6 +288,9 @@ static inline void isa_delay(void) + #ifdef CONFIG_AMIGA_PCMCIA + case AG_ISA: break; + #endif ++#ifdef CONFIG_ATARI_ROM_ISA ++ case ENEC_ISA: break; ++#endif + default: break; /* avoid warnings */ + } + } +@@ -256,10 +321,40 @@ static inline void isa_delay(void) + (ISA_SEX ? raw_outsl(isa_itl(port), (u32 *)(buf), (nr)) : \ + raw_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr)<<1)) + ++ ++#if defined(CONFIG_ATARI_ROM_ISA) ++#define isa_rom_inb_p(p) ({ u8 _v = isa_rom_inb(p); isa_delay(); _v; }) ++#define isa_rom_inw_p(p) ({ u16 _v = isa_rom_inw(p); isa_delay(); _v; }) ++#define isa_rom_inl_p(p) ({ u32 _v = isa_rom_inl(p); isa_delay(); _v; }) ++#define isa_rom_outb_p(v, p) ({ isa_rom_outb((v), (p)); isa_delay(); }) ++#define isa_rom_outw_p(v, p) ({ isa_rom_outw((v), (p)); isa_delay(); }) ++#define isa_rom_outl_p(v, p) ({ isa_rom_outl((v), (p)); isa_delay(); }) ++ ++#define isa_rom_insb(port, buf, nr) raw_rom_insb(isa_itb(port), (u8 *)(buf), (nr)) ++ ++#define isa_rom_insw(port, buf, nr) \ ++ (ISA_SEX ? raw_rom_insw(isa_itw(port), (u16 *)(buf), (nr)) : \ ++ raw_rom_insw_swapw(isa_itw(port), (u16 *)(buf), (nr))) ++ ++#define isa_rom_insl(port, buf, nr) \ ++ (ISA_SEX ? raw_rom_insl(isa_itw(port), (u32 *)(buf), (nr)) : \ ++ raw_rom_insw_swapw(isa_itw(port), (u16 *)(buf), (nr)<<1)) ++ ++#define isa_rom_outsb(port, buf, nr) raw_rom_outsb(isa_itb(port), (u8 *)(buf), (nr)) ++ ++#define isa_rom_outsw(port, buf, nr) \ ++ (ISA_SEX ? raw_rom_outsw(isa_itw(port), (u16 *)(buf), (nr)) : \ ++ raw_rom_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr))) ++ ++#define isa_rom_outsl(port, buf, nr) \ ++ (ISA_SEX ? raw_rom_outsl(isa_itw(port), (u32 *)(buf), (nr)) : \ ++ raw_rom_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr)<<1)) ++#endif ++ + #endif /* CONFIG_ISA */ + + +-#if defined(CONFIG_ISA) && !defined(CONFIG_PCI) ++#if defined(CONFIG_ISA) && !defined(CONFIG_PCI) && !defined(CONFIG_ATARI_ROM_ISA) + #define inb isa_inb + #define inb_p isa_inb_p + #define outb isa_outb +@@ -330,7 +425,41 @@ static inline void isa_delay(void) + #endif + #endif /* CONFIG_PCI */ + +-#if !defined(CONFIG_ISA) && !defined(CONFIG_PCI) ++#if defined(CONFIG_ATARI_ROM_ISA) ++/* ++ * kernel with both ROM port ISA and IDE compiled in, those have ++ * conflicting defs for in/out. Simply consider port < 1024 ++ * ROM port ISA and everything else regular ISA for IDE. read,write not defined ++ * in this case ++ */ ++#define inb(port) ((port) < 1024 ? isa_rom_inb(port) : in_8(port)) ++#define inb_p(port) ((port) < 1024 ? isa_rom_inb_p(port) : in_8(port)) ++#define inw(port) ((port) < 1024 ? isa_rom_inw(port) : in_le16(port)) ++#define inw_p(port) ((port) < 1024 ? isa_rom_inw_p(port) : in_le16(port)) ++#define inl(port) ((port) < 1024 ? isa_rom_inl(port) : in_le32(port)) ++#define inl_p(port) ((port) < 1024 ? isa_rom_inl_p(port) : in_le32(port)) ++ ++#define outb(val, port) ((port) < 1024 ? isa_rom_outb((val), (port)) : out_8((port), (val))) ++#define outb_p(val, port) ((port) < 1024 ? isa_rom_outb_p((val), (port)) : out_8((port), (val))) ++#define outw(val, port) ((port) < 1024 ? isa_rom_outw((val), (port)) : out_le16((port), (val))) ++#define outw_p(val, port) ((port) < 1024 ? isa_rom_outw_p((val), (port)) : out_le16((port), (val))) ++#define outl(val, port) ((port) < 1024 ? isa_rom_outl((val), (port)) : out_le32((port), (val))) ++#define outl_p(val, port) ((port) < 1024 ? isa_rom_outl_p((val), (port)) : out_le32((port), (val))) ++ ++#define insb isa_rom_insb ++#define insw isa_rom_insw ++#define insl isa_rom_insl ++#define outsb isa_rom_outsb ++#define outsw isa_rom_outsw ++#define outsl isa_rom_outsl ++ ++#define readb isa_readb ++#define readw isa_readw ++#define writeb isa_writeb ++#define writew isa_writew ++#endif ++ ++#if !defined(CONFIG_ISA) && !defined(CONFIG_PCI) && !defined(CONFIG_ATARI_ROM_ISA) + /* + * We need to define dummy functions for GENERIC_IOMAP support. + */ +--- a/include/asm-m68k/raw_io.h ++++ b/include/asm-m68k/raw_io.h +@@ -10,7 +10,7 @@ + + #ifdef __KERNEL__ + +-#include ++#include + + + /* Values for nocacheflag and cmode */ +@@ -60,6 +60,46 @@ extern void __iounmap(void *addr, unsign + #define __raw_writew(val,addr) out_be16((addr),(val)) + #define __raw_writel(val,addr) out_be32((addr),(val)) + ++/* ++ * Atari ROM port (cartridge port) ISA adapter, used for the EtherNEC NE2000 ++ * network card driver. ++ * The ISA adapter connects address lines A9-A13 to ISA address lines A0-A4, ++ * and hardwires the rest of the ISA addresses for a base address of 0x300. ++ * ++ * Data lines D8-D15 are connected to ISA data lines D0-D7 for reading. ++ * For writes, address lines A1-A8 are latched to ISA data lines D0-D7 ++ * (meaning the bit pattern on A1-A8 can be read back as byte). ++ * ++ * Reads and writes are byte only. ++ */ ++ ++#if defined(CONFIG_ATARI_ROM_ISA) ++#define rom_in_8(addr) \ ++ ({ u16 __v = (*(__force volatile u16 *) (addr)); __v >>= 8; __v; }) ++#define rom_in_be16(addr) \ ++ ({ u16 __v = (*(__force volatile u16 *) (addr)); __v >>= 8; __v; }) ++#define rom_in_be32(addr) \ ++ ({ u32 __v = (*(__force volatile u32 *) (addr)); __v >>= 8; __v; }) ++#define rom_in_le16(addr) \ ++ ({ u16 __v = le16_to_cpu(*(__force volatile u16 *) (addr)); __v >>= 8; __v; }) ++#define rom_in_le32(addr) \ ++ ({ u32 __v = le32_to_cpu(*(__force volatile u32 *) (addr)); __v >>= 8; __v; }) ++ ++#define rom_out_8(addr, b) ({u8 __w, __v = (b); __w = ((*(__force volatile u8 *) ((addr) + 0x10000 + (__v<<1)))); }) ++#define rom_out_be16(addr, w) ({u16 __w, __v = (w); __w = ((*(__force volatile u16 *) ((addr) + 0x10000 + (__v<<1)))); }) ++#define rom_out_be32(addr, l) ({u32 __w, __v = (l); __w = ((*(__force volatile u32 *) ((addr) + 0x10000 + (__v<<1)))); }) ++#define rom_out_le16(addr, w) ({u16 __w, __v = cpu_to_le16(w); __w = ((*(__force volatile u16 *) ((addr) + 0x10000 + (__v<<1)))); }) ++#define rom_out_le32(addr, l) ({u32 __w, __v = cpu_to_le32(l); __w = ((*(__force volatile u32 *) ((addr) + 0x10000 + (__v<<1)))); }) ++ ++#define raw_rom_inb rom_in_8 ++#define raw_rom_inw rom_in_be16 ++#define raw_rom_inl rom_in_be32 ++ ++#define raw_rom_outb(val, port) rom_out_8((port), (val)) ++#define raw_rom_outw(val, port) rom_out_be16((port), (val)) ++#define raw_rom_outl(val, port) rom_out_be32((port), (val)) ++#endif /* CONFIG_ATARI_ROM_ISA */ ++ + static inline void raw_insb(volatile u8 __iomem *port, u8 *buf, unsigned int len) + { + unsigned int i; +@@ -342,6 +382,80 @@ static inline void raw_outsw_swapw(volat + : "d0", "a0", "a1", "d6"); + } + ++ ++#if defined(CONFIG_ATARI_ROM_ISA) ++static inline void raw_rom_insb(volatile u8 __iomem *port, u8 *buf, unsigned int len) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < len; i++) ++ *buf++ = rom_in_8(port); ++} ++ ++static inline void raw_rom_outsb(volatile u8 __iomem *port, const u8 *buf, ++ unsigned int len) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < len; i++) ++ rom_out_8(port, *buf++); ++} ++ ++static inline void raw_rom_insw(volatile u16 __iomem *port, u16 *buf, ++ unsigned int nr) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < nr; i++) ++ *buf++ = rom_in_be16(port); ++} ++ ++static inline void raw_rom_outsw(volatile u16 __iomem *port, const u16 *buf, ++ unsigned int nr) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < nr; i++) ++ rom_out_be16(port, *buf++); ++} ++ ++static inline void raw_rom_insw_swapw(volatile u16 __iomem *port, u16 *buf, ++ unsigned int nr) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < nr; i++) ++ *buf++ = rom_in_le16(port); ++} ++ ++static inline void raw_rom_outsw_swapw(volatile u16 __iomem *port, const u16 *buf, ++ unsigned int nr) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < nr; i++) ++ rom_out_le16(port, *buf++); ++} ++ ++static inline void raw_rom_insl(volatile u16 __iomem *port, u32 *buf, ++ unsigned int nr) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < nr; i++) ++ *buf++ = rom_in_be32(port); ++} ++ ++static inline void raw_rom_outsl(volatile u16 __iomem *port, const u32 *buf, ++ unsigned int nr) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < nr; i++) ++ rom_out_be32(port, *buf++); ++} ++#endif /* CONFIG_ATARI_ROM_ISA */ ++ + #endif /* __KERNEL__ */ + + #endif /* _RAW_IO_H */ diff --git a/debian/patches/bugfix/m68k/2.6.24/b43-depends-on-HAS_DMA.diff b/debian/patches/bugfix/m68k/2.6.24/b43-depends-on-HAS_DMA.diff new file mode 100644 index 000000000..d91df4ab1 --- /dev/null +++ b/debian/patches/bugfix/m68k/2.6.24/b43-depends-on-HAS_DMA.diff @@ -0,0 +1,32 @@ +Subject: b43 should depend on HAS_DMA +To: Michael Buesch , Stefano Brivio +Cc: linux-wireless@vger.kernel.org + +b43 should depend on HAS_DMA + +Signed-off-by: Geert Uytterhoeven +--- + drivers/net/wireless/b43/Kconfig | 2 +- + drivers/net/wireless/b43legacy/Kconfig | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/wireless/b43/Kconfig ++++ b/drivers/net/wireless/b43/Kconfig +@@ -1,6 +1,6 @@ + config B43 + tristate "Broadcom 43xx wireless support (mac80211 stack)" +- depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 ++ depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 && HAS_DMA + select SSB + select FW_LOADER + select HW_RANDOM +--- a/drivers/net/wireless/b43legacy/Kconfig ++++ b/drivers/net/wireless/b43legacy/Kconfig +@@ -1,6 +1,6 @@ + config B43LEGACY + tristate "Broadcom 43xx-legacy wireless support (mac80211 stack)" +- depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 ++ depends on SSB_POSSIBLE && MAC80211 && WLAN_80211 && HAS_DMA + select SSB + select FW_LOADER + select HW_RANDOM diff --git a/debian/patches/bugfix/m68k/2.6.24/blinux-list-is-subscribers-only.diff b/debian/patches/bugfix/m68k/2.6.24/blinux-list-is-subscribers-only.diff new file mode 100644 index 000000000..5367d0419 --- /dev/null +++ b/debian/patches/bugfix/m68k/2.6.24/blinux-list-is-subscribers-only.diff @@ -0,0 +1,15 @@ +--- + MAINTAINERS | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1323,7 +1323,7 @@ S: Supported + DOUBLETALK DRIVER + P: James R. Van Zandt + M: jrv@vanzandt.mv.com +-L: blinux-list@redhat.com ++L: blinux-list@redhat.com (subscribers-only) + S: Maintained + + DRIVER CORE, KOBJECTS, AND SYSFS diff --git a/debian/patches/bugfix/m68k/2.6.24/checkpatch-print-filenames.diff b/debian/patches/bugfix/m68k/2.6.24/checkpatch-print-filenames.diff new file mode 100644 index 000000000..0a403d40d --- /dev/null +++ b/debian/patches/bugfix/m68k/2.6.24/checkpatch-print-filenames.diff @@ -0,0 +1,28 @@ +Subject: checkpatch: Print filenames of patches + +checkpatch: Print filenames of patches instead of the very uninformative +`Your patch'. + +Signed-off-by: Geert Uytterhoeven +--- +This patch is not `checkpatch' clean :-) +Although I shortened 2 lines, they're still longer than 80 characters... + + scripts/checkpatch.pl | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/scripts/checkpatch.pl ++++ b/scripts/checkpatch.pl +@@ -1408,10 +1408,10 @@ sub process { + } + } + if ($clean == 1 && $quiet == 0) { +- print "Your patch has no obvious style problems and is ready for submission.\n" ++ print "$filename has no obvious style problems and is ready for submission.\n" + } + if ($clean == 0 && $quiet == 0) { +- print "Your patch has style problems, please review. If any of these errors\n"; ++ print "$filename has style problems, please review. If any of these errors\n"; + print "are false positives report them to the maintainer, see\n"; + print "CHECKPATCH in MAINTAINERS.\n"; + } diff --git a/debian/patches/bugfix/m68k/2.6.24/falconide_intr_lock-ratelimit.diff b/debian/patches/bugfix/m68k/2.6.24/falconide_intr_lock-ratelimit.diff new file mode 100644 index 000000000..2434c9519 --- /dev/null +++ b/debian/patches/bugfix/m68k/2.6.24/falconide_intr_lock-ratelimit.diff @@ -0,0 +1,22 @@ +Subject: [PATCH] m68k: Ratelimit ide_release_lock bug messages + +Ratelimit the annoying ide_release_lock bug messages as attempting to release +the already released lock does not appear to cause any harm in practice. + +Signed-off-by: Geert Uytterhoeven +--- + include/asm-m68k/ide.h | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/include/asm-m68k/ide.h ++++ b/include/asm-m68k/ide.h +@@ -114,7 +114,8 @@ static __inline__ void ide_release_lock + { + if (MACH_IS_ATARI) { + if (falconide_intr_lock == 0) { +- printk("ide_release_lock: bug\n"); ++ if (printk_ratelimit()) ++ printk("ide_release_lock: bug\n"); + return; + } + falconide_intr_lock = 0; diff --git a/debian/patches/bugfix/m68k/2.6.24/m68k-q40ints.c-needs-asm-floppy.h.diff b/debian/patches/bugfix/m68k/2.6.24/m68k-q40ints.c-needs-asm-floppy.h.diff new file mode 100644 index 000000000..101d600d9 --- /dev/null +++ b/debian/patches/bugfix/m68k/2.6.24/m68k-q40ints.c-needs-asm-floppy.h.diff @@ -0,0 +1,22 @@ + +arch/m68k/q40/q40ints.c: In function 'q40_irq_handler': +arch/m68k/q40/q40ints.c:214: error: implicit declaration of function 'floppy_hardint' + +FIXME q40_irq_handler() calls floppy_hardint(): + +arch/m68k/q40/q40ints.c:215: error: too few arguments to function 'floppy_hardint' + +--- + arch/m68k/q40/q40ints.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/m68k/q40/q40ints.c ++++ b/arch/m68k/q40/q40ints.c +@@ -16,6 +16,7 @@ + #include + #include + ++#include + #include + #include + #include diff --git a/debian/patches/bugfix/m68k/2.6.24/m68k-replace-linux-68k-by-linux-m68k.diff b/debian/patches/bugfix/m68k/2.6.24/m68k-replace-linux-68k-by-linux-m68k.diff new file mode 100644 index 000000000..27414ee1e --- /dev/null +++ b/debian/patches/bugfix/m68k/2.6.24/m68k-replace-linux-68k-by-linux-m68k.diff @@ -0,0 +1,244 @@ +Subject: m68k: Replace `Linux/68k' by `Linux/m68k' + +m68k: Replace `Linux/68k' by `Linux/m68k' + +We switched to `Linux/m68k' a very long time ago + +From: Geert Uytterhoeven +Signed-off-by: Geert Uytterhoeven +--- + CREDITS | 4 ++-- + Documentation/devices.txt | 10 +++++----- + Documentation/m68k/kernel-options.txt | 2 +- + arch/m68k/Kconfig | 2 +- + arch/m68k/ifpsp060/iskeleton.S | 6 +++--- + arch/m68k/ifpsp060/os.S | 4 ++-- + arch/m68k/kernel/head.S | 2 +- + arch/m68knommu/Kconfig | 2 +- + drivers/net/a2065.c | 4 ++-- + drivers/net/a2065.h | 4 ++-- + drivers/net/apne.c | 2 +- + include/asm-m68knommu/bootstd.h | 2 +- + include/linux/major.h | 2 +- + 13 files changed, 23 insertions(+), 23 deletions(-) + +--- a/CREDITS ++++ b/CREDITS +@@ -174,7 +174,7 @@ N: Ralf Baechle + E: ralf@gnu.org + P: 1024/AF7B30C1 CF 97 C2 CC 6D AE A7 FE C8 BA 9C FC 88 DE 32 C3 + D: Linux/MIPS port +-D: Linux/68k hacker ++D: Linux/m68k hacker + S: Hauptstrasse 19 + S: 79837 St. Blasien + S: Germany +@@ -2123,7 +2123,7 @@ D: dv1394 + + N: Hamish Macdonald + E: hamishm@lucent.com +-D: Linux/68k port ++D: Linux/m68k port + S: 32 Clydesdale Avenue + S: Kanata, Ontario + S: Canada K2M-2G7 +--- a/Documentation/devices.txt ++++ b/Documentation/devices.txt +@@ -19,8 +19,8 @@ The LaTeX version of this document is no + This document is included by reference into the Filesystem Hierarchy + Standard (FHS). The FHS is available from http://www.pathname.com/fhs/. + +-Allocations marked (68k/Amiga) apply to Linux/68k on the Amiga +-platform only. Allocations marked (68k/Atari) apply to Linux/68k on ++Allocations marked (m68k/Amiga) apply to Linux/m68k on the Amiga ++platform only. Allocations marked (m68k/Atari) apply to Linux/m68k on + the Atari platform only. + + The symbol {2.6} means the allocation is obsolete and scheduled for +@@ -328,7 +328,7 @@ Your cooperation is appreciated. + 2 = /dev/inportbm Microsoft Inport bus mouse + 3 = /dev/atibm ATI XL bus mouse + 4 = /dev/jbm J-mouse +- 4 = /dev/amigamouse Amiga mouse (68k/Amiga) ++ 4 = /dev/amigamouse Amiga mouse (m68k/Amiga) + 5 = /dev/atarimouse Atari mouse + 6 = /dev/sunmouse Sun mouse + 7 = /dev/amigamouse1 Second Amiga mouse +@@ -691,7 +691,7 @@ Your cooperation is appreciated. + 2 = /dev/staliomem2 Third Stallion card I/O memory + 3 = /dev/staliomem3 Fourth Stallion card I/O memory + +- 28 char Atari SLM ACSI laser printer (68k/Atari) ++ 28 char Atari SLM ACSI laser printer (m68k/Atari) + 0 = /dev/slm0 First SLM laser printer + 1 = /dev/slm1 Second SLM laser printer + ... +@@ -701,7 +701,7 @@ Your cooperation is appreciated. + 2 = /dev/sbpcd14 Panasonic CD-ROM controller 3 unit 2 + 3 = /dev/sbpcd15 Panasonic CD-ROM controller 3 unit 3 + +- 28 block ACSI disk (68k/Atari) ++ 28 block ACSI disk (m68k/Atari) + 0 = /dev/ada First ACSI disk whole disk + 16 = /dev/adb Second ACSI disk whole disk + 32 = /dev/adc Third ACSI disk whole disk +--- a/Documentation/m68k/kernel-options.txt ++++ b/Documentation/m68k/kernel-options.txt +@@ -852,7 +852,7 @@ use of this option is now highly unrecom + Incorrect use can lead to unpredictable behavior, so please only use + this option if you *know* what you are doing and have a reason to do + so. In any case if you experience problems and need to use this +-option, please inform us about it by mailing to the Linux/68k kernel ++option, please inform us about it by mailing to the Linux/m68k kernel + mailing list. + + The address mask set by this option specifies which addresses are +--- a/arch/m68k/Kconfig ++++ b/arch/m68k/Kconfig +@@ -52,7 +52,7 @@ config NO_IOPORT + config NO_DMA + def_bool SUN3 + +-mainmenu "Linux/68k Kernel Configuration" ++mainmenu "Linux/m68k Kernel Configuration" + + source "init/Kconfig" + +--- a/arch/m68k/ifpsp060/iskeleton.S ++++ b/arch/m68k/ifpsp060/iskeleton.S +@@ -65,7 +65,7 @@ + | To simply continue execution at the next instruction, just + | do an "rte". + | +-| Linux/68k: If returning to user space, check for needed reselections. ++| Linux/m68k: If returning to user space, check for needed reselections. + + .global _060_isp_done + _060_isp_done: +@@ -87,7 +87,7 @@ _060_isp_done: + | a CHK exception stack frame from the Unimplemented Integer Instrcution + | stack frame and branches to this routine. + | +-| Linux/68k: commented out test for tracing ++| Linux/m68k: commented out test for tracing + + .global _060_real_chk + _060_real_chk: +@@ -127,7 +127,7 @@ real_chk_end: + | then it create a Trace exception stack frame from the "chk" exception + | stack frame and branches to the _real_trace() entry point. + | +-| Linux/68k: commented out test for tracing ++| Linux/m68k: commented out test for tracing + + .global _060_real_divbyzero + _060_real_divbyzero: +--- a/arch/m68k/ifpsp060/os.S ++++ b/arch/m68k/ifpsp060/os.S +@@ -65,7 +65,7 @@ + | The result is that Unix processes are allowed to sleep as a consequence + | of a page fault during a _copyout. + | +-| Linux/68k: The _060_[id]mem_{read,write}_{byte,word,long} functions ++| Linux/m68k: The _060_[id]mem_{read,write}_{byte,word,long} functions + | (i.e. all the known length <= 4) are implemented by single moves + | statements instead of (more expensive) copy{in,out} calls, if + | working in user space +@@ -305,7 +305,7 @@ dmwls: move.l %d0,(%a0) | store super + | Assumes that D0/D1/A0/A1 are scratch registers. The _copyin/_copyout + | below assume that the SFC/DFC have been set previously. + | +-| Linux/68k: These are basically non-inlined versions of ++| Linux/m68k: These are basically non-inlined versions of + | memcpy_{to,from}fs, but without long-transfer optimization + | Note: Assumed that SFC/DFC are pointing correctly to user data + | space... Should be right, or are there any exceptions? +--- a/arch/m68k/kernel/head.S ++++ b/arch/m68k/kernel/head.S +@@ -1,7 +1,7 @@ + /* -*- mode: asm -*- + ** + ** head.S -- This file contains the initial boot code for the +-** Linux/68k kernel. ++** Linux/m68k kernel. + ** + ** Copyright 1993 by Hamish Macdonald + ** +--- a/arch/m68knommu/Kconfig ++++ b/arch/m68knommu/Kconfig +@@ -3,7 +3,7 @@ + # see Documentation/kbuild/kconfig-language.txt. + # + +-mainmenu "uClinux/68k (w/o MMU) Kernel Configuration" ++mainmenu "uClinux/m68k (w/o MMU) Kernel Configuration" + + config M68K + bool +--- a/drivers/net/a2065.c ++++ b/drivers/net/a2065.c +@@ -1,5 +1,5 @@ + /* +- * Amiga Linux/68k A2065 Ethernet Driver ++ * Amiga Linux/m68k A2065 Ethernet Driver + * + * (C) Copyright 1995-2003 by Geert Uytterhoeven + * +@@ -12,7 +12,7 @@ + * + * This program is based on + * +- * ariadne.?: Amiga Linux/68k Ariadne Ethernet Driver ++ * ariadne.?: Amiga Linux/m68k Ariadne Ethernet Driver + * (C) Copyright 1995 by Geert Uytterhoeven, + * Peter De Schrijver + * +--- a/drivers/net/a2065.h ++++ b/drivers/net/a2065.h +@@ -1,5 +1,5 @@ + /* +- * Amiga Linux/68k A2065 Ethernet Driver ++ * Amiga Linux/m68k A2065 Ethernet Driver + * + * (C) Copyright 1995 by Geert Uytterhoeven + * +@@ -7,7 +7,7 @@ + * + * This program is based on + * +- * ariadne.?: Amiga Linux/68k Ariadne Ethernet Driver ++ * ariadne.?: Amiga Linux/m68k Ariadne Ethernet Driver + * (C) Copyright 1995 by Geert Uytterhoeven, + * Peter De Schrijver + * +--- a/drivers/net/apne.c ++++ b/drivers/net/apne.c +@@ -1,5 +1,5 @@ + /* +- * Amiga Linux/68k 8390 based PCMCIA Ethernet Driver for the Amiga 1200 ++ * Amiga Linux/m68k 8390 based PCMCIA Ethernet Driver for the Amiga 1200 + * + * (C) Copyright 1997 Alain Malek + * (Alain.Malek@cryogen.com) +--- a/include/asm-m68knommu/bootstd.h ++++ b/include/asm-m68knommu/bootstd.h +@@ -30,7 +30,7 @@ + #define __BN_flash_erase_range 19 + #define __BN_flash_write_range 20 + +-/* Calling conventions compatible to (uC)linux/68k ++/* Calling conventions compatible to (uC)linux/m68k + * We use simmilar macros to call into the bootloader as for uClinux + */ + +--- a/include/linux/major.h ++++ b/include/linux/major.h +@@ -53,7 +53,7 @@ + #define STL_SIOMEMMAJOR 28 + #define ACSI_MAJOR 28 + #define AZTECH_CDROM_MAJOR 29 +-#define GRAPHDEV_MAJOR 29 /* SparcLinux & Linux/68k /dev/fb */ ++#define GRAPHDEV_MAJOR 29 /* SparcLinux & Linux/m68k /dev/fb */ + #define CM206_CDROM_MAJOR 32 + #define IDE2_MAJOR 33 + #define IDE3_MAJOR 34 diff --git a/debian/patches/bugfix/m68k/2.6.24/m68k-scsi-HOST_C-cleanup.diff b/debian/patches/bugfix/m68k/2.6.24/m68k-scsi-HOST_C-cleanup.diff new file mode 100644 index 000000000..99cb18015 --- /dev/null +++ b/debian/patches/bugfix/m68k/2.6.24/m68k-scsi-HOST_C-cleanup.diff @@ -0,0 +1,22 @@ + +FIXME a few more to take care of +FIXME merge include files that are included only once into the .c file + +git grep HOSTS_C + +--- + drivers/scsi/mvme147.c | 3 --- + 1 file changed, 3 deletions(-) + +--- a/drivers/scsi/mvme147.c ++++ b/drivers/scsi/mvme147.c +@@ -125,9 +125,6 @@ static int mvme147_bus_reset(struct scsi + return SUCCESS; + } + +-#define HOSTS_C +- +-#include "mvme147.h" + + static struct scsi_host_template driver_template = { + .proc_name = "MVME147", diff --git a/debian/patches/bugfix/m68k/2.6.24/mac-platform-device.diff b/debian/patches/bugfix/m68k/2.6.24/mac-platform-device.diff new file mode 100644 index 000000000..04043b682 --- /dev/null +++ b/debian/patches/bugfix/m68k/2.6.24/mac-platform-device.diff @@ -0,0 +1,20 @@ +drivers/scsi/mac_esp.c: if (MACHW_PRESENT(MAC_SCSI_96)) { +drivers/scsi/mac_esp.c: if (MACHW_PRESENT(MAC_SCSI_96_2)) { +include/asm-m68k/machw.h:#define MACHW_PRESENT(name) (mac_hw_present.name) +--- + arch/m68k/mac/platform.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- /dev/null ++++ b/arch/m68k/mac/platform.c +@@ -0,0 +1,10 @@ ++/* ++ * Copyright (C) 2007 Geert Uytterhoeven ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive ++ * for more details. ++ */ ++ ++#include ++ diff --git a/debian/patches/bugfix/m68k/2.6.24/series-extra b/debian/patches/bugfix/m68k/2.6.24/series-extra new file mode 100644 index 000000000..d8c0cb809 --- /dev/null +++ b/debian/patches/bugfix/m68k/2.6.24/series-extra @@ -0,0 +1,50 @@ +# --- submitted ++ bugfix/m68k/2.6.24/m68k-cc-cross-prefix.diff m68k ++ bugfix/m68k/2.6.24/m68k-initrd-fix.diff m68k + +# --- for 2.6.24 --- + +# --- for 2.6.25 --- ++ bugfix/m68k/2.6.24/m68k-ARRAY_SIZE-cleanup.diff m68k ++ bugfix/m68k/2.6.24/dio-ARRAY_SIZE-cleanup.diff m68k ++ bugfix/m68k/2.6.24/atari-hades-pci-balance-iomap-and-iounmap.diff m68k ++ bugfix/m68k/2.6.24/nubus-kill-drivers-nubus-nubus_syms-c.diff m68k ++ bugfix/m68k/2.6.24/m68k-kill-arch-m68k-mac-mac_ksyms-c.diff m68k ++ bugfix/m68k/2.6.24/m68k-kill-arch-m68k-hp300-ksyms-c.diff m68k ++ bugfix/m68k/2.6.24/m68k-kill-arch-m68k-amiga-amiga_ksyms-c.diff m68k ++ bugfix/m68k/2.6.24/m68k-kill-arch-m68k-atari-atari_ksyms-c.diff m68k ++ bugfix/m68k/2.6.24/m68k-kill-arch-m68k-mvme16x-mvme16x_ksyms-c.diff m68k ++ bugfix/m68k/2.6.24/mac68k-macii-adb-comment-correction.diff m68k ++ bugfix/m68k/2.6.24/mac68k-remove-dead-code.diff m68k ++ bugfix/m68k/2.6.24/mac68k-add-nubus-card-definitions-and-a-typo-fix.diff m68k ++ bugfix/m68k/2.6.24/mac68k-remove-dead-MAC_ADBKEYCODES.diff m68k + +# --- pending --- ++ bugfix/m68k/2.6.24/633-atari_scc.diff m68k ++ bugfix/m68k/2.6.24/130-adbraw.diff m68k +#+ bugfix/m68k/2.6.24/133-arch.diff m68k ++ bugfix/m68k/2.6.24/134-atari-fat.diff m68k ++ bugfix/m68k/2.6.24/141-ide.diff m68k ++ bugfix/m68k/2.6.24/143-ioext.diff m68k ++ bugfix/m68k/2.6.24/149-mc68681.diff m68k ++ bugfix/m68k/2.6.24/152-pci.diff m68k ++ bugfix/m68k/2.6.24/448-ide.diff m68k ++ bugfix/m68k/2.6.24/478-serial.diff m68k ++ bugfix/m68k/2.6.24/atari-rom-isa.diff m68k ++ bugfix/m68k/2.6.24/atari-ethernec.diff m68k ++ bugfix/m68k/2.6.24/atari-aranym.diff m68k ++ bugfix/m68k/2.6.24/atari-ethernat.diff m68k + ++ bugfix/m68k/2.6.24/falconide_intr_lock-ratelimit.diff m68k ++ bugfix/m68k/2.6.24/zorro-module-device-table.diff m68k ++ bugfix/m68k/2.6.24/m68k-q40ints.c-needs-asm-floppy.h.diff m68k ++ bugfix/m68k/2.6.24/blinux-list-is-subscribers-only.diff m68k ++ bugfix/m68k/2.6.24/b43-depends-on-HAS_DMA.diff m68k ++ bugfix/m68k/2.6.24/amiga-debug=mem.diff m68k ++ bugfix/m68k/2.6.24/m68k-scsi-HOST_C-cleanup.diff m68k ++ bugfix/m68k/2.6.24/amiga-platform-device.diff m68k ++ bugfix/m68k/2.6.24/atari-platform-device.diff m68k ++ bugfix/m68k/2.6.24/mac-platform-device.diff m68k +#+ bugfix/m68k/2.6.24/checkpatch-print-filenames.diff m68k ++ bugfix/m68k/2.6.24/m68k-replace-linux-68k-by-linux-m68k.diff m68k ++ bugfix/m68k/2.6.24/amiga-platform-device2.diff m68k diff --git a/debian/patches/bugfix/m68k/2.6.24/zorro-module-device-table.diff b/debian/patches/bugfix/m68k/2.6.24/zorro-module-device-table.diff new file mode 100644 index 000000000..d70067182 --- /dev/null +++ b/debian/patches/bugfix/m68k/2.6.24/zorro-module-device-table.diff @@ -0,0 +1,238 @@ +Subject: [PATCH] Add Amiga Zorro bus modalias support + +Add Amiga Zorro bus modalias and uevent support + +Signed-off-by: Geert Uytterhoeven +--- + drivers/net/a2065.c | 1 + + drivers/net/ariadne.c | 1 + + drivers/net/hydra.c | 1 + + drivers/net/zorro8390.c | 1 + + drivers/scsi/zorro7xx.c | 1 + + drivers/video/cirrusfb.c | 1 + + drivers/video/fm2fb.c | 1 + + drivers/zorro/zorro-driver.c | 24 ++++++++++++++++++++++++ + drivers/zorro/zorro-sysfs.c | 11 +++++++++++ + include/linux/mod_devicetable.h | 11 +++++++++++ + include/linux/zorro.h | 13 +------------ + scripts/mod/file2alias.c | 14 ++++++++++++++ + 12 files changed, 68 insertions(+), 12 deletions(-) + +--- a/drivers/net/a2065.c ++++ b/drivers/net/a2065.c +@@ -700,6 +700,7 @@ static struct zorro_device_id a2065_zorr + { ZORRO_PROD_AMERISTAR_A2065 }, + { 0 } + }; ++MODULE_DEVICE_TABLE(zorro, a2065_zorro_tbl); + + static struct zorro_driver a2065_driver = { + .name = "a2065", +--- a/drivers/net/ariadne.c ++++ b/drivers/net/ariadne.c +@@ -148,6 +148,7 @@ static struct zorro_device_id ariadne_zo + { ZORRO_PROD_VILLAGE_TRONIC_ARIADNE }, + { 0 } + }; ++MODULE_DEVICE_TABLE(zorro, ariadne_zorro_tbl); + + static struct zorro_driver ariadne_driver = { + .name = "ariadne", +--- a/drivers/net/hydra.c ++++ b/drivers/net/hydra.c +@@ -72,6 +72,7 @@ static struct zorro_device_id hydra_zorr + { ZORRO_PROD_HYDRA_SYSTEMS_AMIGANET }, + { 0 } + }; ++MODULE_DEVICE_TABLE(zorro, hydra_zorro_tbl); + + static struct zorro_driver hydra_driver = { + .name = "hydra", +--- a/drivers/net/zorro8390.c ++++ b/drivers/net/zorro8390.c +@@ -102,6 +102,7 @@ static struct zorro_device_id zorro8390_ + { ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF, }, + { 0 } + }; ++MODULE_DEVICE_TABLE(zorro, zorro8390_zorro_tbl); + + static struct zorro_driver zorro8390_driver = { + .name = "zorro8390", +--- a/drivers/scsi/zorro7xx.c ++++ b/drivers/scsi/zorro7xx.c +@@ -65,6 +65,7 @@ static struct zorro_device_id zorro7xx_z + }, + { 0 } + }; ++MODULE_DEVICE_TABLE(zorro, zorro7xx_zorro_tbl); + + static int __devinit zorro7xx_init_one(struct zorro_dev *z, + const struct zorro_device_id *ent) +--- a/drivers/video/cirrusfb.c ++++ b/drivers/video/cirrusfb.c +@@ -298,6 +298,7 @@ static const struct zorro_device_id cirr + }, + { 0 } + }; ++MODULE_DEVICE_TABLE(zorro, cirrusfb_zorro_table); + + static const struct { + zorro_id id2; +--- a/drivers/video/fm2fb.c ++++ b/drivers/video/fm2fb.c +@@ -219,6 +219,7 @@ static struct zorro_device_id fm2fb_devi + { ZORRO_PROD_HELFRICH_RAINBOW_II }, + { 0 } + }; ++MODULE_DEVICE_TABLE(zorro, fm2fb_devices); + + static struct zorro_driver fm2fb_driver = { + .name = "fm2fb", +--- a/drivers/zorro/zorro-driver.c ++++ b/drivers/zorro/zorro-driver.c +@@ -137,10 +137,34 @@ static int zorro_bus_match(struct device + return 0; + } + ++static int zorro_uevent(struct device *dev, struct kobj_uevent_env *env) ++{ ++#ifdef CONFIG_HOTPLUG ++ struct zorro_dev *z; ++ ++ if (!dev) ++ return -ENODEV; ++ ++ z = to_zorro_dev(dev); ++ if (!z) ++ return -ENODEV; ++ ++ if (add_uevent_var(env, "ZORRO_ID=%08X", z->id) || ++ add_uevent_var(env, "ZORRO_SLOT_NAME=%s", z->dev.bus_id) || ++ add_uevent_var(env, "ZORRO_SLOT_ADDR=%04X", z->slotaddr) || ++ add_uevent_var(env, "MODALIAS=" ZORRO_DEVICE_MODALIAS_FMT, z->id)) ++ return -ENOMEM; ++ ++ return 0; ++#else /* !CONFIG_HOTPLUG */ ++ return -ENODEV; ++#endif /* !CONFIG_HOTPLUG */ ++} + + struct bus_type zorro_bus_type = { + .name = "zorro", + .match = zorro_bus_match, ++ .uevent = zorro_uevent, + .probe = zorro_device_probe, + .remove = zorro_device_remove, + }; +--- a/drivers/zorro/zorro-sysfs.c ++++ b/drivers/zorro/zorro-sysfs.c +@@ -84,6 +84,16 @@ static struct bin_attribute zorro_config + .read = zorro_read_config, + }; + ++static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, ++ char *buf) ++{ ++ struct zorro_dev *z = to_zorro_dev(dev); ++ ++ return sprintf(buf, ZORRO_DEVICE_MODALIAS_FMT "\n", z->id); ++} ++ ++static DEVICE_ATTR(modalias, S_IRUGO, modalias_show, NULL); ++ + void zorro_create_sysfs_dev_files(struct zorro_dev *z) + { + struct device *dev = &z->dev; +@@ -95,6 +105,7 @@ void zorro_create_sysfs_dev_files(struct + device_create_file(dev, &dev_attr_slotaddr); + device_create_file(dev, &dev_attr_slotsize); + device_create_file(dev, &dev_attr_resource); ++ device_create_file(dev, &dev_attr_modalias); + sysfs_create_bin_file(&dev->kobj, &zorro_config_attr); + } + +--- a/include/linux/mod_devicetable.h ++++ b/include/linux/mod_devicetable.h +@@ -367,4 +367,15 @@ struct virtio_device_id { + }; + #define VIRTIO_DEV_ANY_ID 0xffffffff + ++ ++struct zorro_device_id { ++ __u32 id; /* Device ID or ZORRO_WILDCARD */ ++ kernel_ulong_t driver_data; /* Data private to the driver */ ++}; ++ ++#define ZORRO_WILDCARD (0xffffffff) /* not official */ ++ ++#define ZORRO_DEVICE_MODALIAS_FMT "zorro:i%08X" ++ ++ + #endif /* LINUX_MOD_DEVICETABLE_H */ +--- a/include/linux/zorro.h ++++ b/include/linux/zorro.h +@@ -38,8 +38,6 @@ + typedef __u32 zorro_id; + + +-#define ZORRO_WILDCARD (0xffffffff) /* not official */ +- + /* Include the ID list */ + #include + +@@ -116,6 +114,7 @@ struct ConfigDev { + + #include + #include ++#include + + #include + +@@ -155,16 +154,6 @@ extern struct bus_type zorro_bus_type; + + + /* +- * Zorro device IDs +- */ +- +-struct zorro_device_id { +- zorro_id id; /* Device ID or ZORRO_WILDCARD */ +- unsigned long driver_data; /* Data private to the driver */ +-}; +- +- +- /* + * Zorro device drivers + */ + +--- a/scripts/mod/file2alias.c ++++ b/scripts/mod/file2alias.c +@@ -539,6 +539,16 @@ static int do_virtio_entry(const char *f + return 1; + } + ++/* Looks like: zorro:iN. */ ++static int do_zorro_entry(const char *filename, struct zorro_device_id *id, ++ char *alias) ++{ ++ id->id = TO_NATIVE(id->id); ++ strcpy(alias, "zorro:"); ++ ADD(alias, "i", id->id != ZORRO_WILDCARD, id->id); ++ return 1; ++} ++ + /* Ignore any prefix, eg. v850 prepends _ */ + static inline int sym_is(const char *symbol, const char *name) + { +@@ -669,6 +679,10 @@ void handle_moddevtable(struct module *m + do_table(symval, sym->st_size, + sizeof(struct virtio_device_id), "virtio", + do_virtio_entry, mod); ++ else if (sym_is(symname, "__mod_zorro_device_table")) ++ do_table(symval, sym->st_size, ++ sizeof(struct zorro_device_id), "zorro", ++ do_zorro_entry, mod); + free(zeros); + } + diff --git a/debian/patches/series/1~experimental.1-extra b/debian/patches/series/1~experimental.1-extra index 0bcdba3db..269786305 100644 --- a/debian/patches/series/1~experimental.1-extra +++ b/debian/patches/series/1~experimental.1-extra @@ -1,22 +1,52 @@ + features/all/vserver/vs2.2.0-rc5.patch *_vserver *_xen-vserver + features/all/vserver/bindmount-dev.patch *_vserver *_xen-vserver -+ bugfix/m68k/2.6.24/m68k-cc-cross-prefix.diff -+ bugfix/m68k/2.6.24/m68k-initrd-fix.diff -+ bugfix/m68k/2.6.24/m68k-ARRAY_SIZE-cleanup.diff -+ bugfix/m68k/2.6.24/dio-ARRAY_SIZE-cleanup.diff -+ bugfix/m68k/2.6.24/atari-hades-pci-balance-iomap-and-iounmap.diff -+ bugfix/m68k/2.6.24/nubus-kill-drivers-nubus-nubus_syms-c.diff -+ bugfix/m68k/2.6.24/m68k-kill-arch-m68k-mac-mac_ksyms-c.diff -+ bugfix/m68k/2.6.24/m68k-kill-arch-m68k-hp300-ksyms-c.diff -+ bugfix/m68k/2.6.24/m68k-kill-arch-m68k-amiga-amiga_ksyms-c.diff -+ bugfix/m68k/2.6.24/m68k-kill-arch-m68k-atari-atari_ksyms-c.diff -+ bugfix/m68k/2.6.24/m68k-kill-arch-m68k-mvme16x-mvme16x_ksyms-c.diff -+ bugfix/m68k/2.6.24/mac68k-macii-adb-comment-correction.diff -+ bugfix/m68k/2.6.24/mac68k-remove-dead-code.diff -+ bugfix/m68k/2.6.24/mac68k-add-nubus-card-definitions-and-a-typo-fix.diff -+ bugfix/m68k/2.6.24/mac68k-remove-dead-MAC_ADBKEYCODES.diff -+ bugfix/m68k/2.6.24/633-atari_scc.diff -+ bugfix/m68k/2.6.24/130-adbraw.diff -+ bugfix/m68k/2.6.24/133-arch.diff -+ bugfix/m68k/2.6.24/134-atari-fat.diff -+ bugfix/m68k/2.6.24/141-ide.diff +# --- submitted ++ bugfix/m68k/2.6.24/m68k-cc-cross-prefix.diff m68k ++ bugfix/m68k/2.6.24/m68k-initrd-fix.diff m68k + +# --- for 2.6.24 --- + +# --- for 2.6.25 --- ++ bugfix/m68k/2.6.24/m68k-ARRAY_SIZE-cleanup.diff m68k ++ bugfix/m68k/2.6.24/dio-ARRAY_SIZE-cleanup.diff m68k ++ bugfix/m68k/2.6.24/atari-hades-pci-balance-iomap-and-iounmap.diff m68k ++ bugfix/m68k/2.6.24/nubus-kill-drivers-nubus-nubus_syms-c.diff m68k ++ bugfix/m68k/2.6.24/m68k-kill-arch-m68k-mac-mac_ksyms-c.diff m68k ++ bugfix/m68k/2.6.24/m68k-kill-arch-m68k-hp300-ksyms-c.diff m68k ++ bugfix/m68k/2.6.24/m68k-kill-arch-m68k-amiga-amiga_ksyms-c.diff m68k ++ bugfix/m68k/2.6.24/m68k-kill-arch-m68k-atari-atari_ksyms-c.diff m68k ++ bugfix/m68k/2.6.24/m68k-kill-arch-m68k-mvme16x-mvme16x_ksyms-c.diff m68k ++ bugfix/m68k/2.6.24/mac68k-macii-adb-comment-correction.diff m68k ++ bugfix/m68k/2.6.24/mac68k-remove-dead-code.diff m68k ++ bugfix/m68k/2.6.24/mac68k-add-nubus-card-definitions-and-a-typo-fix.diff m68k ++ bugfix/m68k/2.6.24/mac68k-remove-dead-MAC_ADBKEYCODES.diff m68k + +# --- pending --- ++ bugfix/m68k/2.6.24/633-atari_scc.diff m68k ++ bugfix/m68k/2.6.24/130-adbraw.diff m68k +#+ bugfix/m68k/2.6.24/133-arch.diff m68k ++ bugfix/m68k/2.6.24/134-atari-fat.diff m68k ++ bugfix/m68k/2.6.24/141-ide.diff m68k ++ bugfix/m68k/2.6.24/143-ioext.diff m68k ++ bugfix/m68k/2.6.24/149-mc68681.diff m68k ++ bugfix/m68k/2.6.24/152-pci.diff m68k ++ bugfix/m68k/2.6.24/448-ide.diff m68k ++ bugfix/m68k/2.6.24/478-serial.diff m68k ++ bugfix/m68k/2.6.24/atari-rom-isa.diff m68k ++ bugfix/m68k/2.6.24/atari-ethernec.diff m68k ++ bugfix/m68k/2.6.24/atari-aranym.diff m68k ++ bugfix/m68k/2.6.24/atari-ethernat.diff m68k + ++ bugfix/m68k/2.6.24/falconide_intr_lock-ratelimit.diff m68k ++ bugfix/m68k/2.6.24/zorro-module-device-table.diff m68k ++ bugfix/m68k/2.6.24/m68k-q40ints.c-needs-asm-floppy.h.diff m68k ++ bugfix/m68k/2.6.24/blinux-list-is-subscribers-only.diff m68k ++ bugfix/m68k/2.6.24/b43-depends-on-HAS_DMA.diff m68k ++ bugfix/m68k/2.6.24/amiga-debug=mem.diff m68k ++ bugfix/m68k/2.6.24/m68k-scsi-HOST_C-cleanup.diff m68k ++ bugfix/m68k/2.6.24/amiga-platform-device.diff m68k ++ bugfix/m68k/2.6.24/atari-platform-device.diff m68k ++ bugfix/m68k/2.6.24/mac-platform-device.diff m68k +#+ bugfix/m68k/2.6.24/checkpatch-print-filenames.diff m68k ++ bugfix/m68k/2.6.24/m68k-replace-linux-68k-by-linux-m68k.diff m68k ++ bugfix/m68k/2.6.24/amiga-platform-device2.diff m68k