[kernel] r10095 - in dists/trunk/linux-2.6/debian/patches: bugfix/m68k/2.6.24 series
Christian T. Steigies
cts at alioth.debian.org
Sun Jan 13 14:32:13 UTC 2008
Author: cts
Date: Sun Jan 13 14:32:13 2008
New Revision: 10095
Log:
m68k patches should be applied for m68k only
Added:
dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/143-ioext.diff
dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/149-mc68681.diff
dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/152-pci.diff
dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/448-ide.diff
dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/478-serial.diff
dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/amiga-debug=mem.diff
dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/amiga-platform-device.diff
dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/amiga-platform-device2.diff
dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/atari-aranym.diff
dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/atari-ethernat.diff
dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/atari-ethernec.diff
dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/atari-platform-device.diff
dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/atari-rom-isa.diff
dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/b43-depends-on-HAS_DMA.diff
dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/blinux-list-is-subscribers-only.diff
dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/checkpatch-print-filenames.diff
dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/falconide_intr_lock-ratelimit.diff
dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/m68k-q40ints.c-needs-asm-floppy.h.diff
dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/m68k-replace-linux-68k-by-linux-m68k.diff
dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/m68k-scsi-HOST_C-cleanup.diff
dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/mac-platform-device.diff
dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/series-extra
dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/zorro-module-device-table.diff
Removed:
dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/133-arch.diff
Modified:
dists/trunk/linux-2.6/debian/patches/series/1~experimental.1-extra
Added: dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/143-ioext.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/143-ioext.diff Sun Jan 13 14:32:13 2008
@@ -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 at 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 <pmaydell at chiark.greenend.org.uk> 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 <linux/lp.h>
++ */
++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 <linux/netdevice.h>
++
++#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, <msteveb at ozemail.com.au>
++ *
++ * 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 <linux/module.h>
++#include <linux/types.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++#include <linux/termios.h>
++#include <linux/tty.h>
++#include <linux/serial.h>
++
++#include <asm/setup.h>
++#include <asm/irq.h>
++#include <asm/amigahw.h>
++#include <asm/amigaints.h>
++#include <linux/zorro.h>
++
++#include <linux/kernel.h>
++#include <linux/fcntl.h>
++#include <linux/string.h>
++#include <linux/ptrace.h>
++#include <linux/if_ether.h>
++
++#include <asm/system.h>
++
++#include <linux/in.h>
++#include <linux/delay.h>
++/*#include <linux/lp_m68k.h>*/
++
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/inetdevice.h>
++#include <linux/skbuff.h>
++#include <linux/if_plip.h>
++
++#include <linux/tqueue.h>
++#include <linux/ioport.h>
++#include <linux/bitops.h>
++#include <asm/byteorder.h>
++
++#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 <asm/byteorder.h>"
++#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;
++}
Added: dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/149-mc68681.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/149-mc68681.diff Sun Jan 13 14:32:13 2008
@@ -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 at darkness.gun.de) and the data sheet of Phillip's clone device (SCN68681)
++ * (from Richard Hirst, srh at gpt.co.uk)
++ *
++ * 11.11.95 copyright Joerg Dorchain (dorchain at 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
Added: dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/152-pci.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/152-pci.diff Sun Jan 13 14:32:13 2008
@@ -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;
+
+ /*
Added: dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/448-ide.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/448-ide.diff Sun Jan 13 14:32:13 2008
@@ -0,0 +1,22 @@
+To: linus, akpm, B.Zolnierkiewicz at elka.pw.edu.pl
+Cc: lkml
+Subject: [PATCH] m68k IDE compiler bug
+
+From: Roman Zippel <zippel at linux-m68k.org>
+
+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;
Added: dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/478-serial.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/478-serial.diff Sun Jan 13 14:32:13 2008
@@ -0,0 +1,29 @@
+To: linus, akpm
+Cc: lkml
+Subject: [PATCH] M68k SERIAL_PORT_DFNS only if CONFIG_ISA
+
+From: Kars de Jong <jongk at linux-m68k.org>
+
+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 <jongk at linux-m68k.org>
+Signed-off-by: Geert Uytterhoeven <geert at linux-m68k.org>
+---
+ 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
Added: dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/amiga-debug=mem.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/amiga-debug=mem.diff Sun Jan 13 14:32:13 2008
@@ -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;
Added: dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/amiga-platform-device.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/amiga-platform-device.diff Sun Jan 13 14:32:13 2008
@@ -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 <linux/platform_device.h>
++#include <linux/mm.h> // FIXME show_mem()
++
++#include <asm/amigahw.h>
++
++
++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);
++
Added: dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/amiga-platform-device2.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/amiga-platform-device2.diff Sun Jan 13 14:32:13 2008
@@ -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 <asm/amigahw.h>
+
+
++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)
Added: dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/atari-aranym.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/atari-aranym.diff Sun Jan 13 14:32:13 2008
@@ -0,0 +1,534 @@
+Subject: [PATCH] m68k: Atari ARAnyM support
+
+From: Michael Schmitz <schmitz at opal.biophys.uni-duesseldorf.de>
+
+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 <geert at linux-m68k.org>
+---
+ 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 <zippel at linux-m68k.org>
++ *
++ * This software may be used and distributed according to the terms of
++ * the GNU General Public License (GPL), incorporated herein by reference.
++ */
++
++#include <linux/types.h>
++#include <linux/console.h>
++#include <linux/string.h>
++#include <linux/kernel.h>
++#include <linux/io.h>
++#include <asm/machdep.h>
++#include <asm/natfeat.h>
++
++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 <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/module.h>
++#include <net/ieee80211.h>
++#include <asm/natfeat.h>
++#include <asm/virtconvert.h>
++
++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 <asm/dvma.h>
+ #endif
++#include <asm/natfeat.h>
+
+ 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 */
Added: dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/atari-ethernat.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/atari-ethernat.diff Sun Jan 13 14:32:13 2008
@@ -0,0 +1,2581 @@
+From schmitz at 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 <schmitz at opal.biophys.uni-duesseldorf.de>
+To: Geert Uytterhoeven <geert at linux-m68k.org>
+Cc: Michael Schmitz <schmitz at opal.biophys.uni-duesseldorf.de>, linux-m68k at vger.kernel.org, cts at 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 <schmitz at biophys.uni-duesseldorf.de>
+
+---
+ 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 <linux/init.h>
+ #include <linux/delay.h>
+ #include <linux/ioport.h>
++#include <linux/platform_device.h>
+ #include <linux/vt_kern.h>
+ #include <linux/module.h>
+
+@@ -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 <erik at vt.edu>
++ *
++ * hardware multicast code:
++ * Peter Cammaert <pc at denkart.be>
++ *
++ * contributors:
++ * Daris A Nevil <dnevil at snmc.com>
++ * Nicolas Pitre <nico at cam.org>
++ * Russell King <rmk at arm.linux.org.uk>
++ *
++ * 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 <nico at cam.org>\n";
++
++#define SMC_DEBUG 2
++
++/* Debugging level */
++#ifndef SMC_DEBUG
++#define SMC_DEBUG 0
++#endif
++
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/errno.h>
++#include <linux/ioport.h>
++#include <linux/crc32.h>
++#include <linux/platform_device.h>
++#include <linux/spinlock.h>
++#include <linux/ethtool.h>
++#include <linux/mii.h>
++#include <linux/workqueue.h>
++
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++
++#include <asm/hwtest.h>
++#include <asm/atariints.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++
++#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<<invert3[(position>>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 == <anything else>, 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)
Added: dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/atari-ethernec.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/atari-ethernec.diff Sun Jan 13 14:32:13 2008
@@ -0,0 +1,1063 @@
+Subject: [PATCH] m68k: Atari EtherNEC driver
+Cc: Jeff Garzik <jgarzik at pobox.com>, netdev at vger.kernel.org
+
+From: Michael Schmitz <schmitz at opal.biophys.uni-duesseldorf.de>
+
+Atari EtherNEC driver
+
+Signed-off-by: Michael Schmitz <schmitz at debian.org>
+Signed-off-by: Roman Zippel <zippel at linux-m68k.org>
+Signed-off-by: Geert Uytterhoeven <geert at linux-m68k.org>
+---
+ 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 at 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 at 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 at scyld.com)\n";
++static const char version2[] =
++"atari_ethernec.c 11/10/06 Michael Schmitz (schmitz at debian.org)\n";
++
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/isapnp.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/jiffies.h>
++#include <linux/workqueue.h>
++
++#include <asm/system.h>
++#include <asm/atarihw.h>
++#include <asm/atariints.h>
++#include <asm/io.h>
++
++#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. <cough> */
++ 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 */
Added: dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/atari-platform-device.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/atari-platform-device.diff Sun Jan 13 14:32:13 2008
@@ -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 <linux/platform_device.h>
++
Added: dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/atari-rom-isa.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/atari-rom-isa.diff Sun Jan 13 14:32:13 2008
@@ -0,0 +1,401 @@
+Subject: [PATCH] m68k: Atari ROM port ISA adapter support
+
+From: Michael Schmitz <schmitz at opal.biophys.uni-duesseldorf.de>
+
+Atari ROM port ISA adapter support
+
+Signed-off-by: Michael Schmitz <schmitz at debian.org>
+Signed-off-by: Roman Zippel <zippel at linux-m68k.org>
+Signed-off-by: Geert Uytterhoeven <geert at linux-m68k.org>
+---
+ 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 <asm/types.h>
++#include <asm/byteorder.h>
+
+
+ /* 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 */
Added: dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/b43-depends-on-HAS_DMA.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/b43-depends-on-HAS_DMA.diff Sun Jan 13 14:32:13 2008
@@ -0,0 +1,32 @@
+Subject: b43 should depend on HAS_DMA
+To: Michael Buesch <mb at bu3sch.de>, Stefano Brivio <st3 at riseup.net>
+Cc: linux-wireless at vger.kernel.org
+
+b43 should depend on HAS_DMA
+
+Signed-off-by: Geert Uytterhoeven <geert at linux-m68k.org>
+---
+ 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
Added: dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/blinux-list-is-subscribers-only.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/blinux-list-is-subscribers-only.diff Sun Jan 13 14:32:13 2008
@@ -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 at vanzandt.mv.com
+-L: blinux-list at redhat.com
++L: blinux-list at redhat.com (subscribers-only)
+ S: Maintained
+
+ DRIVER CORE, KOBJECTS, AND SYSFS
Added: dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/checkpatch-print-filenames.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/checkpatch-print-filenames.diff Sun Jan 13 14:32:13 2008
@@ -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 <geert at linux-m68k.org>
+---
+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";
+ }
Added: dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/falconide_intr_lock-ratelimit.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/falconide_intr_lock-ratelimit.diff Sun Jan 13 14:32:13 2008
@@ -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 <geert at linux-m68k.org>
+---
+ 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;
Added: dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/m68k-q40ints.c-needs-asm-floppy.h.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/m68k-q40ints.c-needs-asm-floppy.h.diff Sun Jan 13 14:32:13 2008
@@ -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 <linux/errno.h>
+ #include <linux/interrupt.h>
+
++#include <asm/floppy.h>
+ #include <asm/ptrace.h>
+ #include <asm/system.h>
+ #include <asm/irq.h>
Added: dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/m68k-replace-linux-68k-by-linux-m68k.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/m68k-replace-linux-68k-by-linux-m68k.diff Sun Jan 13 14:32:13 2008
@@ -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 <geert at linux-m68k.org>
+Signed-off-by: Geert Uytterhoeven <geert at linux-m68k.org>
+---
+ 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 at 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 at 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 <geert at linux-m68k.org>
+ *
+@@ -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 <geert at linux-m68k.org>
+ *
+@@ -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 at 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
Added: dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/m68k-scsi-HOST_C-cleanup.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/m68k-scsi-HOST_C-cleanup.diff Sun Jan 13 14:32:13 2008
@@ -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",
Added: dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/mac-platform-device.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/mac-platform-device.diff Sun Jan 13 14:32:13 2008
@@ -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 <linux/platform_device.h>
++
Added: dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/series-extra
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/series-extra Sun Jan 13 14:32:13 2008
@@ -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
Added: dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/zorro-module-device-table.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/bugfix/m68k/2.6.24/zorro-module-device-table.diff Sun Jan 13 14:32:13 2008
@@ -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 <geert at linux-m68k.org>
+---
+ 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 <linux/zorro_ids.h>
+
+@@ -116,6 +114,7 @@ struct ConfigDev {
+
+ #include <linux/init.h>
+ #include <linux/ioport.h>
++#include <linux/mod_devicetable.h>
+
+ #include <asm/zorro.h>
+
+@@ -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);
+ }
+
Modified: dists/trunk/linux-2.6/debian/patches/series/1~experimental.1-extra
==============================================================================
--- dists/trunk/linux-2.6/debian/patches/series/1~experimental.1-extra (original)
+++ dists/trunk/linux-2.6/debian/patches/series/1~experimental.1-extra Sun Jan 13 14:32:13 2008
@@ -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
More information about the Kernel-svn-changes
mailing list