aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian T. Steigies <cts@debian.org>2007-05-11 21:14:58 +0000
committerChristian T. Steigies <cts@debian.org>2007-05-11 21:14:58 +0000
commitbe313140ff08f95d85a4a8b3e9b7f61cc9a434ee (patch)
treef020add3755026186e656a5877c204884974485b
parent082a9f7c08cf58b93fdc3553ba5e80efcb20e19f (diff)
parentb9d7543a19cb09914bb6b68a2863878f8dd7d562 (diff)
downloadkernel_replicant_linux-be313140ff08f95d85a4a8b3e9b7f61cc9a434ee.tar.gz
kernel_replicant_linux-be313140ff08f95d85a4a8b3e9b7f61cc9a434ee.tar.bz2
kernel_replicant_linux-be313140ff08f95d85a4a8b3e9b7f61cc9a434ee.zip
add linux-m68k patches for 2.6.21
svn path=/dists/trunk/linux-2.6/; revision=8570
-rw-r--r--debian/patches/bugfix/m68k/130-adbraw.diff44
-rw-r--r--debian/patches/bugfix/m68k/133-arch.diff28
-rw-r--r--debian/patches/bugfix/m68k/134-atari-fat.diff102
-rw-r--r--debian/patches/bugfix/m68k/141-ide.diff38
-rw-r--r--debian/patches/bugfix/m68k/143-ioext.diff1352
-rw-r--r--debian/patches/bugfix/m68k/149-mc68681.diff146
-rw-r--r--debian/patches/bugfix/m68k/152-pci.diff21
-rw-r--r--debian/patches/bugfix/m68k/357-mac89x0.diff177
-rw-r--r--debian/patches/bugfix/m68k/448-ide.diff23
-rw-r--r--debian/patches/bugfix/m68k/478-serial.diff30
-rw-r--r--debian/patches/bugfix/m68k/577-module-arch.diff37
-rw-r--r--debian/patches/bugfix/m68k/600-task_thread_info.diff43
-rw-r--r--debian/patches/bugfix/m68k/611-module_fixup.diff214
-rw-r--r--debian/patches/bugfix/m68k/618-discontig.diff868
-rw-r--r--debian/patches/bugfix/m68k/630-extern-cleanup.diff34
-rw-r--r--debian/patches/bugfix/m68k/631-thread_stack.diff117
-rw-r--r--debian/patches/bugfix/m68k/633-atari_scc.diff1739
-rw-r--r--debian/patches/bugfix/m68k/634-atari_scsi.diff228
-rw-r--r--debian/patches/bugfix/m68k/635-atari_input.diff1162
-rw-r--r--debian/patches/bugfix/m68k/636-atafb.diff5530
-rw-r--r--debian/patches/bugfix/m68k/amiga-a2065-ariadne-stats.diff42
-rw-r--r--debian/patches/bugfix/m68k/atari-aranym.diff542
-rw-r--r--debian/patches/bugfix/m68k/atari-ethernec.diff1106
-rw-r--r--debian/patches/bugfix/m68k/atari-rom-isa.diff340
-rw-r--r--debian/patches/bugfix/m68k/atari-scsi-compile-fixes.diff340
-rw-r--r--debian/patches/bugfix/m68k/atari-scsi-reformat.diff5903
-rw-r--r--debian/patches/bugfix/m68k/atari_NCR5380-work.diff31
-rw-r--r--debian/patches/bugfix/m68k/early-param.diff468
-rw-r--r--debian/patches/bugfix/m68k/ethernec-kill-ETHERNEC_USE_POLL.diff76
-rw-r--r--debian/patches/bugfix/m68k/ethernec-work.diff46
-rw-r--r--debian/patches/bugfix/m68k/falconide_intr_lock-reentrant.diff41
-rw-r--r--debian/patches/bugfix/m68k/hilkbd-warning.diff21
-rw-r--r--debian/patches/bugfix/m68k/irq_lockdep.diff30
-rw-r--r--debian/patches/bugfix/m68k/kmap_atomic-inline.diff30
-rw-r--r--debian/patches/bugfix/m68k/m68k-53c700-scsi.diff1155
-rw-r--r--debian/patches/bugfix/m68k/m68k-as.patch308
-rw-r--r--debian/patches/bugfix/m68k/m68k-generic-io.diff234
-rw-r--r--debian/patches/bugfix/m68k/m68k-linux-gnu-crosscompile.diff20
-rw-r--r--debian/patches/bugfix/m68k/m68k-mvme-scsi-rename.diff348
-rw-r--r--debian/patches/bugfix/m68k/m68k-reformat.diff4818
-rw-r--r--debian/patches/bugfix/m68k/mac68k-cuda-adb-fixes.diff176
-rw-r--r--debian/patches/bugfix/m68k/mac68k-finish_irq_cleanup.diff162
-rw-r--r--debian/patches/bugfix/m68k/mac68k-irq-plan-e.diff270
-rw-r--r--debian/patches/bugfix/m68k/mac68k-irq-prep.diff375
-rw-r--r--debian/patches/bugfix/m68k/mac68k-macii-adb-fixes.diff873
-rw-r--r--debian/patches/bugfix/m68k/mac68k-macmace-fixes.diff951
-rw-r--r--debian/patches/bugfix/m68k/mac68k-macsonic-via-alt-mapping.diff194
-rw-r--r--debian/patches/bugfix/m68k/mac68k-patch_A-mac68k_cvs_nubus_defines.diff222
-rw-r--r--debian/patches/bugfix/m68k/mac68k-patch_B-mac68k_cvs_DP8390_update.diff398
-rw-r--r--debian/patches/bugfix/m68k/mac68k-patch_d-via-alt-mapping.diff30
-rw-r--r--debian/patches/bugfix/m68k/mac68k-remove-unused-adb-header.diff92
-rw-r--r--debian/patches/bugfix/m68k/mac68k-revert-remaining-irq-damage.diff80
-rw-r--r--debian/patches/bugfix/m68k/mac68k-sonic-fixes.diff106
-rw-r--r--debian/patches/bugfix/m68k/nfeth-virt_to_phys.diff19
-rw-r--r--debian/patches/bugfix/m68k/pmu_queue_request-conflict.diff32
-rw-r--r--debian/patches/bugfix/m68k/sun3-3x-cg3-bw2.diff887
-rw-r--r--debian/patches/bugfix/m68k/sun3-3x-serial.diff486
-rw-r--r--debian/patches/bugfix/m68k/sun3-numints.diff23
-rw-r--r--debian/patches/bugfix/m68k/unnecessary-m68k_memoffset.diff30
-rw-r--r--debian/patches/bugfix/m68k/via-pmu68k-dead-code.diff263
-rw-r--r--debian/patches/bugfix/m68k/zorro-resource_size_t-warnings.diff50
61 files changed, 33551 insertions, 0 deletions
diff --git a/debian/patches/bugfix/m68k/130-adbraw.diff b/debian/patches/bugfix/m68k/130-adbraw.diff
new file mode 100644
index 000000000000..2cabbd468cfe
--- /dev/null
+++ b/debian/patches/bugfix/m68k/130-adbraw.diff
@@ -0,0 +1,44 @@
+To: linus, alan
+Cc: lkml
+Subject: [PATCH] ADB raw packets
+
+From: Linux/m68k legacy
+
+ADB: add support for raw packets
+
+---
+ drivers/macintosh/adb.c | 8 +++++---
+ include/linux/adb.h | 1 +
+ 2 files changed, 6 insertions(+), 3 deletions(-)
+
+--- linux-m68k-2.6.21.orig/drivers/macintosh/adb.c
++++ linux-m68k-2.6.21/drivers/macintosh/adb.c
+@@ -478,13 +478,15 @@ adb_request(struct adb_request *req, voi
+ use_sreq = 1;
+ } else
+ use_sreq = 0;
+- req->nbytes = nbytes+1;
++ i = (flags & ADBREQ_RAW) ? 0 : 1;
++ req->nbytes = nbytes+i;
+ req->done = done;
+ req->reply_expected = flags & ADBREQ_REPLY;
+ req->data[0] = ADB_PACKET;
+ va_start(list, nbytes);
+- for (i = 0; i < nbytes; ++i)
+- req->data[i+1] = va_arg(list, int);
++ while (i < req->nbytes) {
++ req->data[i++] = va_arg(list, int);
++ }
+ va_end(list);
+
+ if (flags & ADBREQ_NOSEND)
+--- linux-m68k-2.6.21.orig/include/linux/adb.h
++++ linux-m68k-2.6.21/include/linux/adb.h
+@@ -76,6 +76,7 @@ struct adb_driver {
+ #define ADBREQ_REPLY 1 /* expect reply */
+ #define ADBREQ_SYNC 2 /* poll until done */
+ #define ADBREQ_NOSEND 4 /* build the request, but don't send it */
++#define ADBREQ_RAW 8 /* send raw packet (don't prepend ADB_PACKET) */
+
+ /* Messages sent thru the client_list notifier. You should NOT stop
+ the operation, at least not with this version */
diff --git a/debian/patches/bugfix/m68k/133-arch.diff b/debian/patches/bugfix/m68k/133-arch.diff
new file mode 100644
index 000000000000..2ef342af65dd
--- /dev/null
+++ b/debian/patches/bugfix/m68k/133-arch.diff
@@ -0,0 +1,28 @@
+Subject: [PATCH] Local m68k changes
+
+Local m68k changes, _NEVER_ to be submitted upstream:
+ - Force ARCH to be m68k
+ - Append `-m68k' to EXTRAVERSION
+
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> for m68k CVS only
+
+---
+ Makefile | 2 +-
+ localversion.m68k | 1 +
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+--- linux-m68k-2.6.21.orig/Makefile
++++ linux-m68k-2.6.21/Makefile
+@@ -182,7 +182,7 @@ SUBARCH := $(shell uname -m | sed -e s/i
+ # Default value for CROSS_COMPILE is not to prefix executables
+ # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile
+
+-ARCH ?= $(SUBARCH)
++ARCH ?= m68k
+ CROSS_COMPILE ?=
+
+ # Architecture as present in compile.h
+--- /dev/null
++++ linux-m68k-2.6.21/localversion.m68k
+@@ -0,0 +1 @@
++-m68k
diff --git a/debian/patches/bugfix/m68k/134-atari-fat.diff b/debian/patches/bugfix/m68k/134-atari-fat.diff
new file mode 100644
index 000000000000..5ce087b90d85
--- /dev/null
+++ b/debian/patches/bugfix/m68k/134-atari-fat.diff
@@ -0,0 +1,102 @@
+To: linus, alan
+Cc: lkml
+Subject: [PATCH] Atari FAT updates
+
+From: Linux/m68k legacy
+
+Add support for the Atari-variant of the FAT filesystem
+
+---
+ fs/fat/inode.c | 46 +++++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 43 insertions(+), 3 deletions(-)
+
+--- linux-m68k-2.6.21.orig/fs/fat/inode.c
++++ linux-m68k-2.6.21/fs/fat/inode.c
+@@ -17,6 +17,7 @@
+ #include <linux/smp_lock.h>
+ #include <linux/seq_file.h>
+ #include <linux/msdos_fs.h>
++#include <linux/major.h>
+ #include <linux/pagemap.h>
+ #include <linux/mpage.h>
+ #include <linux/buffer_head.h>
+@@ -852,7 +853,7 @@ enum {
+ Opt_check_n, Opt_check_r, Opt_check_s, Opt_uid, Opt_gid,
+ Opt_umask, Opt_dmask, Opt_fmask, Opt_codepage, Opt_nocase,
+ Opt_quiet, Opt_showexec, Opt_debug, Opt_immutable,
+- Opt_dots, Opt_nodots,
++ Opt_dots, Opt_nodots, Opt_atari_no, Opt_atari_yes,
+ Opt_charset, Opt_shortname_lower, Opt_shortname_win95,
+ Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes,
+ Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes,
+@@ -877,6 +878,9 @@ static match_table_t fat_tokens = {
+ {Opt_showexec, "showexec"},
+ {Opt_debug, "debug"},
+ {Opt_immutable, "sys_immutable"},
++ {Opt_atari_yes, "atari=yes"},
++ {Opt_atari_yes, "atari"},
++ {Opt_atari_no, "atari=no"},
+ {Opt_obsolate, "conv=binary"},
+ {Opt_obsolate, "conv=text"},
+ {Opt_obsolate, "conv=auto"},
+@@ -952,6 +956,13 @@ static int parse_options(char *options,
+ opts->utf8 = opts->unicode_xlate = 0;
+ opts->numtail = 1;
+ opts->nocase = 0;
++ opts->atari = 0;
++
++#ifdef CONFIG_ATARI
++ if(MACH_IS_ATARI)
++ /* make Atari GEMDOS format the default if machine is an Atari */
++ opts->atari = 1;
++#endif
+ *debug = 0;
+
+ if (!options)
+@@ -1000,6 +1011,12 @@ static int parse_options(char *options,
+ case Opt_immutable:
+ opts->sys_immutable = 1;
+ break;
++ case Opt_atari_yes:
++ opts->atari = 1;
++ break;
++ case Opt_atari_no:
++ opts->atari = 0;
++ break;
+ case Opt_uid:
+ if (match_int(&args[0], &option))
+ return 0;
+@@ -1336,8 +1353,31 @@ int fat_fill_super(struct super_block *s
+
+ total_clusters = (total_sectors - sbi->data_start) / sbi->sec_per_clus;
+
+- if (sbi->fat_bits != 32)
+- sbi->fat_bits = (total_clusters > MAX_FAT12) ? 16 : 12;
++ if (!sbi->options.atari) {
++ if (sbi->fat_bits != 32)
++ sbi->fat_bits = (total_clusters > MAX_FAT12) ? 16 : 12;
++ } else {
++ int sectors;
++ /* Atari GEMDOS partitions always have 16-bit fat */
++ if (sbi->fat_bits != 32)
++ sbi->fat_bits = 16;
++ /* If more clusters than fat entries in 16-bit fat, we assume
++ * it's a real MSDOS partition with 12-bit fat.
++ */
++ if (sbi->fat_bits != 32 && total_clusters+2 > sbi->
++ fat_length*SECTOR_SIZE*8/sbi->fat_bits)
++ sbi->fat_bits = 12;
++ /* if it's a floppy disk --> 12bit fat */
++ if (sbi->fat_bits != 32 && MAJOR(sb->s_dev) == FLOPPY_MAJOR)
++ sbi->fat_bits = 12;
++ /* if it's a ramdisk or loopback device and has one of the usual
++ * floppy sizes -> 12bit FAT */
++ sectors = total_sectors + sbi->data_start;
++ if (sbi->fat_bits != 32 && (MAJOR(sb->s_dev) == RAMDISK_MAJOR ||
++ MAJOR(sb->s_dev) == LOOP_MAJOR) &&
++ (sectors == 720 || sectors == 1440 || sectors == 2880))
++ sbi->fat_bits = 12;
++ }
+
+ /* check that FAT table does not overflow */
+ fat_clusters = sbi->fat_length * sb->s_blocksize * 8 / sbi->fat_bits;
diff --git a/debian/patches/bugfix/m68k/141-ide.diff b/debian/patches/bugfix/m68k/141-ide.diff
new file mode 100644
index 000000000000..b4537dc693a3
--- /dev/null
+++ b/debian/patches/bugfix/m68k/141-ide.diff
@@ -0,0 +1,38 @@
+To: linus, alan
+Cc: lkml
+Subject: [PATCH] M68k IDE updates
+
+From: Linux/m68k legacy
+
+M68k IDE updates: Add m68k-isms to the generic ide_fix_driveid()
+
+---
+ drivers/ide/ide-iops.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+--- linux-m68k-2.6.21.orig/drivers/ide/ide-iops.c
++++ linux-m68k-2.6.21/drivers/ide/ide-iops.c
+@@ -313,6 +313,23 @@ void ide_fix_driveid (struct hd_driveid
+ int i;
+ u16 *stringcast;
+
++#ifdef __mc68000__
++ if (!MACH_IS_AMIGA && !MACH_IS_MAC && !MACH_IS_Q40 && !MACH_IS_ATARI)
++ return;
++
++#ifdef M68K_IDE_SWAPW
++ if (M68K_IDE_SWAPW) { /* fix bus byteorder first */
++ u_char *p = (u_char *)id;
++ u_char t;
++ for (i = 0; i < 512; i += 2) {
++ t = p[i];
++ p[i] = p[i+1];
++ p[i+1] = t;
++ }
++ }
++#endif
++#endif /* __mc68000__ */
++
+ id->config = __le16_to_cpu(id->config);
+ id->cyls = __le16_to_cpu(id->cyls);
+ id->reserved2 = __le16_to_cpu(id->reserved2);
diff --git a/debian/patches/bugfix/m68k/143-ioext.diff b/debian/patches/bugfix/m68k/143-ioext.diff
new file mode 100644
index 000000000000..01c02d095522
--- /dev/null
+++ b/debian/patches/bugfix/m68k/143-ioext.diff
@@ -0,0 +1,1352 @@
+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
++++ linux-m68k-2.6.21/drivers/char/16c552.h
+@@ -0,0 +1,165 @@
++/*
++ * Definitions for the 16c552 DACE
++ * (dual-asynchronous-communications-element) used on the GVP
++ * IO-Extender.
++ *
++ * Basically this is two 16c550 uarts's and a parallel port, which is
++ * why the serial definitions should be valid for the 16c550 uart
++ * aswell.
++ *
++ * Data was taken from National Semiconductors duart 16c552
++ * data-sheets and the Texas Instruments DACE 16c552 data-sheets (the
++ * NS version of the chip is _non_ standard and their data-sheets did
++ * cost me several wasted hours of work).
++ *
++ * This file is (C) 1995 Jes Sorensen (jds@kom.auc.dk)
++ *
++ * Moved from drivers/char/ to include/linux/, because it's useful
++ * on more than just the one card. I'm using it on the hp300 DCA
++ * serial driver, for example.
++ * -- Peter Maydell <pmaydell@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
++++ linux-m68k-2.6.21/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
++++ linux-m68k-2.6.21/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@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;
++}
diff --git a/debian/patches/bugfix/m68k/149-mc68681.diff b/debian/patches/bugfix/m68k/149-mc68681.diff
new file mode 100644
index 000000000000..eaad1204f97f
--- /dev/null
+++ b/debian/patches/bugfix/m68k/149-mc68681.diff
@@ -0,0 +1,146 @@
+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
++++ linux-m68k-2.6.21/drivers/char/mc68681.h
+@@ -0,0 +1,131 @@
++#ifndef _MC68681_H_
++#define _MC68681_H_
++
++/*
++ * This describes an MC68681 DUART. It has almost only overlayed registers, which
++ * the structure very ugly.
++ * Note that the ri-register isn't really a register of the duart but a kludge of bsc
++ * to make the ring indicator available.
++ *
++ * The data came from the MFC-31-Developer Kit (from Ralph Seidel,
++ * zodiac@darkness.gun.de) and the data sheet of Phillip's clone device (SCN68681)
++ * (from Richard Hirst, srh@gpt.co.uk)
++ *
++ * 11.11.95 copyright Joerg Dorchain (dorchain@mpi-sb.mpg.de)
++ *
++ */
++
++struct duarthalf {
++union {
++volatile u_char mr1; /* rw */
++volatile u_char mr2; /* rw */
++} mr;
++volatile u_char ri; /* special, read */
++union {
++volatile u_char sr; /* read */
++volatile u_char csr; /* write */
++} sr_csr;
++u_char pad1;
++volatile u_char cr; /* write */
++u_char pad2;
++union {
++volatile u_char rhr; /* read */
++volatile u_char thr; /* write */
++} hr;
++u_char pad3;
++};
++
++struct duart {
++struct duarthalf pa;
++union {
++volatile u_char ipcr; /* read */
++volatile u_char acr; /* write */
++} ipcr_acr;
++u_char pad1;
++union {
++volatile u_char isr; /* read */
++volatile u_char imr; /* write */
++} ir;
++u_char pad2;
++volatile u_char ctu;
++u_char pad3;
++volatile u_char ctl;
++u_char pad4;
++struct duarthalf pb;
++volatile u_char ivr;
++u_char pad5;
++union {
++volatile u_char ipr; /* read */
++volatile u_char opcr; /* write */
++} ipr_opcr;
++u_char pad6;
++union {
++volatile u_char start; /* read */
++volatile u_char sopc; /* write */
++} start_sopc;
++u_char pad7;
++union {
++volatile u_char stop; /* read */
++volatile u_char ropc; /* write */
++} stop_ropc;
++u_char pad8;
++};
++
++#define MR1_BITS 3
++#define MR1_5BITS 0
++#define MR1_6BITS 1
++#define MR1_7BITS 2
++#define MR1_8BITS 3
++
++#define MR1_PARITY_ODD 4
++
++#define MR1_PARITY 24
++#define MR1_PARITY_WITH 0
++#define MR1_PARITY_FORCE 8
++#define MR1_PARITY_NO 16
++#define MR1_PARITY_MULTIDROP 24
++
++#define MR1_ERROR_BLOCK 32
++#define MR1_FFULL_IRQ 64
++#define MR1_RxRTS_ON 128
++
++#define MR2_STOPS 15
++#define MR2_1STOP 7
++#define MR2_2STOP 15
++
++#define MR2_CTS_ON 16
++#define MR2_TxRTS_ON 32
++
++#define MR2_MODE 192
++#define MR2_NORMAL 0
++#define MR2_ECHO 64
++#define MR2_LOCALLOOP 128
++#define MR2_REMOTELOOP 192
++
++#define CR_RXCOMMAND 3
++#define CR_NONE 0
++#define CR_RX_ON 1
++#define CR_RX_OFF 2
++#define CR_TXCOMMAND 12
++#define CR_TX_ON 4
++#define CR_TX_OFF 8
++#define CR_MISC 112
++#define CR_RESET_MR 16
++#define CR_RESET_RX 32
++#define CR_RESET_TX 48
++#define CR_RESET_ERR 64
++#define CR_RESET_BREAK 80
++#define CR_START_BREAK 96
++#define CR_STOP_BREAK 112
++
++#define SR_RXRDY 1
++#define SR_FFULL 2
++#define SR_TXRDY 4
++#define SR_TXEMPT 8
++#define SR_OVERRUN 16
++#define SR_PARITY 32
++#define SR_FRAMING 64
++#define SR_BREAK 128
++
++
++#endif
diff --git a/debian/patches/bugfix/m68k/152-pci.diff b/debian/patches/bugfix/m68k/152-pci.diff
new file mode 100644
index 000000000000..71e738b66aa5
--- /dev/null
+++ b/debian/patches/bugfix/m68k/152-pci.diff
@@ -0,0 +1,21 @@
+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(-)
+
+--- linux-m68k-2.6.21.orig/arch/m68k/kernel/bios32.c
++++ linux-m68k-2.6.21/arch/m68k/kernel/bios32.c
+@@ -284,7 +284,7 @@ static void __init layout_bus(struct pci
+
+ DBG_DEVS(("layout_bus: starting bus %d\n", bus->number));
+
+- if (!bus->devices && !bus->children)
++ if (list_empty(&bus->devices) && list_empty(&bus->children))
+ return;
+
+ /*
diff --git a/debian/patches/bugfix/m68k/357-mac89x0.diff b/debian/patches/bugfix/m68k/357-mac89x0.diff
new file mode 100644
index 000000000000..6827b6698c8d
--- /dev/null
+++ b/debian/patches/bugfix/m68k/357-mac89x0.diff
@@ -0,0 +1,177 @@
+Subject: [PATCH] m68k: Mac89x0 Ethernet netif updates
+Cc: Jeff Garzik <jgarzik@pobox.com>, netdev@vger.kernel.org
+
+From: Matthias Urlichs <smurf@smurf.noris.de>
+
+Macintosh CS89x0 Ethernet: Netif updates
+Addition of netif_stop_queue() before transmission by Michael Schmitz
+
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ drivers/net/Kconfig | 2 -
+ drivers/net/mac89x0.c | 90 +++++++++++++++++---------------------------------
+ 2 files changed, 33 insertions(+), 59 deletions(-)
+
+--- linux-m68k-2.6.21.orig/drivers/net/Kconfig
++++ linux-m68k-2.6.21/drivers/net/Kconfig
+@@ -311,7 +311,7 @@ config MAC8390
+
+ config MAC89x0
+ tristate "Macintosh CS89x0 based ethernet cards"
+- depends on NET_ETHERNET && MAC && BROKEN
++ depends on NET_ETHERNET && MAC
+ ---help---
+ Support for CS89x0 chipset based Ethernet cards. If you have a
+ Nubus or LC-PDS network (Ethernet) card of this type, say Y and
+--- linux-m68k-2.6.21.orig/drivers/net/mac89x0.c
++++ linux-m68k-2.6.21/drivers/net/mac89x0.c
+@@ -128,7 +128,7 @@ struct net_local {
+ extern void reset_chip(struct net_device *dev);
+ #endif
+ static int net_open(struct net_device *dev);
+-static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
++static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
+ static irqreturn_t net_interrupt(int irq, void *dev_id);
+ static void set_multicast_list(struct net_device *dev);
+ static void net_rx(struct net_device *dev);
+@@ -374,56 +374,38 @@ net_open(struct net_device *dev)
+ static int
+ net_send_packet(struct sk_buff *skb, struct net_device *dev)
+ {
+- if (dev->tbusy) {
+- /* If we get here, some higher level has decided we are broken.
+- There should really be a "kick me" function call instead. */
+- int tickssofar = jiffies - dev->trans_start;
+- if (tickssofar < 5)
+- return 1;
+- if (net_debug > 0) printk("%s: transmit timed out, %s?\n", dev->name,
+- tx_done(dev) ? "IRQ conflict" : "network cable problem");
+- /* Try to restart the adaptor. */
+- dev->tbusy=0;
+- dev->trans_start = jiffies;
+- }
+-
+- /* Block a timer-based transmit from overlapping. This could better be
+- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
+- printk("%s: Transmitter access conflict.\n", dev->name);
+- else {
+- struct net_local *lp = netdev_priv(dev);
+- unsigned long flags;
+-
+- if (net_debug > 3)
+- printk("%s: sent %d byte packet of type %x\n",
+- dev->name, skb->len,
+- (skb->data[ETH_ALEN+ETH_ALEN] << 8)
+- | skb->data[ETH_ALEN+ETH_ALEN+1]);
+-
+- /* keep the upload from being interrupted, since we
+- ask the chip to start transmitting before the
+- whole packet has been completely uploaded. */
+- local_irq_save(flags);
+-
+- /* initiate a transmit sequence */
+- writereg(dev, PP_TxCMD, lp->send_cmd);
+- writereg(dev, PP_TxLength, skb->len);
+-
+- /* Test to see if the chip has allocated memory for the packet */
+- if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
+- /* Gasp! It hasn't. But that shouldn't happen since
+- we're waiting for TxOk, so return 1 and requeue this packet. */
+- local_irq_restore(flags);
+- return 1;
+- }
++ struct net_local *lp = netdev_priv(dev);
++ unsigned long flags;
+
+- /* Write the contents of the packet */
+- memcpy_toio(dev->mem_start + PP_TxFrame, skb->data, skb->len+1);
++ if (net_debug > 3)
++ printk("%s: sent %d byte packet of type %x\n",
++ dev->name, skb->len,
++ (skb->data[ETH_ALEN+ETH_ALEN] << 8)
++ | skb->data[ETH_ALEN+ETH_ALEN+1]);
++
++ /* keep the upload from being interrupted, since we
++ ask the chip to start transmitting before the
++ whole packet has been completely uploaded. */
++ local_irq_save(flags);
++ netif_stop_queue(dev);
+
++ /* initiate a transmit sequence */
++ writereg(dev, PP_TxCMD, lp->send_cmd);
++ writereg(dev, PP_TxLength, skb->len);
++
++ /* Test to see if the chip has allocated memory for the packet */
++ if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
++ /* Gasp! It hasn't. But that shouldn't happen since
++ we're waiting for TxOk, so return 1 and requeue this packet. */
+ local_irq_restore(flags);
+- dev->trans_start = jiffies;
++ return 1;
+ }
++
++ /* Write the contents of the packet */
++ memcpy((void *)(dev->mem_start + PP_TxFrame), skb->data, skb->len+1);
++
++ local_irq_restore(flags);
++ dev->trans_start = jiffies;
+ dev_kfree_skb (skb);
+
+ return 0;
+@@ -441,9 +423,6 @@ static irqreturn_t net_interrupt(int irq
+ printk ("net_interrupt(): irq %d for unknown device.\n", irq);
+ return IRQ_NONE;
+ }
+- if (dev->interrupt)
+- printk("%s: Re-entering the interrupt handler.\n", dev->name);
+- dev->interrupt = 1;
+
+ ioaddr = dev->base_addr;
+ lp = netdev_priv(dev);
+@@ -464,8 +443,7 @@ static irqreturn_t net_interrupt(int irq
+ break;
+ case ISQ_TRANSMITTER_EVENT:
+ lp->stats.tx_packets++;
+- dev->tbusy = 0;
+- mark_bh(NET_BH); /* Inform upper layers. */
++ netif_wake_queue(dev);
+ if ((status & TX_OK) == 0) lp->stats.tx_errors++;
+ if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++;
+ if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++;
+@@ -479,8 +457,7 @@ static irqreturn_t net_interrupt(int irq
+ That shouldn't happen since we only ever
+ load one packet. Shrug. Do the right
+ thing anyway. */
+- dev->tbusy = 0;
+- mark_bh(NET_BH); /* Inform upper layers. */
++ netif_wake_queue(dev);
+ }
+ if (status & TX_UNDERRUN) {
+ if (net_debug > 0) printk("%s: transmit underrun\n", dev->name);
+@@ -497,7 +474,6 @@ static irqreturn_t net_interrupt(int irq
+ break;
+ }
+ }
+- dev->interrupt = 0;
+ return IRQ_HANDLED;
+ }
+
+@@ -532,7 +508,7 @@ net_rx(struct net_device *dev)
+ skb_put(skb, length);
+ skb->dev = dev;
+
+- memcpy_fromio(skb->data, dev->mem_start + PP_RxFrame, length);
++ memcpy(skb->data, (void *)(dev->mem_start + PP_RxFrame), length);
+
+ if (net_debug > 3)printk("%s: received %d byte packet of type %x\n",
+ dev->name, length,
+@@ -611,8 +587,6 @@ static void set_multicast_list(struct ne
+ static int set_mac_address(struct net_device *dev, void *addr)
+ {
+ int i;
+- if (dev->start)
+- return -EBUSY;
+ printk("%s: Setting MAC address to ", dev->name);
+ for (i = 0; i < 6; i++)
+ printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]);
diff --git a/debian/patches/bugfix/m68k/448-ide.diff b/debian/patches/bugfix/m68k/448-ide.diff
new file mode 100644
index 000000000000..8d4c0aec061f
--- /dev/null
+++ b/debian/patches/bugfix/m68k/448-ide.diff
@@ -0,0 +1,23 @@
+To: linus, akpm, B.Zolnierkiewicz@elka.pw.edu.pl
+Cc: lkml
+Subject: [PATCH] m68k IDE compiler bug
+
+From: Roman Zippel <zippel@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(-)
+
+--- linux-m68k-2.6.21.orig/include/linux/ide.h
++++ linux-m68k-2.6.21/include/linux/ide.h
+@@ -513,7 +513,7 @@ typedef union {
+ * sense_key : Sense key of the last failed packet command
+ */
+ typedef union {
+- unsigned all :8;
++ u8 all;
+ struct {
+ #if defined(__LITTLE_ENDIAN_BITFIELD)
+ unsigned ili :1;
diff --git a/debian/patches/bugfix/m68k/478-serial.diff b/debian/patches/bugfix/m68k/478-serial.diff
new file mode 100644
index 000000000000..efa2d962d563
--- /dev/null
+++ b/debian/patches/bugfix/m68k/478-serial.diff
@@ -0,0 +1,30 @@
+To: linus, akpm
+Cc: lkml
+Subject: [PATCH] M68k SERIAL_PORT_DFNS only if CONFIG_ISA
+
+From: Kars de Jong <jongk@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@linux-m68k.org>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+
+---
+ include/asm-m68k/serial.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- linux-m68k-2.6.21.orig/include/asm-m68k/serial.h
++++ linux-m68k-2.6.21/include/asm-m68k/serial.h
+@@ -25,9 +25,11 @@
+ #define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
+ #endif
+
++#ifdef CONFIG_ISA
+ #define SERIAL_PORT_DFNS \
+ /* UART CLK PORT IRQ FLAGS */ \
+ { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \
+ { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */ \
+ { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \
+ { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */
++#endif
diff --git a/debian/patches/bugfix/m68k/577-module-arch.diff b/debian/patches/bugfix/m68k/577-module-arch.diff
new file mode 100644
index 000000000000..10e6823bbcf8
--- /dev/null
+++ b/debian/patches/bugfix/m68k/577-module-arch.diff
@@ -0,0 +1,37 @@
+Subject: [PATCH] Allow arch to initialize arch field of the module structure
+
+From: Roman Zippel <zippel@linux-m68k.org>
+
+This will later allow an arch to add module specific information via
+linker generated tables instead of poking directly in the module object
+structure.
+
+Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ include/linux/module.h | 3 +++
+ scripts/mod/modpost.c | 1 +
+ 2 files changed, 4 insertions(+)
+
+--- linux-m68k-2.6.21.orig/include/linux/module.h
++++ linux-m68k-2.6.21/include/linux/module.h
+@@ -356,6 +356,9 @@ struct module
+ keeping pointers to this stuff */
+ char *args;
+ };
++#ifndef MODULE_ARCH_INIT
++#define MODULE_ARCH_INIT {}
++#endif
+
+ /* FIXME: It'd be nice to isolate modules during init, too, so they
+ aren't used before they (may) fail. But presently too much code
+--- linux-m68k-2.6.21.orig/scripts/mod/modpost.c
++++ linux-m68k-2.6.21/scripts/mod/modpost.c
+@@ -1249,6 +1249,7 @@ static void add_header(struct buffer *b,
+ buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
+ " .exit = cleanup_module,\n"
+ "#endif\n");
++ buf_printf(b, " .arch = MODULE_ARCH_INIT,\n");
+ buf_printf(b, "};\n");
+ }
+
diff --git a/debian/patches/bugfix/m68k/600-task_thread_info.diff b/debian/patches/bugfix/m68k/600-task_thread_info.diff
new file mode 100644
index 000000000000..7ea927520c2d
--- /dev/null
+++ b/debian/patches/bugfix/m68k/600-task_thread_info.diff
@@ -0,0 +1,43 @@
+Subject: [PATCH] Wrap access to thread_info
+
+From: Roman Zippel <zippel@linux-m68k.org>
+
+Wrap direct thread_info access
+
+Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ kernel/mutex.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- linux-m68k-2.6.21.orig/kernel/mutex.c
++++ linux-m68k-2.6.21/kernel/mutex.c
+@@ -133,7 +133,7 @@ __mutex_lock_common(struct mutex *lock,
+
+ debug_mutex_lock_common(lock, &waiter);
+ mutex_acquire(&lock->dep_map, subclass, 0, _RET_IP_);
+- debug_mutex_add_waiter(lock, &waiter, task->thread_info);
++ debug_mutex_add_waiter(lock, &waiter, task_thread_info(task));
+
+ /* add waiting tasks to the end of the waitqueue (FIFO): */
+ list_add_tail(&waiter.list, &lock->wait_list);
+@@ -159,7 +159,7 @@ __mutex_lock_common(struct mutex *lock,
+ */
+ if (unlikely(state == TASK_INTERRUPTIBLE &&
+ signal_pending(task))) {
+- mutex_remove_waiter(lock, &waiter, task->thread_info);
++ mutex_remove_waiter(lock, &waiter, task_thread_info(task));
+ mutex_release(&lock->dep_map, 1, _RET_IP_);
+ spin_unlock_mutex(&lock->wait_lock, flags);
+
+@@ -175,8 +175,8 @@ __mutex_lock_common(struct mutex *lock,
+ }
+
+ /* got the lock - rejoice! */
+- mutex_remove_waiter(lock, &waiter, task->thread_info);
+- debug_mutex_set_owner(lock, task->thread_info);
++ mutex_remove_waiter(lock, &waiter, task_thread_info(task));
++ debug_mutex_set_owner(lock, task_thread_info(task));
+
+ /* set it to 0 if there are no waiters left: */
+ if (likely(list_empty(&lock->wait_list)))
diff --git a/debian/patches/bugfix/m68k/611-module_fixup.diff b/debian/patches/bugfix/m68k/611-module_fixup.diff
new file mode 100644
index 000000000000..94aa02f4698c
--- /dev/null
+++ b/debian/patches/bugfix/m68k/611-module_fixup.diff
@@ -0,0 +1,214 @@
+Subject: [PATCH] m68k: runtime patching infrastructure
+
+From: Roman Zippel <zippel@linux-m68k.org>
+
+Add the basic infrastructure to allow runtime patching of kernel and
+modules to optimize a few functions with parameters, which are only
+calculated once during bootup and are otherwise constant.
+Use this for the conversion between virtual and physical addresses.
+
+Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ arch/m68k/Makefile | 1 +
+ arch/m68k/kernel/module.c | 24 +++++++++++++++++++++++-
+ arch/m68k/kernel/module.lds | 7 +++++++
+ arch/m68k/kernel/vmlinux-std.lds | 5 +++++
+ arch/m68k/kernel/vmlinux-sun3.lds | 5 +++++
+ arch/m68k/mm/motorola.c | 3 +++
+ include/asm-m68k/module.h | 33 ++++++++++++++++++++++++++++++++-
+ include/asm-m68k/page.h | 29 ++++++++++++++++++++++++++---
+ 8 files changed, 102 insertions(+), 5 deletions(-)
+
+--- linux-m68k-2.6.21.orig/arch/m68k/Makefile
++++ linux-m68k-2.6.21/arch/m68k/Makefile
+@@ -19,6 +19,7 @@ COMPILE_ARCH = $(shell uname -m)
+ # override top level makefile
+ AS += -m68020
+ LDFLAGS := -m m68kelf
++LDFLAGS_MODULE += -T $(srctree)/arch/m68k/kernel/module.lds
+ ifneq ($(COMPILE_ARCH),$(ARCH))
+ # prefix for cross-compiling binaries
+ CROSS_COMPILE = m68k-linux-gnu-
+--- linux-m68k-2.6.21.orig/arch/m68k/kernel/module.c
++++ linux-m68k-2.6.21/arch/m68k/kernel/module.c
+@@ -1,3 +1,9 @@
++/*
++ * 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/moduleloader.h>
+ #include <linux/elf.h>
+ #include <linux/vmalloc.h>
+@@ -116,10 +122,26 @@ int apply_relocate_add(Elf32_Shdr *sechd
+ return 0;
+ }
+
++void module_fixup(struct module *mod, struct m68k_fixup_info *start,
++ struct m68k_fixup_info *end)
++{
++ struct m68k_fixup_info *fixup;
++
++ for (fixup = start; fixup < end; fixup++) {
++ switch (fixup->type) {
++ case m68k_fixup_memoffset:
++ *(u32 *)fixup->addr = m68k_memoffset;
++ break;
++ }
++ }
++}
++
+ int module_finalize(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+- struct module *me)
++ struct module *mod)
+ {
++ module_fixup(mod, mod->arch.fixup_start, mod->arch.fixup_end);
++
+ return 0;
+ }
+
+--- /dev/null
++++ linux-m68k-2.6.21/arch/m68k/kernel/module.lds
+@@ -0,0 +1,7 @@
++SECTIONS {
++ .m68k_fixup : {
++ __start_fixup = .;
++ *(.m68k_fixup)
++ __stop_fixup = .;
++ }
++}
+--- linux-m68k-2.6.21.orig/arch/m68k/kernel/vmlinux-std.lds
++++ linux-m68k-2.6.21/arch/m68k/kernel/vmlinux-std.lds
+@@ -60,6 +60,11 @@ SECTIONS
+ __con_initcall_start = .;
+ .con_initcall.init : { *(.con_initcall.init) }
+ __con_initcall_end = .;
++ .m68k_fixup : {
++ __start_fixup = .;
++ *(.m68k_fixup)
++ __stop_fixup = .;
++ }
+ SECURITY_INIT
+ #ifdef CONFIG_BLK_DEV_INITRD
+ . = ALIGN(8192);
+--- linux-m68k-2.6.21.orig/arch/m68k/kernel/vmlinux-sun3.lds
++++ linux-m68k-2.6.21/arch/m68k/kernel/vmlinux-sun3.lds
+@@ -54,6 +54,11 @@ __init_begin = .;
+ __con_initcall_start = .;
+ .con_initcall.init : { *(.con_initcall.init) }
+ __con_initcall_end = .;
++ .m68k_fixup : {
++ __start_fixup = .;
++ *(.m68k_fixup)
++ __stop_fixup = .;
++ }
+ SECURITY_INIT
+ #ifdef CONFIG_BLK_DEV_INITRD
+ . = ALIGN(8192);
+--- linux-m68k-2.6.21.orig/arch/m68k/mm/motorola.c
++++ linux-m68k-2.6.21/arch/m68k/mm/motorola.c
+@@ -222,6 +222,9 @@ void __init paging_init(void)
+ pgprot_val(protection_map[i]) |= _PAGE_CACHE040;
+ }
+
++ module_fixup(NULL, __start_fixup, __stop_fixup);
++ flush_icache();
++
+ /*
+ * Map the physical memory available into the kernel virtual
+ * address space. It may allocate some memory for page
+--- linux-m68k-2.6.21.orig/include/asm-m68k/module.h
++++ linux-m68k-2.6.21/include/asm-m68k/module.h
+@@ -1,7 +1,38 @@
+ #ifndef _ASM_M68K_MODULE_H
+ #define _ASM_M68K_MODULE_H
+-struct mod_arch_specific { };
++
++struct mod_arch_specific {
++ struct m68k_fixup_info *fixup_start, *fixup_end;
++};
++
++#define MODULE_ARCH_INIT { \
++ .fixup_start = __start_fixup, \
++ .fixup_end = __stop_fixup, \
++}
++
+ #define Elf_Shdr Elf32_Shdr
+ #define Elf_Sym Elf32_Sym
+ #define Elf_Ehdr Elf32_Ehdr
++
++
++enum m68k_fixup_type {
++ m68k_fixup_memoffset,
++};
++
++struct m68k_fixup_info {
++ enum m68k_fixup_type type;
++ void *addr;
++};
++
++#define m68k_fixup(type, addr) \
++ " .section \".m68k_fixup\",\"aw\"\n" \
++ " .long " #type "," #addr "\n" \
++ " .previous\n"
++
++extern struct m68k_fixup_info __start_fixup[], __stop_fixup[];
++
++struct module;
++extern void module_fixup(struct module *mod, struct m68k_fixup_info *start,
++ struct m68k_fixup_info *end);
++
+ #endif /* _ASM_M68K_MODULE_H */
+--- linux-m68k-2.6.21.orig/include/asm-m68k/page.h
++++ linux-m68k-2.6.21/include/asm-m68k/page.h
+@@ -27,6 +27,8 @@
+
+ #ifndef __ASSEMBLY__
+
++#include <asm/module.h>
++
+ #define get_user_page(vaddr) __get_free_page(GFP_KERNEL)
+ #define free_user_page(page, addr) free_page(addr)
+
+@@ -114,14 +116,35 @@ typedef struct { unsigned long pgprot; }
+
+ #ifndef __ASSEMBLY__
+
++extern unsigned long m68k_memoffset;
++
+ #ifndef CONFIG_SUN3
+
+ #define WANT_PAGE_VIRTUAL
+ #ifdef CONFIG_SINGLE_MEMORY_CHUNK
+-extern unsigned long m68k_memoffset;
+
+-#define __pa(vaddr) ((unsigned long)(vaddr)+m68k_memoffset)
+-#define __va(paddr) ((void *)((unsigned long)(paddr)-m68k_memoffset))
++static inline unsigned long ___pa(void *vaddr)
++{
++ unsigned long paddr;
++ asm (
++ "1: addl #0,%0\n"
++ m68k_fixup(%c2, 1b+2)
++ : "=r" (paddr)
++ : "0" (vaddr), "i" (m68k_fixup_memoffset));
++ return paddr;
++}
++#define __pa(vaddr) ___pa((void *)(vaddr))
++static inline void *__va(unsigned long paddr)
++{
++ void *vaddr;
++ asm (
++ "1: subl #0,%0\n"
++ m68k_fixup(%c2, 1b+2)
++ : "=r" (vaddr)
++ : "0" (paddr), "i" (m68k_fixup_memoffset));
++ return vaddr;
++}
++
+ #else
+ #define __pa(vaddr) virt_to_phys((void *)(vaddr))
+ #define __va(paddr) phys_to_virt((unsigned long)(paddr))
diff --git a/debian/patches/bugfix/m68k/618-discontig.diff b/debian/patches/bugfix/m68k/618-discontig.diff
new file mode 100644
index 000000000000..ef8ec464fa93
--- /dev/null
+++ b/debian/patches/bugfix/m68k/618-discontig.diff
@@ -0,0 +1,868 @@
+To: linus, akpm
+Cc: lkml
+Subject: [PATCH] m68k: Discontinuous memory support
+
+From: Roman Zippel <zippel@linux-m68k.org>
+
+Fix support for discontinuous memory
+
+Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ arch/m68k/Kconfig | 13 +++
+ arch/m68k/kernel/module.c | 3
+ arch/m68k/kernel/setup.c | 37 ++---------
+ arch/m68k/mm/init.c | 119 +++++++++++++++++++++++-------------
+ arch/m68k/mm/memory.c | 73 ----------------------
+ arch/m68k/mm/motorola.c | 102 +++++++++++++++++++++---------
+ arch/m68k/sun3/config.c | 2
+ include/asm-m68k/mmzone.h | 9 ++
+ include/asm-m68k/module.h | 1
+ include/asm-m68k/motorola_pgtable.h | 10 +--
+ include/asm-m68k/page.h | 52 ++++++++++++---
+ include/asm-m68k/pgalloc.h | 3
+ include/asm-m68k/pgtable.h | 17 -----
+ include/asm-m68k/sun3_pgtable.h | 4 -
+ include/asm-m68k/virtconvert.h | 48 +++-----------
+ mm/page_alloc.c | 2
+ 16 files changed, 247 insertions(+), 248 deletions(-)
+
+--- linux-m68k-2.6.21.orig/arch/m68k/Kconfig
++++ linux-m68k-2.6.21/arch/m68k/Kconfig
+@@ -355,8 +355,9 @@ config RMW_INSNS
+ adventurous.
+
+ config SINGLE_MEMORY_CHUNK
+- bool "Use one physical chunk of memory only"
+- depends on ADVANCED && !SUN3
++ bool "Use one physical chunk of memory only" if ADVANCED && !SUN3
++ default y if SUN3
++ select NEED_MULTIPLE_NODES
+ help
+ Ignore all but the first contiguous chunk of physical memory for VM
+ purposes. This will save a few bytes kernel size and may speed up
+@@ -377,6 +378,14 @@ config 060_WRITETHROUGH
+ is hardwired on. The 53c710 SCSI driver is known to suffer from
+ this problem.
+
++config ARCH_DISCONTIGMEM_ENABLE
++ def_bool !SINGLE_MEMORY_CHUNK
++
++config NODES_SHIFT
++ int
++ default "3"
++ depends on !SINGLE_MEMORY_CHUNK
++
+ source "mm/Kconfig"
+
+ endmenu
+--- linux-m68k-2.6.21.orig/arch/m68k/kernel/module.c
++++ linux-m68k-2.6.21/arch/m68k/kernel/module.c
+@@ -132,6 +132,9 @@ void module_fixup(struct module *mod, st
+ case m68k_fixup_memoffset:
+ *(u32 *)fixup->addr = m68k_memoffset;
+ break;
++ case m68k_fixup_vnode_shift:
++ *(u16 *)fixup->addr += m68k_virt_to_node_shift;
++ break;
+ }
+ }
+ }
+--- linux-m68k-2.6.21.orig/arch/m68k/kernel/setup.c
++++ linux-m68k-2.6.21/arch/m68k/kernel/setup.c
+@@ -60,14 +60,12 @@ extern unsigned long availmem;
+ int m68k_num_memory;
+ int m68k_realnum_memory;
+ EXPORT_SYMBOL(m68k_realnum_memory);
+-#ifdef CONFIG_SINGLE_MEMORY_CHUNK
+ unsigned long m68k_memoffset;
+ EXPORT_SYMBOL(m68k_memoffset);
+-#endif
+ struct mem_info m68k_memory[NUM_MEMINFO];
+ EXPORT_SYMBOL(m68k_memory);
+
+-static struct mem_info m68k_ramdisk;
++struct mem_info m68k_ramdisk;
+
+ static char m68k_command_line[CL_SIZE];
+
+@@ -208,9 +206,6 @@ static void __init m68k_parse_bootinfo(c
+ void __init setup_arch(char **cmdline_p)
+ {
+ extern int _etext, _edata, _end;
+-#ifndef CONFIG_SUN3
+- unsigned long endmem, startmem;
+-#endif
+ int i;
+
+ /* The bootinfo is located right after the kernel bss */
+@@ -320,30 +315,16 @@ void __init setup_arch(char **cmdline_p)
+ panic("No configuration setup");
+ }
+
+-#ifndef CONFIG_SUN3
+- startmem= m68k_memory[0].addr;
+- endmem = startmem + m68k_memory[0].size;
+- high_memory = (void *)PAGE_OFFSET;
+- for (i = 0; i < m68k_num_memory; i++) {
+- m68k_memory[i].size &= MASK_256K;
+- if (m68k_memory[i].addr < startmem)
+- startmem = m68k_memory[i].addr;
+- if (m68k_memory[i].addr+m68k_memory[i].size > endmem)
+- endmem = m68k_memory[i].addr+m68k_memory[i].size;
+- high_memory += m68k_memory[i].size;
+- }
+-
+- availmem += init_bootmem_node(NODE_DATA(0), availmem >> PAGE_SHIFT,
+- startmem >> PAGE_SHIFT, endmem >> PAGE_SHIFT);
+-
+- for (i = 0; i < m68k_num_memory; i++)
+- free_bootmem(m68k_memory[i].addr, m68k_memory[i].size);
+-
+- reserve_bootmem(m68k_memory[0].addr, availmem - m68k_memory[0].addr);
++ paging_init();
+
++#ifndef CONFIG_SUN3
++ for (i = 1; i < m68k_num_memory; i++)
++ free_bootmem_node(NODE_DATA(i), m68k_memory[i].addr,
++ m68k_memory[i].size);
+ #ifdef CONFIG_BLK_DEV_INITRD
+ if (m68k_ramdisk.size) {
+- reserve_bootmem(m68k_ramdisk.addr, m68k_ramdisk.size);
++ reserve_bootmem_node(__virt_to_node(phys_to_virt(m68k_ramdisk.addr)),
++ m68k_ramdisk.addr, m68k_ramdisk.size);
+ initrd_start = (unsigned long)phys_to_virt(m68k_ramdisk.addr);
+ initrd_end = initrd_start + m68k_ramdisk.size;
+ printk("initrd: %08lx - %08lx\n", initrd_start, initrd_end);
+@@ -362,8 +343,6 @@ void __init setup_arch(char **cmdline_p)
+
+ #endif /* !CONFIG_SUN3 */
+
+- paging_init();
+-
+ /* set ISA defs early as possible */
+ #if defined(CONFIG_ISA) && defined(MULTI_ISA)
+ #if defined(CONFIG_Q40)
+--- linux-m68k-2.6.21.orig/arch/m68k/mm/init.c
++++ linux-m68k-2.6.21/arch/m68k/mm/init.c
+@@ -7,6 +7,7 @@
+ * to motorola.c and sun3mmu.c
+ */
+
++#include <linux/module.h>
+ #include <linux/signal.h>
+ #include <linux/sched.h>
+ #include <linux/mm.h>
+@@ -31,6 +32,37 @@
+
+ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+
++static bootmem_data_t __initdata bootmem_data[MAX_NUMNODES];
++
++pg_data_t pg_data_map[MAX_NUMNODES];
++EXPORT_SYMBOL(pg_data_map);
++
++int m68k_virt_to_node_shift;
++
++#ifndef CONFIG_SINGLE_MEMORY_CHUNK
++pg_data_t *pg_data_table[65];
++EXPORT_SYMBOL(pg_data_table);
++#endif
++
++void m68k_setup_node(int node)
++{
++#ifndef CONFIG_SINGLE_MEMORY_CHUNK
++ struct mem_info *info = m68k_memory + node;
++ int i, end;
++
++ i = (unsigned long)phys_to_virt(info->addr) >> __virt_to_node_shift();
++ end = (unsigned long)phys_to_virt(info->addr + info->size - 1) >> __virt_to_node_shift();
++ for (; i <= end; i++) {
++ if (pg_data_table[i])
++ printk("overlap at %u for chunk %u\n", i, node);
++ pg_data_table[i] = pg_data_map + node;
++ }
++#endif
++ pg_data_map[node].bdata = bootmem_data + node;
++ node_set_online(node);
++}
++
++
+ /*
+ * ZERO_PAGE is a special page that is used for zero-initialized
+ * data and COW.
+@@ -40,52 +72,51 @@ void *empty_zero_page;
+
+ void show_mem(void)
+ {
+- unsigned long i;
+- int free = 0, total = 0, reserved = 0, shared = 0;
+- int cached = 0;
+-
+- printk("\nMem-info:\n");
+- show_free_areas();
+- printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
+- i = max_mapnr;
+- while (i-- > 0) {
+- total++;
+- if (PageReserved(mem_map+i))
+- reserved++;
+- else if (PageSwapCache(mem_map+i))
+- cached++;
+- else if (!page_count(mem_map+i))
+- free++;
+- else
+- shared += page_count(mem_map+i) - 1;
+- }
+- printk("%d pages of RAM\n",total);
+- printk("%d free pages\n",free);
+- printk("%d reserved pages\n",reserved);
+- printk("%d pages shared\n",shared);
+- printk("%d pages swap cached\n",cached);
++ pg_data_t *pgdat;
++ int free = 0, total = 0, reserved = 0, shared = 0;
++ int cached = 0;
++ int i;
++
++ printk("\nMem-info:\n");
++ show_free_areas();
++ printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
++ for_each_online_pgdat(pgdat) {
++ for (i = 0; i < pgdat->node_spanned_pages; i++) {
++ struct page *page = pgdat->node_mem_map + i;
++ total++;
++ if (PageReserved(page))
++ reserved++;
++ else if (PageSwapCache(page))
++ cached++;
++ else if (!page_count(page))
++ free++;
++ else
++ shared += page_count(page) - 1;
++ }
++ }
++ printk("%d pages of RAM\n",total);
++ printk("%d free pages\n",free);
++ printk("%d reserved pages\n",reserved);
++ printk("%d pages shared\n",shared);
++ printk("%d pages swap cached\n",cached);
+ }
+
+ extern void init_pointer_table(unsigned long ptable);
+
+ /* References to section boundaries */
+
+-extern char _text, _etext, _edata, __bss_start, _end;
+-extern char __init_begin, __init_end;
++extern char _text[], _etext[];
++extern char __init_begin[], __init_end[];
+
+ extern pmd_t *zero_pgtable;
+
+ void __init mem_init(void)
+ {
++ pg_data_t *pgdat;
+ int codepages = 0;
+ int datapages = 0;
+ int initpages = 0;
+- unsigned long tmp;
+-#ifndef CONFIG_SUN3
+ int i;
+-#endif
+-
+- max_mapnr = num_physpages = (((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT);
+
+ #ifdef CONFIG_ATARI
+ if (MACH_IS_ATARI)
+@@ -93,19 +124,25 @@ void __init mem_init(void)
+ #endif
+
+ /* this will put all memory onto the freelists */
+- totalram_pages = free_all_bootmem();
+-
+- for (tmp = PAGE_OFFSET ; tmp < (unsigned long)high_memory; tmp += PAGE_SIZE) {
+- if (PageReserved(virt_to_page(tmp))) {
+- if (tmp >= (unsigned long)&_text
+- && tmp < (unsigned long)&_etext)
++ totalram_pages = num_physpages = 0;
++ for_each_online_pgdat(pgdat) {
++ num_physpages += pgdat->node_present_pages;
++
++ totalram_pages += free_all_bootmem_node(pgdat);
++ for (i = 0; i < pgdat->node_spanned_pages; i++) {
++ struct page *page = pgdat->node_mem_map + i;
++ char *addr = page_to_virt(page);
++
++ if (!PageReserved(page))
++ continue;
++ if (addr >= _text &&
++ addr < _etext)
+ codepages++;
+- else if (tmp >= (unsigned long) &__init_begin
+- && tmp < (unsigned long) &__init_end)
++ else if (addr >= __init_begin &&
++ addr < __init_end)
+ initpages++;
+ else
+ datapages++;
+- continue;
+ }
+ }
+
+@@ -124,7 +161,7 @@ void __init mem_init(void)
+
+ printk("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init)\n",
+ (unsigned long)nr_free_pages() << (PAGE_SHIFT-10),
+- max_mapnr << (PAGE_SHIFT-10),
++ totalram_pages << (PAGE_SHIFT-10),
+ codepages << (PAGE_SHIFT-10),
+ datapages << (PAGE_SHIFT-10),
+ initpages << (PAGE_SHIFT-10));
+--- linux-m68k-2.6.21.orig/arch/m68k/mm/memory.c
++++ linux-m68k-2.6.21/arch/m68k/mm/memory.c
+@@ -127,67 +127,6 @@ int free_pointer_table (pmd_t *ptable)
+ return 0;
+ }
+
+-#ifdef DEBUG_INVALID_PTOV
+-int mm_inv_cnt = 5;
+-#endif
+-
+-#ifndef CONFIG_SINGLE_MEMORY_CHUNK
+-/*
+- * The following two routines map from a physical address to a kernel
+- * virtual address and vice versa.
+- */
+-unsigned long mm_vtop(unsigned long vaddr)
+-{
+- int i=0;
+- unsigned long voff = (unsigned long)vaddr - PAGE_OFFSET;
+-
+- do {
+- if (voff < m68k_memory[i].size) {
+-#ifdef DEBUGPV
+- printk ("VTOP(%p)=%lx\n", vaddr,
+- m68k_memory[i].addr + voff);
+-#endif
+- return m68k_memory[i].addr + voff;
+- }
+- voff -= m68k_memory[i].size;
+- } while (++i < m68k_num_memory);
+-
+- /* As a special case allow `__pa(high_memory)'. */
+- if (voff == 0)
+- return m68k_memory[i-1].addr + m68k_memory[i-1].size;
+-
+- return -1;
+-}
+-EXPORT_SYMBOL(mm_vtop);
+-
+-unsigned long mm_ptov (unsigned long paddr)
+-{
+- int i = 0;
+- unsigned long poff, voff = PAGE_OFFSET;
+-
+- do {
+- poff = paddr - m68k_memory[i].addr;
+- if (poff < m68k_memory[i].size) {
+-#ifdef DEBUGPV
+- printk ("PTOV(%lx)=%lx\n", paddr, poff + voff);
+-#endif
+- return poff + voff;
+- }
+- voff += m68k_memory[i].size;
+- } while (++i < m68k_num_memory);
+-
+-#ifdef DEBUG_INVALID_PTOV
+- if (mm_inv_cnt > 0) {
+- mm_inv_cnt--;
+- printk("Invalid use of phys_to_virt(0x%lx) at 0x%p!\n",
+- paddr, __builtin_return_address(0));
+- }
+-#endif
+- return -1;
+-}
+-EXPORT_SYMBOL(mm_ptov);
+-#endif
+-
+ /* invalidate page in both caches */
+ static inline void clear040(unsigned long paddr)
+ {
+@@ -354,15 +293,3 @@ void cache_push (unsigned long paddr, in
+ }
+ EXPORT_SYMBOL(cache_push);
+
+-#ifndef CONFIG_SINGLE_MEMORY_CHUNK
+-int mm_end_of_chunk (unsigned long addr, int len)
+-{
+- int i;
+-
+- for (i = 0; i < m68k_num_memory; i++)
+- if (m68k_memory[i].addr + m68k_memory[i].size == addr + len)
+- return 1;
+- return 0;
+-}
+-EXPORT_SYMBOL(mm_end_of_chunk);
+-#endif
+--- linux-m68k-2.6.21.orig/arch/m68k/mm/motorola.c
++++ linux-m68k-2.6.21/arch/m68k/mm/motorola.c
+@@ -43,6 +43,12 @@ unsigned long mm_cachebits;
+ EXPORT_SYMBOL(mm_cachebits);
+ #endif
+
++/* size of memory already mapped in head.S */
++#define INIT_MAPPED_SIZE (4UL<<20)
++
++extern unsigned long availmem;
++extern struct mem_info m68k_ramdisk;
++
+ static pte_t * __init kernel_page_table(void)
+ {
+ pte_t *ptablep;
+@@ -98,19 +104,20 @@ static pmd_t * __init kernel_ptr_table(v
+ return last_pgtable;
+ }
+
+-static unsigned long __init
+-map_chunk (unsigned long addr, long size)
++static void __init map_node(int node)
+ {
+ #define PTRTREESIZE (256*1024)
+ #define ROOTTREESIZE (32*1024*1024)
+- static unsigned long virtaddr = PAGE_OFFSET;
+- unsigned long physaddr;
++ unsigned long physaddr, virtaddr, size;
+ pgd_t *pgd_dir;
+ pmd_t *pmd_dir;
+ pte_t *pte_dir;
+
+- physaddr = (addr | m68k_supervisor_cachemode |
+- _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
++ size = m68k_memory[node].size;
++ physaddr = m68k_memory[node].addr;
++ virtaddr = (unsigned long)phys_to_virt(physaddr);
++ physaddr |= m68k_supervisor_cachemode |
++ _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY;
+ if (CPU_IS_040_OR_060)
+ physaddr |= _PAGE_GLOBAL040;
+
+@@ -190,8 +197,6 @@ map_chunk (unsigned long addr, long size
+ #ifdef DEBUG
+ printk("\n");
+ #endif
+-
+- return virtaddr;
+ }
+
+ /*
+@@ -200,15 +205,16 @@ map_chunk (unsigned long addr, long size
+ */
+ void __init paging_init(void)
+ {
+- int chunk;
+- unsigned long mem_avail = 0;
+ unsigned long zones_size[MAX_NR_ZONES] = { 0, };
++ unsigned long min_addr, max_addr;
++ unsigned long addr, size, end;
++ int i;
+
+ #ifdef DEBUG
+ {
+ extern unsigned long availmem;
+- printk ("start of paging_init (%p, %lx, %lx, %lx)\n",
+- kernel_pg_dir, availmem, start_mem, end_mem);
++ printk ("start of paging_init (%p, %lx)\n",
++ kernel_pg_dir, availmem);
+ }
+ #endif
+
+@@ -222,27 +228,62 @@ void __init paging_init(void)
+ pgprot_val(protection_map[i]) |= _PAGE_CACHE040;
+ }
+
++ min_addr = m68k_memory[0].addr;
++ max_addr = min_addr + m68k_memory[0].size;
++ for (i = 1; i < m68k_num_memory;) {
++ if (m68k_memory[i].addr < min_addr) {
++ printk("Ignoring memory chunk at 0x%lx:0x%lx before the first chunk\n",
++ m68k_memory[i].addr, m68k_memory[i].size);
++ printk("Fix your bootloader or use a memfile to make use of this area!\n");
++ m68k_num_memory--;
++ memmove(m68k_memory + i, m68k_memory + i + 1,
++ (m68k_num_memory - i) * sizeof(struct mem_info));
++ continue;
++ }
++ addr = m68k_memory[i].addr + m68k_memory[i].size;
++ if (addr > max_addr)
++ max_addr = addr;
++ i++;
++ }
++ m68k_memoffset = min_addr - PAGE_OFFSET;
++ m68k_virt_to_node_shift = fls(max_addr - min_addr - 1) - 6;
++
+ module_fixup(NULL, __start_fixup, __stop_fixup);
+ flush_icache();
+
++ high_memory = phys_to_virt(max_addr);
++
++ min_low_pfn = availmem >> PAGE_SHIFT;
++ max_low_pfn = max_addr >> PAGE_SHIFT;
++
++ for (i = 0; i < m68k_num_memory; i++) {
++ addr = m68k_memory[i].addr;
++ end = addr + m68k_memory[i].size;
++ m68k_setup_node(i);
++ availmem = PAGE_ALIGN(availmem);
++ availmem += init_bootmem_node(NODE_DATA(i),
++ availmem >> PAGE_SHIFT,
++ addr >> PAGE_SHIFT,
++ end >> PAGE_SHIFT);
++ }
++
+ /*
+ * Map the physical memory available into the kernel virtual
+- * address space. It may allocate some memory for page
+- * tables and thus modify availmem.
++ * address space. First initialize the bootmem allocator with
++ * the memory we already mapped, so map_node() has something
++ * to allocate.
+ */
++ addr = m68k_memory[0].addr;
++ size = m68k_memory[0].size;
++ free_bootmem_node(NODE_DATA(0), availmem, min(INIT_MAPPED_SIZE, size) - (availmem - addr));
++ map_node(0);
++ if (size > INIT_MAPPED_SIZE)
++ free_bootmem_node(NODE_DATA(0), addr + INIT_MAPPED_SIZE, size - INIT_MAPPED_SIZE);
+
+- for (chunk = 0; chunk < m68k_num_memory; chunk++) {
+- mem_avail = map_chunk (m68k_memory[chunk].addr,
+- m68k_memory[chunk].size);
+-
+- }
++ for (i = 1; i < m68k_num_memory; i++)
++ map_node(i);
+
+ flush_tlb_all();
+-#ifdef DEBUG
+- printk ("memory available is %ldKB\n", mem_avail >> 10);
+- printk ("start_mem is %#lx\nvirtual_end is %#lx\n",
+- start_mem, end_mem);
+-#endif
+
+ /*
+ * initialize the bad page table and bad page to point
+@@ -259,14 +300,11 @@ void __init paging_init(void)
+ #ifdef DEBUG
+ printk ("before free_area_init\n");
+ #endif
+- zones_size[ZONE_DMA] = (mach_max_dma_address < (unsigned long)high_memory ?
+- (mach_max_dma_address+1) : (unsigned long)high_memory);
+- zones_size[ZONE_NORMAL] = (unsigned long)high_memory - zones_size[0];
+-
+- zones_size[ZONE_DMA] = (zones_size[ZONE_DMA] - PAGE_OFFSET) >> PAGE_SHIFT;
+- zones_size[ZONE_NORMAL] >>= PAGE_SHIFT;
+-
+- free_area_init(zones_size);
++ for (i = 0; i < m68k_num_memory; i++) {
++ zones_size[ZONE_DMA] = m68k_memory[i].size >> PAGE_SHIFT;
++ free_area_init_node(i, pg_data_map + i, zones_size,
++ m68k_memory[i].addr >> PAGE_SHIFT, NULL);
++ }
+ }
+
+ extern char __init_begin, __init_end;
+--- linux-m68k-2.6.21.orig/arch/m68k/sun3/config.c
++++ linux-m68k-2.6.21/arch/m68k/sun3/config.c
+@@ -21,6 +21,7 @@
+ #include <asm/contregs.h>
+ #include <asm/movs.h>
+ #include <asm/pgtable.h>
++#include <asm/pgalloc.h>
+ #include <asm/sun3-head.h>
+ #include <asm/sun3mmu.h>
+ #include <asm/rtc.h>
+@@ -127,6 +128,7 @@ void __init sun3_bootmem_alloc(unsigned
+ high_memory = (void *)memory_end;
+ availmem = memory_start;
+
++ m68k_setup_node(0);
+ availmem += init_bootmem_node(NODE_DATA(0), start_page, 0, num_pages);
+ availmem = (availmem + (PAGE_SIZE-1)) & PAGE_MASK;
+
+--- /dev/null
++++ linux-m68k-2.6.21/include/asm-m68k/mmzone.h
+@@ -0,0 +1,9 @@
++#ifndef _ASM_M68K_MMZONE_H_
++#define _ASM_M68K_MMZONE_H_
++
++extern pg_data_t pg_data_map[];
++
++#define NODE_DATA(nid) (&pg_data_map[nid])
++#define NODE_MEM_MAP(nid) (NODE_DATA(nid)->node_mem_map)
++
++#endif /* _ASM_M68K_MMZONE_H_ */
+--- linux-m68k-2.6.21.orig/include/asm-m68k/module.h
++++ linux-m68k-2.6.21/include/asm-m68k/module.h
+@@ -17,6 +17,7 @@ struct mod_arch_specific {
+
+ enum m68k_fixup_type {
+ m68k_fixup_memoffset,
++ m68k_fixup_vnode_shift,
+ };
+
+ struct m68k_fixup_info {
+--- linux-m68k-2.6.21.orig/include/asm-m68k/motorola_pgtable.h
++++ linux-m68k-2.6.21/include/asm-m68k/motorola_pgtable.h
+@@ -130,7 +130,7 @@ static inline void pgd_set(pgd_t *pgdp,
+ #define pte_present(pte) (pte_val(pte) & (_PAGE_PRESENT | _PAGE_PROTNONE))
+ #define pte_clear(mm,addr,ptep) ({ pte_val(*(ptep)) = 0; })
+
+-#define pte_page(pte) (mem_map + ((unsigned long)(__va(pte_val(pte)) - PAGE_OFFSET) >> PAGE_SHIFT))
++#define pte_page(pte) virt_to_page(__va(pte_val(pte)))
+ #define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT)
+ #define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
+
+@@ -143,7 +143,7 @@ static inline void pgd_set(pgd_t *pgdp,
+ while (--__i >= 0) \
+ *__ptr++ = 0; \
+ })
+-#define pmd_page(pmd) (mem_map + ((unsigned long)(__va(pmd_val(pmd)) - PAGE_OFFSET) >> PAGE_SHIFT))
++#define pmd_page(pmd) virt_to_page(__va(pmd_val(pmd)))
+
+
+ #define pgd_none(pgd) (!pgd_val(pgd))
+@@ -223,10 +223,10 @@ static inline pte_t *pte_offset_kernel(p
+ return (pte_t *)__pmd_page(*pmdp) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
+ }
+
+-#define pte_offset_map(pmdp,address) ((pte_t *)kmap(pmd_page(*pmdp)) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
++#define pte_offset_map(pmdp,address) ((pte_t *)__pmd_page(*pmdp) + (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
+ #define pte_offset_map_nested(pmdp, address) pte_offset_map(pmdp, address)
+-#define pte_unmap(pte) kunmap(pte)
+-#define pte_unmap_nested(pte) kunmap(pte)
++#define pte_unmap(pte) ((void)0)
++#define pte_unmap_nested(pte) ((void)0)
+
+ /*
+ * Allocate and free page tables. The xxx_kernel() versions are
+--- linux-m68k-2.6.21.orig/include/asm-m68k/page.h
++++ linux-m68k-2.6.21/include/asm-m68k/page.h
+@@ -121,7 +121,6 @@ extern unsigned long m68k_memoffset;
+ #ifndef CONFIG_SUN3
+
+ #define WANT_PAGE_VIRTUAL
+-#ifdef CONFIG_SINGLE_MEMORY_CHUNK
+
+ static inline unsigned long ___pa(void *vaddr)
+ {
+@@ -133,7 +132,7 @@ static inline unsigned long ___pa(void *
+ : "0" (vaddr), "i" (m68k_fixup_memoffset));
+ return paddr;
+ }
+-#define __pa(vaddr) ___pa((void *)(vaddr))
++#define __pa(vaddr) ___pa((void *)(vaddr))
+ static inline void *__va(unsigned long paddr)
+ {
+ void *vaddr;
+@@ -145,11 +144,6 @@ static inline void *__va(unsigned long p
+ return vaddr;
+ }
+
+-#else
+-#define __pa(vaddr) virt_to_phys((void *)(vaddr))
+-#define __va(paddr) phys_to_virt((unsigned long)(paddr))
+-#endif
+-
+ #else /* !CONFIG_SUN3 */
+ /* This #define is a horrible hack to suppress lots of warnings. --m */
+ #define __pa(x) ___pa((unsigned long)(x))
+@@ -184,11 +178,47 @@ static inline void *__va(unsigned long x
+ #define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT)
+ #define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT)
+
+-#define virt_to_page(kaddr) (mem_map + (((unsigned long)(kaddr)-PAGE_OFFSET) >> PAGE_SHIFT))
+-#define page_to_virt(page) ((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET)
++extern int m68k_virt_to_node_shift;
++
++#ifdef CONFIG_SINGLE_MEMORY_CHUNK
++#define __virt_to_node(addr) (&pg_data_map[0])
++#else
++extern struct pglist_data *pg_data_table[];
++
++static inline __attribute_const__ int __virt_to_node_shift(void)
++{
++ int shift;
++
++ asm (
++ "1: moveq #0,%0\n"
++ m68k_fixup(%c1, 1b)
++ : "=d" (shift)
++ : "i" (m68k_fixup_vnode_shift));
++ return shift;
++}
++
++#define __virt_to_node(addr) (pg_data_table[(unsigned long)(addr) >> __virt_to_node_shift()])
++#endif
+
+-#define pfn_to_page(pfn) virt_to_page(pfn_to_virt(pfn))
+-#define page_to_pfn(page) virt_to_pfn(page_to_virt(page))
++#define virt_to_page(addr) ({ \
++ pfn_to_page(virt_to_pfn(addr)); \
++})
++#define page_to_virt(page) ({ \
++ pfn_to_virt(page_to_pfn(page)); \
++})
++
++#define pfn_to_page(pfn) ({ \
++ unsigned long __pfn = (pfn); \
++ struct pglist_data *pgdat; \
++ pgdat = __virt_to_node((unsigned long)pfn_to_virt(__pfn)); \
++ pgdat->node_mem_map + (__pfn - pgdat->node_start_pfn); \
++})
++#define page_to_pfn(_page) ({ \
++ struct page *__p = (_page); \
++ struct pglist_data *pgdat; \
++ pgdat = &pg_data_map[page_to_nid(__p)]; \
++ ((__p) - pgdat->node_mem_map) + pgdat->node_start_pfn; \
++})
+
+ #define virt_addr_valid(kaddr) ((void *)(kaddr) >= (void *)PAGE_OFFSET && (void *)(kaddr) < high_memory)
+ #define pfn_valid(pfn) virt_addr_valid(pfn_to_virt(pfn))
+--- linux-m68k-2.6.21.orig/include/asm-m68k/pgalloc.h
++++ linux-m68k-2.6.21/include/asm-m68k/pgalloc.h
+@@ -8,11 +8,12 @@
+ #include <asm/virtconvert.h>
+
+
+-
+ #ifdef CONFIG_SUN3
+ #include <asm/sun3_pgalloc.h>
+ #else
+ #include <asm/motorola_pgalloc.h>
+ #endif
+
++extern void m68k_setup_node(int node);
++
+ #endif /* M68K_PGALLOC_H */
+--- linux-m68k-2.6.21.orig/include/asm-m68k/pgtable.h
++++ linux-m68k-2.6.21/include/asm-m68k/pgtable.h
+@@ -107,22 +107,7 @@ extern void *empty_zero_page;
+ /* 64-bit machines, beware! SRB. */
+ #define SIZEOF_PTR_LOG2 2
+
+-/*
+- * Check if the addr/len goes up to the end of a physical
+- * memory chunk. Used for DMA functions.
+- */
+-#ifdef CONFIG_SINGLE_MEMORY_CHUNK
+-/*
+- * It makes no sense to consider whether we cross a memory boundary if
+- * we support just one physical chunk of memory.
+- */
+-static inline int mm_end_of_chunk(unsigned long addr, int len)
+-{
+- return 0;
+-}
+-#else
+-int mm_end_of_chunk (unsigned long addr, int len);
+-#endif
++#define mm_end_of_chunk(addr, len) 0
+
+ extern void kernel_set_cachemode(void *addr, unsigned long size, int cmode);
+
+--- linux-m68k-2.6.21.orig/include/asm-m68k/sun3_pgtable.h
++++ linux-m68k-2.6.21/include/asm-m68k/sun3_pgtable.h
+@@ -132,8 +132,8 @@ static inline void pte_clear (struct mm_
+ #define pfn_pte(pfn, pgprot) \
+ ({ pte_t __pte; pte_val(__pte) = pfn | pgprot_val(pgprot); __pte; })
+
+-#define pte_page(pte) (mem_map+((__pte_page(pte) - PAGE_OFFSET) >> PAGE_SHIFT))
+-#define pmd_page(pmd) (mem_map+((__pmd_page(pmd) - PAGE_OFFSET) >> PAGE_SHIFT))
++#define pte_page(pte) virt_to_page(__pte_page(pte))
++#define pmd_page(pmd) virt_to_page(__pmd_page(pmd))
+
+
+ static inline int pmd_none2 (pmd_t *pmd) { return !pmd_val (*pmd); }
+--- linux-m68k-2.6.21.orig/include/asm-m68k/virtconvert.h
++++ linux-m68k-2.6.21/include/asm-m68k/virtconvert.h
+@@ -8,56 +8,34 @@
+ #ifdef __KERNEL__
+
+ #include <linux/compiler.h>
++#include <linux/mmzone.h>
+ #include <asm/setup.h>
+ #include <asm/page.h>
+
+-#ifdef CONFIG_AMIGA
+-#include <asm/amigahw.h>
+-#endif
+-
+ /*
+ * Change virtual addresses to physical addresses and vv.
+ */
+-#ifndef CONFIG_SUN3
+-extern unsigned long mm_vtop(unsigned long addr) __attribute_const__;
+-extern unsigned long mm_ptov(unsigned long addr) __attribute_const__;
+-#else
+-static inline unsigned long mm_vtop(unsigned long vaddr)
+-{
+- return __pa(vaddr);
+-}
+-
+-static inline unsigned long mm_ptov(unsigned long paddr)
+-{
+- return (unsigned long)__va(paddr);
+-}
+-#endif
+-
+-#ifdef CONFIG_SINGLE_MEMORY_CHUNK
+-static inline unsigned long virt_to_phys(void *vaddr)
+-{
+- return (unsigned long)vaddr - PAGE_OFFSET + m68k_memory[0].addr;
+-}
+-
+-static inline void * phys_to_virt(unsigned long paddr)
+-{
+- return (void *)(paddr - m68k_memory[0].addr + PAGE_OFFSET);
+-}
+-#else
+ static inline unsigned long virt_to_phys(void *address)
+ {
+- return mm_vtop((unsigned long)address);
++ return __pa(address);
+ }
+
+ static inline void *phys_to_virt(unsigned long address)
+ {
+- return (void *) mm_ptov(address);
++ return __va(address);
+ }
+-#endif
+
+ /* Permanent address of a page. */
+-#define __page_address(page) (PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT))
+-#define page_to_phys(page) virt_to_phys((void *)__page_address(page))
++#ifdef CONFIG_SINGLE_MEMORY_CHUNK
++#define page_to_phys(page) \
++ __pa(PAGE_OFFSET + (((page) - pg_data_map[0].node_mem_map) << PAGE_SHIFT))
++#else
++#define page_to_phys(page) ({ \
++ struct pglist_data *pgdat; \
++ pgdat = pg_data_table[page_to_nid(page)]; \
++ page_to_pfn(page) << PAGE_SHIFT; \
++})
++#endif
+
+ /*
+ * IO bus memory addresses are 1:1 with the physical address,
+--- linux-m68k-2.6.21.orig/mm/page_alloc.c
++++ linux-m68k-2.6.21/mm/page_alloc.c
+@@ -2713,7 +2713,7 @@ static void __init alloc_node_mem_map(st
+ map = alloc_bootmem_node(pgdat, size);
+ pgdat->node_mem_map = map + (pgdat->node_start_pfn - start);
+ }
+-#ifdef CONFIG_FLATMEM
++#ifndef CONFIG_NEED_MULTIPLE_NODES
+ /*
+ * With no DISCONTIG, the global mem_map is just set as node 0's
+ */
diff --git a/debian/patches/bugfix/m68k/630-extern-cleanup.diff b/debian/patches/bugfix/m68k/630-extern-cleanup.diff
new file mode 100644
index 000000000000..823760ceeb7f
--- /dev/null
+++ b/debian/patches/bugfix/m68k/630-extern-cleanup.diff
@@ -0,0 +1,34 @@
+To: linus, akpm
+Cc: lkml
+Subject: [PATCH] m68k: Kill superfluous externs
+
+Kill a few superfluous extern declarations.
+
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ arch/m68k/mm/motorola.c | 7 +------
+ 1 file changed, 1 insertion(+), 6 deletions(-)
+
+--- linux-m68k-2.6.21.orig/arch/m68k/mm/motorola.c
++++ linux-m68k-2.6.21/arch/m68k/mm/motorola.c
+@@ -47,7 +47,6 @@ EXPORT_SYMBOL(mm_cachebits);
+ #define INIT_MAPPED_SIZE (4UL<<20)
+
+ extern unsigned long availmem;
+-extern struct mem_info m68k_ramdisk;
+
+ static pte_t * __init kernel_page_table(void)
+ {
+@@ -211,11 +210,7 @@ void __init paging_init(void)
+ int i;
+
+ #ifdef DEBUG
+- {
+- extern unsigned long availmem;
+- printk ("start of paging_init (%p, %lx)\n",
+- kernel_pg_dir, availmem);
+- }
++ printk ("start of paging_init (%p, %lx)\n", kernel_pg_dir, availmem);
+ #endif
+
+ /* Fix the cache mode in the page descriptors for the 680[46]0. */
diff --git a/debian/patches/bugfix/m68k/631-thread_stack.diff b/debian/patches/bugfix/m68k/631-thread_stack.diff
new file mode 100644
index 000000000000..71342f24a0cc
--- /dev/null
+++ b/debian/patches/bugfix/m68k/631-thread_stack.diff
@@ -0,0 +1,117 @@
+To: linus, akpm
+Cc: lkml
+Subject: [PATCH] Thread stack abstractions
+
+From: Roman Zippel <zippel@linux-m68k.org>
+
+Thread stack abstractions:
+ - Move thread_info into task_struct
+ - Adapt thread_info initialization
+ - Abstract thread_info access
+ - Thread_info field becomes stack
+ - Change get_task_struct/put_task_struct into inline functions
+ - Move task_struct into <linux/task_struct.h>
+
+Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
+
+---
+ include/asm-m68k/thread_info.h | 12 ++++++------
+ include/linux/init_task.h | 2 +-
+ include/linux/sched.h | 3 ++-
+ kernel/fork.c | 10 +++++-----
+ 4 files changed, 14 insertions(+), 13 deletions(-)
+
+--- linux-m68k-2.6.21.orig/include/asm-m68k/thread_info.h
++++ linux-m68k-2.6.21/include/asm-m68k/thread_info.h
+@@ -26,24 +26,24 @@ struct thread_info {
+
+ /* THREAD_SIZE should be 8k, so handle differently for 4k and 8k machines */
+ #if PAGE_SHIFT == 13 /* 8k machines */
+-#define alloc_thread_info(tsk) ((struct thread_info *)__get_free_pages(GFP_KERNEL,0))
+-#define free_thread_info(ti) free_pages((unsigned long)(ti),0)
++#define alloc_thread_stack(tsk) ((void *)__get_free_pages(GFP_KERNEL,0))
++#define free_thread_stack(ti) free_pages((unsigned long)(ti),0)
+ #else /* otherwise assume 4k pages */
+-#define alloc_thread_info(tsk) ((struct thread_info *)__get_free_pages(GFP_KERNEL,1))
+-#define free_thread_info(ti) free_pages((unsigned long)(ti),1)
++#define alloc_thread_stack(tsk) ((void *)__get_free_pages(GFP_KERNEL,1))
++#define free_thread_stack(ti) free_pages((unsigned long)(ti),1)
+ #endif /* PAGE_SHIFT == 13 */
+
+ #define init_thread_info (init_task.thread.info)
+ #define init_stack (init_thread_union.stack)
+
+ #define task_thread_info(tsk) (&(tsk)->thread.info)
+-#define task_stack_page(tsk) ((void *)(tsk)->thread_info)
++#define task_stack_page(tsk) ((void *)(tsk)->stack)
+ #define current_thread_info() task_thread_info(current)
+
+ #define __HAVE_THREAD_FUNCTIONS
+
+ #define setup_thread_stack(p, org) ({ \
+- *(struct task_struct **)(p)->thread_info = (p); \
++ *(struct task_struct **)(p)->stack = (p); \
+ task_thread_info(p)->task = (p); \
+ })
+
+--- linux-m68k-2.6.21.orig/include/linux/init_task.h
++++ linux-m68k-2.6.21/include/linux/init_task.h
+@@ -95,7 +95,7 @@ extern struct group_info init_groups;
+ #define INIT_TASK(tsk) \
+ { \
+ .state = 0, \
+- .thread_info = &init_thread_info, \
++ .stack = &init_stack, \
+ .usage = ATOMIC_INIT(2), \
+ .flags = 0, \
+ .lock_depth = -1, \
+--- linux-m68k-2.6.21.orig/include/linux/sched.h
++++ linux-m68k-2.6.21/include/linux/sched.h
+@@ -799,7 +799,8 @@ struct prio_array;
+
+ struct task_struct {
+ volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
+- struct thread_info *thread_info;
++ //struct thread_info *thread_info;
++ void *stack;
+ atomic_t usage;
+ unsigned long flags; /* per process flags, defined below */
+ unsigned long ptrace;
+--- linux-m68k-2.6.21.orig/kernel/fork.c
++++ linux-m68k-2.6.21/kernel/fork.c
+@@ -106,7 +106,7 @@ static struct kmem_cache *mm_cachep;
+
+ void free_task(struct task_struct *tsk)
+ {
+- free_thread_info(tsk->thread_info);
++ free_thread_stack(tsk->stack);
+ rt_mutex_debug_task_free(tsk);
+ free_task_struct(tsk);
+ }
+@@ -161,7 +161,7 @@ void __init fork_init(unsigned long memp
+ static struct task_struct *dup_task_struct(struct task_struct *orig)
+ {
+ struct task_struct *tsk;
+- struct thread_info *ti;
++ void *stack;
+
+ prepare_to_copy(orig);
+
+@@ -169,14 +169,14 @@ static struct task_struct *dup_task_stru
+ if (!tsk)
+ return NULL;
+
+- ti = alloc_thread_info(tsk);
+- if (!ti) {
++ stack = alloc_thread_stack(tsk);
++ if (!stack) {
+ free_task_struct(tsk);
+ return NULL;
+ }
+
+ *tsk = *orig;
+- tsk->thread_info = ti;
++ tsk->stack = stack;
+ setup_thread_stack(tsk, orig);
+
+ #ifdef CONFIG_CC_STACKPROTECTOR
diff --git a/debian/patches/bugfix/m68k/633-atari_scc.diff b/debian/patches/bugfix/m68k/633-atari_scc.diff
new file mode 100644
index 000000000000..11897918653e
--- /dev/null
+++ b/debian/patches/bugfix/m68k/633-atari_scc.diff
@@ -0,0 +1,1739 @@
+To: linus, akpm
+Cc: lkml
+Subject: [PATCH] m68k: Atari SCC serial driver
+
+From: Michael Schmitz <schmitz@opal.biophys.uni-duesseldorf.de>
+
+Atari SCC serial driver - this one works less well in 2.6 than it did in 2.4,
+most likely due to the way flip buffer push is handled now - i.e. no
+immediate push of received characters to the line disc. if the handler
+runs in interrupt context, and the bottom half for pushing is run as
+delayed task. 9 out of 10 ping packets end up in the bit bucket this way.
+I haven't figured out how to prevent overruns yet, and getting this right
+will require a bit more testing.
+
+Anyway, the basics are working, and maybe someone can figure out a better
+way to push characters up to the ldisc.
+
+Signed-off-by: Michael Schmitz <schmitz@debian.org>
+Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ drivers/char/Makefile | 1
+ drivers/char/atari_scc.c | 1701 +++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 1702 insertions(+)
+
+--- linux-m68k-2.6.21.orig/drivers/char/Makefile
++++ linux-m68k-2.6.21/drivers/char/Makefile
+@@ -29,6 +29,7 @@ obj-$(CONFIG_DIGIEPCA) += epca.o
+ obj-$(CONFIG_SPECIALIX) += specialix.o
+ obj-$(CONFIG_MOXA_INTELLIO) += moxa.o
+ obj-$(CONFIG_A2232) += ser_a2232.o generic_serial.o
++obj-$(CONFIG_ATARI_SCC) += atari_scc.o generic_serial.o
+ obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o
+ obj-$(CONFIG_MOXA_SMARTIO) += mxser.o
+ obj-$(CONFIG_MOXA_SMARTIO_NEW) += mxser_new.o
+--- /dev/null
++++ linux-m68k-2.6.21/drivers/char/atari_scc.c
+@@ -0,0 +1,1701 @@
++/*
++ * drivers/char/atari_scc.c: Atari TT/Falcon Am8530 SCC serial ports implementation.
++ *
++ * Copyright 2005 Michael Schmitz
++ *
++ * Based on:
++ * drivers/char/vme_scc.c: MVME147, MVME162, BVME6000 SCC serial ports
++ * implementation.
++ * Copyright 1999 Richard Hirst <richard@sleepie.demon.co.uk>
++ *
++ * which, in turn, was
++ *
++ * Based on atari_SCC.c which was
++ * Copyright 1994-95 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
++ * Partially based on PC-Linux serial.c by Linus Torvalds and Theodore Ts'o
++ *
++ * 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/module.h>
++#include <linux/kdev_t.h>
++#include <asm/io.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/ioport.h>
++#include <linux/interrupt.h>
++#include <linux/errno.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/mm.h>
++#include <linux/serial.h>
++#include <linux/fcntl.h>
++#include <linux/major.h>
++#include <linux/delay.h>
++#include <linux/slab.h>
++#include <linux/miscdevice.h>
++#include <linux/console.h>
++#include <linux/init.h>
++#include <asm/setup.h>
++#include <asm/uaccess.h>
++#include <asm/bootinfo.h>
++
++#include <asm/atarihw.h>
++#include <asm/atariints.h>
++
++#include <linux/generic_serial.h>
++#include "scc.h"
++
++#define CONFIG_TT_SCC 1
++#define CONFIG_FALCON_SCC 1
++
++#define CHANNEL_A 0
++#define CHANNEL_B 1
++
++#define SCC_MINOR_BASE 64
++
++/* Shadows for all SCC write registers */
++static unsigned char scc_shadow[2][16];
++
++/* Location to access for SCC register access delay */
++static volatile unsigned char *scc_del = NULL;
++
++/* To keep track of STATUS_REG state for detection of Ext/Status int source */
++static unsigned char scc_last_status_reg[2];
++
++/***************************** Prototypes *****************************/
++
++/* Function prototypes */
++static void scc_disable_tx_interrupts(void *ptr);
++static void scc_enable_tx_interrupts(void *ptr);
++static void scc_disable_rx_interrupts(void *ptr);
++static void scc_enable_rx_interrupts(void *ptr);
++static int scc_get_CD(void *ptr);
++static void scc_shutdown_port(void *ptr);
++static int scc_set_real_termios(void *ptr);
++static void scc_hungup(void *ptr);
++static void scc_close(void *ptr);
++static int scc_chars_in_buffer(void *ptr);
++static int scc_open(struct tty_struct *tty, struct file *filp);
++static int scc_ioctl(struct tty_struct *tty, struct file *filp,
++ unsigned int cmd, unsigned long arg);
++static void scc_throttle(struct tty_struct *tty);
++static void scc_unthrottle(struct tty_struct *tty);
++static irqreturn_t scc_tx_int(int irq, void *data);
++static irqreturn_t scc_rx_int(int irq, void *data);
++static irqreturn_t scc_stat_int(int irq, void *data);
++static irqreturn_t scc_spcond_int(int irq, void *data);
++static void scc_setsignals(struct scc_port *port, int dtr, int rts);
++static void scc_break_ctl(struct tty_struct *tty, int break_state);
++
++static struct tty_driver *scc_driver;
++
++struct scc_port scc_ports[2];
++
++int scc_initialized = 0;
++
++/*
++ * Flags to indicate one of the serial ports has already been initialized by the
++ * serial debug driver. We may want to hold off reinitializing ...
++ */
++
++/* Flag that Modem1 port is already initialized and used */
++extern int atari_SCC_init_done;
++/* Can be set somewhere, if a SCC master reset has already be done and should
++ * not be repeated; used by kgdb */
++extern int atari_SCC_reset_done;
++
++/*---------------------------------------------------------------------------
++ * Interface from generic_serial.c back here
++ *--------------------------------------------------------------------------*/
++
++static struct real_driver scc_real_driver = {
++ .disable_tx_interrupts = scc_disable_tx_interrupts,
++ .enable_tx_interrupts = scc_enable_tx_interrupts,
++ .disable_rx_interrupts = scc_disable_rx_interrupts,
++ .enable_rx_interrupts = scc_enable_rx_interrupts,
++ .get_CD = scc_get_CD,
++ .shutdown_port = scc_shutdown_port,
++ .set_real_termios = scc_set_real_termios,
++ .chars_in_buffer = scc_chars_in_buffer,
++ .close = scc_close,
++ .hungup = scc_hungup,
++};
++
++static struct tty_operations scc_ops = {
++ .open = scc_open,
++ .close = gs_close,
++ .write = gs_write,
++ .put_char = gs_put_char,
++ .flush_chars = gs_flush_chars,
++ .write_room = gs_write_room,
++ .chars_in_buffer = gs_chars_in_buffer,
++ .flush_buffer = gs_flush_buffer,
++ .ioctl = scc_ioctl,
++ .throttle = scc_throttle,
++ .unthrottle = scc_unthrottle,
++ .set_termios = gs_set_termios,
++ .stop = gs_stop,
++ .start = gs_start,
++ .hangup = gs_hangup,
++ .break_ctl = scc_break_ctl,
++};
++
++/* BRG values for the standard speeds and the various clock sources */
++
++typedef struct {
++ unsigned clksrc; /* clock source to use or -1 for not possible */
++ unsigned div; /* divisor: 1, 2 and 4 correspond to
++ * direct 1:16, 1:32 and 1:64 modes,
++ * divisors >= 4 yield a BRG value of
++ * div/2-2 (in 1:16 mode)
++ */
++} BAUD_ENTRY;
++
++/* A pointer for each channel to the current baud table */
++static BAUD_ENTRY *scc_baud_table[2];
++
++/* Baud table format:
++ *
++ * Each entry consists of the clock source (CLK_RTxC, CLK_TRxC or
++ * CLK_PCLK) and a divisor. The following rules apply to the divisor:
++ *
++ * - CLK_RTxC: 1 or even (1, 2 and 4 are the direct modes, > 4 use
++ * the BRG)
++ *
++ * - CLK_TRxC: 1, 2 or 4 (no BRG, only direct modes possible)
++ *
++ * - CLK_PCLK: >= 4 and even (no direct modes, only BRG)
++ *
++ */
++
++/* This table is used if RTxC = 3.672 MHz. This is the case for TT's
++ * channel A and for both channels on the Mega STE/Falcon. (TRxC is unused)
++ */
++
++static BAUD_ENTRY bdtab_norm[20] = {
++ /* B0 */ { 0, 0 },
++ /* B50 */ { CLK_RTxC, 4590 },
++ /* B75 */ { CLK_RTxC, 3060 },
++ /* B110 */ { CLK_PCLK, 4576 },
++ /* B134 */ { CLK_PCLK, 3756 },
++ /* B150 */ { CLK_RTxC, 1530 },
++ /* B200 */ { CLK_PCLK, 2516 },
++ /* B300 */ { CLK_PCLK, 1678 },
++ /* B600 */ { CLK_PCLK, 838 },
++ /* B1200 */ { CLK_PCLK, 420 },
++ /* B1800 */ { CLK_PCLK, 280 },
++ /* B2400 */ { CLK_PCLK, 210 },
++ /* B4800 */ { CLK_RTxC, 48 },
++ /* B9600 */ { CLK_RTxC, 24 },
++ /* B19200 */ { CLK_RTxC, 12 },
++ /* B38400 */ { CLK_RTxC, 6 }, /* #15 spd_extra */
++ /* B57600 */ { CLK_RTxC, 4 }, /* #16 spd_hi */
++ /* B115200 */ { CLK_RTxC, 2 }, /* #17 spd_vhi */
++ /* B230400 */ { CLK_RTxC, 1 }, /* #18 spd_shi */
++ /* B460800 */ { 0, 0 } /* #19 spd_warp: Impossible */
++};
++
++/* This is a special table for the TT channel B with 307.2 kHz at RTxC
++ * and 2.4576 MHz at TRxC
++ */
++static BAUD_ENTRY bdtab_TTChB[20] = {
++ /* B0 */ { 0, 0 },
++ /* B50 */ { CLK_RTxC, 384 },
++ /* B75 */ { CLK_RTxC, 256 },
++ /* B110 */ { CLK_PCLK, 4576 },
++ /* B134 */ { CLK_PCLK, 3756 },
++ /* B150 */ { CLK_RTxC, 128 },
++ /* B200 */ { CLK_RTxC, 96 },
++ /* B300 */ { CLK_RTxC, 64 },
++ /* B600 */ { CLK_RTxC, 32 },
++ /* B1200 */ { CLK_RTxC, 16 },
++ /* B1800 */ { CLK_PCLK, 280 },
++ /* B2400 */ { CLK_RTxC, 8 },
++ /* B4800 */ { CLK_RTxC, 4 },
++ /* B9600 */ { CLK_RTxC, 2 },
++ /* B19200 */ { CLK_RTxC, 1 },
++ /* B38400 */ { CLK_TRxC, 4 },
++ /* B57600 */ { CLK_TRxC, 2 }, /* 57600 is not possible, use 76800 instead */
++ /* B115200 */ { CLK_TRxC, 1 }, /* 115200 is not possible, use 153600 instead */
++ /* B230400 */ { 0, 0 }, /* #18 spd_shi: Impossible */
++ /* B460800 */ { 0, 0 } /* #19 spd_warp: Impossible */
++};
++
++
++/*----------------------------------------------------------------------------
++ * atari_scc_init() and support functions
++ *---------------------------------------------------------------------------*/
++
++static int scc_init_drivers(void)
++{
++ int error;
++
++ scc_driver = alloc_tty_driver(2);
++ if (!scc_driver)
++ return -ENOMEM;
++ scc_driver->owner = THIS_MODULE;
++ scc_driver->driver_name = "scc";
++ scc_driver->name = "ttyS";
++ scc_driver->major = TTY_MAJOR;
++ scc_driver->minor_start = SCC_MINOR_BASE;
++ scc_driver->type = TTY_DRIVER_TYPE_SERIAL;
++ scc_driver->subtype = SERIAL_TYPE_NORMAL;
++ scc_driver->init_termios = tty_std_termios;
++ scc_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
++ scc_driver->flags = TTY_DRIVER_REAL_RAW;
++
++ tty_set_operations(scc_driver, &scc_ops);
++
++ if ((error = tty_register_driver(scc_driver))) {
++ printk(KERN_ERR "scc: Couldn't register scc driver, error = %d\n",
++ error);
++ put_tty_driver(scc_driver);
++ return 1;
++ }
++
++ return 0;
++}
++
++
++/* ports[] array is indexed by line no (i.e. [0] for ttyS0, [1] for ttyS1).
++ */
++
++static void scc_init_portstructs(void)
++{
++ struct scc_port *port;
++ int i;
++
++ for (i = 0; i < 2; i++) {
++ port = scc_ports + i;
++ port->gs.magic = SCC_MAGIC;
++ port->gs.close_delay = HZ/2;
++ port->gs.closing_wait = 30 * HZ;
++ port->gs.rd = &scc_real_driver;
++#ifdef NEW_WRITE_LOCKING
++ port->gs.port_write_sem = MUTEX;
++#endif
++ init_waitqueue_head(&port->gs.open_wait);
++ init_waitqueue_head(&port->gs.close_wait);
++ }
++}
++
++
++#ifdef CONFIG_TT_SCC
++static int atari_tt_scc_init(void)
++{
++ struct scc_port *port;
++
++ printk(KERN_INFO "SCC: Atari TT Serial Driver\n");
++ /* FIXME channel A may be switchable between modem and LAN port */
++ /* Init channel A */
++ if (atari_SCC_init_done)
++ printk(KERN_INFO "SCC: already initialized, expect trouble!\n");
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: init channel A\n");
++#endif
++ port = &scc_ports[0];
++ port->channel = CHANNEL_A;
++ port->ctrlp = (volatile unsigned char *)&scc.cha_a_ctrl;
++ port->datap = port->ctrlp + 1;
++ port->port_a = &scc_ports[0];
++ port->port_b = &scc_ports[1];
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: request channel A irqs, port = %p\n", port);
++#endif
++ request_irq(IRQ_SCCA_TX, scc_tx_int, IRQ_TYPE_PRIO, "SCC-A TX", port);
++ request_irq(IRQ_SCCA_STAT, scc_stat_int, IRQ_TYPE_PRIO,
++ "SCC-A status", port);
++ request_irq(IRQ_SCCA_RX, scc_rx_int, IRQ_TYPE_PRIO, "SCC-A RX", port);
++ request_irq(IRQ_SCCA_SPCOND, scc_spcond_int, IRQ_TYPE_PRIO,
++ "SCC-A special cond", port);
++ {
++ SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: read SCC status\n");
++#endif
++ /* on the first access, read status register to reset internal pointers */
++ SCCread(STATUS_REG);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: reset SCC\n");
++#endif
++ /* FIXME: master reset, once only */
++ SCCwrite(MASTER_INT_CTRL, MIC_HARD_RESET);
++ udelay(40);
++
++ /* disable interrupts for this channel */
++ SCCwrite(INT_AND_DMA_REG, 0);
++ /* Set the interrupt vector ; 0x60 for all Atari models */
++ SCCwrite(INT_VECTOR_REG, 0x60);
++ /* Interrupt parameters: vector includes status, status low */
++ SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT);
++ SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB);
++
++ /* disable interrupts for this channel */
++ SCCwrite(INT_AND_DMA_REG, 0);
++ }
++
++ if (!atari_SCC_init_done) {
++ /* Init channel B */
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: init channel B\n");
++#endif
++ port = &scc_ports[1];
++ port->channel = CHANNEL_B;
++ port->ctrlp = (volatile unsigned char *)&scc.cha_b_ctrl;
++ port->datap = port->ctrlp + 1;
++ port->port_a = &scc_ports[0];
++ port->port_b = &scc_ports[1];
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: request channel B irqs, port = %p\n", port);
++#endif
++ request_irq(IRQ_SCCB_TX, scc_tx_int, IRQ_TYPE_PRIO,
++ "SCC-B TX", port);
++ request_irq(IRQ_SCCB_STAT, scc_stat_int, IRQ_TYPE_PRIO,
++ "SCC-B status", port);
++ request_irq(IRQ_SCCB_RX, scc_rx_int, IRQ_TYPE_PRIO,
++ "SCC-B RX", port);
++ request_irq(IRQ_SCCB_SPCOND, scc_spcond_int, IRQ_TYPE_PRIO,
++ "SCC-B special cond", port);
++ {
++ SCC_ACCESS_INIT(port);
++
++ /* disable interrupts for this channel */
++ SCCwrite(INT_AND_DMA_REG, 0);
++ }
++/* not implemented yet */
++#if 0
++ request_irq(IRQ_TT_MFP_RI, scc_ri_int, IRQ_TYPE_SLOW,
++ "TT-MFP ring indicator (modem 2)", port);
++#endif
++
++ }
++
++ /* once only: initalize MFP timer C for RTxC */
++ tt_mfp.tim_ct_cd = (tt_mfp.tim_ct_cd & ~0x70) | 0x10;
++ tt_mfp.tim_dt_c = 1;
++ atari_turnoff_irq(IRQ_TT_MFP_TIMC);
++
++ /* set baud tables */
++ scc_baud_table[CHANNEL_A] = bdtab_norm;
++ scc_baud_table[CHANNEL_B] = bdtab_TTChB;
++
++ /* Initialise the tty driver structures and register */
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: scc_init_portstructs()\n");
++#endif
++ scc_init_portstructs();
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: scc_init_drivers()\n");
++#endif
++ scc_init_drivers();
++
++ return 0;
++}
++#endif
++
++
++#ifdef CONFIG_FALCON_SCC
++static int atari_falcon_scc_init(void)
++{
++ struct scc_port *port;
++
++ printk(KERN_INFO "SCC: Atari Falcon Serial Driver\n");
++ if (atari_SCC_init_done)
++ printk(KERN_INFO "SCC: already initialized, expect trouble!\n");
++
++ /* Init channel A */
++ port = &scc_ports[0];
++ port->channel = CHANNEL_A;
++ port->ctrlp = (volatile unsigned char *)&scc.cha_a_ctrl;
++ port->datap = port->ctrlp + 2;
++ port->port_a = &scc_ports[0];
++ port->port_b = &scc_ports[1];
++ request_irq(IRQ_SCCA_TX, scc_tx_int, IRQ_TYPE_PRIO, "SCC-A TX", port);
++ request_irq(IRQ_SCCA_STAT, scc_stat_int, IRQ_TYPE_PRIO,
++ "SCC-A status", port);
++ request_irq(IRQ_SCCA_RX, scc_rx_int, IRQ_TYPE_PRIO, "SCC-A RX", port);
++ request_irq(IRQ_SCCA_SPCOND, scc_spcond_int, IRQ_TYPE_PRIO,
++ "SCC-A special cond", port);
++ {
++ SCC_ACCESS_INIT(port);
++
++ /* on the first access, read status register to reset internal pointers */
++ SCCread(STATUS_REG);
++
++ /* FIXME: master reset, once only */
++ SCCwrite(MASTER_INT_CTRL, MIC_HARD_RESET);
++ udelay(40);
++
++ /* disable interrupts for this channel */
++ SCCwrite(INT_AND_DMA_REG, 0);
++ /* Set the interrupt vector */
++ SCCwrite(INT_VECTOR_REG, 0x60);
++ /* Interrupt parameters: vector includes status, status low */
++ SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT);
++ SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB);
++ }
++
++ /* conditionalize if port in use by console ?? */
++ /* Init channel B */
++ port = &scc_ports[1];
++ port->channel = CHANNEL_B;
++ port->ctrlp = (volatile unsigned char *)&scc.cha_b_ctrl;
++ port->datap = port->ctrlp + 2;
++ port->port_a = &scc_ports[0];
++ port->port_b = &scc_ports[1];
++ request_irq(IRQ_SCCB_TX, scc_tx_int, IRQ_TYPE_PRIO, "SCC-B TX", port);
++ request_irq(IRQ_SCCB_STAT, scc_stat_int, IRQ_TYPE_PRIO,
++ "SCC-B status", port);
++ request_irq(IRQ_SCCB_RX, scc_rx_int, IRQ_TYPE_PRIO, "SCC-B RX", port);
++ request_irq(IRQ_SCCB_SPCOND, scc_spcond_int, IRQ_TYPE_PRIO,
++ "SCC-B special cond", port);
++
++ {
++ SCC_ACCESS_INIT(port); /* Either channel will do */
++
++ /* disable interrupts for this channel */
++ SCCwrite(INT_AND_DMA_REG, 0);
++ }
++
++ /* set baud tables */
++ scc_baud_table[CHANNEL_A] = bdtab_norm;
++ scc_baud_table[CHANNEL_B] = bdtab_norm;
++
++ /* Initialise the tty driver structures and register */
++ scc_init_portstructs();
++ scc_init_drivers();
++
++ return 0;
++}
++#endif
++
++
++#ifdef CONFIG_ST_SCC
++static int atari_st_scc_init(void)
++{
++ struct scc_port *port;
++
++ int escc = ATARIHW_PRESENT(ST_ESCC);
++
++ printk(KERN_INFO "SCC: Atari MegaST/E Serial Driver\n");
++ /* FIXME: ports reversed logic */
++ /* Init channel A */
++ port = &scc_ports[1];
++ port->channel = CHANNEL_A;
++ port->ctrlp = (volatile unsigned char *)(escc ? &st_escc.cha_a_ctrl : &scc.cha_a_ctrl);
++ port->datap = port->ctrlp + 4;
++ port->port_a = &scc_ports[1];
++ port->port_b = &scc_ports[0];
++ request_irq(IRQ_SCCA_TX, scc_tx_int, IRQ_TYPE_PRIO, "SCC-A TX", port);
++ request_irq(IRQ_SCCA_STAT, scc_stat_int, IRQ_TYPE_PRIO,
++ "SCC-A status", port);
++ request_irq(IRQ_SCCA_RX, scc_rx_int, IRQ_TYPE_PRIO, "SCC-A RX", port);
++ request_irq(SCCA_SPCOND, scc_spcond_int, IRQ_TYPE_PRIO,
++ "SCC-A special cond", port);
++ {
++ SCC_ACCESS_INIT(port);
++
++ /* on the first access, read status register to reset internal pointers */
++ SCCread(STATUS_REG);
++
++ /* FIXME: master reset, once only */
++ SCCwrite(MASTER_INT_CTRL, MIC_HARD_RESET);
++ udelay(40);
++
++ /* disable interrupts for this channel */
++ SCCwrite(INT_AND_DMA_REG, 0);
++ /* Set the interrupt vector */
++ SCCwrite(INT_VECTOR_REG, BVME_IRQ_SCC_BASE);
++ /* Interrupt parameters: vector includes status, status low */
++ SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT);
++ SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB);
++ }
++
++ /* Init channel B */
++ port = &scc_ports[0];
++ port->channel = CHANNEL_B;
++ port->ctrlp = (volatile unsigned char *)(escc ? &st_escc.cha_b_ctrl : &scc.cha_b_ctrl);
++ port->datap = port->ctrlp + 4;
++ port->port_a = &scc_ports[0];
++ port->port_b = &scc_ports[1];
++ request_irq(IRQ_SCCB_TX, scc_tx_int, IRQ_TYPE_PRIO, "SCC-B TX", port);
++ request_irq(IRQ_SCCB_STAT, scc_stat_int, IRQ_TYPE_PRIO,
++ "SCC-B status", port);
++ request_irq(IRQ_SCCB_RX, scc_rx_int, IRQ_TYPE_PRIO, "SCC-B RX", port);
++ request_irq(IRQ_SCCB_SPCOND, scc_spcond_int, IRQ_TYPE_PRIO,
++ "SCC-B special cond", port);
++
++ {
++ SCC_ACCESS_INIT(port); /* Either channel will do */
++
++ /* disable interrupts for this channel */
++ SCCwrite(INT_AND_DMA_REG, 0);
++ }
++
++ /* set baud tables */
++ scc_baud_table[CHANNEL_A] = bdtab_norm;
++ scc_baud_table[CHANNEL_B] = bdtab_norm;
++
++ /* Initialise the tty driver structures and register */
++ scc_init_portstructs();
++ scc_init_drivers();
++
++ return 0;
++}
++#endif
++
++
++int atari_scc_init(void)
++{
++ int res = -ENODEV;
++ static int called = 0;
++
++ if (called)
++ return res;
++ called = 1;
++
++ if (!(ATARIHW_PRESENT(SCC) || ATARIHW_PRESENT(ST_ESCC)))
++ return -ENODEV;
++
++ scc_del = &mfp.par_dt_reg;
++
++#ifdef CONFIG_TT_SCC
++ if (MACH_IS_TT)
++ res = atari_tt_scc_init();
++#endif
++#ifdef CONFIG_FALCON_SCC
++ if (MACH_IS_FALCON)
++ res = atari_falcon_scc_init();
++#endif
++#ifdef CONFIG_ST_SCC
++ if (MACH_IS_ST)
++ res = atari_st_scc_init();
++#endif
++ return res;
++}
++
++void atari_scc_cleanup(void)
++{
++ struct scc_port *port;
++
++ tty_unregister_driver(scc_driver);
++ port = &scc_ports[0];
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: free channel A irqs, port = %p\n", port);
++#endif
++ free_irq(IRQ_SCCA_TX, port);
++ free_irq(IRQ_SCCA_STAT, port);
++ free_irq(IRQ_SCCA_RX, port);
++ free_irq(IRQ_SCCA_SPCOND, port);
++
++ port = &scc_ports[1];
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: free channel A irqs, port = %p\n", port);
++#endif
++ free_irq(IRQ_SCCB_TX, port);
++ free_irq(IRQ_SCCB_STAT, port);
++ free_irq(IRQ_SCCB_RX, port);
++ free_irq(IRQ_SCCB_SPCOND, port);
++
++}
++
++module_init(atari_scc_init);
++module_exit(atari_scc_cleanup);
++
++/*---------------------------------------------------------------------------
++ * Interrupt handlers
++ *--------------------------------------------------------------------------*/
++
++static irqreturn_t scc_rx_int(int irq, void *data)
++{
++ unsigned char ch;
++ struct scc_port *port = data;
++ struct tty_struct *tty = port->gs.tty;
++ SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: rx_int ...\n");
++#endif
++ ch = SCCread_NB(RX_DATA_REG);
++ if (!tty) {
++ printk(KERN_WARNING "scc_rx_int with NULL tty!\n");
++ SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
++ return IRQ_HANDLED;
++ }
++ tty_insert_flip_char(tty, ch, 0);
++#if 0
++ if (tty->flip.count < TTY_FLIPBUF_SIZE) {
++ *tty->flip.char_buf_ptr = ch;
++ *tty->flip.flag_buf_ptr = 0;
++ tty->flip.flag_buf_ptr++;
++ tty->flip.char_buf_ptr++;
++ tty->flip.count++;
++ }
++#endif
++ /* Check if another character is already ready; in that case, the
++ * spcond_int() function must be used, because this character may have an
++ * error condition that isn't signalled by the interrupt vector used!
++ */
++ if (SCCread(INT_PENDING_REG) &
++ (port->channel == CHANNEL_A ? IPR_A_RX : IPR_B_RX)) {
++ scc_spcond_int(irq, data);
++ return IRQ_HANDLED;
++ }
++
++ SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
++
++ tty_flip_buffer_push(tty);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: rx_int done\n");
++#endif
++ return IRQ_HANDLED;
++}
++
++
++static irqreturn_t scc_spcond_int(int irq, void *data)
++{
++ struct scc_port *port = data;
++ struct tty_struct *tty = port->gs.tty;
++ unsigned char stat, ch, err;
++ int int_pending_mask = port->channel == CHANNEL_A ? IPR_A_RX : IPR_B_RX;
++
++ SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: spcond_int ...\n");
++#endif
++ if (!tty) {
++ printk(KERN_WARNING "scc_spcond_int with NULL tty!\n");
++ SCCwrite(COMMAND_REG, CR_ERROR_RESET);
++ SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
++ return IRQ_HANDLED;
++ }
++ do {
++ stat = SCCread(SPCOND_STATUS_REG);
++ ch = SCCread_NB(RX_DATA_REG);
++
++ if (stat & SCSR_RX_OVERRUN)
++ err = TTY_OVERRUN;
++ else if (stat & SCSR_PARITY_ERR)
++ err = TTY_PARITY;
++ else if (stat & SCSR_CRC_FRAME_ERR)
++ err = TTY_FRAME;
++ else
++ err = 0;
++
++ tty_insert_flip_char(tty, ch, err);
++#if 0
++ if (tty->flip.count < TTY_FLIPBUF_SIZE) {
++ *tty->flip.char_buf_ptr = ch;
++ *tty->flip.flag_buf_ptr = err;
++ tty->flip.flag_buf_ptr++;
++ tty->flip.char_buf_ptr++;
++ tty->flip.count++;
++ }
++#endif
++ /* ++TeSche: *All* errors have to be cleared manually,
++ * else the condition persists for the next chars
++ */
++ if (err)
++ SCCwrite(COMMAND_REG, CR_ERROR_RESET);
++
++ } while (SCCread(INT_PENDING_REG) & int_pending_mask);
++
++ SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
++
++ tty_flip_buffer_push(tty);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: spcond_int done\n");
++#endif
++ return IRQ_HANDLED;
++}
++
++/* not implemented yet */
++#if 0
++static void scc_ri_int(int irq, void *data)
++{
++ struct scc_port *port = data;
++ /* update input line counter */
++ port->icount.rng++;
++ wake_up_interruptible(&port->delta_msr_wait);
++}
++#endif
++
++static irqreturn_t scc_tx_int(int irq, void *data)
++{
++ struct scc_port *port = data;
++ SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: tx_int irq %d port %p ...\n", irq, data);
++#endif
++ if (!port->gs.tty) {
++ printk(KERN_WARNING "scc_tx_int with NULL tty!\n");
++ SCCmod(INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0);
++ SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET);
++ SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
++ return IRQ_HANDLED;
++ }
++ while ((SCCread_NB(STATUS_REG) & SR_TX_BUF_EMPTY)) {
++ if (port->x_char) {
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: tx_int writing char %c\n",
++ port->x_char);
++#endif
++ SCCwrite(TX_DATA_REG, port->x_char);
++ port->x_char = 0;
++ } else if ((port->gs.xmit_cnt <= 0) || port->gs.tty->stopped ||
++ port->gs.tty->hw_stopped) {
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: nothing to do!\n");
++#endif
++ break;
++ } else {
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: tx_int writing buf %c\n",
++ port->gs.xmit_buf[port->gs.xmit_tail]);
++#endif
++ SCCwrite(TX_DATA_REG, port->gs.xmit_buf[port->gs.xmit_tail++]);
++ port->gs.xmit_tail = port->gs.xmit_tail & (SERIAL_XMIT_SIZE-1);
++ if (--port->gs.xmit_cnt <= 0)
++ break;
++ }
++ }
++ if ((port->gs.xmit_cnt <= 0) || port->gs.tty->stopped ||
++ port->gs.tty->hw_stopped) {
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: nothing to do, disabling int\n");
++#endif
++ /* disable tx interrupts */
++ SCCmod(INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0);
++ SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET); /* disable tx_int on next tx underrun? */
++ port->gs.flags &= ~GS_TX_INTEN;
++ }
++ if (port->gs.tty && port->gs.xmit_cnt <= port->gs.wakeup_chars) {
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: waking up tty!\n");
++#endif
++ tty_wakeup(port->gs.tty);
++ }
++
++ SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: tx_int done\n");
++#endif
++ return IRQ_HANDLED;
++}
++
++
++static irqreturn_t scc_stat_int(int irq, void *data)
++{
++ struct scc_port *port = data;
++ unsigned channel = port->channel;
++ unsigned char last_sr, sr, changed;
++ SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: stat_int ...\n");
++#endif
++ last_sr = scc_last_status_reg[channel];
++ sr = scc_last_status_reg[channel] = SCCread_NB(STATUS_REG);
++ changed = last_sr ^ sr;
++
++ if (changed & SR_DCD) {
++ port->c_dcd = !!(sr & SR_DCD);
++ if (!(port->gs.flags & ASYNC_CHECK_CD))
++ ; /* Don't report DCD changes */
++ else if (port->c_dcd) {
++ /* Are we blocking in open? */
++ wake_up_interruptible(&port->gs.open_wait);
++ } else {
++ if (port->gs.tty)
++ tty_hangup(port->gs.tty);
++ }
++ }
++
++ // FIXME: CTS and DSR status changes?
++
++ SCCwrite(COMMAND_REG, CR_EXTSTAT_RESET);
++ SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: stat_int done\n");
++#endif
++ return IRQ_HANDLED;
++}
++
++
++/*---------------------------------------------------------------------------
++ * generic_serial.c callback funtions
++ *--------------------------------------------------------------------------*/
++
++static void scc_disable_tx_interrupts(void *ptr)
++{
++ struct scc_port *port = ptr;
++ unsigned long flags;
++ SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: disable_tx_int ...\n");
++#endif
++ local_irq_save(flags);
++ SCCmod(INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0);
++ port->gs.flags &= ~GS_TX_INTEN;
++ local_irq_restore(flags);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: disable_tx_int done!\n");
++#endif
++}
++
++
++static void scc_enable_tx_interrupts(void *ptr)
++{
++ struct scc_port *port = ptr;
++ unsigned long flags;
++
++ SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: enable_tx_int ...\n");
++#endif
++ local_irq_save(flags);
++ SCCmod(INT_AND_DMA_REG, 0xff, IDR_TX_INT_ENAB);
++ /* restart the transmitter */
++ scc_tx_int(0, port);
++ local_irq_restore(flags);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: enable_tx_int done!\n");
++#endif
++}
++
++
++static void scc_disable_rx_interrupts(void *ptr)
++{
++ struct scc_port *port = ptr;
++ unsigned long flags;
++
++ SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: disable_rx_int ...\n");
++#endif
++ local_irq_save(flags);
++ SCCmod(INT_AND_DMA_REG,
++ ~(IDR_RX_INT_MASK|IDR_PARERR_AS_SPCOND|IDR_EXTSTAT_INT_ENAB), 0);
++ local_irq_restore(flags);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: disable_rx_int done!\n");
++#endif
++}
++
++
++static void scc_enable_rx_interrupts(void *ptr)
++{
++ struct scc_port *port = ptr;
++ unsigned long flags;
++
++ SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: enable_rx_int ...\n");
++#endif
++ local_irq_save(flags);
++ SCCmod(INT_AND_DMA_REG, 0xff,
++ IDR_EXTSTAT_INT_ENAB|IDR_PARERR_AS_SPCOND|IDR_RX_INT_ALL);
++ local_irq_restore(flags);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: enable_rx_int done!\n");
++#endif
++}
++
++
++static int scc_get_CD(void *ptr)
++{
++ struct scc_port *port = ptr;
++ unsigned channel = port->channel;
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: get_CD!\n");
++#endif
++ return !!(scc_last_status_reg[channel] & SR_DCD);
++}
++
++
++static void scc_shutdown_port(void *ptr)
++{
++ struct scc_port *port = ptr;
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: shutdown_port ...\n");
++#endif
++ port->gs.flags &= ~GS_ACTIVE;
++ if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL)
++ scc_setsignals(port, 0, 0);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: shutdown_port done!\n");
++#endif
++}
++
++
++static int scc_set_real_termios(void *ptr)
++{
++ /* the SCC has char sizes 5,7,6,8 in that order! */
++ static int chsize_map[4] = { 0, 2, 1, 3 };
++ unsigned int cflag, baud, baudbits, baudidx, brgmode;
++ unsigned int clkmode, clksrc, div, chsize, channel, brgval = 0;
++ unsigned long flags;
++ struct scc_port *port = ptr;
++ SCC_ACCESS_INIT(port);
++
++ if (!port->gs.tty || !port->gs.tty->termios)
++ return 0;
++
++ channel = port->channel;
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: termios for channel %p\n", channel);
++#endif
++ cflag = port->gs.tty->termios->c_cflag;
++ baud = port->gs.baud;
++ baudbits = cflag & CBAUD;
++ chsize = (cflag & CSIZE) >> 4;
++
++ if (baud == 0) {
++ /* speed == 0 -> drop DTR */
++ local_irq_save(flags);
++ SCCmod(TX_CTRL_REG, ~TCR_DTR, 0);
++ local_irq_restore(flags);
++ return 0;
++ } else if ((MACH_IS_TT && (baud < 50 || baud > 115200)) ||
++ (MACH_IS_FALCON && (baud < 50 || baud > 230400))) {
++ printk(KERN_NOTICE "SCC: Bad speed requested, %d\n", baud);
++ return 0;
++ }
++
++ if (cflag & CLOCAL)
++ port->gs.flags &= ~ASYNC_CHECK_CD;
++ else
++ port->gs.flags |= ASYNC_CHECK_CD;
++
++ // calculate brgval for Atari; enable direct modes!
++
++ /* convert baud rate from gs.baud to table index, set custom divisor eventually */
++
++ div = 0;
++ clksrc = 0;
++ baudidx = 0;
++
++ switch (baud) {
++ case 50:
++ baudidx = 1;
++ break;
++ case 75:
++ baudidx = 2;
++ break;
++ case 110:
++ baudidx = 3;
++ break;
++ case 134:
++ baudidx = 4;
++ break;
++ case 150:
++ baudidx = 5;
++ break;
++ case 200:
++ baudidx = 6;
++ break;
++ case 300:
++ baudidx = 7;
++ break;
++ case 600:
++ baudidx = 8;
++ break;
++ case 1200:
++ baudidx = 9;
++ break;
++ case 1800:
++ baudidx = 10;
++ break;
++ case 2400:
++ baudidx = 11;
++ break;
++ case 4800:
++ baudidx = 12;
++ break;
++ case 9600:
++ baudidx = 13;
++ break;
++ case 19200:
++ baudidx = 14;
++ break;
++ case 38400:
++ baudidx = 15;
++ break;
++ case 57600:
++ baudidx = 16;
++ break;
++ case 115200:
++ baudidx = 17;
++ break;
++ case 230400:
++ baudidx = 18;
++ break;
++ default:
++ baudidx = 15;
++ break;
++ }
++
++ /* do we have a custom divisor ?? */
++ if (!div) {
++ if (baudidx > 19)
++ baudidx = 19;
++ clksrc = scc_baud_table[channel][baudidx].clksrc;
++ div = scc_baud_table[channel][baudidx].div;
++ if (!div) {
++ printk(" SCC_change_speed: divisor = 0 !!!");
++ return 0;
++ }
++ }
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: termios baud %d baudbits %d baudidx %d \n clksrc %d div %d\n",
++ baud, baudbits, baudidx, clksrc, div);
++#endif
++ /* compute the SCC's clock source, clock mode, BRG mode and BRG
++ * value from clksrc and div
++ */
++ if (div <= 4) {
++ clkmode = (div == 1 ? A1CR_CLKMODE_x16 :
++ div == 2 ? A1CR_CLKMODE_x32 :
++ A1CR_CLKMODE_x64);
++ clksrc = (clksrc == CLK_RTxC
++ ? CCR_TXCLK_RTxC | CCR_RXCLK_RTxC
++ : CCR_TXCLK_TRxC | CCR_RXCLK_TRxC);
++ brgmode = 0; /* off */
++ brgval = 0;
++ } else {
++ brgval = div/2 - 2;
++ brgmode = (DCR_BRG_ENAB |
++ (clksrc == CLK_PCLK ? DCR_BRG_USE_PCLK : 0));
++ clkmode = A1CR_CLKMODE_x16;
++ clksrc = CCR_TXCLK_BRG | CCR_RXCLK_BRG;
++ }
++
++ //printk(KERN_INFO "SCC: termios baud %d baudbits %d baudidx %d \n clksrc %d clkmode %d div %d brgval %d brgmode %d\n",
++ // baud, baudbits, baudidx, clksrc, clkmode, div, brgval, brgmode);
++
++ /* Now we have all parameters and can go to set them: */
++ local_irq_save(flags);
++
++#ifdef DEBUG
++ printk(" brgval=%d brgmode=%02x clkmode=%02x clksrc=%02x\n",
++ brgval, brgmode, clkmode, clksrc);
++#endif
++ /* receiver's character size and auto-enables */
++#if 0 // auto-enable considered harmful ...
++ SCCmod(RX_CTRL_REG, ~(RCR_CHSIZE_MASK|RCR_AUTO_ENAB_MODE),
++ (chsize_map[chsize] << 6) |
++ ((cflag & CRTSCTS) ? RCR_AUTO_ENAB_MODE : 0));
++#else
++ /* receiver's character size */
++ SCCmod(RX_CTRL_REG, ~RCR_CHSIZE_MASK, chsize_map[chsize] << 6);
++#endif
++#ifdef DEBUG
++ printk(" RX_CTRL_REG <- %02x\n", SCCread( RX_CTRL_REG ));
++#endif
++
++ // clock mode changes depending on baud rate
++ /* parity and stop bits (both, Tx and Rx) and clock mode */
++ SCCmod(AUX1_CTRL_REG,
++ ~(A1CR_PARITY_MASK | A1CR_MODE_MASK | A1CR_CLKMODE_MASK),
++ ((cflag & PARENB
++ ? (cflag & PARODD ? A1CR_PARITY_ODD : A1CR_PARITY_EVEN)
++ : A1CR_PARITY_NONE)
++ | (cflag & CSTOPB ? A1CR_MODE_ASYNC_2 : A1CR_MODE_ASYNC_1)
++ | clkmode));
++
++#ifdef DEBUG
++ printk(" AUX1_CTRL_REG <- %02x\n", SCCread(AUX1_CTRL_REG));
++#endif
++ /* sender's character size, set DTR for valid baud rate */
++ SCCmod(TX_CTRL_REG, ~TCR_CHSIZE_MASK, chsize_map[chsize] << 5 | TCR_DTR);
++#ifdef DEBUG
++ printk(" TX_CTRL_REG <- %02x\n", SCCread(TX_CTRL_REG));
++#endif
++
++ // clock sources change for TT !!
++ /* clock sources never change */
++ /* clock sources */
++ SCCmod(CLK_CTRL_REG, ~(CCR_TXCLK_MASK | CCR_RXCLK_MASK), clksrc);
++#ifdef DEBUG
++ printk(" CLK_CTRL_REG <- %02x\n", SCCread(CLK_CTRL_REG));
++#endif
++
++ /* disable BRG before changing the value */
++ SCCmod(DPLL_CTRL_REG, ~DCR_BRG_ENAB, 0);
++ /* BRG value */
++ SCCwrite(TIMER_LOW_REG, brgval & 0xff);
++ SCCwrite(TIMER_HIGH_REG, (brgval >> 8) & 0xff);
++ /* BRG enable, and clock source never changes */
++ //SCCmod(DPLL_CTRL_REG, 0xff, DCR_BRG_ENAB);
++ SCCmod(DPLL_CTRL_REG, ~(DCR_BRG_ENAB | DCR_BRG_USE_PCLK), brgmode);
++#ifdef DEBUG
++ printk(" TIMER_LOW_REG <- %02x\n", SCCread(TIMER_LOW_REG));
++ printk(" TIMER_HIGH_REG <- %02x\n", SCCread(TIMER_HIGH_REG));
++#endif
++#ifdef DEBUG
++ printk(" DPLL_CTRL_REG <- %02x\n", SCCread(DPLL_CTRL_REG));
++#endif
++
++ local_irq_restore(flags);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: done termios for channel %d\n", channel);
++#endif
++ return 0;
++}
++
++
++static int scc_chars_in_buffer(void *ptr)
++{
++ struct scc_port *port = ptr;
++#ifdef DEBUG
++ int rv;
++#endif
++ SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++ rv = (SCCread(SPCOND_STATUS_REG) & SCSR_ALL_SENT) ? 0 : 1;
++ printk(KERN_INFO "SCC: chars_in_buffer: %d\n", rv);
++ return rv;
++#else
++ return (SCCread(SPCOND_STATUS_REG) & SCSR_ALL_SENT) ? 0 : 1;
++#endif
++}
++
++
++/* Comment taken from sx.c (2.4.0):
++ I haven't the foggiest why the decrement use count has to happen
++ here. The whole linux serial drivers stuff needs to be redesigned.
++ My guess is that this is a hack to minimize the impact of a bug
++ elsewhere. Thinking about it some more. (try it sometime) Try
++ running minicom on a serial port that is driven by a modularized
++ driver. Have the modem hangup. Then remove the driver module. Then
++ exit minicom. I expect an "oops". -- REW */
++
++static void scc_hungup(void *ptr)
++{
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: hungup ...\n");
++#endif
++ scc_disable_tx_interrupts(ptr);
++ scc_disable_rx_interrupts(ptr);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: hungup done\n");
++#endif
++}
++
++
++static void scc_close(void *ptr)
++{
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: close ...\n");
++#endif
++ scc_disable_tx_interrupts(ptr);
++ scc_disable_rx_interrupts(ptr);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: close done\n");
++#endif
++}
++
++
++/*---------------------------------------------------------------------------
++ * Internal support functions
++ *--------------------------------------------------------------------------*/
++
++static void scc_setsignals(struct scc_port *port, int dtr, int rts)
++{
++ unsigned long flags;
++ unsigned char t;
++ SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: setsignals dtr %d rts %d...\n", dtr, rts);
++#endif
++ local_irq_save(flags);
++ t = SCCread(TX_CTRL_REG);
++ if (dtr >= 0)
++ t = dtr? (t | TCR_DTR): (t & ~TCR_DTR);
++ if (rts >= 0)
++ t = rts? (t | TCR_RTS): (t & ~TCR_RTS);
++ SCCwrite(TX_CTRL_REG, t);
++ local_irq_restore(flags);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: setsignals done\n");
++#endif
++}
++
++
++static void scc_send_xchar(struct tty_struct *tty, char ch)
++{
++ struct scc_port *port = (struct scc_port *)tty->driver_data;
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: send_xchar ...\n");
++#endif
++ port->x_char = ch;
++ if (ch)
++ scc_enable_tx_interrupts(port);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: send_xchar done\n");
++#endif
++}
++
++
++/*---------------------------------------------------------------------------
++ * Driver entrypoints referenced from above
++ *--------------------------------------------------------------------------*/
++
++static int scc_open(struct tty_struct *tty, struct file *filp)
++{
++ int line = tty->index;
++ int retval;
++ struct scc_port *port = &scc_ports[line];
++ int i, channel = port->channel;
++ unsigned long flags;
++ SCC_ACCESS_INIT(port);
++
++ static const struct {
++ unsigned reg, val;
++ } scc_init_tab[] = {
++ /* no parity, 1 stop bit, async, 1:16 */
++ { AUX1_CTRL_REG, A1CR_PARITY_NONE|A1CR_MODE_ASYNC_1|A1CR_CLKMODE_x64 },
++ /* parity error is special cond, ints disabled, no DMA */
++ { INT_AND_DMA_REG, IDR_PARERR_AS_SPCOND | IDR_RX_INT_DISAB },
++ /* Rx 8 bits/char, no auto enable, Rx off */
++ { RX_CTRL_REG, RCR_CHSIZE_8 },
++ /* DTR off, Tx 8 bits/char, RTS off, Tx off */
++ { TX_CTRL_REG, TCR_CHSIZE_8 },
++ /* special features off */
++ { AUX2_CTRL_REG, 0 },
++ /* RTxC is XTAL, TRxC is input, both clocks = RTxC */
++ { CLK_CTRL_REG, CCR_TRxCOUT_XTAL | CCR_TXCLK_RTxC | CCR_RXCLK_RTxC },
++ { DPLL_CTRL_REG, 0 },
++ /* Start Rx */
++ { RX_CTRL_REG, RCR_RX_ENAB | RCR_CHSIZE_8 },
++ /* Start Tx */
++ { TX_CTRL_REG, TCR_TX_ENAB | TCR_RTS | TCR_DTR | TCR_CHSIZE_8 },
++ /* Ext/Stat ints: CTS, DCD, SYNC (DSR) */
++ { INT_CTRL_REG, ICR_ENAB_DCD_INT | ICR_ENAB_CTS_INT | ICR_ENAB_SYNC_INT },
++ /* Reset Ext/Stat ints */
++ { COMMAND_REG, CR_EXTSTAT_RESET },
++ /* ...again */
++ { COMMAND_REG, CR_EXTSTAT_RESET },
++ /* Rx int always, TX int off, Ext/Stat int on */
++ { INT_AND_DMA_REG, IDR_EXTSTAT_INT_ENAB |
++ IDR_PARERR_AS_SPCOND | IDR_RX_INT_ALL }
++ };
++
++ if (atari_SCC_init_done && line == 1)
++ return -ENODEV;
++
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: open port ...\n");
++#endif
++ if (!(port->gs.flags & ASYNC_INITIALIZED)) {
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: init port ...\n");
++#endif
++ local_irq_save(flags);
++
++ SCCmod(MASTER_INT_CTRL, 0x3f,
++ channel == 0 ? MIC_CH_A_RESET : MIC_CH_B_RESET);
++ udelay(40); /* extra delay after a reset */
++
++ for (i = 0; i < sizeof(scc_init_tab)/sizeof(*scc_init_tab); ++i)
++ SCCwrite(scc_init_tab[i].reg, scc_init_tab[i].val);
++
++
++ /* remember status register for detection of DCD and CTS changes */
++ scc_last_status_reg[channel] = SCCread(STATUS_REG);
++
++ port->c_dcd = 0; /* Prevent initial 1->0 interrupt */
++ scc_setsignals(port, 1, 1);
++ local_irq_restore(flags);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: init port done!\n");
++#endif
++ }
++
++ tty->driver_data = port;
++ port->gs.tty = tty;
++ port->gs.count++;
++#ifdef DEBUG
++ printk(KERN_WARNING "SCC: gs init port ...\n");
++#endif
++ retval = gs_init_port(&port->gs);
++ if (retval) {
++ port->gs.count--;
++ return retval;
++ }
++#ifdef DEBUG
++ printk(KERN_WARNING "SCC: gs init port done!\n");
++#endif
++ port->gs.flags |= GS_ACTIVE;
++
++#ifdef DEBUG
++ printk(KERN_WARNING "SCC: gs wait ready ...\n");
++#endif
++ retval = gs_block_til_ready(port, filp);
++#ifdef DEBUG
++ printk(KERN_WARNING "SCC: gs wait ready done!\n");
++#endif
++ if (retval) {
++ port->gs.count--;
++ return retval;
++ }
++
++ port->c_dcd = scc_get_CD(port);
++
++#ifdef DEBUG
++ printk(KERN_WARNING "SCC: enable rx ints ...\n");
++#endif
++ scc_enable_rx_interrupts(port);
++#ifdef DEBUG
++ printk(KERN_WARNING "SCC: enable rx ints done!\n");
++
++ printk(KERN_INFO "SCC: open port done!\n");
++#endif
++ return 0;
++}
++
++
++static void scc_throttle(struct tty_struct *tty)
++{
++ struct scc_port *port = (struct scc_port *)tty->driver_data;
++ unsigned long flags;
++ SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: throttle ...\n");
++#endif
++ if (tty->termios->c_cflag & CRTSCTS) {
++ local_irq_save(flags);
++ SCCmod(TX_CTRL_REG, ~TCR_RTS, 0);
++ local_irq_restore(flags);
++ }
++ if (I_IXOFF(tty))
++ scc_send_xchar(tty, STOP_CHAR(tty));
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: throttle done!\n");
++#endif
++}
++
++
++static void scc_unthrottle(struct tty_struct *tty)
++{
++ struct scc_port *port = (struct scc_port *)tty->driver_data;
++ unsigned long flags;
++ SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: unthrottle ...\n");
++#endif
++ if (tty->termios->c_cflag & CRTSCTS) {
++ local_irq_save(flags);
++ SCCmod(TX_CTRL_REG, 0xff, TCR_RTS);
++ local_irq_restore(flags);
++ }
++ if (I_IXOFF(tty))
++ scc_send_xchar(tty, START_CHAR(tty));
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: unthrottle done!\n");
++#endif
++}
++
++
++static int scc_ioctl(struct tty_struct *tty, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ struct scc_port *port = (struct scc_port *)tty->driver_data;
++ int retval;
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: ioctl! cmd %d, arg %p \n", cmd, arg);
++#endif
++ //if (serial_paranoia_check(info, tty->device, "zs_ioctl"))
++ // return -ENODEV;
++
++ if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
++ (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
++ (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
++ if (tty->flags & (1 << TTY_IO_ERROR))
++ return -EIO;
++ }
++
++ switch (cmd) {
++ case TCSBRK: /* SVID version: non-zero arg --> no break */
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: ioctl TCSBRK\n");
++#endif
++ retval = tty_check_change(tty);
++ if (retval)
++ return retval;
++ tty_wait_until_sent(tty, 0);
++ //if (!arg)
++ // send_break(info, HZ/4); /* 1/4 second */
++ return 0;
++ case TCSBRKP: /* support for POSIX tcsendbreak() */
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: ioctl TCSBRKP\n");
++#endif
++ retval = tty_check_change(tty);
++ if (retval)
++ return retval;
++ tty_wait_until_sent(tty, 0);
++ //send_break(info, arg ? arg*(HZ/10) : HZ/4);
++ return 0;
++ case TIOCGSOFTCAR:
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: ioctl TIOCGSOFTCAR\n");
++#endif
++ if (put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg))
++ return -EFAULT;
++ return 0;
++ case TIOCSSOFTCAR:
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: ioctl TIOCSSOFTCAR\n");
++#endif
++ if (get_user(arg, (unsigned long *)arg))
++ return -EFAULT;
++ tty->termios->c_cflag =
++ ((tty->termios->c_cflag & ~CLOCAL) |
++ (arg ? CLOCAL : 0));
++ return 0;
++ case TIOCMGET:
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: ioctl TIOCMGET\n");
++#endif
++ //return get_modem_info(info, (unsigned int *)arg);
++ return 0;
++ case TIOCMBIS:
++ case TIOCMBIC:
++ case TIOCMSET:
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: ioctl TIOCMSET\n");
++#endif
++ //return set_modem_info(info, cmd, (unsigned int *)arg);
++ return 0;
++ case TIOCGSERIAL:
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: ioctl TIOCGSERIAL\n");
++#endif
++ return 0;
++ //return get_serial_info(info,
++ // (struct serial_struct *)arg);
++ case TIOCSSERIAL:
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: ioctl TIOCSSERIAL\n");
++#endif
++ return 0;
++ //return set_serial_info(info,
++ // (struct serial_struct *)arg);
++ case TIOCSERGETLSR: /* Get line status register */
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: ioctl TIOCSERGETLSR\n");
++#endif
++ return 0;
++ //return get_lsr_info(info, (unsigned int *)arg);
++
++ case TIOCSERGSTRUCT:
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: ioctl TIOCSERGSTRUCT\n");
++#endif
++ return 0;
++ if (copy_to_user((struct scc_port *)arg,
++ port, sizeof(struct scc_port)))
++ return -EFAULT;
++ return 0;
++
++ default:
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: ioctl default\n");
++#endif
++ return -ENOIOCTLCMD;
++ }
++ return 0;
++}
++
++
++static void scc_break_ctl(struct tty_struct *tty, int break_state)
++{
++ struct scc_port *port = (struct scc_port *)tty->driver_data;
++ unsigned long flags;
++ SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: break ctl ...\n");
++#endif
++ local_irq_save(flags);
++ SCCmod(TX_CTRL_REG, ~TCR_SEND_BREAK, break_state ? TCR_SEND_BREAK : 0);
++ local_irq_restore(flags);
++#ifdef DEBUG
++ printk(KERN_INFO "SCC: break ctl done!\n");
++#endif
++}
++
++
++/*---------------------------------------------------------------------------
++ * Serial console stuff...
++ *--------------------------------------------------------------------------*/
++#if 1
++#define scc_delay() \
++ asm volatile ("tstb %0" : : "m" (*scc_del) : "cc")
++
++#define SCC_WRITE(reg,val) \
++ do { \
++ scc.cha_b_ctrl = (reg); \
++ scc_delay(); \
++ scc.cha_b_ctrl = (val); \
++ scc_delay(); \
++ } while (0)
++
++/* loops_per_jiffy isn't initialized yet, so we can't use udelay(). This does a
++ * delay of ~ 60us. */
++#define LONG_DELAY() \
++ do { \
++ int i; \
++ for (i = 100; i > 0; --i) \
++ scc_delay(); \
++ } while (0)
++
++static void atari_init_scc_port(int cflag)
++{
++ extern int atari_SCC_reset_done;
++ static int clksrc_table[9] =
++ /* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */
++ { 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 };
++ static int brgsrc_table[9] =
++ /* reg 14: 0 = RTxC, 2 = PCLK */
++ { 2, 2, 2, 2, 2, 2, 0, 2, 2 };
++ static int clkmode_table[9] =
++ /* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */
++ { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 };
++ static int div_table[9] =
++ /* reg12 (BRG low) */
++ { 208, 138, 103, 50, 24, 11, 1, 0, 0 };
++
++ int baud = cflag & CBAUD;
++ int clksrc, clkmode, div, reg3, reg5;
++
++ scc_del = &mfp.par_dt_reg;
++
++ if (cflag & CBAUDEX)
++ baud += B38400;
++ if (baud < B1200 || baud > B38400+2)
++ baud = B9600; /* use default 9600bps for non-implemented rates */
++ baud -= B1200; /* tables starts at 1200bps */
++
++ clksrc = clksrc_table[baud];
++ clkmode = clkmode_table[baud];
++ div = div_table[baud];
++ if (ATARIHW_PRESENT(TT_MFP) && baud >= 6) {
++ /* special treatment for TT, where rates >= 38400 are done via TRxC */
++ clksrc = 0x28; /* TRxC */
++ clkmode = baud == 6 ? 0xc0 :
++ baud == 7 ? 0x80 : /* really 76800bps */
++ 0x40; /* really 153600bps */
++ div = 0;
++ }
++
++ reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40;
++ reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */;
++
++ (void)scc.cha_b_ctrl; /* reset reg pointer */
++ SCC_WRITE(9, 0xc0); /* reset */
++ LONG_DELAY(); /* extra delay after WR9 access */
++ SCC_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
++ 0x04 /* 1 stopbit */ |
++ clkmode);
++ SCC_WRITE(3, reg3);
++ SCC_WRITE(5, reg5);
++ SCC_WRITE(9, 0); /* no interrupts */
++ LONG_DELAY(); /* extra delay after WR9 access */
++ SCC_WRITE(10, 0); /* NRZ mode */
++ SCC_WRITE(11, clksrc); /* main clock source */
++ SCC_WRITE(12, div); /* BRG value */
++ SCC_WRITE(13, 0); /* BRG high byte */
++ SCC_WRITE(14, brgsrc_table[baud]);
++ SCC_WRITE(14, brgsrc_table[baud] | (div ? 1 : 0));
++ SCC_WRITE(3, reg3 | 1);
++ SCC_WRITE(5, reg5 | 8);
++
++ atari_SCC_reset_done = 1;
++ atari_SCC_init_done = 1;
++}
++
++static void scc_ch_write(char ch)
++{
++ volatile char *p = NULL;
++
++ if (MACH_IS_TT || MACH_IS_FALCON)
++ p = (volatile char *)&scc.cha_b_ctrl;
++
++ if (MACH_IS_ST)
++ p = (volatile char *)&scc.cha_b_ctrl;
++
++ if (MACH_IS_STE)
++ p = (volatile char *)&st_escc.cha_b_ctrl;
++
++ do {
++ scc_delay();
++ }
++ while (!(*p & 4));
++ // scc_delay();
++ // *p = 8;
++ scc_delay();
++ *(p+1) = ch;
++}
++
++/* The console must be locked when we get here. */
++
++static void scc_console_write(struct console *co, const char *str, unsigned count)
++{
++ unsigned long flags;
++
++ //printk("scc_console_write: %s\n", str);
++ local_irq_save(flags);
++
++ while (count--) {
++ if (*str == '\n')
++ scc_ch_write('\r');
++ scc_ch_write(*str++);
++ }
++ local_irq_restore(flags);
++ //printk("scc_console_write done!\n");
++}
++
++static struct tty_driver *scc_console_device(struct console *c, int *index)
++{
++ *index = c->index;
++ return scc_driver;
++}
++
++
++static int __init scc_console_setup(struct console *co, char *options)
++{
++ printk("scc_console_setup: initializing SCC port B\n");
++ atari_init_scc_port(B9600|CS8);
++ printk("scc_console_setup: done!\n");
++ return 0;
++}
++
++
++static struct console sercons = {
++ .name = "ttyS",
++ .write = scc_console_write,
++ .device = scc_console_device,
++ .setup = scc_console_setup,
++ .flags = CON_PRINTBUFFER,
++ .index = -1,
++};
++
++
++static int __init vme_scc_console_init(void)
++{
++ if (MACH_IS_TT || MACH_IS_ST || MACH_IS_FALCON)
++ register_console(&sercons);
++ return 0;
++}
++
++console_initcall(vme_scc_console_init);
++#endif
++
++/***************************** End of Functions *********************/
++
++MODULE_AUTHOR("Michael Schmitz");
++MODULE_DESCRIPTION("Atari Amd8350 SCC serial driver");
++MODULE_LICENSE("GPL");
diff --git a/debian/patches/bugfix/m68k/634-atari_scsi.diff b/debian/patches/bugfix/m68k/634-atari_scsi.diff
new file mode 100644
index 000000000000..af34018334ac
--- /dev/null
+++ b/debian/patches/bugfix/m68k/634-atari_scsi.diff
@@ -0,0 +1,228 @@
+Cc: James E.J. Bottomley <James.Bottomley@SteelEye.com>,
+ linux-scsi@vger.kernel.org
+Subject: [PATCH] m68k: Atari SCSI revival
+
+From: Michael Schmitz <schmitz@opal.biophys.uni-duesseldorf.de>
+
+SCSI should be working on a TT (but someone should really try!) but causes
+trouble on a Falcon (as in: it ate a filesystem of mine) at least when
+used concurrently with IDE. I have the notion it's because locking of the
+ST-DMA interrupt by IDE is broken in 2.6 (the IDE driver always complains
+about trying to release an already-released ST-DMA). Needs more work, but
+that's on the IDE or m68k interrupt side rather than SCSI.
+
+Signed-off-by: Michael Schmitz <schmitz@debian.org>
+Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ drivers/scsi/Kconfig | 2 -
+ drivers/scsi/atari_NCR5380.c | 52 ++++++++++++++++++++++++++++++++++++++-----
+ drivers/scsi/atari_scsi.c | 10 +++-----
+ drivers/scsi/atari_scsi.h | 30 +++++++++++++++++++++---
+ 4 files changed, 77 insertions(+), 17 deletions(-)
+
+--- linux-m68k-2.6.21.orig/drivers/scsi/Kconfig
++++ linux-m68k-2.6.21/drivers/scsi/Kconfig
+@@ -1649,7 +1649,7 @@ config OKTAGON_SCSI
+
+ config ATARI_SCSI
+ tristate "Atari native SCSI support"
+- depends on ATARI && SCSI && BROKEN
++ depends on ATARI && SCSI
+ select SCSI_SPI_ATTRS
+ ---help---
+ If you have an Atari with built-in NCR5380 SCSI controller (TT,
+--- linux-m68k-2.6.21.orig/drivers/scsi/atari_NCR5380.c
++++ linux-m68k-2.6.21/drivers/scsi/atari_NCR5380.c
+@@ -264,7 +264,7 @@ static struct scsi_host_template *the_te
+ (struct NCR5380_hostdata *)(in)->hostdata
+ #define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata)
+
+-#define NEXT(cmd) ((Scsi_Cmnd *)((cmd)->host_scribble))
++#define NEXT(cmd) ((cmd)->host_scribble)
+ #define NEXTADDR(cmd) ((Scsi_Cmnd **)&((cmd)->host_scribble))
+
+ #define HOSTNO instance->host_no
+@@ -716,7 +716,7 @@ static void NCR5380_print_status (struct
+ printk("NCR5380_print_status: no memory for print buffer\n");
+ return;
+ }
+- len = NCR5380_proc_info(pr_bfr, &start, 0, PAGE_SIZE, HOSTNO, 0);
++ len = NCR5380_proc_info(instance, pr_bfr, &start, 0, PAGE_SIZE, 0);
+ pr_bfr[len] = 0;
+ printk("\n%s\n", pr_bfr);
+ free_page((unsigned long) pr_bfr);
+@@ -878,6 +878,46 @@ static int NCR5380_init (struct Scsi_Hos
+ }
+
+ /*
++ * our own old-style timeout update
++ */
++/*
++ * The strategy is to cause the timer code to call scsi_times_out()
++ * when the soonest timeout is pending.
++ * The arguments are used when we are queueing a new command, because
++ * we do not want to subtract the time used from this time, but when we
++ * set the timer, we want to take this value into account.
++ */
++
++int atari_scsi_update_timeout(Scsi_Cmnd * SCset, int timeout)
++{
++ int rtn;
++
++ /*
++ * We are using the new error handling code to actually register/deregister
++ * timers for timeout.
++ */
++
++ if (!timer_pending(&SCset->eh_timeout)) {
++ rtn = 0;
++ } else {
++ rtn = SCset->eh_timeout.expires - jiffies;
++ }
++
++ if (timeout == 0) {
++ del_timer(&SCset->eh_timeout);
++ SCset->eh_timeout.data = (unsigned long) NULL;
++ SCset->eh_timeout.expires = 0;
++ } else {
++ if (SCset->eh_timeout.data != (unsigned long) NULL)
++ del_timer(&SCset->eh_timeout);
++ SCset->eh_timeout.data = (unsigned long) SCset;
++ SCset->eh_timeout.expires = jiffies + timeout;
++ add_timer(&SCset->eh_timeout);
++ }
++ return rtn;
++}
++
++/*
+ * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd,
+ * void (*done)(Scsi_Cmnd *))
+ *
+@@ -902,7 +942,7 @@ int NCR5380_queue_command (Scsi_Cmnd *cm
+ Scsi_Cmnd *tmp;
+ int oldto;
+ unsigned long flags;
+- extern int update_timeout(Scsi_Cmnd * SCset, int timeout);
++ // extern int update_timeout(Scsi_Cmnd * SCset, int timeout);
+
+ #if (NDEBUG & NDEBUG_NO_WRITE)
+ switch (cmd->cmnd[0]) {
+@@ -978,9 +1018,9 @@ int NCR5380_queue_command (Scsi_Cmnd *cm
+ * alter queues and touch the lock.
+ */
+ if (!IS_A_TT()) {
+- oldto = update_timeout(cmd, 0);
++ oldto = atari_scsi_update_timeout(cmd, 0);
+ falcon_get_lock();
+- update_timeout(cmd, oldto);
++ atari_scsi_update_timeout(cmd, oldto);
+ }
+ if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+ LIST(cmd, hostdata->issue_queue);
+@@ -1435,7 +1475,7 @@ static int NCR5380_select (struct Scsi_H
+ local_irq_restore(flags);
+
+ /* Wait for arbitration logic to complete */
+-#if NCR_TIMEOUT
++#if defined(NCR_TIMEOUT)
+ {
+ unsigned long timeout = jiffies + 2*NCR_TIMEOUT;
+
+--- linux-m68k-2.6.21.orig/drivers/scsi/atari_scsi.c
++++ linux-m68k-2.6.21/drivers/scsi/atari_scsi.c
+@@ -395,7 +395,7 @@ static irqreturn_t scsi_tt_intr (int irq
+
+ #endif /* REAL_DMA */
+
+- NCR5380_intr (0, 0, 0);
++ NCR5380_intr(0, 0);
+
+ #if 0
+ /* To be sure the int is not masked */
+@@ -461,7 +461,7 @@ static irqreturn_t scsi_falcon_intr (int
+
+ #endif /* REAL_DMA */
+
+- NCR5380_intr (0, 0, 0);
++ NCR5380_intr(0, 0);
+ return IRQ_HANDLED;
+ }
+
+@@ -557,11 +557,11 @@ static void falcon_get_lock( void )
+
+ local_irq_save(flags);
+
+- while( !in_interrupt() && falcon_got_lock && stdma_others_waiting() )
++ while (!in_irq() && falcon_got_lock && stdma_others_waiting())
+ sleep_on( &falcon_fairness_wait );
+
+ while (!falcon_got_lock) {
+- if (in_interrupt())
++ if (in_irq())
+ panic( "Falcon SCSI hasn't ST-DMA lock in interrupt" );
+ if (!falcon_trying_lock) {
+ falcon_trying_lock = 1;
+@@ -763,7 +763,6 @@ int atari_scsi_detect (struct scsi_host_
+ return( 1 );
+ }
+
+-#ifdef MODULE
+ int atari_scsi_release (struct Scsi_Host *sh)
+ {
+ if (IS_A_TT())
+@@ -772,7 +771,6 @@ int atari_scsi_release (struct Scsi_Host
+ atari_stram_free (atari_dma_buffer);
+ return 1;
+ }
+-#endif
+
+ void __init atari_scsi_setup(char *str, int *ints)
+ {
+--- linux-m68k-2.6.21.orig/drivers/scsi/atari_scsi.h
++++ linux-m68k-2.6.21/drivers/scsi/atari_scsi.h
+@@ -21,11 +21,7 @@
+ int atari_scsi_detect (struct scsi_host_template *);
+ const char *atari_scsi_info (struct Scsi_Host *);
+ int atari_scsi_reset (Scsi_Cmnd *, unsigned int);
+-#ifdef MODULE
+ int atari_scsi_release (struct Scsi_Host *);
+-#else
+-#define atari_scsi_release NULL
+-#endif
+
+ /* The values for CMD_PER_LUN and CAN_QUEUE are somehow arbitrary. Higher
+ * values should work, too; try it! (but cmd_per_lun costs memory!) */
+@@ -63,6 +59,32 @@ int atari_scsi_release (struct Scsi_Host
+ #define NCR5380_dma_xfer_len(i,cmd,phase) \
+ atari_dma_xfer_len(cmd->SCp.this_residual,cmd,((phase) & SR_IO) ? 0 : 1)
+
++/* former generic SCSI error handling stuff */
++
++#define SCSI_ABORT_SNOOZE 0
++#define SCSI_ABORT_SUCCESS 1
++#define SCSI_ABORT_PENDING 2
++#define SCSI_ABORT_BUSY 3
++#define SCSI_ABORT_NOT_RUNNING 4
++#define SCSI_ABORT_ERROR 5
++
++#define SCSI_RESET_SNOOZE 0
++#define SCSI_RESET_PUNT 1
++#define SCSI_RESET_SUCCESS 2
++#define SCSI_RESET_PENDING 3
++#define SCSI_RESET_WAKEUP 4
++#define SCSI_RESET_NOT_RUNNING 5
++#define SCSI_RESET_ERROR 6
++
++#define SCSI_RESET_SYNCHRONOUS 0x01
++#define SCSI_RESET_ASYNCHRONOUS 0x02
++#define SCSI_RESET_SUGGEST_BUS_RESET 0x04
++#define SCSI_RESET_SUGGEST_HOST_RESET 0x08
++
++#define SCSI_RESET_BUS_RESET 0x100
++#define SCSI_RESET_HOST_RESET 0x200
++#define SCSI_RESET_ACTION 0xff
++
+ /* Debugging printk definitions:
+ *
+ * ARB -> arbitration
diff --git a/debian/patches/bugfix/m68k/635-atari_input.diff b/debian/patches/bugfix/m68k/635-atari_input.diff
new file mode 100644
index 000000000000..2aed8c8c889f
--- /dev/null
+++ b/debian/patches/bugfix/m68k/635-atari_input.diff
@@ -0,0 +1,1162 @@
+Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>,
+ linux-input@atrey.karlin.mff.cuni.cz
+Subject: [PATCH] m68k: Atari keyboard and mouse support.
+
+From: Michael Schmitz <schmitz@opal.biophys.uni-duesseldorf.de>
+
+Atari keyboard and mouse support.
+(reformating and Kconfig fixes by Roman Zippel)
+
+Signed-off-by: Michael Schmitz <schmitz@debian.org>
+Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ arch/m68k/Kconfig | 3
+ arch/m68k/atari/Makefile | 1
+ arch/m68k/atari/atakeyb.c | 730 +++++++++++++++++++++++++++++++++++++++
+ drivers/input/keyboard/Kconfig | 11
+ drivers/input/keyboard/Makefile | 1
+ drivers/input/keyboard/atakbd.c | 134 +++++++
+ drivers/input/mouse/Kconfig | 11
+ drivers/input/mouse/Makefile | 1
+ drivers/input/mouse/atarimouse.c | 160 ++++++++
+ include/asm-m68k/atarikb.h | 6
+ include/linux/input.h | 1
+ 11 files changed, 1059 insertions(+)
+
+--- linux-m68k-2.6.21.orig/arch/m68k/Kconfig
++++ linux-m68k-2.6.21/arch/m68k/Kconfig
+@@ -409,6 +409,9 @@ config STRAM_PROC
+ help
+ Say Y here to report ST-RAM usage statistics in /proc/stram.
+
++config ATARI_KBD_CORE
++ bool
++
+ config HEARTBEAT
+ bool "Use power LED as a heartbeat" if AMIGA || APOLLO || ATARI || MAC ||Q40
+ default y if !AMIGA && !APOLLO && !ATARI && !MAC && !Q40 && HP300
+--- linux-m68k-2.6.21.orig/arch/m68k/atari/Makefile
++++ linux-m68k-2.6.21/arch/m68k/atari/Makefile
+@@ -8,3 +8,4 @@ obj-y := config.o time.o debug.o ataint
+ ifeq ($(CONFIG_PCI),y)
+ obj-$(CONFIG_HADES) += hades-pci.o
+ endif
++obj-$(CONFIG_ATARI_KBD_CORE) += atakeyb.o
+--- /dev/null
++++ linux-m68k-2.6.21/arch/m68k/atari/atakeyb.c
+@@ -0,0 +1,730 @@
++/*
++ * linux/atari/atakeyb.c
++ *
++ * Atari Keyboard driver for 680x0 Linux
++ *
++ * 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.
++ */
++
++/*
++ * Atari support by Robert de Vries
++ * enhanced by Bjoern Brauel and Roman Hodek
++ */
++
++#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/errno.h>
++#include <linux/keyboard.h>
++#include <linux/delay.h>
++#include <linux/timer.h>
++#include <linux/kd.h>
++#include <linux/random.h>
++#include <linux/init.h>
++#include <linux/kbd_kern.h>
++
++#include <asm/atariints.h>
++#include <asm/atarihw.h>
++#include <asm/atarikb.h>
++#include <asm/atari_joystick.h>
++#include <asm/irq.h>
++
++static void atakeyb_rep(unsigned long ignore);
++extern unsigned int keymap_count;
++
++/* Hook for MIDI serial driver */
++void (*atari_MIDI_interrupt_hook) (void);
++/* Hook for mouse driver */
++void (*atari_mouse_interrupt_hook) (char *);
++/* Hook for keyboard inputdev driver */
++void (*atari_input_keyboard_interrupt_hook) (unsigned char, char);
++/* Hook for mouse inputdev driver */
++void (*atari_input_mouse_interrupt_hook) (char *);
++
++/* variables for IKBD self test: */
++
++/* state: 0: off; >0: in progress; >1: 0xf1 received */
++static volatile int ikbd_self_test;
++/* timestamp when last received a char */
++static volatile unsigned long self_test_last_rcv;
++/* bitmap of keys reported as broken */
++static unsigned long broken_keys[128/(sizeof(unsigned long)*8)] = { 0, };
++
++#define BREAK_MASK (0x80)
++
++/*
++ * ++roman: The following changes were applied manually:
++ *
++ * - The Alt (= Meta) key works in combination with Shift and
++ * Control, e.g. Alt+Shift+a sends Meta-A (0xc1), Alt+Control+A sends
++ * Meta-Ctrl-A (0x81) ...
++ *
++ * - The parentheses on the keypad send '(' and ')' with all
++ * modifiers (as would do e.g. keypad '+'), but they cannot be used as
++ * application keys (i.e. sending Esc O c).
++ *
++ * - HELP and UNDO are mapped to be F21 and F24, resp, that send the
++ * codes "\E[M" and "\E[P". (This is better than the old mapping to
++ * F11 and F12, because these codes are on Shift+F1/2 anyway.) This
++ * way, applications that allow their own keyboard mappings
++ * (e.g. tcsh, X Windows) can be configured to use them in the way
++ * the label suggests (providing help or undoing).
++ *
++ * - Console switching is done with Alt+Fx (consoles 1..10) and
++ * Shift+Alt+Fx (consoles 11..20).
++ *
++ * - The misc. special function implemented in the kernel are mapped
++ * to the following key combinations:
++ *
++ * ClrHome -> Home/Find
++ * Shift + ClrHome -> End/Select
++ * Shift + Up -> Page Up
++ * Shift + Down -> Page Down
++ * Alt + Help -> show system status
++ * Shift + Help -> show memory info
++ * Ctrl + Help -> show registers
++ * Ctrl + Alt + Del -> Reboot
++ * Alt + Undo -> switch to last console
++ * Shift + Undo -> send interrupt
++ * Alt + Insert -> stop/start output (same as ^S/^Q)
++ * Alt + Up -> Scroll back console (if implemented)
++ * Alt + Down -> Scroll forward console (if implemented)
++ * Alt + CapsLock -> NumLock
++ *
++ * ++Andreas:
++ *
++ * - Help mapped to K_HELP
++ * - Undo mapped to K_UNDO (= K_F246)
++ * - Keypad Left/Right Parenthesis mapped to new K_PPAREN[LR]
++ */
++
++static u_short ataplain_map[NR_KEYS] __initdata = {
++ 0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036,
++ 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf009,
++ 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
++ 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73,
++ 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b,
++ 0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76,
++ 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf200,
++ 0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
++ 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114,
++ 0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
++ 0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
++ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
++ 0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
++ 0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
++ 0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
++ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
++};
++
++typedef enum kb_state_t {
++ KEYBOARD, AMOUSE, RMOUSE, JOYSTICK, CLOCK, RESYNC
++} KB_STATE_T;
++
++#define IS_SYNC_CODE(sc) ((sc) >= 0x04 && (sc) <= 0xfb)
++
++typedef struct keyboard_state {
++ unsigned char buf[6];
++ int len;
++ KB_STATE_T state;
++} KEYBOARD_STATE;
++
++KEYBOARD_STATE kb_state;
++
++#define DEFAULT_KEYB_REP_DELAY (HZ/4)
++#define DEFAULT_KEYB_REP_RATE (HZ/25)
++
++/* These could be settable by some ioctl() in future... */
++static unsigned int key_repeat_delay = DEFAULT_KEYB_REP_DELAY;
++static unsigned int key_repeat_rate = DEFAULT_KEYB_REP_RATE;
++
++static unsigned char rep_scancode;
++static struct timer_list atakeyb_rep_timer = {
++ .function = atakeyb_rep,
++};
++
++static void atakeyb_rep(unsigned long ignore)
++{
++ /* Disable keyboard for the time we call handle_scancode(), else a race
++ * in the keyboard tty queue may happen */
++ atari_disable_irq(IRQ_MFP_ACIA);
++ del_timer(&atakeyb_rep_timer);
++
++ /* A keyboard int may have come in before we disabled the irq, so
++ * double-check whether rep_scancode is still != 0 */
++ if (rep_scancode) {
++ init_timer(&atakeyb_rep_timer);
++ atakeyb_rep_timer.expires = jiffies + key_repeat_rate;
++ add_timer(&atakeyb_rep_timer);
++
++ //handle_scancode(rep_scancode, 1);
++ if (atari_input_keyboard_interrupt_hook)
++ atari_input_keyboard_interrupt_hook(rep_scancode, 1);
++ }
++
++ atari_enable_irq(IRQ_MFP_ACIA);
++}
++
++
++/* ++roman: If a keyboard overrun happened, we can't tell in general how much
++ * bytes have been lost and in which state of the packet structure we are now.
++ * This usually causes keyboards bytes to be interpreted as mouse movements
++ * and vice versa, which is very annoying. It seems better to throw away some
++ * bytes (that are usually mouse bytes) than to misinterpret them. Therefor I
++ * introduced the RESYNC state for IKBD data. In this state, the bytes up to
++ * one that really looks like a key event (0x04..0xf2) or the start of a mouse
++ * packet (0xf8..0xfb) are thrown away, but at most 2 bytes. This at least
++ * speeds up the resynchronization of the event structure, even if maybe a
++ * mouse movement is lost. However, nothing is perfect. For bytes 0x01..0x03,
++ * it's really hard to decide whether they're mouse or keyboard bytes. Since
++ * overruns usually occur when moving the Atari mouse rapidly, they're seen as
++ * mouse bytes here. If this is wrong, only a make code of the keyboard gets
++ * lost, which isn't too bad. Loosing a break code would be disastrous,
++ * because then the keyboard repeat strikes...
++ */
++
++static irqreturn_t atari_keyboard_interrupt(int irq, void *dummy)
++{
++ u_char acia_stat;
++ int scancode;
++ int break_flag;
++
++repeat:
++ if (acia.mid_ctrl & ACIA_IRQ)
++ if (atari_MIDI_interrupt_hook)
++ atari_MIDI_interrupt_hook();
++ acia_stat = acia.key_ctrl;
++ /* check out if the interrupt came from this ACIA */
++ if (!((acia_stat | acia.mid_ctrl) & ACIA_IRQ))
++ return IRQ_HANDLED;
++
++ if (acia_stat & ACIA_OVRN) {
++ /* a very fast typist or a slow system, give a warning */
++ /* ...happens often if interrupts were disabled for too long */
++ printk(KERN_DEBUG "Keyboard overrun\n");
++ scancode = acia.key_data;
++ /* Turn off autorepeating in case a break code has been lost */
++ del_timer(&atakeyb_rep_timer);
++ rep_scancode = 0;
++ if (ikbd_self_test)
++ /* During self test, don't do resyncing, just process the code */
++ goto interpret_scancode;
++ else if (IS_SYNC_CODE(scancode)) {
++ /* This code seem already to be the start of a new packet or a
++ * single scancode */
++ kb_state.state = KEYBOARD;
++ goto interpret_scancode;
++ } else {
++ /* Go to RESYNC state and skip this byte */
++ kb_state.state = RESYNC;
++ kb_state.len = 1; /* skip max. 1 another byte */
++ goto repeat;
++ }
++ }
++
++ if (acia_stat & ACIA_RDRF) {
++ /* received a character */
++ scancode = acia.key_data; /* get it or reset the ACIA, I'll get it! */
++ tasklet_schedule(&keyboard_tasklet);
++ interpret_scancode:
++ switch (kb_state.state) {
++ case KEYBOARD:
++ switch (scancode) {
++ case 0xF7:
++ kb_state.state = AMOUSE;
++ kb_state.len = 0;
++ break;
++
++ case 0xF8:
++ case 0xF9:
++ case 0xFA:
++ case 0xFB:
++ kb_state.state = RMOUSE;
++ kb_state.len = 1;
++ kb_state.buf[0] = scancode;
++ break;
++
++ case 0xFC:
++ kb_state.state = CLOCK;
++ kb_state.len = 0;
++ break;
++
++ case 0xFE:
++ case 0xFF:
++ kb_state.state = JOYSTICK;
++ kb_state.len = 1;
++ kb_state.buf[0] = scancode;
++ break;
++
++ case 0xF1:
++ /* during self-test, note that 0xf1 received */
++ if (ikbd_self_test) {
++ ++ikbd_self_test;
++ self_test_last_rcv = jiffies;
++ break;
++ }
++ /* FALL THROUGH */
++
++ default:
++ break_flag = scancode & BREAK_MASK;
++ scancode &= ~BREAK_MASK;
++ if (ikbd_self_test) {
++ /* Scancodes sent during the self-test stand for broken
++ * keys (keys being down). The code *should* be a break
++ * code, but nevertheless some AT keyboard interfaces send
++ * make codes instead. Therefore, simply ignore
++ * break_flag...
++ */
++ int keyval = plain_map[scancode], keytyp;
++
++ set_bit(scancode, broken_keys);
++ self_test_last_rcv = jiffies;
++ keyval = plain_map[scancode];
++ keytyp = KTYP(keyval) - 0xf0;
++ keyval = KVAL(keyval);
++
++ printk(KERN_WARNING "Key with scancode %d ", scancode);
++ if (keytyp == KT_LATIN || keytyp == KT_LETTER) {
++ if (keyval < ' ')
++ printk("('^%c') ", keyval + '@');
++ else
++ printk("('%c') ", keyval);
++ }
++ printk("is broken -- will be ignored.\n");
++ break;
++ } else if (test_bit(scancode, broken_keys))
++ break;
++
++#if 0 // FIXME; hangs at boot
++ if (break_flag) {
++ del_timer(&atakeyb_rep_timer);
++ rep_scancode = 0;
++ } else {
++ del_timer(&atakeyb_rep_timer);
++ rep_scancode = scancode;
++ atakeyb_rep_timer.expires = jiffies + key_repeat_delay;
++ add_timer(&atakeyb_rep_timer);
++ }
++#endif
++
++ // handle_scancode(scancode, !break_flag);
++ if (atari_input_keyboard_interrupt_hook)
++ atari_input_keyboard_interrupt_hook((unsigned char)scancode, !break_flag);
++ break;
++ }
++ break;
++
++ case AMOUSE:
++ kb_state.buf[kb_state.len++] = scancode;
++ if (kb_state.len == 5) {
++ kb_state.state = KEYBOARD;
++ /* not yet used */
++ /* wake up someone waiting for this */
++ }
++ break;
++
++ case RMOUSE:
++ kb_state.buf[kb_state.len++] = scancode;
++ if (kb_state.len == 3) {
++ kb_state.state = KEYBOARD;
++ if (atari_mouse_interrupt_hook)
++ atari_mouse_interrupt_hook(kb_state.buf);
++ }
++ break;
++
++ case JOYSTICK:
++ kb_state.buf[1] = scancode;
++ kb_state.state = KEYBOARD;
++#ifdef FIXED_ATARI_JOYSTICK
++ atari_joystick_interrupt(kb_state.buf);
++#endif
++ break;
++
++ case CLOCK:
++ kb_state.buf[kb_state.len++] = scancode;
++ if (kb_state.len == 6) {
++ kb_state.state = KEYBOARD;
++ /* wake up someone waiting for this.
++ But will this ever be used, as Linux keeps its own time.
++ Perhaps for synchronization purposes? */
++ /* wake_up_interruptible(&clock_wait); */
++ }
++ break;
++
++ case RESYNC:
++ if (kb_state.len <= 0 || IS_SYNC_CODE(scancode)) {
++ kb_state.state = KEYBOARD;
++ goto interpret_scancode;
++ }
++ kb_state.len--;
++ break;
++ }
++ }
++
++#if 0
++ if (acia_stat & ACIA_CTS)
++ /* cannot happen */;
++#endif
++
++ if (acia_stat & (ACIA_FE | ACIA_PE)) {
++ printk("Error in keyboard communication\n");
++ }
++
++ /* handle_scancode() can take a lot of time, so check again if
++ * some character arrived
++ */
++ goto repeat;
++}
++
++/*
++ * I write to the keyboard without using interrupts, I poll instead.
++ * This takes for the maximum length string allowed (7) at 7812.5 baud
++ * 8 data 1 start 1 stop bit: 9.0 ms
++ * If this takes too long for normal operation, interrupt driven writing
++ * is the solution. (I made a feeble attempt in that direction but I
++ * kept it simple for now.)
++ */
++void ikbd_write(const char *str, int len)
++{
++ u_char acia_stat;
++
++ if ((len < 1) || (len > 7))
++ panic("ikbd: maximum string length exceeded");
++ while (len) {
++ acia_stat = acia.key_ctrl;
++ if (acia_stat & ACIA_TDRE) {
++ acia.key_data = *str++;
++ len--;
++ }
++ }
++}
++
++/* Reset (without touching the clock) */
++void ikbd_reset(void)
++{
++ static const char cmd[2] = { 0x80, 0x01 };
++
++ ikbd_write(cmd, 2);
++
++ /*
++ * if all's well code 0xF1 is returned, else the break codes of
++ * all keys making contact
++ */
++}
++
++/* Set mouse button action */
++void ikbd_mouse_button_action(int mode)
++{
++ char cmd[2] = { 0x07, mode };
++
++ ikbd_write(cmd, 2);
++}
++
++/* Set relative mouse position reporting */
++void ikbd_mouse_rel_pos(void)
++{
++ static const char cmd[1] = { 0x08 };
++
++ ikbd_write(cmd, 1);
++}
++
++/* Set absolute mouse position reporting */
++void ikbd_mouse_abs_pos(int xmax, int ymax)
++{
++ char cmd[5] = { 0x09, xmax>>8, xmax&0xFF, ymax>>8, ymax&0xFF };
++
++ ikbd_write(cmd, 5);
++}
++
++/* Set mouse keycode mode */
++void ikbd_mouse_kbd_mode(int dx, int dy)
++{
++ char cmd[3] = { 0x0A, dx, dy };
++
++ ikbd_write(cmd, 3);
++}
++
++/* Set mouse threshold */
++void ikbd_mouse_thresh(int x, int y)
++{
++ char cmd[3] = { 0x0B, x, y };
++
++ ikbd_write(cmd, 3);
++}
++
++/* Set mouse scale */
++void ikbd_mouse_scale(int x, int y)
++{
++ char cmd[3] = { 0x0C, x, y };
++
++ ikbd_write(cmd, 3);
++}
++
++/* Interrogate mouse position */
++void ikbd_mouse_pos_get(int *x, int *y)
++{
++ static const char cmd[1] = { 0x0D };
++
++ ikbd_write(cmd, 1);
++
++ /* wait for returning bytes */
++}
++
++/* Load mouse position */
++void ikbd_mouse_pos_set(int x, int y)
++{
++ char cmd[6] = { 0x0E, 0x00, x>>8, x&0xFF, y>>8, y&0xFF };
++
++ ikbd_write(cmd, 6);
++}
++
++/* Set Y=0 at bottom */
++void ikbd_mouse_y0_bot(void)
++{
++ static const char cmd[1] = { 0x0F };
++
++ ikbd_write(cmd, 1);
++}
++
++/* Set Y=0 at top */
++void ikbd_mouse_y0_top(void)
++{
++ static const char cmd[1] = { 0x10 };
++
++ ikbd_write(cmd, 1);
++}
++
++/* Resume */
++void ikbd_resume(void)
++{
++ static const char cmd[1] = { 0x11 };
++
++ ikbd_write(cmd, 1);
++}
++
++/* Disable mouse */
++void ikbd_mouse_disable(void)
++{
++ static const char cmd[1] = { 0x12 };
++
++ ikbd_write(cmd, 1);
++}
++
++/* Pause output */
++void ikbd_pause(void)
++{
++ static const char cmd[1] = { 0x13 };
++
++ ikbd_write(cmd, 1);
++}
++
++/* Set joystick event reporting */
++void ikbd_joystick_event_on(void)
++{
++ static const char cmd[1] = { 0x14 };
++
++ ikbd_write(cmd, 1);
++}
++
++/* Set joystick interrogation mode */
++void ikbd_joystick_event_off(void)
++{
++ static const char cmd[1] = { 0x15 };
++
++ ikbd_write(cmd, 1);
++}
++
++/* Joystick interrogation */
++void ikbd_joystick_get_state(void)
++{
++ static const char cmd[1] = { 0x16 };
++
++ ikbd_write(cmd, 1);
++}
++
++#if 0
++/* This disables all other ikbd activities !!!! */
++/* Set joystick monitoring */
++void ikbd_joystick_monitor(int rate)
++{
++ static const char cmd[2] = { 0x17, rate };
++
++ ikbd_write(cmd, 2);
++
++ kb_state.state = JOYSTICK_MONITOR;
++}
++#endif
++
++/* some joystick routines not in yet (0x18-0x19) */
++
++/* Disable joysticks */
++void ikbd_joystick_disable(void)
++{
++ static const char cmd[1] = { 0x1A };
++
++ ikbd_write(cmd, 1);
++}
++
++/* Time-of-day clock set */
++void ikbd_clock_set(int year, int month, int day, int hour, int minute, int second)
++{
++ char cmd[7] = { 0x1B, year, month, day, hour, minute, second };
++
++ ikbd_write(cmd, 7);
++}
++
++/* Interrogate time-of-day clock */
++void ikbd_clock_get(int *year, int *month, int *day, int *hour, int *minute, int second)
++{
++ static const char cmd[1] = { 0x1C };
++
++ ikbd_write(cmd, 1);
++}
++
++/* Memory load */
++void ikbd_mem_write(int address, int size, char *data)
++{
++ panic("Attempt to write data into keyboard memory");
++}
++
++/* Memory read */
++void ikbd_mem_read(int address, char data[6])
++{
++ char cmd[3] = { 0x21, address>>8, address&0xFF };
++
++ ikbd_write(cmd, 3);
++
++ /* receive data and put it in data */
++}
++
++/* Controller execute */
++void ikbd_exec(int address)
++{
++ char cmd[3] = { 0x22, address>>8, address&0xFF };
++
++ ikbd_write(cmd, 3);
++}
++
++/* Status inquiries (0x87-0x9A) not yet implemented */
++
++/* Set the state of the caps lock led. */
++void atari_kbd_leds(unsigned int leds)
++{
++ char cmd[6] = {32, 0, 4, 1, 254 + ((leds & 4) != 0), 0};
++
++ ikbd_write(cmd, 6);
++}
++
++/*
++ * The original code sometimes left the interrupt line of
++ * the ACIAs low forever. I hope, it is fixed now.
++ *
++ * Martin Rogge, 20 Aug 1995
++ */
++
++static int atari_keyb_done = 0;
++
++int __init atari_keyb_init(void)
++{
++ if (atari_keyb_done)
++ return 0;
++
++ /* setup key map */
++ memcpy(key_maps[0], ataplain_map, sizeof(plain_map));
++
++ kb_state.state = KEYBOARD;
++ kb_state.len = 0;
++
++ request_irq(IRQ_MFP_ACIA, atari_keyboard_interrupt, IRQ_TYPE_SLOW,
++ "keyboard/mouse/MIDI", atari_keyboard_interrupt);
++
++ atari_turnoff_irq(IRQ_MFP_ACIA);
++ do {
++ /* reset IKBD ACIA */
++ acia.key_ctrl = ACIA_RESET |
++ (atari_switches & ATARI_SWITCH_IKBD) ? ACIA_RHTID : 0;
++ (void)acia.key_ctrl;
++ (void)acia.key_data;
++
++ /* reset MIDI ACIA */
++ acia.mid_ctrl = ACIA_RESET |
++ (atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0;
++ (void)acia.mid_ctrl;
++ (void)acia.mid_data;
++
++ /* divide 500kHz by 64 gives 7812.5 baud */
++ /* 8 data no parity 1 start 1 stop bit */
++ /* receive interrupt enabled */
++ /* RTS low (except if switch selected), transmit interrupt disabled */
++ acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RIE) |
++ ((atari_switches & ATARI_SWITCH_IKBD) ?
++ ACIA_RHTID : ACIA_RLTID);
++
++ acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S |
++ (atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0;
++
++ /* make sure the interrupt line is up */
++ } while ((mfp.par_dt_reg & 0x10) == 0);
++
++ /* enable ACIA Interrupts */
++ mfp.active_edge &= ~0x10;
++ atari_turnon_irq(IRQ_MFP_ACIA);
++
++ ikbd_self_test = 1;
++ ikbd_reset();
++ /* wait for a period of inactivity (here: 0.25s), then assume the IKBD's
++ * self-test is finished */
++ self_test_last_rcv = jiffies;
++ while (time_before(jiffies, self_test_last_rcv + HZ/4))
++ barrier();
++ /* if not incremented: no 0xf1 received */
++ if (ikbd_self_test == 1)
++ printk(KERN_ERR "WARNING: keyboard self test failed!\n");
++ ikbd_self_test = 0;
++
++ ikbd_mouse_disable();
++ ikbd_joystick_disable();
++
++#ifdef FIXED_ATARI_JOYSTICK
++ atari_joystick_init();
++#endif
++
++ // flag init done
++ atari_keyb_done = 1;
++ return 0;
++}
++
++
++int atari_kbdrate(struct kbd_repeat *k)
++{
++ if (k->delay > 0) {
++ /* convert from msec to jiffies */
++ key_repeat_delay = (k->delay * HZ + 500) / 1000;
++ if (key_repeat_delay < 1)
++ key_repeat_delay = 1;
++ }
++ if (k->period > 0) {
++ key_repeat_rate = (k->period * HZ + 500) / 1000;
++ if (key_repeat_rate < 1)
++ key_repeat_rate = 1;
++ }
++
++ k->delay = key_repeat_delay * 1000 / HZ;
++ k->period = key_repeat_rate * 1000 / HZ;
++
++ return 0;
++}
++
++int atari_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode)
++{
++#ifdef CONFIG_MAGIC_SYSRQ
++ /* ALT+HELP pressed? */
++ if ((keycode == 98) && ((shift_state & 0xff) == 8))
++ *keycodep = 0xff;
++ else
++#endif
++ *keycodep = keycode;
++ return 1;
++}
+--- linux-m68k-2.6.21.orig/drivers/input/keyboard/Kconfig
++++ linux-m68k-2.6.21/drivers/input/keyboard/Kconfig
+@@ -164,6 +164,17 @@ config KEYBOARD_AMIGA
+ To compile this driver as a module, choose M here: the
+ module will be called amikbd.
+
++config KEYBOARD_ATARI
++ tristate "Atari keyboard"
++ depends on ATARI
++ select ATARI_KBD_CORE
++ help
++ Say Y here if you are running Linux on any Atari and have a keyboard
++ attached.
++
++ To compile this driver as a module, choose M here: the
++ module will be called atakbd.
++
+ config KEYBOARD_HIL_OLD
+ tristate "HP HIL keyboard support (simple driver)"
+ depends on GSC || HP300
+--- linux-m68k-2.6.21.orig/drivers/input/keyboard/Makefile
++++ linux-m68k-2.6.21/drivers/input/keyboard/Makefile
+@@ -9,6 +9,7 @@ obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd
+ obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o
+ obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
+ obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
++obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
+ obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o
+ obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
+ obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
+--- /dev/null
++++ linux-m68k-2.6.21/drivers/input/keyboard/atakbd.c
+@@ -0,0 +1,134 @@
++/*
++ * atakbd.c
++ *
++ * Copyright (c) 2005 Michael Schmitz
++ *
++ * Based on amikbd.c, which is
++ *
++ * Copyright (c) 2000-2001 Vojtech Pavlik
++ *
++ * Based on the work of:
++ * Hamish Macdonald
++ */
++
++/*
++ * Atari keyboard driver for Linux/m68k
++ *
++ * The low level init and interrupt stuff is handled in arch/mm68k/atari/atakeyb.c
++ * (the keyboard ACIA also handles the mouse and joystick data, and the keyboard
++ * interrupt is shared with the MIDI ACIA so MIDI data also get handled there).
++ * This driver only deals with handing key events off to the input layer.
++ */
++
++/*
++ * 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
++ *
++ * Should you need to contact me, the author, you can do so either by
++ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
++ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/input.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++
++#include <asm/atariints.h>
++#include <asm/atarihw.h>
++#include <asm/atarikb.h>
++#include <asm/irq.h>
++
++MODULE_AUTHOR("Michael Schmitz <schmitz@biophys.uni-duesseldorf.de>");
++MODULE_DESCRIPTION("Atari keyboard driver");
++MODULE_LICENSE("GPL");
++
++static unsigned char atakbd_keycode[0x72];
++
++static struct input_dev *atakbd_dev;
++
++static void atakbd_interrupt(unsigned char scancode, char down)
++{
++
++ if (scancode < 0x72) { /* scancodes < 0xf2 are keys */
++
++ // report raw events here?
++
++ scancode = atakbd_keycode[scancode];
++
++ if (scancode == KEY_CAPSLOCK) { /* CapsLock is a toggle switch key on Amiga */
++ input_report_key(atakbd_dev, scancode, 1);
++ input_report_key(atakbd_dev, scancode, 0);
++ input_sync(atakbd_dev);
++ } else {
++ input_report_key(atakbd_dev, scancode, down);
++ input_sync(atakbd_dev);
++ }
++ } else /* scancodes >= 0xf2 are mouse data, most likely */
++ printk(KERN_INFO "atakbd: unhandled scancode %x\n", scancode);
++
++ return;
++}
++
++static int __init atakbd_init(void)
++{
++ int i;
++
++ if (!ATARIHW_PRESENT(ST_MFP))
++ return -EIO;
++
++ // TODO: request_mem_region if not done in arch code
++
++ if (!(atakbd_dev = input_allocate_device()))
++ return -ENOMEM;
++
++ // need to init core driver if not already done so
++ if (atari_keyb_init())
++ return -ENODEV;
++
++ atakbd_dev->name = "Atari Keyboard";
++ atakbd_dev->phys = "atakbd/input0";
++ atakbd_dev->id.bustype = BUS_ATARI;
++ atakbd_dev->id.vendor = 0x0001;
++ atakbd_dev->id.product = 0x0001;
++ atakbd_dev->id.version = 0x0100;
++
++ atakbd_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
++ atakbd_dev->keycode = atakbd_keycode;
++ atakbd_dev->keycodesize = sizeof(unsigned char);
++ atakbd_dev->keycodemax = ARRAY_SIZE(atakbd_keycode);
++
++ for (i = 1; i < 0x72; i++) {
++ atakbd_keycode[i] = i;
++ set_bit(atakbd_keycode[i], atakbd_dev->keybit);
++ }
++
++ input_register_device(atakbd_dev);
++
++ atari_input_keyboard_interrupt_hook = atakbd_interrupt;
++
++ printk(KERN_INFO "input: %s at IKBD ACIA\n", atakbd_dev->name);
++
++ return 0;
++}
++
++static void __exit atakbd_exit(void)
++{
++ atari_input_keyboard_interrupt_hook = NULL;
++ input_unregister_device(atakbd_dev);
++}
++
++module_init(atakbd_init);
++module_exit(atakbd_exit);
+--- linux-m68k-2.6.21.orig/drivers/input/mouse/Kconfig
++++ linux-m68k-2.6.21/drivers/input/mouse/Kconfig
+@@ -96,6 +96,17 @@ config MOUSE_AMIGA
+ To compile this driver as a module, choose M here: the
+ module will be called amimouse.
+
++config MOUSE_ATARI
++ tristate "Atari mouse"
++ depends on ATARI
++ select ATARI_KBD_CORE
++ help
++ Say Y here if you have an Atari and want its native mouse
++ supported by the kernel.
++
++ To compile this driver as a module, choose M here: the
++ module will be called atarimouse.
++
+ config MOUSE_RISCPC
+ tristate "Acorn RiscPC mouse"
+ depends on ARCH_ACORN
+--- linux-m68k-2.6.21.orig/drivers/input/mouse/Makefile
++++ linux-m68k-2.6.21/drivers/input/mouse/Makefile
+@@ -5,6 +5,7 @@
+ # Each configuration option enables a list of files.
+
+ obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o
++obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o
+ obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o
+ obj-$(CONFIG_MOUSE_INPORT) += inport.o
+ obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o
+--- /dev/null
++++ linux-m68k-2.6.21/drivers/input/mouse/atarimouse.c
+@@ -0,0 +1,160 @@
++/*
++ * Atari mouse driver for Linux/m68k
++ *
++ * Copyright (c) 2005 Michael Schmitz
++ *
++ * Based on:
++ * Amiga mouse driver for Linux/m68k
++ *
++ * Copyright (c) 2000-2002 Vojtech Pavlik
++ *
++ */
++/*
++ * The low level init and interrupt stuff is handled in arch/mm68k/atari/atakeyb.c
++ * (the keyboard ACIA also handles the mouse and joystick data, and the keyboard
++ * interrupt is shared with the MIDI ACIA so MIDI data also get handled there).
++ * This driver only deals with handing key events off to the input layer.
++ *
++ * Largely based on the old:
++ *
++ * Atari Mouse Driver for Linux
++ * by Robert de Vries (robert@and.nl) 19Jul93
++ *
++ * 16 Nov 1994 Andreas Schwab
++ * Compatibility with busmouse
++ * Support for three button mouse (shamelessly stolen from MiNT)
++ * third button wired to one of the joystick directions on joystick 1
++ *
++ * 1996/02/11 Andreas Schwab
++ * Module support
++ * Allow multiple open's
++ *
++ * Converted to use new generic busmouse code. 5 Apr 1998
++ * Russell King <rmk@arm.uk.linux.org>
++ */
++
++
++/*
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published by
++ * the Free Software Foundation
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/input.h>
++#include <linux/interrupt.h>
++
++#include <asm/irq.h>
++#include <asm/setup.h>
++#include <asm/system.h>
++#include <asm/uaccess.h>
++#include <asm/atarihw.h>
++#include <asm/atarikb.h>
++#include <asm/atariints.h>
++
++MODULE_AUTHOR("Michael Schmitz <schmitz@biophys.uni-duesseldorf.de>");
++MODULE_DESCRIPTION("Atari mouse driver");
++MODULE_LICENSE("GPL");
++
++static int mouse_threshold[2] = {2,2};
++
++#ifdef __MODULE__
++MODULE_PARM(mouse_threshold, "2i");
++#endif
++#ifdef FIXED_ATARI_JOYSTICK
++extern int atari_mouse_buttons;
++#endif
++static int atamouse_used = 0;
++
++static struct input_dev *atamouse_dev;
++
++static void atamouse_interrupt(char *buf)
++{
++ int buttons, dx, dy;
++
++/* ikbd_mouse_disable(); */
++
++ buttons = (buf[0] & 1) | ((buf[0] & 2) << 1);
++#ifdef FIXED_ATARI_JOYSTICK
++ buttons |= atari_mouse_buttons & 2;
++ atari_mouse_buttons = buttons;
++#endif
++/* ikbd_mouse_rel_pos(); */
++
++ /* only relative events get here */
++ dx = buf[1];
++ dy = -buf[2];
++
++ input_report_rel(atamouse_dev, REL_X, dx);
++ input_report_rel(atamouse_dev, REL_Y, dy);
++
++ input_report_key(atamouse_dev, BTN_LEFT, buttons & 0x1);
++ input_report_key(atamouse_dev, BTN_MIDDLE, buttons & 0x2);
++ input_report_key(atamouse_dev, BTN_RIGHT, buttons & 0x4);
++
++ input_sync(atamouse_dev);
++
++ return;
++}
++
++static int atamouse_open(struct input_dev *dev)
++{
++ if (atamouse_used++)
++ return 0;
++
++#ifdef FIXED_ATARI_JOYSTICK
++ atari_mouse_buttons = 0;
++#endif
++ ikbd_mouse_y0_top();
++ ikbd_mouse_thresh(mouse_threshold[0], mouse_threshold[1]);
++ ikbd_mouse_rel_pos();
++ atari_input_mouse_interrupt_hook = atamouse_interrupt;
++ return 0;
++}
++
++static void atamouse_close(struct input_dev *dev)
++{
++ if (!--atamouse_used) {
++ ikbd_mouse_disable();
++ atari_mouse_interrupt_hook = NULL;
++ }
++}
++
++static int __init atamouse_init(void)
++{
++ if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP))
++ return -ENODEV;
++
++ if (!(atamouse_dev = input_allocate_device()))
++ return -ENOMEM;
++
++ if (!(atari_keyb_init()))
++ return -ENODEV;
++
++ atamouse_dev->name = "Atari mouse";
++ atamouse_dev->phys = "atamouse/input0";
++ atamouse_dev->id.bustype = BUS_ATARI;
++ atamouse_dev->id.vendor = 0x0001;
++ atamouse_dev->id.product = 0x0002;
++ atamouse_dev->id.version = 0x0100;
++
++ atamouse_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
++ atamouse_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
++ atamouse_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
++ atamouse_dev->open = atamouse_open;
++ atamouse_dev->close = atamouse_close;
++
++ input_register_device(atamouse_dev);
++
++ printk(KERN_INFO "input: %s at keyboard ACIA\n", atamouse_dev->name);
++ return 0;
++}
++
++static void __exit atamouse_exit(void)
++{
++ input_unregister_device(atamouse_dev);
++}
++
++module_init(atamouse_init);
++module_exit(atamouse_exit);
+--- linux-m68k-2.6.21.orig/include/asm-m68k/atarikb.h
++++ linux-m68k-2.6.21/include/asm-m68k/atarikb.h
+@@ -36,5 +36,11 @@ void ikbd_joystick_disable(void);
+ extern void (*atari_MIDI_interrupt_hook) (void);
+ /* Hook for mouse driver */
+ extern void (*atari_mouse_interrupt_hook) (char *);
++/* Hook for keyboard inputdev driver */
++extern void (*atari_input_keyboard_interrupt_hook) (unsigned char, char);
++/* Hook for mouse inputdev driver */
++extern void (*atari_input_mouse_interrupt_hook) (char *);
++
++int atari_keyb_init(void);
+
+ #endif /* _LINUX_ATARIKB_H */
+--- linux-m68k-2.6.21.orig/include/linux/input.h
++++ linux-m68k-2.6.21/include/linux/input.h
+@@ -676,6 +676,7 @@ struct input_absinfo {
+ #define BUS_I2C 0x18
+ #define BUS_HOST 0x19
+ #define BUS_GSC 0x1A
++#define BUS_ATARI 0x1B
+
+ /*
+ * Values describing the status of a force-feedback effect
diff --git a/debian/patches/bugfix/m68k/636-atafb.diff b/debian/patches/bugfix/m68k/636-atafb.diff
new file mode 100644
index 000000000000..da79fd9df523
--- /dev/null
+++ b/debian/patches/bugfix/m68k/636-atafb.diff
@@ -0,0 +1,5530 @@
+Cc: Antonino Daplas <adaplas@gmail.com>,
+ James Simmons <jsimmons@infradead.org>,
+ linux-fbdev-devel@lists.sourceforge.net
+Subject: [PATCH] m68k: Atari fb revival
+
+From: Michael Schmitz <schmitz@opal.biophys.uni-duesseldorf.de>
+
+Update the atari fb to 2.6 by Michael Schmitz,
+Reformatting and rewrite of bit plane functions by Roman Zippel,
+A few more fixes by Geert Uytterhoeven.
+
+Signed-off-by: Michael Schmitz <schmitz@debian.org>
+Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ drivers/video/Kconfig | 5
+ drivers/video/Makefile | 3
+ drivers/video/atafb.c | 2799 +++++++++++++++++++++--------------------
+ drivers/video/atafb.h | 36
+ drivers/video/atafb_iplan2p2.c | 293 ++++
+ drivers/video/atafb_iplan2p4.c | 308 ++++
+ drivers/video/atafb_iplan2p8.c | 345 +++++
+ drivers/video/atafb_mfb.c | 112 +
+ drivers/video/atafb_utils.h | 400 +++++
+ 9 files changed, 2986 insertions(+), 1315 deletions(-)
+
+--- linux-m68k-2.6.21.orig/drivers/video/Kconfig
++++ linux-m68k-2.6.21/drivers/video/Kconfig
+@@ -389,7 +389,10 @@ config FB_ARC
+
+ config FB_ATARI
+ bool "Atari native chipset support"
+- depends on (FB = y) && ATARI && BROKEN
++ depends on (FB = y) && ATARI
++ select FB_CFB_FILLRECT
++ select FB_CFB_COPYAREA
++ select FB_CFB_IMAGEBLIT
+ help
+ This is the frame buffer device driver for the builtin graphics
+ chipset found in Ataris.
+--- linux-m68k-2.6.21.orig/drivers/video/Makefile
++++ linux-m68k-2.6.21/drivers/video/Makefile
+@@ -63,7 +63,8 @@ obj-$(CONFIG_FB_TCX) += tcx
+ obj-$(CONFIG_FB_LEO) += leo.o sbuslib.o
+ obj-$(CONFIG_FB_SGIVW) += sgivwfb.o
+ obj-$(CONFIG_FB_ACORN) += acornfb.o
+-obj-$(CONFIG_FB_ATARI) += atafb.o
++obj-$(CONFIG_FB_ATARI) += atafb.o c2p.o atafb_mfb.o \
++ atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o
+ obj-$(CONFIG_FB_MAC) += macfb.o
+ obj-$(CONFIG_FB_HGA) += hgafb.o
+ obj-$(CONFIG_FB_IGA) += igafb.o
+--- linux-m68k-2.6.21.orig/drivers/video/atafb.c
++++ linux-m68k-2.6.21/drivers/video/atafb.c
+@@ -2,7 +2,7 @@
+ * linux/drivers/video/atafb.c -- Atari builtin chipset frame buffer device
+ *
+ * Copyright (C) 1994 Martin Schaller & Roman Hodek
+- *
++ *
+ * 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.
+@@ -70,14 +70,8 @@
+ #include <linux/fb.h>
+ #include <asm/atarikb.h>
+
+-#include <video/fbcon.h>
+-#include <video/fbcon-cfb8.h>
+-#include <video/fbcon-cfb16.h>
+-#include <video/fbcon-iplan2p2.h>
+-#include <video/fbcon-iplan2p4.h>
+-#include <video/fbcon-iplan2p8.h>
+-#include <video/fbcon-mfb.h>
+-
++#include "c2p.h"
++#include "atafb.h"
+
+ #define SWITCH_ACIA 0x01 /* modes for switch on OverScan */
+ #define SWITCH_SND6 0x40
+@@ -87,22 +81,48 @@
+
+ #define up(x, r) (((x) + (r) - 1) & ~((r)-1))
+
++ /*
++ * Interface to the world
++ */
++
++static int atafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info);
++static int atafb_set_par(struct fb_info *info);
++static int atafb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
++ unsigned int blue, unsigned int transp,
++ struct fb_info *info);
++static int atafb_blank(int blank, struct fb_info *info);
++static int atafb_pan_display(struct fb_var_screeninfo *var,
++ struct fb_info *info);
++static void atafb_fillrect(struct fb_info *info,
++ const struct fb_fillrect *rect);
++static void atafb_copyarea(struct fb_info *info,
++ const struct fb_copyarea *region);
++static void atafb_imageblit(struct fb_info *info, const struct fb_image *image);
++static int atafb_ioctl(struct fb_info *info, unsigned int cmd,
++ unsigned long arg);
+
+-static int default_par=0; /* default resolution (0=none) */
+
+-static unsigned long default_mem_req=0;
++static int default_par; /* default resolution (0=none) */
+
+-static int hwscroll=-1;
++static unsigned long default_mem_req;
++
++static int hwscroll = -1;
+
+ static int use_hwscroll = 1;
+
+-static int sttt_xres=640,st_yres=400,tt_yres=480;
+-static int sttt_xres_virtual=640,sttt_yres_virtual=400;
+-static int ovsc_offset=0, ovsc_addlen=0;
++static int sttt_xres = 640, st_yres = 400, tt_yres = 480;
++static int sttt_xres_virtual = 640, sttt_yres_virtual = 400;
++static int ovsc_offset, ovsc_addlen;
++
++ /*
++ * Hardware parameters for current mode
++ */
+
+ static struct atafb_par {
+ void *screen_base;
+ int yres_virtual;
++ u_long next_line;
++ u_long next_plane;
+ #if defined ATAFB_TT || defined ATAFB_STE
+ union {
+ struct {
+@@ -138,7 +158,7 @@ static struct atafb_par {
+ /* Don't calculate an own resolution, and thus don't change the one found when
+ * booting (currently used for the Falcon to keep settings for internal video
+ * hardware extensions (e.g. ScreenBlaster) */
+-static int DontCalcRes = 0;
++static int DontCalcRes = 0;
+
+ #ifdef ATAFB_FALCON
+ #define HHT hw.falcon.hht
+@@ -163,83 +183,84 @@ static int DontCalcRes = 0;
+ #define VMO_PREMASK 0x0c
+ #endif
+
+-static struct fb_info fb_info;
++static struct fb_info fb_info = {
++ .fix = {
++ .id = "Atari ",
++ .visual = FB_VISUAL_PSEUDOCOLOR,
++ .accel = FB_ACCEL_NONE,
++ }
++};
+
+ static void *screen_base; /* base address of screen */
+ static void *real_screen_base; /* (only for Overscan) */
+
+ static int screen_len;
+
+-static int current_par_valid=0;
+-
+-static int mono_moni=0;
++static int current_par_valid;
+
+-static struct display disp;
++static int mono_moni;
+
+
+ #ifdef ATAFB_EXT
+-/* external video handling */
+
+-static unsigned external_xres;
+-static unsigned external_xres_virtual;
+-static unsigned external_yres;
+-/* not needed - atafb will never support panning/hardwarescroll with external
+- * static unsigned external_yres_virtual;
+-*/
++/* external video handling */
++static unsigned int external_xres;
++static unsigned int external_xres_virtual;
++static unsigned int external_yres;
+
+-static unsigned external_depth;
+-static int external_pmode;
+-static void *external_addr = 0;
+-static unsigned long external_len;
+-static unsigned long external_vgaiobase = 0;
+-static unsigned int external_bitspercol = 6;
+-
+-/*
+-JOE <joe@amber.dinoco.de>:
+-added card type for external driver, is only needed for
+-colormap handling.
+-*/
++/*
++ * not needed - atafb will never support panning/hardwarescroll with external
++ * static unsigned int external_yres_virtual;
++ */
++static unsigned int external_depth;
++static int external_pmode;
++static void *external_addr;
++static unsigned long external_len;
++static unsigned long external_vgaiobase;
++static unsigned int external_bitspercol = 6;
+
++/*
++ * JOE <joe@amber.dinoco.de>:
++ * added card type for external driver, is only needed for
++ * colormap handling.
++ */
+ enum cardtype { IS_VGA, IS_MV300 };
+ static enum cardtype external_card_type = IS_VGA;
+
+ /*
+-The MV300 mixes the color registers. So we need an array of munged
+-indices in order to access the correct reg.
+-*/
+-static int MV300_reg_1bit[2]={0,1};
+-static int MV300_reg_4bit[16]={
+-0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };
+-static int MV300_reg_8bit[256]={
+-0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
+-8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
+-4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
+-12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
+-2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
+-10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
+-6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
+-14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
+-1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
+-9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
+-5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
+-13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
+-3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
+-11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
+-7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
+-15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255 };
++ * The MV300 mixes the color registers. So we need an array of munged
++ * indices in order to access the correct reg.
++ */
++static int MV300_reg_1bit[2] = {
++ 0, 1
++};
++static int MV300_reg_4bit[16] = {
++ 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15
++};
++static int MV300_reg_8bit[256] = {
++ 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
++ 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
++ 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
++ 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
++ 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
++ 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
++ 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
++ 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
++ 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
++ 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
++ 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
++ 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
++ 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
++ 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
++ 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
++ 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255
++};
+
+ static int *MV300_reg = MV300_reg_8bit;
+-
+-/*
+-And on the MV300 it's difficult to read out the hardware palette. So we
+-just keep track of the set colors in our own array here, and use that!
+-*/
+-
+-static struct { unsigned char red,green,blue,pad; } ext_color[256];
+ #endif /* ATAFB_EXT */
+
+
+-static int inverse=0;
++static int inverse;
+
+ extern int fontheight_8x8;
+ extern int fontwidth_8x8;
+@@ -249,96 +270,154 @@ extern int fontheight_8x16;
+ extern int fontwidth_8x16;
+ extern unsigned char fontdata_8x16[];
+
++/*
++ * struct fb_ops {
++ * * open/release and usage marking
++ * struct module *owner;
++ * int (*fb_open)(struct fb_info *info, int user);
++ * int (*fb_release)(struct fb_info *info, int user);
++ *
++ * * For framebuffers with strange non linear layouts or that do not
++ * * work with normal memory mapped access
++ * ssize_t (*fb_read)(struct file *file, char __user *buf, size_t count, loff_t *ppos);
++ * ssize_t (*fb_write)(struct file *file, const char __user *buf, size_t count, loff_t *ppos);
++ *
++ * * checks var and eventually tweaks it to something supported,
++ * * DOES NOT MODIFY PAR *
++ * int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
++ *
++ * * set the video mode according to info->var *
++ * int (*fb_set_par)(struct fb_info *info);
++ *
++ * * set color register *
++ * int (*fb_setcolreg)(unsigned int regno, unsigned int red, unsigned int green,
++ * unsigned int blue, unsigned int transp, struct fb_info *info);
++ *
++ * * set color registers in batch *
++ * int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);
++ *
++ * * blank display *
++ * int (*fb_blank)(int blank, struct fb_info *info);
++ *
++ * * pan display *
++ * int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);
++ *
++ * *** The meat of the drawing engine ***
++ * * Draws a rectangle *
++ * void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
++ * * Copy data from area to another *
++ * void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
++ * * Draws a image to the display *
++ * void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
++ *
++ * * Draws cursor *
++ * int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);
++ *
++ * * Rotates the display *
++ * void (*fb_rotate)(struct fb_info *info, int angle);
++ *
++ * * wait for blit idle, optional *
++ * int (*fb_sync)(struct fb_info *info);
++ *
++ * * perform fb specific ioctl (optional) *
++ * int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
++ * unsigned long arg);
++ *
++ * * Handle 32bit compat ioctl (optional) *
++ * int (*fb_compat_ioctl)(struct fb_info *info, unsigned int cmd,
++ * unsigned long arg);
++ *
++ * * perform fb specific mmap *
++ * int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
++ *
++ * * save current hardware state *
++ * void (*fb_save_state)(struct fb_info *info);
++ *
++ * * restore saved state *
++ * void (*fb_restore_state)(struct fb_info *info);
++ * } ;
++ */
++
++
+ /* ++roman: This structure abstracts from the underlying hardware (ST(e),
+ * TT, or Falcon.
+ *
+- * int (*detect)( void )
++ * int (*detect)(void)
+ * This function should detect the current video mode settings and
+ * store them in atafb_predefined[0] for later reference by the
+ * user. Return the index+1 of an equivalent predefined mode or 0
+ * if there is no such.
+- *
+- * int (*encode_fix)( struct fb_fix_screeninfo *fix,
+- * struct atafb_par *par )
++ *
++ * int (*encode_fix)(struct fb_fix_screeninfo *fix,
++ * struct atafb_par *par)
+ * This function should fill in the 'fix' structure based on the
+ * values in the 'par' structure.
+- *
+- * int (*decode_var)( struct fb_var_screeninfo *var,
+- * struct atafb_par *par )
++ * !!! Obsolete, perhaps !!!
++ *
++ * int (*decode_var)(struct fb_var_screeninfo *var,
++ * struct atafb_par *par)
+ * Get the video params out of 'var'. If a value doesn't fit, round
+ * it up, if it's too big, return EINVAL.
+- * Round up in the following order: bits_per_pixel, xres, yres,
+- * xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields,
++ * Round up in the following order: bits_per_pixel, xres, yres,
++ * xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields,
+ * horizontal timing, vertical timing.
+ *
+- * int (*encode_var)( struct fb_var_screeninfo *var,
+- * struct atafb_par *par );
++ * int (*encode_var)(struct fb_var_screeninfo *var,
++ * struct atafb_par *par);
+ * Fill the 'var' structure based on the values in 'par' and maybe
+ * other values read out of the hardware.
+- *
+- * void (*get_par)( struct atafb_par *par )
++ *
++ * void (*get_par)(struct atafb_par *par)
+ * Fill the hardware's 'par' structure.
+- *
+- * void (*set_par)( struct atafb_par *par )
++ * !!! Used only by detect() !!!
++ *
++ * void (*set_par)(struct atafb_par *par)
+ * Set the hardware according to 'par'.
+- *
+- * int (*getcolreg)( unsigned regno, unsigned *red,
+- * unsigned *green, unsigned *blue,
+- * unsigned *transp, struct fb_info *info )
+- * Read a single color register and split it into
+- * colors/transparent. Return != 0 for invalid regno.
+ *
+ * void (*set_screen_base)(void *s_base)
+ * Set the base address of the displayed frame buffer. Only called
+ * if yres_virtual > yres or xres_virtual > xres.
+ *
+- * int (*blank)( int blank_mode )
+- * Blank the screen if blank_mode!=0, else unblank. If blank==NULL then
++ * int (*blank)(int blank_mode)
++ * Blank the screen if blank_mode != 0, else unblank. If blank == NULL then
+ * the caller blanks by setting the CLUT to all black. Return 0 if blanking
+ * succeeded, !=0 if un-/blanking failed due to e.g. a video mode which
+ * doesn't support it. Implements VESA suspend and powerdown modes on
+ * hardware that supports disabling hsync/vsync:
+- * blank_mode==2: suspend vsync, 3:suspend hsync, 4: powerdown.
++ * blank_mode == 2: suspend vsync, 3:suspend hsync, 4: powerdown.
+ */
+
+ static struct fb_hwswitch {
+- int (*detect)( void );
+- int (*encode_fix)( struct fb_fix_screeninfo *fix,
+- struct atafb_par *par );
+- int (*decode_var)( struct fb_var_screeninfo *var,
+- struct atafb_par *par );
+- int (*encode_var)( struct fb_var_screeninfo *var,
+- struct atafb_par *par );
+- void (*get_par)( struct atafb_par *par );
+- void (*set_par)( struct atafb_par *par );
+- int (*getcolreg)( unsigned regno, unsigned *red,
+- unsigned *green, unsigned *blue,
+- unsigned *transp, struct fb_info *info );
++ int (*detect)(void);
++ int (*encode_fix)(struct fb_fix_screeninfo *fix,
++ struct atafb_par *par);
++ int (*decode_var)(struct fb_var_screeninfo *var,
++ struct atafb_par *par);
++ int (*encode_var)(struct fb_var_screeninfo *var,
++ struct atafb_par *par);
++ void (*get_par)(struct atafb_par *par);
++ void (*set_par)(struct atafb_par *par);
+ void (*set_screen_base)(void *s_base);
+- int (*blank)( int blank_mode );
+- int (*pan_display)( struct fb_var_screeninfo *var,
+- struct atafb_par *par);
++ int (*blank)(int blank_mode);
++ int (*pan_display)(struct fb_var_screeninfo *var,
++ struct fb_info *info);
+ } *fbhw;
+
+-static char *autodetect_names[] = {"autodetect", NULL};
+-static char *stlow_names[] = {"stlow", NULL};
+-static char *stmid_names[] = {"stmid", "default5", NULL};
+-static char *sthigh_names[] = {"sthigh", "default4", NULL};
+-static char *ttlow_names[] = {"ttlow", NULL};
+-static char *ttmid_names[]= {"ttmid", "default1", NULL};
+-static char *tthigh_names[]= {"tthigh", "default2", NULL};
+-static char *vga2_names[] = {"vga2", NULL};
+-static char *vga4_names[] = {"vga4", NULL};
+-static char *vga16_names[] = {"vga16", "default3", NULL};
+-static char *vga256_names[] = {"vga256", NULL};
+-static char *falh2_names[] = {"falh2", NULL};
+-static char *falh16_names[] = {"falh16", NULL};
++static char *autodetect_names[] = { "autodetect", NULL };
++static char *stlow_names[] = { "stlow", NULL };
++static char *stmid_names[] = { "stmid", "default5", NULL };
++static char *sthigh_names[] = { "sthigh", "default4", NULL };
++static char *ttlow_names[] = { "ttlow", NULL };
++static char *ttmid_names[] = { "ttmid", "default1", NULL };
++static char *tthigh_names[] = { "tthigh", "default2", NULL };
++static char *vga2_names[] = { "vga2", NULL };
++static char *vga4_names[] = { "vga4", NULL };
++static char *vga16_names[] = { "vga16", "default3", NULL };
++static char *vga256_names[] = { "vga256", NULL };
++static char *falh2_names[] = { "falh2", NULL };
++static char *falh16_names[] = { "falh16", NULL };
+
+ static char **fb_var_names[] = {
+- /* Writing the name arrays directly in this array (via "(char *[]){...}")
+- * crashes gcc 2.5.8 (sigsegv) if the inner array
+- * contains more than two items. I've also seen that all elements
+- * were identical to the last (my cross-gcc) :-(*/
+ autodetect_names,
+ stlow_names,
+ stmid_names,
+@@ -353,18 +432,17 @@ static char **fb_var_names[] = {
+ falh2_names,
+ falh16_names,
+ NULL
+- /* ,NULL */ /* this causes a sigsegv on my gcc-2.5.8 */
+ };
+
+ static struct fb_var_screeninfo atafb_predefined[] = {
+- /*
+- * yres_virtual==0 means use hw-scrolling if possible, else yres
+- */
+- { /* autodetect */
+- 0, 0, 0, 0, 0, 0, 0, 0, /* xres-grayscale */
+- {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, /* red green blue tran*/
++ /*
++ * yres_virtual == 0 means use hw-scrolling if possible, else yres
++ */
++ { /* autodetect */
++ 0, 0, 0, 0, 0, 0, 0, 0, /* xres-grayscale */
++ {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, /* red green blue tran*/
+ 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+- { /* st low */
++ { /* st low */
+ 320, 200, 320, 0, 0, 0, 4, 0,
+ {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+@@ -414,27 +492,100 @@ static struct fb_var_screeninfo atafb_pr
+ 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
+ };
+
+-static int num_atafb_predefined=ARRAY_SIZE(atafb_predefined);
++static int num_atafb_predefined = ARRAY_SIZE(atafb_predefined);
+
++static struct fb_videomode atafb_modedb[] __initdata = {
++ /*
++ * Atari Video Modes
++ *
++ * If you change these, make sure to update DEFMODE_* as well!
++ */
+
+-static int
+-get_video_mode(char *vname)
++ /*
++ * ST/TT Video Modes
++ */
++
++ {
++ /* 320x200, 15 kHz, 60 Hz (ST low) */
++ "st-low", 60, 320, 200, 32000, 32, 16, 31, 14, 96, 4,
++ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
++ }, {
++ /* 640x200, 15 kHz, 60 Hz (ST medium) */
++ "st-mid", 60, 640, 200, 32000, 32, 16, 31, 14, 96, 4,
++ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
++ }, {
++ /* 640x400, 30.25 kHz, 63.5 Hz (ST high) */
++ "st-high", 63, 640, 400, 32000, 128, 0, 40, 14, 128, 4,
++ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
++ }, {
++ /* 320x480, 15 kHz, 60 Hz (TT low) */
++ "tt-low", 60, 320, 480, 31041, 120, 100, 8, 16, 140, 30,
++ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
++ }, {
++ /* 640x480, 29 kHz, 57 Hz (TT medium) */
++ "tt-mid", 60, 640, 480, 31041, 120, 100, 8, 16, 140, 30,
++ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
++ }, {
++ /* 1280x960, 29 kHz, 60 Hz (TT high) */
++ "tt-high", 57, 640, 960, 31041, 120, 100, 8, 16, 140, 30,
++ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
++ },
++
++ /*
++ * VGA Video Modes
++ */
++
++ {
++ /* 640x480, 31 kHz, 60 Hz (VGA) */
++ "vga", 63.5, 640, 480, 32000, 18, 42, 31, 11, 96, 3,
++ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
++ }, {
++ /* 640x400, 31 kHz, 70 Hz (VGA) */
++ "vga70", 70, 640, 400, 32000, 18, 42, 31, 11, 96, 3,
++ FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
++ },
++
++ /*
++ * Falcon HiRes Video Modes
++ */
++
++ {
++ /* 896x608, 31 kHz, 60 Hz (Falcon High) */
++ "falh", 60, 896, 608, 32000, 18, 42, 31, 1, 96,3,
++ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
++ },
++};
++
++#define NUM_TOTAL_MODES ARRAY_SIZE(atafb_modedb)
++
++static char *mode_option __initdata = NULL;
++
++ /* default modes */
++
++#define DEFMODE_TT 5 /* "tt-high" for TT */
++#define DEFMODE_F30 7 /* "vga70" for Falcon */
++#define DEFMODE_STE 2 /* "st-high" for ST/E */
++#define DEFMODE_EXT 6 /* "vga" for external */
++
++
++static int get_video_mode(char *vname)
+ {
+- char ***name_list;
+- char **name;
+- int i;
+- name_list=fb_var_names;
+- for (i = 0 ; i < num_atafb_predefined ; i++) {
+- name=*(name_list++);
+- if (! name || ! *name)
+- break;
+- while (*name) {
+- if (! strcmp(vname, *name))
+- return i+1;
+- name++;
++ char ***name_list;
++ char **name;
++ int i;
++
++ name_list = fb_var_names;
++ for (i = 0; i < num_atafb_predefined; i++) {
++ name = *name_list++;
++ if (!name || !*name)
++ break;
++ while (*name) {
++ if (!strcmp(vname, *name))
++ return i + 1;
++ name++;
++ }
+ }
+- }
+- return 0;
++ return 0;
+ }
+
+
+@@ -443,93 +594,84 @@ get_video_mode(char *vname)
+
+ #ifdef ATAFB_TT
+
+-static int tt_encode_fix( struct fb_fix_screeninfo *fix,
+- struct atafb_par *par )
+-
++static int tt_encode_fix(struct fb_fix_screeninfo *fix, struct atafb_par *par)
+ {
+ int mode;
+
+- strcpy(fix->id,"Atari Builtin");
++ strcpy(fix->id, "Atari Builtin");
+ fix->smem_start = (unsigned long)real_screen_base;
+ fix->smem_len = screen_len;
+- fix->type=FB_TYPE_INTERLEAVED_PLANES;
+- fix->type_aux=2;
+- fix->visual=FB_VISUAL_PSEUDOCOLOR;
++ fix->type = FB_TYPE_INTERLEAVED_PLANES;
++ fix->type_aux = 2;
++ fix->visual = FB_VISUAL_PSEUDOCOLOR;
+ mode = par->hw.tt.mode & TT_SHIFTER_MODEMASK;
+ if (mode == TT_SHIFTER_TTHIGH || mode == TT_SHIFTER_STHIGH) {
+- fix->type=FB_TYPE_PACKED_PIXELS;
+- fix->type_aux=0;
++ fix->type = FB_TYPE_PACKED_PIXELS;
++ fix->type_aux = 0;
+ if (mode == TT_SHIFTER_TTHIGH)
+- fix->visual=FB_VISUAL_MONO01;
++ fix->visual = FB_VISUAL_MONO01;
+ }
+- fix->xpanstep=0;
+- fix->ypanstep=1;
+- fix->ywrapstep=0;
++ fix->xpanstep = 0;
++ fix->ypanstep = 1;
++ fix->ywrapstep = 0;
+ fix->line_length = 0;
+ fix->accel = FB_ACCEL_ATARIBLITT;
+ return 0;
+ }
+
+-
+-static int tt_decode_var( struct fb_var_screeninfo *var,
+- struct atafb_par *par )
++static int tt_decode_var(struct fb_var_screeninfo *var, struct atafb_par *par)
+ {
+- int xres=var->xres;
+- int yres=var->yres;
+- int bpp=var->bits_per_pixel;
++ int xres = var->xres;
++ int yres = var->yres;
++ int bpp = var->bits_per_pixel;
+ int linelen;
+ int yres_virtual = var->yres_virtual;
+
+ if (mono_moni) {
+- if (bpp > 1 || xres > sttt_xres*2 || yres >tt_yres*2)
++ if (bpp > 1 || xres > sttt_xres * 2 || yres > tt_yres * 2)
+ return -EINVAL;
+- par->hw.tt.mode=TT_SHIFTER_TTHIGH;
+- xres=sttt_xres*2;
+- yres=tt_yres*2;
+- bpp=1;
++ par->hw.tt.mode = TT_SHIFTER_TTHIGH;
++ xres = sttt_xres * 2;
++ yres = tt_yres * 2;
++ bpp = 1;
+ } else {
+ if (bpp > 8 || xres > sttt_xres || yres > tt_yres)
+ return -EINVAL;
+ if (bpp > 4) {
+- if (xres > sttt_xres/2 || yres > tt_yres)
++ if (xres > sttt_xres / 2 || yres > tt_yres)
+ return -EINVAL;
+- par->hw.tt.mode=TT_SHIFTER_TTLOW;
+- xres=sttt_xres/2;
+- yres=tt_yres;
+- bpp=8;
+- }
+- else if (bpp > 2) {
++ par->hw.tt.mode = TT_SHIFTER_TTLOW;
++ xres = sttt_xres / 2;
++ yres = tt_yres;
++ bpp = 8;
++ } else if (bpp > 2) {
+ if (xres > sttt_xres || yres > tt_yres)
+ return -EINVAL;
+- if (xres > sttt_xres/2 || yres > st_yres/2) {
+- par->hw.tt.mode=TT_SHIFTER_TTMID;
+- xres=sttt_xres;
+- yres=tt_yres;
+- bpp=4;
++ if (xres > sttt_xres / 2 || yres > st_yres / 2) {
++ par->hw.tt.mode = TT_SHIFTER_TTMID;
++ xres = sttt_xres;
++ yres = tt_yres;
++ bpp = 4;
++ } else {
++ par->hw.tt.mode = TT_SHIFTER_STLOW;
++ xres = sttt_xres / 2;
++ yres = st_yres / 2;
++ bpp = 4;
+ }
+- else {
+- par->hw.tt.mode=TT_SHIFTER_STLOW;
+- xres=sttt_xres/2;
+- yres=st_yres/2;
+- bpp=4;
+- }
+- }
+- else if (bpp > 1) {
+- if (xres > sttt_xres || yres > st_yres/2)
++ } else if (bpp > 1) {
++ if (xres > sttt_xres || yres > st_yres / 2)
+ return -EINVAL;
+- par->hw.tt.mode=TT_SHIFTER_STMID;
+- xres=sttt_xres;
+- yres=st_yres/2;
+- bpp=2;
+- }
+- else if (var->xres > sttt_xres || var->yres > st_yres) {
++ par->hw.tt.mode = TT_SHIFTER_STMID;
++ xres = sttt_xres;
++ yres = st_yres / 2;
++ bpp = 2;
++ } else if (var->xres > sttt_xres || var->yres > st_yres) {
+ return -EINVAL;
+- }
+- else {
+- par->hw.tt.mode=TT_SHIFTER_STHIGH;
+- xres=sttt_xres;
+- yres=st_yres;
+- bpp=1;
++ } else {
++ par->hw.tt.mode = TT_SHIFTER_STHIGH;
++ xres = sttt_xres;
++ yres = st_yres;
++ bpp = 1;
+ }
+ }
+ if (yres_virtual <= 0)
+@@ -537,10 +679,10 @@ static int tt_decode_var( struct fb_var_
+ else if (yres_virtual < yres)
+ yres_virtual = yres;
+ if (var->sync & FB_SYNC_EXT)
+- par->hw.tt.sync=0;
++ par->hw.tt.sync = 0;
+ else
+- par->hw.tt.sync=1;
+- linelen=xres*bpp/8;
++ par->hw.tt.sync = 1;
++ linelen = xres * bpp / 8;
+ if (yres_virtual * linelen > screen_len && screen_len)
+ return -EINVAL;
+ if (yres * linelen > screen_len && screen_len)
+@@ -552,154 +694,123 @@ static int tt_decode_var( struct fb_var_
+ return 0;
+ }
+
+-static int tt_encode_var( struct fb_var_screeninfo *var,
+- struct atafb_par *par )
++static int tt_encode_var(struct fb_var_screeninfo *var, struct atafb_par *par)
+ {
+ int linelen;
+ memset(var, 0, sizeof(struct fb_var_screeninfo));
+- var->red.offset=0;
+- var->red.length=4;
+- var->red.msb_right=0;
+- var->grayscale=0;
+-
+- var->pixclock=31041;
+- var->left_margin=120; /* these may be incorrect */
+- var->right_margin=100;
+- var->upper_margin=8;
+- var->lower_margin=16;
+- var->hsync_len=140;
+- var->vsync_len=30;
++ var->red.offset = 0;
++ var->red.length = 4;
++ var->red.msb_right = 0;
++ var->grayscale = 0;
++
++ var->pixclock = 31041;
++ var->left_margin = 120; /* these may be incorrect */
++ var->right_margin = 100;
++ var->upper_margin = 8;
++ var->lower_margin = 16;
++ var->hsync_len = 140;
++ var->vsync_len = 30;
+
+- var->height=-1;
+- var->width=-1;
++ var->height = -1;
++ var->width = -1;
+
+ if (par->hw.tt.sync & 1)
+- var->sync=0;
++ var->sync = 0;
+ else
+- var->sync=FB_SYNC_EXT;
++ var->sync = FB_SYNC_EXT;
+
+ switch (par->hw.tt.mode & TT_SHIFTER_MODEMASK) {
+ case TT_SHIFTER_STLOW:
+- var->xres=sttt_xres/2;
+- var->xres_virtual=sttt_xres_virtual/2;
+- var->yres=st_yres/2;
+- var->bits_per_pixel=4;
++ var->xres = sttt_xres / 2;
++ var->xres_virtual = sttt_xres_virtual / 2;
++ var->yres = st_yres / 2;
++ var->bits_per_pixel = 4;
+ break;
+ case TT_SHIFTER_STMID:
+- var->xres=sttt_xres;
+- var->xres_virtual=sttt_xres_virtual;
+- var->yres=st_yres/2;
+- var->bits_per_pixel=2;
++ var->xres = sttt_xres;
++ var->xres_virtual = sttt_xres_virtual;
++ var->yres = st_yres / 2;
++ var->bits_per_pixel = 2;
+ break;
+ case TT_SHIFTER_STHIGH:
+- var->xres=sttt_xres;
+- var->xres_virtual=sttt_xres_virtual;
+- var->yres=st_yres;
+- var->bits_per_pixel=1;
++ var->xres = sttt_xres;
++ var->xres_virtual = sttt_xres_virtual;
++ var->yres = st_yres;
++ var->bits_per_pixel = 1;
+ break;
+ case TT_SHIFTER_TTLOW:
+- var->xres=sttt_xres/2;
+- var->xres_virtual=sttt_xres_virtual/2;
+- var->yres=tt_yres;
+- var->bits_per_pixel=8;
++ var->xres = sttt_xres / 2;
++ var->xres_virtual = sttt_xres_virtual / 2;
++ var->yres = tt_yres;
++ var->bits_per_pixel = 8;
+ break;
+ case TT_SHIFTER_TTMID:
+- var->xres=sttt_xres;
+- var->xres_virtual=sttt_xres_virtual;
+- var->yres=tt_yres;
+- var->bits_per_pixel=4;
++ var->xres = sttt_xres;
++ var->xres_virtual = sttt_xres_virtual;
++ var->yres = tt_yres;
++ var->bits_per_pixel = 4;
+ break;
+ case TT_SHIFTER_TTHIGH:
+- var->red.length=0;
+- var->xres=sttt_xres*2;
+- var->xres_virtual=sttt_xres_virtual*2;
+- var->yres=tt_yres*2;
+- var->bits_per_pixel=1;
++ var->red.length = 0;
++ var->xres = sttt_xres * 2;
++ var->xres_virtual = sttt_xres_virtual * 2;
++ var->yres = tt_yres * 2;
++ var->bits_per_pixel = 1;
+ break;
+- }
+- var->blue=var->green=var->red;
+- var->transp.offset=0;
+- var->transp.length=0;
+- var->transp.msb_right=0;
+- linelen=var->xres_virtual * var->bits_per_pixel / 8;
+- if (! use_hwscroll)
+- var->yres_virtual=var->yres;
++ }
++ var->blue = var->green = var->red;
++ var->transp.offset = 0;
++ var->transp.length = 0;
++ var->transp.msb_right = 0;
++ linelen = var->xres_virtual * var->bits_per_pixel / 8;
++ if (!use_hwscroll)
++ var->yres_virtual = var->yres;
+ else if (screen_len) {
+ if (par->yres_virtual)
+ var->yres_virtual = par->yres_virtual;
+ else
+- /* yres_virtual==0 means use maximum */
++ /* yres_virtual == 0 means use maximum */
+ var->yres_virtual = screen_len / linelen;
+ } else {
+ if (hwscroll < 0)
+ var->yres_virtual = 2 * var->yres;
+ else
+- var->yres_virtual=var->yres+hwscroll * 16;
++ var->yres_virtual = var->yres + hwscroll * 16;
+ }
+- var->xoffset=0;
++ var->xoffset = 0;
+ if (screen_base)
+- var->yoffset=(par->screen_base - screen_base)/linelen;
++ var->yoffset = (par->screen_base - screen_base) / linelen;
+ else
+- var->yoffset=0;
+- var->nonstd=0;
+- var->activate=0;
+- var->vmode=FB_VMODE_NONINTERLACED;
++ var->yoffset = 0;
++ var->nonstd = 0;
++ var->activate = 0;
++ var->vmode = FB_VMODE_NONINTERLACED;
+ return 0;
+ }
+
+-
+-static void tt_get_par( struct atafb_par *par )
++static void tt_get_par(struct atafb_par *par)
+ {
+ unsigned long addr;
+- par->hw.tt.mode=shifter_tt.tt_shiftmode;
+- par->hw.tt.sync=shifter.syncmode;
++ par->hw.tt.mode = shifter_tt.tt_shiftmode;
++ par->hw.tt.sync = shifter.syncmode;
+ addr = ((shifter.bas_hi & 0xff) << 16) |
+ ((shifter.bas_md & 0xff) << 8) |
+ ((shifter.bas_lo & 0xff));
+ par->screen_base = phys_to_virt(addr);
+ }
+
+-static void tt_set_par( struct atafb_par *par )
++static void tt_set_par(struct atafb_par *par)
+ {
+- shifter_tt.tt_shiftmode=par->hw.tt.mode;
+- shifter.syncmode=par->hw.tt.sync;
++ shifter_tt.tt_shiftmode = par->hw.tt.mode;
++ shifter.syncmode = par->hw.tt.sync;
+ /* only set screen_base if really necessary */
+ if (current_par.screen_base != par->screen_base)
+ fbhw->set_screen_base(par->screen_base);
+ }
+
+-
+-static int tt_getcolreg(unsigned regno, unsigned *red,
+- unsigned *green, unsigned *blue,
+- unsigned *transp, struct fb_info *info)
+-{
+- int t, col;
+-
+- if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH)
+- regno += 254;
+- if (regno > 255)
+- return 1;
+- t = tt_palette[regno];
+- col = t & 15;
+- col |= col << 4;
+- col |= col << 8;
+- *blue = col;
+- col = (t >> 4) & 15;
+- col |= col << 4;
+- col |= col << 8;
+- *green = col;
+- col = (t >> 8) & 15;
+- col |= col << 4;
+- col |= col << 8;
+- *red = col;
+- *transp = 0;
+- return 0;
+-}
+-
+-
+-static int tt_setcolreg(unsigned regno, unsigned red,
+- unsigned green, unsigned blue,
+- unsigned transp, struct fb_info *info)
++static int tt_setcolreg(unsigned int regno, unsigned int red,
++ unsigned int green, unsigned int blue,
++ unsigned int transp, struct fb_info *info)
+ {
+ if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH)
+ regno += 254;
+@@ -708,15 +819,14 @@ static int tt_setcolreg(unsigned regno,
+ tt_palette[regno] = (((red >> 12) << 8) | ((green >> 12) << 4) |
+ (blue >> 12));
+ if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) ==
+- TT_SHIFTER_STHIGH && regno == 254)
++ TT_SHIFTER_STHIGH && regno == 254)
+ tt_palette[0] = 0;
+ return 0;
+ }
+
+-
+-static int tt_detect( void )
+-
+-{ struct atafb_par par;
++static int tt_detect(void)
++{
++ struct atafb_par par;
+
+ /* Determine the connected monitor: The DMA sound must be
+ * disabled before reading the MFP GPIP, because the Sound
+@@ -726,9 +836,9 @@ static int tt_detect( void )
+ * announced that the Eagle is TT compatible, but only the PCM is
+ * missing...
+ */
+- if (ATARIHW_PRESENT(PCM_8BIT)) {
++ if (ATARIHW_PRESENT(PCM_8BIT)) {
+ tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+- udelay(20); /* wait a while for things to settle down */
++ udelay(20); /* wait a while for things to settle down */
+ }
+ mono_moni = (mfp.par_dt_reg & 0x80) == 0;
+
+@@ -755,19 +865,24 @@ static struct pixel_clock {
+ unsigned long f; /* f/[Hz] */
+ unsigned long t; /* t/[ps] (=1/f) */
+ int right, hsync, left; /* standard timing in clock cycles, not pixel */
+- /* hsync initialized in falcon_detect() */
++ /* hsync initialized in falcon_detect() */
+ int sync_mask; /* or-mask for hw.falcon.sync to set this clock */
+ int control_mask; /* ditto, for hw.falcon.vid_control */
+-}
+-f25 = {25175000, 39721, 18, 0, 42, 0x0, VCO_CLOCK25},
+-f32 = {32000000, 31250, 18, 0, 42, 0x0, 0},
+-fext = { 0, 0, 18, 0, 42, 0x1, 0};
++} f25 = {
++ 25175000, 39721, 18, 0, 42, 0x0, VCO_CLOCK25
++}, f32 = {
++ 32000000, 31250, 18, 0, 42, 0x0, 0
++}, fext = {
++ 0, 0, 18, 0, 42, 0x1, 0
++};
+
+ /* VIDEL-prescale values [mon_type][pixel_length from VCO] */
+-static int vdl_prescale[4][3] = {{4,2,1}, {4,2,1}, {4,2,2}, {4,2,1}};
++static int vdl_prescale[4][3] = {
++ { 4,2,1 }, { 4,2,1 }, { 4,2,2 }, { 4,2,1 }
++};
+
+ /* Default hsync timing [mon_type] in picoseconds */
+-static long h_syncs[4] = {3000000, 4875000, 4000000, 4875000};
++static long h_syncs[4] = { 3000000, 4875000, 4000000, 4875000 };
+
+ #ifdef FBCON_HAS_CFB16
+ static u16 fbcon_cfb16_cmap[16];
+@@ -775,12 +890,12 @@ static u16 fbcon_cfb16_cmap[16];
+
+ static inline int hxx_prescale(struct falcon_hw *hw)
+ {
+- return hw->ste_mode ? 16 :
+- vdl_prescale[mon_type][hw->vid_mode >> 2 & 0x3];
++ return hw->ste_mode ? 16
++ : vdl_prescale[mon_type][hw->vid_mode >> 2 & 0x3];
+ }
+
+-static int falcon_encode_fix( struct fb_fix_screeninfo *fix,
+- struct atafb_par *par )
++static int falcon_encode_fix(struct fb_fix_screeninfo *fix,
++ struct atafb_par *par)
+ {
+ strcpy(fix->id, "Atari Builtin");
+ fix->smem_start = (unsigned long)real_screen_base;
+@@ -796,8 +911,7 @@ static int falcon_encode_fix( struct fb_
+ fix->type_aux = 0;
+ /* no smooth scrolling with longword aligned video mem */
+ fix->xpanstep = 32;
+- }
+- else if (par->hw.falcon.f_shift & 0x100) {
++ } else if (par->hw.falcon.f_shift & 0x100) {
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->type_aux = 0;
+ /* Is this ok or should it be DIRECTCOLOR? */
+@@ -809,9 +923,8 @@ static int falcon_encode_fix( struct fb_
+ return 0;
+ }
+
+-
+-static int falcon_decode_var( struct fb_var_screeninfo *var,
+- struct atafb_par *par )
++static int falcon_decode_var(struct fb_var_screeninfo *var,
++ struct atafb_par *par)
+ {
+ int bpp = var->bits_per_pixel;
+ int xres = var->xres;
+@@ -823,17 +936,19 @@ static int falcon_decode_var( struct fb_
+ int linelen;
+ int interlace = 0, doubleline = 0;
+ struct pixel_clock *pclock;
+- int plen; /* width of pixel in clock cycles */
++ int plen; /* width of pixel in clock cycles */
+ int xstretch;
+ int prescale;
+ int longoffset = 0;
+ int hfreq, vfreq;
++ int hdb_off, hde_off, base_off;
++ int gstart, gend1, gend2, align;
+
+ /*
+ Get the video params out of 'var'. If a value doesn't fit, round
+ it up, if it's too big, return EINVAL.
+- Round up in the following order: bits_per_pixel, xres, yres,
+- xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields,
++ Round up in the following order: bits_per_pixel, xres, yres,
++ xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields,
+ horizontal timing, vertical timing.
+
+ There is a maximum of screen resolution determined by pixelclock
+@@ -843,11 +958,11 @@ static int falcon_decode_var( struct fb_
+ Frequency range for multisync monitors is given via command line.
+ For TV and SM124 both frequencies are fixed.
+
+- X % 16 == 0 to fit 8x?? font (except 1 bitplane modes must use X%32==0)
++ X % 16 == 0 to fit 8x?? font (except 1 bitplane modes must use X%32 == 0)
+ Y % 16 == 0 to fit 8x16 font
+ Y % 8 == 0 if Y<400
+
+- Currently interlace and doubleline mode in var are ignored.
++ Currently interlace and doubleline mode in var are ignored.
+ On SM124 and TV only the standard resolutions can be used.
+ */
+
+@@ -855,43 +970,38 @@ static int falcon_decode_var( struct fb_
+ if (!xres || !yres || !bpp)
+ return -EINVAL;
+
+- if (mon_type == F_MON_SM && bpp != 1) {
++ if (mon_type == F_MON_SM && bpp != 1)
+ return -EINVAL;
+- }
+- else if (bpp <= 1) {
++
++ if (bpp <= 1) {
+ bpp = 1;
+ par->hw.falcon.f_shift = 0x400;
+ par->hw.falcon.st_shift = 0x200;
+- }
+- else if (bpp <= 2) {
++ } else if (bpp <= 2) {
+ bpp = 2;
+ par->hw.falcon.f_shift = 0x000;
+ par->hw.falcon.st_shift = 0x100;
+- }
+- else if (bpp <= 4) {
++ } else if (bpp <= 4) {
+ bpp = 4;
+ par->hw.falcon.f_shift = 0x000;
+ par->hw.falcon.st_shift = 0x000;
+- }
+- else if (bpp <= 8) {
++ } else if (bpp <= 8) {
+ bpp = 8;
+ par->hw.falcon.f_shift = 0x010;
+- }
+- else if (bpp <= 16) {
+- bpp = 16; /* packed pixel mode */
+- par->hw.falcon.f_shift = 0x100; /* hicolor, no overlay */
+- }
+- else
++ } else if (bpp <= 16) {
++ bpp = 16; /* packed pixel mode */
++ par->hw.falcon.f_shift = 0x100; /* hicolor, no overlay */
++ } else
+ return -EINVAL;
+ par->hw.falcon.bpp = bpp;
+
+ if (mon_type == F_MON_SM || DontCalcRes) {
+ /* Skip all calculations. VGA/TV/SC1224 only supported. */
+ struct fb_var_screeninfo *myvar = &atafb_predefined[0];
+-
++
+ if (bpp > myvar->bits_per_pixel ||
+- var->xres > myvar->xres ||
+- var->yres > myvar->yres)
++ var->xres > myvar->xres ||
++ var->yres > myvar->yres)
+ return -EINVAL;
+ fbhw->get_par(par); /* Current par will be new par */
+ goto set_screen_base; /* Don't forget this */
+@@ -910,8 +1020,8 @@ static int falcon_decode_var( struct fb_
+ yres = 400;
+
+ /* 2 planes must use STE compatibility mode */
+- par->hw.falcon.ste_mode = bpp==2;
+- par->hw.falcon.mono = bpp==1;
++ par->hw.falcon.ste_mode = bpp == 2;
++ par->hw.falcon.mono = bpp == 1;
+
+ /* Total and visible scanline length must be a multiple of one longword,
+ * this and the console fontwidth yields the alignment for xres and
+@@ -967,8 +1077,7 @@ static int falcon_decode_var( struct fb_
+ left_margin = hsync_len = 128 / plen;
+ right_margin = 0;
+ /* TODO set all margins */
+- }
+- else
++ } else
+ #endif
+ if (mon_type == F_MON_SC || mon_type == F_MON_TV) {
+ plen = 2 * xstretch;
+@@ -1002,26 +1111,24 @@ static int falcon_decode_var( struct fb_
+ vsync_len *= 2;
+ }
+ }
+- }
+- else
+- { /* F_MON_VGA */
++ } else { /* F_MON_VGA */
+ if (bpp == 16)
+- xstretch = 2; /* Double pixel width only for hicolor */
++ xstretch = 2; /* Double pixel width only for hicolor */
+ /* Default values are used for vert./hor. timing if no pixelclock given. */
+ if (var->pixclock == 0) {
+ int linesize;
+
+ /* Choose master pixelclock depending on hor. timing */
+ plen = 1 * xstretch;
+- if ((plen * xres + f25.right+f25.hsync+f25.left) *
++ if ((plen * xres + f25.right + f25.hsync + f25.left) *
+ fb_info.monspecs.hfmin < f25.f)
+ pclock = &f25;
+- else if ((plen * xres + f32.right+f32.hsync+f32.left) *
+- fb_info.monspecs.hfmin < f32.f)
++ else if ((plen * xres + f32.right + f32.hsync +
++ f32.left) * fb_info.monspecs.hfmin < f32.f)
+ pclock = &f32;
+- else if ((plen * xres + fext.right+fext.hsync+fext.left) *
+- fb_info.monspecs.hfmin < fext.f
+- && fext.f)
++ else if ((plen * xres + fext.right + fext.hsync +
++ fext.left) * fb_info.monspecs.hfmin < fext.f &&
++ fext.f)
+ pclock = &fext;
+ else
+ return -EINVAL;
+@@ -1033,22 +1140,24 @@ static int falcon_decode_var( struct fb_
+ upper_margin = 31;
+ lower_margin = 11;
+ vsync_len = 3;
+- }
+- else {
++ } else {
+ /* Choose largest pixelclock <= wanted clock */
+ int i;
+ unsigned long pcl = ULONG_MAX;
+ pclock = 0;
+- for (i=1; i <= 4; i *= 2) {
+- if (f25.t*i >= var->pixclock && f25.t*i < pcl) {
++ for (i = 1; i <= 4; i *= 2) {
++ if (f25.t * i >= var->pixclock &&
++ f25.t * i < pcl) {
+ pcl = f25.t * i;
+ pclock = &f25;
+ }
+- if (f32.t*i >= var->pixclock && f32.t*i < pcl) {
++ if (f32.t * i >= var->pixclock &&
++ f32.t * i < pcl) {
+ pcl = f32.t * i;
+ pclock = &f32;
+ }
+- if (fext.t && fext.t*i >= var->pixclock && fext.t*i < pcl) {
++ if (fext.t && fext.t * i >= var->pixclock &&
++ fext.t * i < pcl) {
+ pcl = fext.t * i;
+ pclock = &fext;
+ }
+@@ -1070,8 +1179,7 @@ static int falcon_decode_var( struct fb_
+ upper_margin = (upper_margin + 1) / 2;
+ lower_margin = (lower_margin + 1) / 2;
+ vsync_len = (vsync_len + 1) / 2;
+- }
+- else if (var->vmode & FB_VMODE_DOUBLE) {
++ } else if (var->vmode & FB_VMODE_DOUBLE) {
+ /* External unit is [double lines per frame] */
+ upper_margin *= 2;
+ lower_margin *= 2;
+@@ -1079,7 +1187,7 @@ static int falcon_decode_var( struct fb_
+ }
+ }
+ if (pclock == &fext)
+- longoffset = 1; /* VIDEL doesn't synchronize on short offset */
++ longoffset = 1; /* VIDEL doesn't synchronize on short offset */
+ }
+ /* Is video bus bandwidth (32MB/s) too low for this resolution? */
+ /* this is definitely wrong if bus clock != 32MHz */
+@@ -1098,7 +1206,7 @@ static int falcon_decode_var( struct fb_
+ * between interlace and non-interlace without messing around
+ * with these.
+ */
+- again:
++again:
+ /* Set base_offset 128 and video bus width */
+ par->hw.falcon.vid_control = mon_type | f030_bus_width;
+ if (!longoffset)
+@@ -1112,37 +1220,34 @@ static int falcon_decode_var( struct fb_
+ /* External or internal clock */
+ par->hw.falcon.sync = pclock->sync_mask | 0x2;
+ /* Pixellength and prescale */
+- par->hw.falcon.vid_mode = (2/plen) << 2;
++ par->hw.falcon.vid_mode = (2 / plen) << 2;
+ if (doubleline)
+ par->hw.falcon.vid_mode |= VMO_DOUBLE;
+ if (interlace)
+ par->hw.falcon.vid_mode |= VMO_INTER;
+
+ /*********************
+- Horizontal timing: unit = [master clock cycles]
+- unit of hxx-registers: [master clock cycles * prescale]
+- Hxx-registers are 9 bit wide
+-
+- 1 line = ((hht + 2) * 2 * prescale) clock cycles
+-
+- graphic output = hdb & 0x200 ?
+- ((hht+2)*2 - hdb + hde) * prescale - hdboff + hdeoff:
+- ( hht + 2 - hdb + hde) * prescale - hdboff + hdeoff
+- (this must be a multiple of plen*128/bpp, on VGA pixels
+- to the right may be cut off with a bigger right margin)
+-
+- start of graphics relative to start of 1st halfline = hdb & 0x200 ?
+- (hdb - hht - 2) * prescale + hdboff :
+- hdb * prescale + hdboff
+-
+- end of graphics relative to start of 1st halfline =
+- (hde + hht + 2) * prescale + hdeoff
+- *********************/
++ * Horizontal timing: unit = [master clock cycles]
++ * unit of hxx-registers: [master clock cycles * prescale]
++ * Hxx-registers are 9 bit wide
++ *
++ * 1 line = ((hht + 2) * 2 * prescale) clock cycles
++ *
++ * graphic output = hdb & 0x200 ?
++ * ((hht + 2) * 2 - hdb + hde) * prescale - hdboff + hdeoff:
++ * (hht + 2 - hdb + hde) * prescale - hdboff + hdeoff
++ * (this must be a multiple of plen*128/bpp, on VGA pixels
++ * to the right may be cut off with a bigger right margin)
++ *
++ * start of graphics relative to start of 1st halfline = hdb & 0x200 ?
++ * (hdb - hht - 2) * prescale + hdboff :
++ * hdb * prescale + hdboff
++ *
++ * end of graphics relative to start of 1st halfline =
++ * (hde + hht + 2) * prescale + hdeoff
++ *********************/
+ /* Calculate VIDEL registers */
+- {
+- int hdb_off, hde_off, base_off;
+- int gstart, gend1, gend2, align;
+-
++{
+ prescale = hxx_prescale(&par->hw.falcon);
+ base_off = par->hw.falcon.vid_control & VCO_SHORTOFFS ? 64 : 128;
+
+@@ -1154,8 +1259,7 @@ static int falcon_decode_var( struct fb_
+ align = 1;
+ hde_off = 0;
+ hdb_off = (base_off + 16 * plen) + prescale;
+- }
+- else {
++ } else {
+ align = 128 / bpp;
+ hde_off = ((128 / bpp + 2) * plen);
+ if (par->hw.falcon.ste_mode)
+@@ -1164,23 +1268,24 @@ static int falcon_decode_var( struct fb_
+ hdb_off = (base_off + (128 / bpp + 18) * plen) + prescale;
+ }
+
+- gstart = (prescale/2 + plen * left_margin) / prescale;
++ gstart = (prescale / 2 + plen * left_margin) / prescale;
+ /* gend1 is for hde (gend-gstart multiple of align), shifter's xres */
+- gend1 = gstart + ((xres + align-1) / align)*align * plen / prescale;
++ gend1 = gstart + ((xres + align - 1) / align) * align * plen / prescale;
+ /* gend2 is for hbb, visible xres (rest to gend1 is cut off by hblank) */
+ gend2 = gstart + xres * plen / prescale;
+ par->HHT = plen * (left_margin + xres + right_margin) /
+ (2 * prescale) - 2;
+ /* par->HHT = (gend2 + plen * right_margin / prescale) / 2 - 2;*/
+
+- par->HDB = gstart - hdb_off/prescale;
++ par->HDB = gstart - hdb_off / prescale;
+ par->HBE = gstart;
+- if (par->HDB < 0) par->HDB += par->HHT + 2 + 0x200;
+- par->HDE = gend1 - par->HHT - 2 - hde_off/prescale;
++ if (par->HDB < 0)
++ par->HDB += par->HHT + 2 + 0x200;
++ par->HDE = gend1 - par->HHT - 2 - hde_off / prescale;
+ par->HBB = gend2 - par->HHT - 2;
+ #if 0
+ /* One more Videl constraint: data fetch of two lines must not overlap */
+- if ((par->HDB & 0x200) && (par->HDB & ~0x200) - par->HDE <= 5) {
++ if ((par->HDB & 0x200) && (par->HDB & ~0x200) - par->HDE <= 5) {
+ /* if this happens increase margins, decrease hfreq. */
+ }
+ #endif
+@@ -1189,11 +1294,11 @@ static int falcon_decode_var( struct fb_
+ par->HSS = par->HHT + 2 - plen * hsync_len / prescale;
+ if (par->HSS < par->HBB)
+ par->HSS = par->HBB;
+- }
++}
+
+ /* check hor. frequency */
+- hfreq = pclock->f / ((par->HHT+2)*prescale*2);
+- if (hfreq > fb_info.monspecs.hfmax && mon_type!=F_MON_VGA) {
++ hfreq = pclock->f / ((par->HHT + 2) * prescale * 2);
++ if (hfreq > fb_info.monspecs.hfmax && mon_type != F_MON_VGA) {
+ /* ++guenther: ^^^^^^^^^^^^^^^^^^^ can't remember why I did this */
+ /* Too high -> enlarge margin */
+ left_margin += 1;
+@@ -1213,12 +1318,14 @@ static int falcon_decode_var( struct fb_
+ par->VBE = (upper_margin * 2 + 1); /* must begin on odd halfline */
+ par->VDB = par->VBE;
+ par->VDE = yres;
+- if (!interlace) par->VDE <<= 1;
+- if (doubleline) par->VDE <<= 1; /* VDE now half lines per (half-)frame */
++ if (!interlace)
++ par->VDE <<= 1;
++ if (doubleline)
++ par->VDE <<= 1; /* VDE now half lines per (half-)frame */
+ par->VDE += par->VDB;
+ par->VBB = par->VDE;
+ par->VFT = par->VBB + (lower_margin * 2 - 1) - 1;
+- par->VSS = par->VFT+1 - (vsync_len * 2 - 1);
++ par->VSS = par->VFT + 1 - (vsync_len * 2 - 1);
+ /* vbb,vss,vft must be even in interlace mode */
+ if (interlace) {
+ par->VBB++;
+@@ -1229,55 +1336,53 @@ static int falcon_decode_var( struct fb_
+ /* V-frequency check, hope I didn't create any loop here. */
+ /* Interlace and doubleline are mutually exclusive. */
+ vfreq = (hfreq * 2) / (par->VFT + 1);
+- if (vfreq > fb_info.monspecs.vfmax && !doubleline && !interlace) {
++ if (vfreq > fb_info.monspecs.vfmax && !doubleline && !interlace) {
+ /* Too high -> try again with doubleline */
+ doubleline = 1;
+ goto again;
+- }
+- else if (vfreq < fb_info.monspecs.vfmin && !interlace && !doubleline) {
++ } else if (vfreq < fb_info.monspecs.vfmin && !interlace && !doubleline) {
+ /* Too low -> try again with interlace */
+ interlace = 1;
+ goto again;
+- }
+- else if (vfreq < fb_info.monspecs.vfmin && doubleline) {
++ } else if (vfreq < fb_info.monspecs.vfmin && doubleline) {
+ /* Doubleline too low -> clear doubleline and enlarge margins */
+ int lines;
+ doubleline = 0;
+- for (lines=0;
+- (hfreq*2)/(par->VFT+1+4*lines-2*yres)>fb_info.monspecs.vfmax;
++ for (lines = 0;
++ (hfreq * 2) / (par->VFT + 1 + 4 * lines - 2 * yres) >
++ fb_info.monspecs.vfmax;
+ lines++)
+ ;
+ upper_margin += lines;
+ lower_margin += lines;
+ goto again;
+- }
+- else if (vfreq > fb_info.monspecs.vfmax && doubleline) {
++ } else if (vfreq > fb_info.monspecs.vfmax && doubleline) {
+ /* Doubleline too high -> enlarge margins */
+ int lines;
+- for (lines=0;
+- (hfreq*2)/(par->VFT+1+4*lines)>fb_info.monspecs.vfmax;
+- lines+=2)
++ for (lines = 0;
++ (hfreq * 2) / (par->VFT + 1 + 4 * lines) >
++ fb_info.monspecs.vfmax;
++ lines += 2)
+ ;
+ upper_margin += lines;
+ lower_margin += lines;
+ goto again;
+- }
+- else if (vfreq > fb_info.monspecs.vfmax && interlace) {
++ } else if (vfreq > fb_info.monspecs.vfmax && interlace) {
+ /* Interlace, too high -> enlarge margins */
+ int lines;
+- for (lines=0;
+- (hfreq*2)/(par->VFT+1+4*lines)>fb_info.monspecs.vfmax;
++ for (lines = 0;
++ (hfreq * 2) / (par->VFT + 1 + 4 * lines) >
++ fb_info.monspecs.vfmax;
+ lines++)
+ ;
+ upper_margin += lines;
+ lower_margin += lines;
+ goto again;
+- }
+- else if (vfreq < fb_info.monspecs.vfmin ||
+- vfreq > fb_info.monspecs.vfmax)
++ } else if (vfreq < fb_info.monspecs.vfmin ||
++ vfreq > fb_info.monspecs.vfmax)
+ return -EINVAL;
+
+- set_screen_base:
++set_screen_base:
+ linelen = xres_virtual * bpp / 8;
+ if (yres_virtual * linelen > screen_len && screen_len)
+ return -EINVAL;
+@@ -1289,11 +1394,20 @@ static int falcon_decode_var( struct fb_
+ par->screen_base = screen_base + var->yoffset * linelen;
+ par->hw.falcon.xoffset = 0;
+
++ // FIXME!!! sort of works, no crash
++ //par->next_line = linelen;
++ //par->next_plane = yres_virtual * linelen;
++ par->next_line = linelen;
++ par->next_plane = 2;
++ // crashes
++ //par->next_plane = linelen;
++ //par->next_line = yres_virtual * linelen;
++
+ return 0;
+ }
+
+-static int falcon_encode_var( struct fb_var_screeninfo *var,
+- struct atafb_par *par )
++static int falcon_encode_var(struct fb_var_screeninfo *var,
++ struct atafb_par *par)
+ {
+ /* !!! only for VGA !!! */
+ int linelen;
+@@ -1306,10 +1420,10 @@ static int falcon_encode_var( struct fb_
+ var->pixclock = hw->sync & 0x1 ? fext.t :
+ hw->vid_control & VCO_CLOCK25 ? f25.t : f32.t;
+
+- var->height=-1;
+- var->width=-1;
++ var->height = -1;
++ var->width = -1;
+
+- var->sync=0;
++ var->sync = 0;
+ if (hw->vid_control & VCO_HSYPOS)
+ var->sync |= FB_SYNC_HOR_HIGH_ACT;
+ if (hw->vid_control & VCO_VSYPOS)
+@@ -1320,7 +1434,7 @@ static int falcon_encode_var( struct fb_
+ var->vmode |= FB_VMODE_INTERLACED;
+ if (hw->vid_mode & VMO_DOUBLE)
+ var->vmode |= FB_VMODE_DOUBLE;
+-
++
+ /* visible y resolution:
+ * Graphics display starts at line VDB and ends at line
+ * VDE. If interlace mode off unit of VC-registers is
+@@ -1332,14 +1446,15 @@ static int falcon_encode_var( struct fb_
+ if (var->vmode & FB_VMODE_DOUBLE)
+ var->yres >>= 1;
+
+- /* to get bpp, we must examine f_shift and st_shift.
++ /*
++ * to get bpp, we must examine f_shift and st_shift.
+ * f_shift is valid if any of bits no. 10, 8 or 4
+ * is set. Priority in f_shift is: 10 ">" 8 ">" 4, i.e.
+ * if bit 10 set then bit 8 and bit 4 don't care...
+ * If all these bits are 0 get display depth from st_shift
+ * (as for ST and STE)
+ */
+- if (hw->f_shift & 0x400) /* 2 colors */
++ if (hw->f_shift & 0x400) /* 2 colors */
+ var->bits_per_pixel = 1;
+ else if (hw->f_shift & 0x100) /* hicolor */
+ var->bits_per_pixel = 16;
+@@ -1349,7 +1464,7 @@ static int falcon_encode_var( struct fb_
+ var->bits_per_pixel = 4;
+ else if (hw->st_shift == 0x100)
+ var->bits_per_pixel = 2;
+- else /* if (hw->st_shift == 0x200) */
++ else /* if (hw->st_shift == 0x200) */
+ var->bits_per_pixel = 1;
+
+ var->xres = hw->line_width * 16 / var->bits_per_pixel;
+@@ -1358,42 +1473,42 @@ static int falcon_encode_var( struct fb_
+ var->xres_virtual += 16;
+
+ if (var->bits_per_pixel == 16) {
+- var->red.offset=11;
+- var->red.length=5;
+- var->red.msb_right=0;
+- var->green.offset=5;
+- var->green.length=6;
+- var->green.msb_right=0;
+- var->blue.offset=0;
+- var->blue.length=5;
+- var->blue.msb_right=0;
+- }
+- else {
+- var->red.offset=0;
++ var->red.offset = 11;
++ var->red.length = 5;
++ var->red.msb_right = 0;
++ var->green.offset = 5;
++ var->green.length = 6;
++ var->green.msb_right = 0;
++ var->blue.offset = 0;
++ var->blue.length = 5;
++ var->blue.msb_right = 0;
++ } else {
++ var->red.offset = 0;
+ var->red.length = hw->ste_mode ? 4 : 6;
+- var->red.msb_right=0;
+- var->grayscale=0;
+- var->blue=var->green=var->red;
+- }
+- var->transp.offset=0;
+- var->transp.length=0;
+- var->transp.msb_right=0;
++ if (var->red.length > var->bits_per_pixel)
++ var->red.length = var->bits_per_pixel;
++ var->red.msb_right = 0;
++ var->grayscale = 0;
++ var->blue = var->green = var->red;
++ }
++ var->transp.offset = 0;
++ var->transp.length = 0;
++ var->transp.msb_right = 0;
+
+ linelen = var->xres_virtual * var->bits_per_pixel / 8;
+ if (screen_len) {
+ if (par->yres_virtual)
+ var->yres_virtual = par->yres_virtual;
+ else
+- /* yres_virtual==0 means use maximum */
++ /* yres_virtual == 0 means use maximum */
+ var->yres_virtual = screen_len / linelen;
+- }
+- else {
++ } else {
+ if (hwscroll < 0)
+ var->yres_virtual = 2 * var->yres;
+ else
+- var->yres_virtual=var->yres+hwscroll * 16;
++ var->yres_virtual = var->yres + hwscroll * 16;
+ }
+- var->xoffset=0; /* TODO change this */
++ var->xoffset = 0; /* TODO change this */
+
+ /* hdX-offsets */
+ prescale = hxx_prescale(hw);
+@@ -1402,8 +1517,7 @@ static int falcon_encode_var( struct fb_
+ if (hw->f_shift & 0x100) {
+ hde_off = 0;
+ hdb_off = (base_off + 16 * plen) + prescale;
+- }
+- else {
++ } else {
+ hde_off = ((128 / var->bits_per_pixel + 2) * plen);
+ if (hw->ste_mode)
+ hdb_off = (64 + base_off + (128 / var->bits_per_pixel + 2) * plen)
+@@ -1415,8 +1529,8 @@ static int falcon_encode_var( struct fb_
+
+ /* Right margin includes hsync */
+ var->left_margin = hdb_off + prescale * ((hw->hdb & 0x1ff) -
+- (hw->hdb & 0x200 ? 2+hw->hht : 0));
+- if (hw->ste_mode || mon_type!=F_MON_VGA)
++ (hw->hdb & 0x200 ? 2 + hw->hht : 0));
++ if (hw->ste_mode || mon_type != F_MON_VGA)
+ var->right_margin = prescale * (hw->hht + 2 - hw->hde) - hde_off;
+ else
+ /* can't use this in ste_mode, because hbb is +1 off */
+@@ -1424,15 +1538,14 @@ static int falcon_encode_var( struct fb_
+ var->hsync_len = prescale * (hw->hht + 2 - hw->hss);
+
+ /* Lower margin includes vsync */
+- var->upper_margin = hw->vdb / 2 ; /* round down to full lines */
+- var->lower_margin = (hw->vft+1 - hw->vde + 1) / 2; /* round up */
+- var->vsync_len = (hw->vft+1 - hw->vss + 1) / 2; /* round up */
++ var->upper_margin = hw->vdb / 2; /* round down to full lines */
++ var->lower_margin = (hw->vft + 1 - hw->vde + 1) / 2; /* round up */
++ var->vsync_len = (hw->vft + 1 - hw->vss + 1) / 2; /* round up */
+ if (var->vmode & FB_VMODE_INTERLACED) {
+ var->upper_margin *= 2;
+ var->lower_margin *= 2;
+ var->vsync_len *= 2;
+- }
+- else if (var->vmode & FB_VMODE_DOUBLE) {
++ } else if (var->vmode & FB_VMODE_DOUBLE) {
+ var->upper_margin = (var->upper_margin + 1) / 2;
+ var->lower_margin = (var->lower_margin + 1) / 2;
+ var->vsync_len = (var->vsync_len + 1) / 2;
+@@ -1447,20 +1560,19 @@ static int falcon_encode_var( struct fb_
+ var->lower_margin -= var->vsync_len;
+
+ if (screen_base)
+- var->yoffset=(par->screen_base - screen_base)/linelen;
++ var->yoffset = (par->screen_base - screen_base) / linelen;
+ else
+- var->yoffset=0;
+- var->nonstd=0; /* what is this for? */
+- var->activate=0;
++ var->yoffset = 0;
++ var->nonstd = 0; /* what is this for? */
++ var->activate = 0;
+ return 0;
+ }
+
+-
+-static int f_change_mode = 0;
++static int f_change_mode;
+ static struct falcon_hw f_new_mode;
+-static int f_pan_display = 0;
++static int f_pan_display;
+
+-static void falcon_get_par( struct atafb_par *par )
++static void falcon_get_par(struct atafb_par *par)
+ {
+ unsigned long addr;
+ struct falcon_hw *hw = &par->hw.falcon;
+@@ -1492,12 +1604,12 @@ static void falcon_get_par( struct atafb
+ par->screen_base = phys_to_virt(addr);
+
+ /* derived parameters */
+- hw->ste_mode = (hw->f_shift & 0x510)==0 && hw->st_shift==0x100;
++ hw->ste_mode = (hw->f_shift & 0x510) == 0 && hw->st_shift == 0x100;
+ hw->mono = (hw->f_shift & 0x400) ||
+- ((hw->f_shift & 0x510)==0 && hw->st_shift==0x200);
++ ((hw->f_shift & 0x510) == 0 && hw->st_shift == 0x200);
+ }
+
+-static void falcon_set_par( struct atafb_par *par )
++static void falcon_set_par(struct atafb_par *par)
+ {
+ f_change_mode = 0;
+
+@@ -1519,8 +1631,7 @@ static void falcon_set_par( struct atafb
+ f_change_mode = 1;
+ }
+
+-
+-static irqreturn_t falcon_vbl_switcher( int irq, void *dummy )
++static irqreturn_t falcon_vbl_switcher(int irq, void *dummy)
+ {
+ struct falcon_hw *hw = &f_new_mode;
+
+@@ -1529,11 +1640,10 @@ static irqreturn_t falcon_vbl_switcher(
+
+ if (hw->sync & 0x1) {
+ /* Enable external pixelclock. This code only for ScreenWonder */
+- *(volatile unsigned short*)0xffff9202 = 0xffbf;
+- }
+- else {
++ *(volatile unsigned short *)0xffff9202 = 0xffbf;
++ } else {
+ /* Turn off external clocks. Read sets all output bits to 1. */
+- *(volatile unsigned short*)0xffff9202;
++ *(volatile unsigned short *)0xffff9202;
+ }
+ shifter.syncmode = hw->sync;
+
+@@ -1550,15 +1660,14 @@ static irqreturn_t falcon_vbl_switcher(
+ videl.vde = hw->vde;
+ videl.vss = hw->vss;
+
+- videl.f_shift = 0; /* write enables Falcon palette, 0: 4 planes */
++ videl.f_shift = 0; /* write enables Falcon palette, 0: 4 planes */
+ if (hw->ste_mode) {
+- videl.st_shift = hw->st_shift; /* write enables STE palette */
+- }
+- else {
++ videl.st_shift = hw->st_shift; /* write enables STE palette */
++ } else {
+ /* IMPORTANT:
+- * set st_shift 0, so we can tell the screen-depth if f_shift==0.
++ * set st_shift 0, so we can tell the screen-depth if f_shift == 0.
+ * Writing 0 to f_shift enables 4 plane Falcon mode but
+- * doesn't set st_shift. st_shift!=0 (!=4planes) is impossible
++ * doesn't set st_shift. st_shift != 0 (!= 4planes) is impossible
+ * with Falcon palette.
+ */
+ videl.st_shift = 0;
+@@ -1580,12 +1689,13 @@ static irqreturn_t falcon_vbl_switcher(
+ return IRQ_HANDLED;
+ }
+
+-
+-static int falcon_pan_display( struct fb_var_screeninfo *var,
+- struct atafb_par *par )
++static int falcon_pan_display(struct fb_var_screeninfo *var,
++ struct fb_info *info)
+ {
++ struct atafb_par *par = (struct atafb_par *)info->par;
++
+ int xoffset;
+- int bpp = fb_display[fb_info.currcon].var.bits_per_pixel;
++ int bpp = info->var.bits_per_pixel;
+
+ if (bpp == 1)
+ var->xoffset = up(var->xoffset, 32);
+@@ -1596,45 +1706,24 @@ static int falcon_pan_display( struct fb
+ var->xoffset = up(var->xoffset, 2);
+ }
+ par->hw.falcon.line_offset = bpp *
+- (fb_display[fb_info.currcon].var.xres_virtual - fb_display[fb_info.currcon].var.xres) / 16;
++ (info->var.xres_virtual - info->var.xres) / 16;
+ if (par->hw.falcon.xoffset)
+ par->hw.falcon.line_offset -= bpp;
+ xoffset = var->xoffset - par->hw.falcon.xoffset;
+
+ par->screen_base = screen_base +
+- (var->yoffset * fb_display[fb_info.currcon].var.xres_virtual + xoffset) * bpp / 8;
++ (var->yoffset * info->var.xres_virtual + xoffset) * bpp / 8;
+ if (fbhw->set_screen_base)
+- fbhw->set_screen_base (par->screen_base);
++ fbhw->set_screen_base(par->screen_base);
+ else
+- return -EINVAL; /* shouldn't happen */
++ return -EINVAL; /* shouldn't happen */
+ f_pan_display = 1;
+ return 0;
+ }
+
+-
+-static int falcon_getcolreg( unsigned regno, unsigned *red,
+- unsigned *green, unsigned *blue,
+- unsigned *transp, struct fb_info *info )
+-{ unsigned long col;
+-
+- if (regno > 255)
+- return 1;
+- /* This works in STE-mode (with 4bit/color) since f030_col-registers
+- * hold up to 6bit/color.
+- * Even with hicolor r/g/b=5/6/5 bit!
+- */
+- col = f030_col[regno];
+- *red = (col >> 16) & 0xff00;
+- *green = (col >> 8) & 0xff00;
+- *blue = (col << 8) & 0xff00;
+- *transp = 0;
+- return 0;
+-}
+-
+-
+-static int falcon_setcolreg( unsigned regno, unsigned red,
+- unsigned green, unsigned blue,
+- unsigned transp, struct fb_info *info )
++static int falcon_setcolreg(unsigned int regno, unsigned int red,
++ unsigned int green, unsigned int blue,
++ unsigned int transp, struct fb_info *info)
+ {
+ if (regno > 255)
+ return 1;
+@@ -1655,13 +1744,12 @@ static int falcon_setcolreg( unsigned re
+ return 0;
+ }
+
+-
+-static int falcon_blank( int blank_mode )
++static int falcon_blank(int blank_mode)
+ {
+-/* ++guenther: we can switch off graphics by changing VDB and VDE,
+- * so VIDEL doesn't hog the bus while saving.
+- * (this may affect usleep()).
+- */
++ /* ++guenther: we can switch off graphics by changing VDB and VDE,
++ * so VIDEL doesn't hog the bus while saving.
++ * (this may affect usleep()).
++ */
+ int vdb, vss, hbe, hss;
+
+ if (mon_type == F_MON_SM) /* this doesn't work on SM124 */
+@@ -1694,14 +1782,13 @@ static int falcon_blank( int blank_mode
+ return 0;
+ }
+
+-
+-static int falcon_detect( void )
++static int falcon_detect(void)
+ {
+ struct atafb_par par;
+ unsigned char fhw;
+
+ /* Determine connected monitor and set monitor parameters */
+- fhw = *(unsigned char*)0xffff8006;
++ fhw = *(unsigned char *)0xffff8006;
+ mon_type = fhw >> 6 & 0x3;
+ /* bit 1 of fhw: 1=32 bit ram bus, 0=16 bit */
+ f030_bus_width = fhw << 6 & 0x80;
+@@ -1715,7 +1802,7 @@ static int falcon_detect( void )
+ case F_MON_SC:
+ case F_MON_TV:
+ /* PAL...NTSC */
+- fb_info.monspecs.vfmin = 49; /* not 50, since TOS defaults to 49.9x Hz */
++ fb_info.monspecs.vfmin = 49; /* not 50, since TOS defaults to 49.9x Hz */
+ fb_info.monspecs.vfmax = 60;
+ fb_info.monspecs.hfmin = 15620;
+ fb_info.monspecs.hfmax = 15755;
+@@ -1740,13 +1827,12 @@ static int falcon_detect( void )
+
+ #ifdef ATAFB_STE
+
+-static int stste_encode_fix( struct fb_fix_screeninfo *fix,
+- struct atafb_par *par )
+-
++static int stste_encode_fix(struct fb_fix_screeninfo *fix,
++ struct atafb_par *par)
+ {
+ int mode;
+
+- strcpy(fix->id,"Atari Builtin");
++ strcpy(fix->id, "Atari Builtin");
+ fix->smem_start = (unsigned long)real_screen_base;
+ fix->smem_len = screen_len;
+ fix->type = FB_TYPE_INTERLEAVED_PLANES;
+@@ -1771,43 +1857,40 @@ static int stste_encode_fix( struct fb_f
+ return 0;
+ }
+
+-
+-static int stste_decode_var( struct fb_var_screeninfo *var,
+- struct atafb_par *par )
++static int stste_decode_var(struct fb_var_screeninfo *var,
++ struct atafb_par *par)
+ {
+- int xres=var->xres;
+- int yres=var->yres;
+- int bpp=var->bits_per_pixel;
++ int xres = var->xres;
++ int yres = var->yres;
++ int bpp = var->bits_per_pixel;
+ int linelen;
+ int yres_virtual = var->yres_virtual;
+
+ if (mono_moni) {
+ if (bpp > 1 || xres > sttt_xres || yres > st_yres)
+ return -EINVAL;
+- par->hw.st.mode=ST_HIGH;
+- xres=sttt_xres;
+- yres=st_yres;
+- bpp=1;
++ par->hw.st.mode = ST_HIGH;
++ xres = sttt_xres;
++ yres = st_yres;
++ bpp = 1;
+ } else {
+ if (bpp > 4 || xres > sttt_xres || yres > st_yres)
+ return -EINVAL;
+ if (bpp > 2) {
+- if (xres > sttt_xres/2 || yres > st_yres/2)
++ if (xres > sttt_xres / 2 || yres > st_yres / 2)
+ return -EINVAL;
+- par->hw.st.mode=ST_LOW;
+- xres=sttt_xres/2;
+- yres=st_yres/2;
+- bpp=4;
+- }
+- else if (bpp > 1) {
+- if (xres > sttt_xres || yres > st_yres/2)
++ par->hw.st.mode = ST_LOW;
++ xres = sttt_xres / 2;
++ yres = st_yres / 2;
++ bpp = 4;
++ } else if (bpp > 1) {
++ if (xres > sttt_xres || yres > st_yres / 2)
+ return -EINVAL;
+- par->hw.st.mode=ST_MID;
+- xres=sttt_xres;
+- yres=st_yres/2;
+- bpp=2;
+- }
+- else
++ par->hw.st.mode = ST_MID;
++ xres = sttt_xres;
++ yres = st_yres / 2;
++ bpp = 2;
++ } else
+ return -EINVAL;
+ }
+ if (yres_virtual <= 0)
+@@ -1815,10 +1898,10 @@ static int stste_decode_var( struct fb_v
+ else if (yres_virtual < yres)
+ yres_virtual = yres;
+ if (var->sync & FB_SYNC_EXT)
+- par->hw.st.sync=(par->hw.st.sync & ~1) | 1;
++ par->hw.st.sync = (par->hw.st.sync & ~1) | 1;
+ else
+- par->hw.st.sync=(par->hw.st.sync & ~1);
+- linelen=xres*bpp/8;
++ par->hw.st.sync = (par->hw.st.sync & ~1);
++ linelen = xres * bpp / 8;
+ if (yres_virtual * linelen > screen_len && screen_len)
+ return -EINVAL;
+ if (yres * linelen > screen_len && screen_len)
+@@ -1826,93 +1909,91 @@ static int stste_decode_var( struct fb_v
+ if (var->yoffset + yres > yres_virtual && yres_virtual)
+ return -EINVAL;
+ par->yres_virtual = yres_virtual;
+- par->screen_base=screen_base+ var->yoffset*linelen;
++ par->screen_base = screen_base + var->yoffset * linelen;
+ return 0;
+ }
+
+-static int stste_encode_var( struct fb_var_screeninfo *var,
+- struct atafb_par *par )
++static int stste_encode_var(struct fb_var_screeninfo *var,
++ struct atafb_par *par)
+ {
+ int linelen;
+ memset(var, 0, sizeof(struct fb_var_screeninfo));
+- var->red.offset=0;
++ var->red.offset = 0;
+ var->red.length = ATARIHW_PRESENT(EXTD_SHIFTER) ? 4 : 3;
+- var->red.msb_right=0;
+- var->grayscale=0;
++ var->red.msb_right = 0;
++ var->grayscale = 0;
+
+- var->pixclock=31041;
+- var->left_margin=120; /* these are incorrect */
+- var->right_margin=100;
+- var->upper_margin=8;
+- var->lower_margin=16;
+- var->hsync_len=140;
+- var->vsync_len=30;
++ var->pixclock = 31041;
++ var->left_margin = 120; /* these are incorrect */
++ var->right_margin = 100;
++ var->upper_margin = 8;
++ var->lower_margin = 16;
++ var->hsync_len = 140;
++ var->vsync_len = 30;
+
+- var->height=-1;
+- var->width=-1;
++ var->height = -1;
++ var->width = -1;
+
+ if (!(par->hw.st.sync & 1))
+- var->sync=0;
++ var->sync = 0;
+ else
+- var->sync=FB_SYNC_EXT;
++ var->sync = FB_SYNC_EXT;
+
+ switch (par->hw.st.mode & 3) {
+ case ST_LOW:
+- var->xres=sttt_xres/2;
+- var->yres=st_yres/2;
+- var->bits_per_pixel=4;
++ var->xres = sttt_xres / 2;
++ var->yres = st_yres / 2;
++ var->bits_per_pixel = 4;
+ break;
+ case ST_MID:
+- var->xres=sttt_xres;
+- var->yres=st_yres/2;
+- var->bits_per_pixel=2;
++ var->xres = sttt_xres;
++ var->yres = st_yres / 2;
++ var->bits_per_pixel = 2;
+ break;
+ case ST_HIGH:
+- var->xres=sttt_xres;
+- var->yres=st_yres;
+- var->bits_per_pixel=1;
++ var->xres = sttt_xres;
++ var->yres = st_yres;
++ var->bits_per_pixel = 1;
+ break;
+- }
+- var->blue=var->green=var->red;
+- var->transp.offset=0;
+- var->transp.length=0;
+- var->transp.msb_right=0;
+- var->xres_virtual=sttt_xres_virtual;
+- linelen=var->xres_virtual * var->bits_per_pixel / 8;
+- ovsc_addlen=linelen*(sttt_yres_virtual - st_yres);
+-
+- if (! use_hwscroll)
+- var->yres_virtual=var->yres;
++ }
++ var->blue = var->green = var->red;
++ var->transp.offset = 0;
++ var->transp.length = 0;
++ var->transp.msb_right = 0;
++ var->xres_virtual = sttt_xres_virtual;
++ linelen = var->xres_virtual * var->bits_per_pixel / 8;
++ ovsc_addlen = linelen * (sttt_yres_virtual - st_yres);
++
++ if (!use_hwscroll)
++ var->yres_virtual = var->yres;
+ else if (screen_len) {
+ if (par->yres_virtual)
+ var->yres_virtual = par->yres_virtual;
+ else
+- /* yres_virtual==0 means use maximum */
++ /* yres_virtual == 0 means use maximum */
+ var->yres_virtual = screen_len / linelen;
+- }
+- else {
++ } else {
+ if (hwscroll < 0)
+ var->yres_virtual = 2 * var->yres;
+ else
+- var->yres_virtual=var->yres+hwscroll * 16;
++ var->yres_virtual = var->yres + hwscroll * 16;
+ }
+- var->xoffset=0;
++ var->xoffset = 0;
+ if (screen_base)
+- var->yoffset=(par->screen_base - screen_base)/linelen;
++ var->yoffset = (par->screen_base - screen_base) / linelen;
+ else
+- var->yoffset=0;
+- var->nonstd=0;
+- var->activate=0;
+- var->vmode=FB_VMODE_NONINTERLACED;
++ var->yoffset = 0;
++ var->nonstd = 0;
++ var->activate = 0;
++ var->vmode = FB_VMODE_NONINTERLACED;
+ return 0;
+ }
+
+-
+-static void stste_get_par( struct atafb_par *par )
++static void stste_get_par(struct atafb_par *par)
+ {
+ unsigned long addr;
+- par->hw.st.mode=shifter_tt.st_shiftmode;
+- par->hw.st.sync=shifter.syncmode;
++ par->hw.st.mode = shifter_tt.st_shiftmode;
++ par->hw.st.sync = shifter.syncmode;
+ addr = ((shifter.bas_hi & 0xff) << 16) |
+ ((shifter.bas_md & 0xff) << 8);
+ if (ATARIHW_PRESENT(EXTD_SHIFTER))
+@@ -1920,55 +2001,18 @@ static void stste_get_par( struct atafb_
+ par->screen_base = phys_to_virt(addr);
+ }
+
+-static void stste_set_par( struct atafb_par *par )
++static void stste_set_par(struct atafb_par *par)
+ {
+- shifter_tt.st_shiftmode=par->hw.st.mode;
+- shifter.syncmode=par->hw.st.sync;
++ shifter_tt.st_shiftmode = par->hw.st.mode;
++ shifter.syncmode = par->hw.st.sync;
+ /* only set screen_base if really necessary */
+ if (current_par.screen_base != par->screen_base)
+ fbhw->set_screen_base(par->screen_base);
+ }
+
+-
+-static int stste_getcolreg(unsigned regno, unsigned *red,
+- unsigned *green, unsigned *blue,
+- unsigned *transp, struct fb_info *info)
+-{
+- unsigned col, t;
+-
+- if (regno > 15)
+- return 1;
+- col = shifter_tt.color_reg[regno];
+- if (ATARIHW_PRESENT(EXTD_SHIFTER)) {
+- t = ((col >> 7) & 0xe) | ((col >> 11) & 1);
+- t |= t << 4;
+- *red = t | (t << 8);
+- t = ((col >> 3) & 0xe) | ((col >> 7) & 1);
+- t |= t << 4;
+- *green = t | (t << 8);
+- t = ((col << 1) & 0xe) | ((col >> 3) & 1);
+- t |= t << 4;
+- *blue = t | (t << 8);
+- }
+- else {
+- t = (col >> 7) & 0xe;
+- t |= t << 4;
+- *red = t | (t << 8);
+- t = (col >> 3) & 0xe;
+- t |= t << 4;
+- *green = t | (t << 8);
+- t = (col << 1) & 0xe;
+- t |= t << 4;
+- *blue = t | (t << 8);
+- }
+- *transp = 0;
+- return 0;
+-}
+-
+-
+-static int stste_setcolreg(unsigned regno, unsigned red,
+- unsigned green, unsigned blue,
+- unsigned transp, struct fb_info *info)
++static int stste_setcolreg(unsigned int regno, unsigned int red,
++ unsigned int green, unsigned int blue,
++ unsigned int transp, struct fb_info *info)
+ {
+ if (regno > 15)
+ return 1;
+@@ -1988,10 +2032,9 @@ static int stste_setcolreg(unsigned regn
+ return 0;
+ }
+
+-
+-static int stste_detect( void )
+-
+-{ struct atafb_par par;
++static int stste_detect(void)
++{
++ struct atafb_par par;
+
+ /* Determine the connected monitor: The DMA sound must be
+ * disabled before reading the MFP GPIP, because the Sound
+@@ -1999,7 +2042,7 @@ static int stste_detect( void )
+ */
+ if (ATARIHW_PRESENT(PCM_8BIT)) {
+ tt_dmasnd.ctrl = DMASND_CTRL_OFF;
+- udelay(20); /* wait a while for things to settle down */
++ udelay(20); /* wait a while for things to settle down */
+ }
+ mono_moni = (mfp.par_dt_reg & 0x80) == 0;
+
+@@ -2014,12 +2057,12 @@ static int stste_detect( void )
+ static void stste_set_screen_base(void *s_base)
+ {
+ unsigned long addr;
+- addr= virt_to_phys(s_base);
++ addr = virt_to_phys(s_base);
+ /* Setup Screen Memory */
+- shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16);
+- shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8);
++ shifter.bas_hi = (unsigned char)((addr & 0xff0000) >> 16);
++ shifter.bas_md = (unsigned char)((addr & 0x00ff00) >> 8);
+ if (ATARIHW_PRESENT(EXTD_SHIFTER))
+- shifter.bas_lo=(unsigned char) (addr & 0x0000ff);
++ shifter.bas_lo = (unsigned char)(addr & 0x0000ff);
+ }
+
+ #endif /* ATAFB_STE */
+@@ -2045,51 +2088,49 @@ static void stste_set_screen_base(void *
+ /* SWITCH_ACIA may be used for Falcon (ScreenBlaster III internal!) */
+ static void st_ovsc_switch(void)
+ {
+- unsigned long flags;
+- register unsigned char old, new;
++ unsigned long flags;
++ register unsigned char old, new;
+
+- if (!(atari_switches & ATARI_SWITCH_OVSC_MASK))
+- return;
+- local_irq_save(flags);
++ if (!(atari_switches & ATARI_SWITCH_OVSC_MASK))
++ return;
++ local_irq_save(flags);
+
+- mfp.tim_ct_b = 0x10;
+- mfp.active_edge |= 8;
+- mfp.tim_ct_b = 0;
+- mfp.tim_dt_b = 0xf0;
+- mfp.tim_ct_b = 8;
+- while (mfp.tim_dt_b > 1) /* TOS does it this way, don't ask why */
+- ;
+- new = mfp.tim_dt_b;
+- do {
+- udelay(LINE_DELAY);
+- old = new;
++ mfp.tim_ct_b = 0x10;
++ mfp.active_edge |= 8;
++ mfp.tim_ct_b = 0;
++ mfp.tim_dt_b = 0xf0;
++ mfp.tim_ct_b = 8;
++ while (mfp.tim_dt_b > 1) /* TOS does it this way, don't ask why */
++ ;
+ new = mfp.tim_dt_b;
+- } while (old != new);
+- mfp.tim_ct_b = 0x10;
+- udelay(SYNC_DELAY);
+-
+- if (atari_switches & ATARI_SWITCH_OVSC_IKBD)
+- acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID | ACIA_RIE;
+- if (atari_switches & ATARI_SWITCH_OVSC_MIDI)
+- acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID;
+- if (atari_switches & (ATARI_SWITCH_OVSC_SND6|ATARI_SWITCH_OVSC_SND7)) {
+- sound_ym.rd_data_reg_sel = 14;
+- sound_ym.wd_data = sound_ym.rd_data_reg_sel |
+- ((atari_switches&ATARI_SWITCH_OVSC_SND6) ? 0x40:0) |
+- ((atari_switches&ATARI_SWITCH_OVSC_SND7) ? 0x80:0);
+- }
+- local_irq_restore(flags);
++ do {
++ udelay(LINE_DELAY);
++ old = new;
++ new = mfp.tim_dt_b;
++ } while (old != new);
++ mfp.tim_ct_b = 0x10;
++ udelay(SYNC_DELAY);
++
++ if (atari_switches & ATARI_SWITCH_OVSC_IKBD)
++ acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID | ACIA_RIE;
++ if (atari_switches & ATARI_SWITCH_OVSC_MIDI)
++ acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID;
++ if (atari_switches & (ATARI_SWITCH_OVSC_SND6|ATARI_SWITCH_OVSC_SND7)) {
++ sound_ym.rd_data_reg_sel = 14;
++ sound_ym.wd_data = sound_ym.rd_data_reg_sel |
++ ((atari_switches & ATARI_SWITCH_OVSC_SND6) ? 0x40:0) |
++ ((atari_switches & ATARI_SWITCH_OVSC_SND7) ? 0x80:0);
++ }
++ local_irq_restore(flags);
+ }
+
+ /* ------------------- External Video ---------------------- */
+
+ #ifdef ATAFB_EXT
+
+-static int ext_encode_fix( struct fb_fix_screeninfo *fix,
+- struct atafb_par *par )
+-
++static int ext_encode_fix(struct fb_fix_screeninfo *fix, struct atafb_par *par)
+ {
+- strcpy(fix->id,"Unknown Extern");
++ strcpy(fix->id, "Unknown Extern");
+ fix->smem_start = (unsigned long)external_addr;
+ fix->smem_len = PAGE_ALIGN(external_len);
+ if (external_depth == 1) {
+@@ -2099,31 +2140,29 @@ static int ext_encode_fix( struct fb_fix
+ fix->visual =
+ (external_pmode == FB_TYPE_INTERLEAVED_PLANES ||
+ external_pmode == FB_TYPE_PACKED_PIXELS) ?
+- FB_VISUAL_MONO10 :
+- FB_VISUAL_MONO01;
+- }
+- else {
++ FB_VISUAL_MONO10 : FB_VISUAL_MONO01;
++ } else {
+ /* Use STATIC if we don't know how to access color registers */
+ int visual = external_vgaiobase ?
+ FB_VISUAL_PSEUDOCOLOR :
+ FB_VISUAL_STATIC_PSEUDOCOLOR;
+ switch (external_pmode) {
+- case -1: /* truecolor */
+- fix->type=FB_TYPE_PACKED_PIXELS;
+- fix->visual=FB_VISUAL_TRUECOLOR;
++ case -1: /* truecolor */
++ fix->type = FB_TYPE_PACKED_PIXELS;
++ fix->visual = FB_VISUAL_TRUECOLOR;
+ break;
+- case FB_TYPE_PACKED_PIXELS:
+- fix->type=FB_TYPE_PACKED_PIXELS;
+- fix->visual=visual;
++ case FB_TYPE_PACKED_PIXELS:
++ fix->type = FB_TYPE_PACKED_PIXELS;
++ fix->visual = visual;
+ break;
+- case FB_TYPE_PLANES:
+- fix->type=FB_TYPE_PLANES;
+- fix->visual=visual;
++ case FB_TYPE_PLANES:
++ fix->type = FB_TYPE_PLANES;
++ fix->visual = visual;
+ break;
+- case FB_TYPE_INTERLEAVED_PLANES:
+- fix->type=FB_TYPE_INTERLEAVED_PLANES;
+- fix->type_aux=2;
+- fix->visual=visual;
++ case FB_TYPE_INTERLEAVED_PLANES:
++ fix->type = FB_TYPE_INTERLEAVED_PLANES;
++ fix->type_aux = 2;
++ fix->visual = visual;
+ break;
+ }
+ }
+@@ -2134,137 +2173,112 @@ static int ext_encode_fix( struct fb_fix
+ return 0;
+ }
+
+-
+-static int ext_decode_var( struct fb_var_screeninfo *var,
+- struct atafb_par *par )
++static int ext_decode_var(struct fb_var_screeninfo *var, struct atafb_par *par)
+ {
+ struct fb_var_screeninfo *myvar = &atafb_predefined[0];
+-
++
+ if (var->bits_per_pixel > myvar->bits_per_pixel ||
+- var->xres > myvar->xres ||
+- var->xres_virtual > myvar->xres_virtual ||
+- var->yres > myvar->yres ||
+- var->xoffset > 0 ||
+- var->yoffset > 0)
++ var->xres > myvar->xres ||
++ var->xres_virtual > myvar->xres_virtual ||
++ var->yres > myvar->yres ||
++ var->xoffset > 0 ||
++ var->yoffset > 0)
+ return -EINVAL;
+ return 0;
+ }
+
+-
+-static int ext_encode_var( struct fb_var_screeninfo *var,
+- struct atafb_par *par )
++static int ext_encode_var(struct fb_var_screeninfo *var, struct atafb_par *par)
+ {
+ memset(var, 0, sizeof(struct fb_var_screeninfo));
+- var->red.offset=0;
+- var->red.length=(external_pmode == -1) ? external_depth/3 :
++ var->red.offset = 0;
++ var->red.length = (external_pmode == -1) ? external_depth / 3 :
+ (external_vgaiobase ? external_bitspercol : 0);
+- var->red.msb_right=0;
+- var->grayscale=0;
++ var->red.msb_right = 0;
++ var->grayscale = 0;
+
+- var->pixclock=31041;
+- var->left_margin=120; /* these are surely incorrect */
+- var->right_margin=100;
+- var->upper_margin=8;
+- var->lower_margin=16;
+- var->hsync_len=140;
+- var->vsync_len=30;
++ var->pixclock = 31041;
++ var->left_margin = 120; /* these are surely incorrect */
++ var->right_margin = 100;
++ var->upper_margin = 8;
++ var->lower_margin = 16;
++ var->hsync_len = 140;
++ var->vsync_len = 30;
+
+- var->height=-1;
+- var->width=-1;
++ var->height = -1;
++ var->width = -1;
+
+- var->sync=0;
++ var->sync = 0;
+
+ var->xres = external_xres;
+ var->yres = external_yres;
+ var->xres_virtual = external_xres_virtual;
+ var->bits_per_pixel = external_depth;
+-
+- var->blue=var->green=var->red;
+- var->transp.offset=0;
+- var->transp.length=0;
+- var->transp.msb_right=0;
+- var->yres_virtual=var->yres;
+- var->xoffset=0;
+- var->yoffset=0;
+- var->nonstd=0;
+- var->activate=0;
+- var->vmode=FB_VMODE_NONINTERLACED;
++
++ var->blue = var->green = var->red;
++ var->transp.offset = 0;
++ var->transp.length = 0;
++ var->transp.msb_right = 0;
++ var->yres_virtual = var->yres;
++ var->xoffset = 0;
++ var->yoffset = 0;
++ var->nonstd = 0;
++ var->activate = 0;
++ var->vmode = FB_VMODE_NONINTERLACED;
+ return 0;
+ }
+
+-
+-static void ext_get_par( struct atafb_par *par )
++static void ext_get_par(struct atafb_par *par)
+ {
+ par->screen_base = external_addr;
+ }
+
+-static void ext_set_par( struct atafb_par *par )
++static void ext_set_par(struct atafb_par *par)
+ {
+ }
+
+ #define OUTB(port,val) \
+- *((unsigned volatile char *) ((port)+external_vgaiobase))=(val)
++ *((unsigned volatile char *) ((port)+external_vgaiobase)) = (val)
+ #define INB(port) \
+ (*((unsigned volatile char *) ((port)+external_vgaiobase)))
+-#define DACDelay \
++#define DACDelay \
+ do { \
+- unsigned char tmp=INB(0x3da); \
+- tmp=INB(0x3da); \
++ unsigned char tmp = INB(0x3da); \
++ tmp = INB(0x3da); \
+ } while (0)
+
+-static int ext_getcolreg( unsigned regno, unsigned *red,
+- unsigned *green, unsigned *blue,
+- unsigned *transp, struct fb_info *info )
++static int ext_setcolreg(unsigned int regno, unsigned int red,
++ unsigned int green, unsigned int blue,
++ unsigned int transp, struct fb_info *info)
+ {
+- if (! external_vgaiobase)
++ unsigned char colmask = (1 << external_bitspercol) - 1;
++
++ if (!external_vgaiobase)
+ return 1;
+
+- *red = ext_color[regno].red;
+- *green = ext_color[regno].green;
+- *blue = ext_color[regno].blue;
+- *transp=0;
+- return 0;
+-}
+-
+-static int ext_setcolreg( unsigned regno, unsigned red,
+- unsigned green, unsigned blue,
+- unsigned transp, struct fb_info *info )
++ switch (external_card_type) {
++ case IS_VGA:
++ OUTB(0x3c8, regno);
++ DACDelay;
++ OUTB(0x3c9, red & colmask);
++ DACDelay;
++ OUTB(0x3c9, green & colmask);
++ DACDelay;
++ OUTB(0x3c9, blue & colmask);
++ DACDelay;
++ return 0;
+
+-{ unsigned char colmask = (1 << external_bitspercol) - 1;
++ case IS_MV300:
++ OUTB((MV300_reg[regno] << 2) + 1, red);
++ OUTB((MV300_reg[regno] << 2) + 1, green);
++ OUTB((MV300_reg[regno] << 2) + 1, blue);
++ return 0;
+
+- if (! external_vgaiobase)
++ default:
+ return 1;
+-
+- ext_color[regno].red = red;
+- ext_color[regno].green = green;
+- ext_color[regno].blue = blue;
+-
+- switch (external_card_type) {
+- case IS_VGA:
+- OUTB(0x3c8, regno);
+- DACDelay;
+- OUTB(0x3c9, red & colmask);
+- DACDelay;
+- OUTB(0x3c9, green & colmask);
+- DACDelay;
+- OUTB(0x3c9, blue & colmask);
+- DACDelay;
+- return 0;
+-
+- case IS_MV300:
+- OUTB((MV300_reg[regno] << 2)+1, red);
+- OUTB((MV300_reg[regno] << 2)+1, green);
+- OUTB((MV300_reg[regno] << 2)+1, blue);
+- return 0;
+-
+- default:
+- return 1;
+- }
++ }
+ }
+-
+-
+-static int ext_detect( void )
+
++static int ext_detect(void)
+ {
+ struct fb_var_screeninfo *myvar = &atafb_predefined[0];
+ struct atafb_par dummy_par;
+@@ -2284,213 +2298,182 @@ static int ext_detect( void )
+ static void set_screen_base(void *s_base)
+ {
+ unsigned long addr;
+- addr= virt_to_phys(s_base);
++
++ addr = virt_to_phys(s_base);
+ /* Setup Screen Memory */
+- shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16);
+- shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8);
+- shifter.bas_lo=(unsigned char) (addr & 0x0000ff);
++ shifter.bas_hi = (unsigned char)((addr & 0xff0000) >> 16);
++ shifter.bas_md = (unsigned char)((addr & 0x00ff00) >> 8);
++ shifter.bas_lo = (unsigned char)(addr & 0x0000ff);
+ }
+
+-
+-static int pan_display( struct fb_var_screeninfo *var,
+- struct atafb_par *par )
++static int pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+ {
++ struct atafb_par *par = (struct atafb_par *)info->par;
++
+ if (!fbhw->set_screen_base ||
+- (!ATARIHW_PRESENT(EXTD_SHIFTER) && var->xoffset))
++ (!ATARIHW_PRESENT(EXTD_SHIFTER) && var->xoffset))
+ return -EINVAL;
+ var->xoffset = up(var->xoffset, 16);
+ par->screen_base = screen_base +
+- (var->yoffset * fb_display[fb_info.currcon].var.xres_virtual + var->xoffset)
+- * fb_display[fb_info.currcon].var.bits_per_pixel / 8;
+- fbhw->set_screen_base (par->screen_base);
++ (var->yoffset * info->var.xres_virtual + var->xoffset)
++ * info->var.bits_per_pixel / 8;
++ fbhw->set_screen_base(par->screen_base);
+ return 0;
+ }
+
+-
+ /* ------------ Interfaces to hardware functions ------------ */
+
+-
+ #ifdef ATAFB_TT
+ static struct fb_hwswitch tt_switch = {
+- tt_detect, tt_encode_fix, tt_decode_var, tt_encode_var,
+- tt_get_par, tt_set_par, tt_getcolreg,
+- set_screen_base, NULL, pan_display
++ .detect = tt_detect,
++ .encode_fix = tt_encode_fix,
++ .decode_var = tt_decode_var,
++ .encode_var = tt_encode_var,
++ .get_par = tt_get_par,
++ .set_par = tt_set_par,
++ .set_screen_base = set_screen_base,
++ .pan_display = pan_display,
+ };
+ #endif
+
+ #ifdef ATAFB_FALCON
+ static struct fb_hwswitch falcon_switch = {
+- falcon_detect, falcon_encode_fix, falcon_decode_var, falcon_encode_var,
+- falcon_get_par, falcon_set_par, falcon_getcolreg,
+- set_screen_base, falcon_blank, falcon_pan_display
++ .detect = falcon_detect,
++ .encode_fix = falcon_encode_fix,
++ .decode_var = falcon_decode_var,
++ .encode_var = falcon_encode_var,
++ .get_par = falcon_get_par,
++ .set_par = falcon_set_par,
++ .set_screen_base = set_screen_base,
++ .blank = falcon_blank,
++ .pan_display = falcon_pan_display,
+ };
+ #endif
+
+ #ifdef ATAFB_STE
+ static struct fb_hwswitch st_switch = {
+- stste_detect, stste_encode_fix, stste_decode_var, stste_encode_var,
+- stste_get_par, stste_set_par, stste_getcolreg,
+- stste_set_screen_base, NULL, pan_display
++ .detect = stste_detect,
++ .encode_fix = stste_encode_fix,
++ .decode_var = stste_decode_var,
++ .encode_var = stste_encode_var,
++ .get_par = stste_get_par,
++ .set_par = stste_set_par,
++ .set_screen_base = stste_set_screen_base,
++ .pan_display = pan_display
+ };
+ #endif
+
+ #ifdef ATAFB_EXT
+ static struct fb_hwswitch ext_switch = {
+- ext_detect, ext_encode_fix, ext_decode_var, ext_encode_var,
+- ext_get_par, ext_set_par, ext_getcolreg, NULL, NULL, NULL
++ .detect = ext_detect,
++ .encode_fix = ext_encode_fix,
++ .decode_var = ext_decode_var,
++ .encode_var = ext_encode_var,
++ .get_par = ext_get_par,
++ .set_par = ext_set_par,
+ };
+ #endif
+
+-
+-
+-static void atafb_get_par( struct atafb_par *par )
++static void ata_get_par(struct atafb_par *par)
+ {
+- if (current_par_valid) {
+- *par=current_par;
+- }
++ if (current_par_valid)
++ *par = current_par;
+ else
+ fbhw->get_par(par);
+ }
+
+-
+-static void atafb_set_par( struct atafb_par *par )
++static void ata_set_par(struct atafb_par *par)
+ {
+ fbhw->set_par(par);
+- current_par=*par;
+- current_par_valid=1;
++ current_par = *par;
++ current_par_valid = 1;
+ }
+
+
+-
+ /* =========================================================== */
+ /* ============== Hardware Independent Functions ============= */
+ /* =========================================================== */
+
+-
+ /* used for hardware scrolling */
+
+-static int
+-fb_update_var(int con, struct fb_info *info)
+-{
+- int off=fb_display[con].var.yoffset*fb_display[con].var.xres_virtual*
+- fb_display[con].var.bits_per_pixel>>3;
+-
+- current_par.screen_base=screen_base + off;
+-
+- if (fbhw->set_screen_base)
+- fbhw->set_screen_base(current_par.screen_base);
+- return 0;
+-}
+-
+-static int
+-do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
++static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
+ {
+- int err,activate;
++ int err, activate;
+ struct atafb_par par;
+- if ((err=fbhw->decode_var(var, &par)))
++
++ err = fbhw->decode_var(var, &par);
++ if (err)
+ return err;
+- activate=var->activate;
++ activate = var->activate;
+ if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive)
+- atafb_set_par(&par);
++ ata_set_par(&par);
+ fbhw->encode_var(var, &par);
+- var->activate=activate;
++ var->activate = activate;
+ return 0;
+ }
+
+-static int
+-atafb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
++static int atafb_get_fix(struct fb_fix_screeninfo *fix, struct fb_info *info)
+ {
+ struct atafb_par par;
+- if (con == -1)
+- atafb_get_par(&par);
+- else {
+- int err;
+- if ((err=fbhw->decode_var(&fb_display[con].var,&par)))
+- return err;
+- }
++ int err;
++ // Get fix directly (case con == -1 before)??
++ err = fbhw->decode_var(&info->var, &par);
++ if (err)
++ return err;
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+ return fbhw->encode_fix(fix, &par);
+ }
+-
+-static int
+-atafb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
++
++static int atafb_get_var(struct fb_var_screeninfo *var, struct fb_info *info)
+ {
+ struct atafb_par par;
+- if (con == -1) {
+- atafb_get_par(&par);
+- fbhw->encode_var(var, &par);
+- }
+- else
+- *var=fb_display[con].var;
++
++ ata_get_par(&par);
++ fbhw->encode_var(var, &par);
++
+ return 0;
+ }
+
+-static void
+-atafb_set_disp(int con, struct fb_info *info)
++// No longer called by fbcon!
++// Still called by set_var internally
++
++static void atafb_set_disp(struct fb_info *info)
+ {
+- struct fb_fix_screeninfo fix;
+- struct fb_var_screeninfo var;
+- struct display *display;
++ atafb_get_var(&info->var, info);
++ atafb_get_fix(&info->fix, info);
+
+- if (con >= 0)
+- display = &fb_display[con];
+- else
+- display = &disp; /* used during initialization */
++ info->screen_base = (void *)info->fix.smem_start;
+
+- atafb_get_fix(&fix, con, info);
+- atafb_get_var(&var, con, info);
+- if (con == -1)
+- con=0;
+- info->screen_base = (void *)fix.smem_start;
+- display->visual = fix.visual;
+- display->type = fix.type;
+- display->type_aux = fix.type_aux;
+- display->ypanstep = fix.ypanstep;
+- display->ywrapstep = fix.ywrapstep;
+- display->line_length = fix.line_length;
+- if (fix.visual != FB_VISUAL_PSEUDOCOLOR &&
+- fix.visual != FB_VISUAL_DIRECTCOLOR)
+- display->can_soft_blank = 0;
+- else
+- display->can_soft_blank = 1;
+- display->inverse =
+- (fix.visual == FB_VISUAL_MONO01 ? !inverse : inverse);
+- switch (fix.type) {
+- case FB_TYPE_INTERLEAVED_PLANES:
+- switch (var.bits_per_pixel) {
+-#ifdef FBCON_HAS_IPLAN2P2
+- case 2:
+- display->dispsw = &fbcon_iplan2p2;
++ switch (info->fix.type) {
++ case FB_TYPE_INTERLEAVED_PLANES:
++ switch (info->var.bits_per_pixel) {
++ case 2:
++ // display->dispsw = &fbcon_iplan2p2;
+ break;
+-#endif
+-#ifdef FBCON_HAS_IPLAN2P4
+- case 4:
+- display->dispsw = &fbcon_iplan2p4;
++ case 4:
++ // display->dispsw = &fbcon_iplan2p4;
+ break;
+-#endif
+-#ifdef FBCON_HAS_IPLAN2P8
+- case 8:
+- display->dispsw = &fbcon_iplan2p8;
++ case 8:
++ // display->dispsw = &fbcon_iplan2p8;
+ break;
+-#endif
+ }
+ break;
+- case FB_TYPE_PACKED_PIXELS:
+- switch (var.bits_per_pixel) {
++ case FB_TYPE_PACKED_PIXELS:
++ switch (info->var.bits_per_pixel) {
+ #ifdef FBCON_HAS_MFB
+- case 1:
+- display->dispsw = &fbcon_mfb;
++ case 1:
++ // display->dispsw = &fbcon_mfb;
+ break;
+ #endif
+ #ifdef FBCON_HAS_CFB8
+- case 8:
+- display->dispsw = &fbcon_cfb8;
++ case 8:
++ // display->dispsw = &fbcon_cfb8;
+ break;
+ #endif
+ #ifdef FBCON_HAS_CFB16
+- case 16:
+- display->dispsw = &fbcon_cfb16;
+- display->dispsw_data = fbcon_cfb16_cmap;
++ case 16:
++ // display->dispsw = &fbcon_cfb16;
++ // display->dispsw_data = fbcon_cfb16_cmap;
+ break;
+ #endif
+ }
+@@ -2498,74 +2481,203 @@ atafb_set_disp(int con, struct fb_info *
+ }
+ }
+
++static int atafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
++ u_int transp, struct fb_info *info)
++{
++ red >>= 8;
++ green >>= 8;
++ blue >>= 8;
++
++ return info->fbops->fb_setcolreg(regno, red, green, blue, transp, info);
++}
++
+ static int
+-atafb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
++atafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+ {
+- int err,oldxres,oldyres,oldbpp,oldxres_virtual,
+- oldyres_virtual,oldyoffset;
+- if ((err=do_fb_set_var(var, con==info->currcon)))
+- return err;
+- if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+- oldxres=fb_display[con].var.xres;
+- oldyres=fb_display[con].var.yres;
+- oldxres_virtual=fb_display[con].var.xres_virtual;
+- oldyres_virtual=fb_display[con].var.yres_virtual;
+- oldbpp=fb_display[con].var.bits_per_pixel;
+- oldyoffset=fb_display[con].var.yoffset;
+- fb_display[con].var=*var;
+- if (oldxres != var->xres || oldyres != var->yres
+- || oldxres_virtual != var->xres_virtual
+- || oldyres_virtual != var->yres_virtual
+- || oldbpp != var->bits_per_pixel
+- || oldyoffset != var->yoffset) {
+- atafb_set_disp(con, info);
+- (*fb_info.changevar)(con);
+- fb_alloc_cmap(&fb_display[con].cmap, 0, 0);
+- do_install_cmap(con, info);
+- }
++ int xoffset = var->xoffset;
++ int yoffset = var->yoffset;
++ int err;
++
++ if (var->vmode & FB_VMODE_YWRAP) {
++ if (yoffset < 0 || yoffset >= info->var.yres_virtual || xoffset)
++ return -EINVAL;
++ } else {
++ if (xoffset + info->var.xres > info->var.xres_virtual ||
++ yoffset + info->var.yres > info->var.yres_virtual)
++ return -EINVAL;
+ }
+- var->activate=0;
++
++ if (fbhw->pan_display) {
++ err = fbhw->pan_display(var, info);
++ if (err)
++ return err;
++ } else
++ return -EINVAL;
++
++ info->var.xoffset = xoffset;
++ info->var.yoffset = yoffset;
++
++ if (var->vmode & FB_VMODE_YWRAP)
++ info->var.vmode |= FB_VMODE_YWRAP;
++ else
++ info->var.vmode &= ~FB_VMODE_YWRAP;
++
+ return 0;
+ }
+
++/*
++ * generic drawing routines; imageblit needs updating for image depth > 1
++ */
++
++#if BITS_PER_LONG == 32
++#define BYTES_PER_LONG 4
++#define SHIFT_PER_LONG 5
++#elif BITS_PER_LONG == 64
++#define BYTES_PER_LONG 8
++#define SHIFT_PER_LONG 6
++#else
++#define Please update me
++#endif
+
+
+-static int
+-atafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
++static void atafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+ {
+- if (con == info->currcon) /* current console ? */
+- return fb_get_cmap(cmap, kspc, fbhw->getcolreg, info);
++ struct atafb_par *par = (struct atafb_par *)info->par;
++ int x2, y2;
++ u32 width, height;
++
++ if (!rect->width || !rect->height)
++ return;
++
++ /*
++ * We could use hardware clipping but on many cards you get around
++ * hardware clipping by writing to framebuffer directly.
++ * */
++ x2 = rect->dx + rect->width;
++ y2 = rect->dy + rect->height;
++ x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
++ y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
++ width = x2 - rect->dx;
++ height = y2 - rect->dy;
++
++ if (info->var.bits_per_pixel == 1)
++ atafb_mfb_fillrect(info, par->next_line, rect->color,
++ rect->dy, rect->dx, height, width);
++ else if (info->var.bits_per_pixel == 2)
++ atafb_iplan2p2_fillrect(info, par->next_line, rect->color,
++ rect->dy, rect->dx, height, width);
++ else if (info->var.bits_per_pixel == 4)
++ atafb_iplan2p4_fillrect(info, par->next_line, rect->color,
++ rect->dy, rect->dx, height, width);
+ else
+- if (fb_display[con].cmap.len) /* non default colormap ? */
+- fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
+- else
+- fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
+- cmap, kspc ? 0 : 2);
+- return 0;
++ atafb_iplan2p8_fillrect(info, par->next_line, rect->color,
++ rect->dy, rect->dx, height, width);
++
++ return;
+ }
+
+-static int
+-atafb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info)
++static void atafb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+ {
+- int xoffset = var->xoffset;
+- int yoffset = var->yoffset;
+- int err;
++ struct atafb_par *par = (struct atafb_par *)info->par;
++ int x2, y2;
++ u32 dx, dy, sx, sy, width, height;
++ int rev_copy = 0;
++
++ /* clip the destination */
++ x2 = area->dx + area->width;
++ y2 = area->dy + area->height;
++ dx = area->dx > 0 ? area->dx : 0;
++ dy = area->dy > 0 ? area->dy : 0;
++ x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
++ y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
++ width = x2 - dx;
++ height = y2 - dy;
++
++ /* update sx,sy */
++ sx = area->sx + (dx - area->dx);
++ sy = area->sy + (dy - area->dy);
++
++ /* the source must be completely inside the virtual screen */
++ if (sx < 0 || sy < 0 || (sx + width) > info->var.xres_virtual ||
++ (sy + height) > info->var.yres_virtual)
++ return;
+
+- if ( xoffset < 0 || xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual
+- || yoffset < 0 || yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
+- return -EINVAL;
++ if (dy > sy || (dy == sy && dx > sx)) {
++ dy += height;
++ sy += height;
++ rev_copy = 1;
++ }
++
++ if (info->var.bits_per_pixel == 1)
++ atafb_mfb_copyarea(info, par->next_line, sy, sx, dy, dx, height, width);
++ else if (info->var.bits_per_pixel == 2)
++ atafb_iplan2p2_copyarea(info, par->next_line, sy, sx, dy, dx, height, width);
++ else if (info->var.bits_per_pixel == 4)
++ atafb_iplan2p4_copyarea(info, par->next_line, sy, sx, dy, dx, height, width);
++ else
++ atafb_iplan2p8_copyarea(info, par->next_line, sy, sx, dy, dx, height, width);
++
++ return;
++}
+
+- if (con == info->currcon) {
+- if (fbhw->pan_display) {
+- if ((err = fbhw->pan_display(var, &current_par)))
+- return err;
++static void atafb_imageblit(struct fb_info *info, const struct fb_image *image)
++{
++ struct atafb_par *par = (struct atafb_par *)info->par;
++ int x2, y2;
++ unsigned long *dst;
++ int dst_idx;
++ const char *src;
++ u32 dx, dy, width, height, pitch;
++
++ /*
++ * We could use hardware clipping but on many cards you get around
++ * hardware clipping by writing to framebuffer directly like we are
++ * doing here.
++ */
++ x2 = image->dx + image->width;
++ y2 = image->dy + image->height;
++ dx = image->dx;
++ dy = image->dy;
++ x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
++ y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
++ width = x2 - dx;
++ height = y2 - dy;
++
++ if (image->depth == 1) {
++ // used for font data
++ dst = (unsigned long *)
++ ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1));
++ dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8;
++ dst_idx += dy * par->next_line * 8 + dx;
++ src = image->data;
++ pitch = (image->width + 7) / 8;
++ while (height--) {
++
++ if (info->var.bits_per_pixel == 1)
++ atafb_mfb_linefill(info, par->next_line,
++ dy, dx, width, src,
++ image->bg_color, image->fg_color);
++ else if (info->var.bits_per_pixel == 2)
++ atafb_iplan2p2_linefill(info, par->next_line,
++ dy, dx, width, src,
++ image->bg_color, image->fg_color);
++ else if (info->var.bits_per_pixel == 4)
++ atafb_iplan2p4_linefill(info, par->next_line,
++ dy, dx, width, src,
++ image->bg_color, image->fg_color);
++ else
++ atafb_iplan2p8_linefill(info, par->next_line,
++ dy, dx, width, src,
++ image->bg_color, image->fg_color);
++ dy++;
++ src += pitch;
+ }
+- else
+- return -EINVAL;
++ } else {
++ // only used for logo; broken
++ c2p(info->screen_base, image->data, dx, dy, width, height,
++ par->next_line, par->next_plane, image->width,
++ info->var.bits_per_pixel);
+ }
+- fb_display[con].var.xoffset = var->xoffset;
+- fb_display[con].var.yoffset = var->yoffset;
+- return 0;
+ }
+
+ static int
+@@ -2584,7 +2696,7 @@ atafb_ioctl(struct fb_info *info, unsign
+ if (copy_from_user((void *)&current_par, (void *)arg,
+ sizeof(struct atafb_par)))
+ return -EFAULT;
+- atafb_set_par(&current_par);
++ ata_set_par(&current_par);
+ return 0;
+ #endif
+ }
+@@ -2598,42 +2710,82 @@ atafb_ioctl(struct fb_info *info, unsign
+ * 3 = suspend hsync
+ * 4 = off
+ */
+-static int
+-atafb_blank(int blank, struct fb_info *info)
++static int atafb_blank(int blank, struct fb_info *info)
+ {
+ unsigned short black[16];
+ struct fb_cmap cmap;
+ if (fbhw->blank && !fbhw->blank(blank))
+ return 1;
+ if (blank) {
+- memset(black, 0, 16*sizeof(unsigned short));
+- cmap.red=black;
+- cmap.green=black;
+- cmap.blue=black;
+- cmap.transp=NULL;
+- cmap.start=0;
+- cmap.len=16;
+- fb_set_cmap(&cmap, 1, info);
++ memset(black, 0, 16 * sizeof(unsigned short));
++ cmap.red = black;
++ cmap.green = black;
++ cmap.blue = black;
++ cmap.transp = NULL;
++ cmap.start = 0;
++ cmap.len = 16;
++ fb_set_cmap(&cmap, info);
+ }
++#if 0
+ else
+- do_install_cmap(info->currcon, info);
++ do_install_cmap(info);
++#endif
++ return 0;
++}
++
++ /*
++ * New fbcon interface ...
++ */
++
++ /* check var by decoding var into hw par, rounding if necessary,
++ * then encoding hw par back into new, validated var */
++static int atafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
++{
++ int err;
++ struct atafb_par par;
++
++ /* Validate wanted screen parameters */
++ // if ((err = ata_decode_var(var, &par)))
++ err = fbhw->decode_var(var, &par);
++ if (err)
++ return err;
++
++ /* Encode (possibly rounded) screen parameters */
++ fbhw->encode_var(var, &par);
+ return 0;
+ }
+
++ /* actually set hw par by decoding var, then setting hardware from
++ * hw par just decoded */
++static int atafb_set_par(struct fb_info *info)
++{
++ struct atafb_par *par = (struct atafb_par *)info->par;
++
++ /* Decode wanted screen parameters */
++ fbhw->decode_var(&info->var, par);
++ fbhw->encode_fix(&info->fix, par);
++
++ /* Set new videomode */
++ ata_set_par(par);
++
++ return 0;
++}
++
++
+ static struct fb_ops atafb_ops = {
+ .owner = THIS_MODULE,
+- .fb_get_fix = atafb_get_fix,
+- .fb_get_var = atafb_get_var,
+- .fb_set_var = atafb_set_var,
+- .fb_get_cmap = atafb_get_cmap,
+- .fb_set_cmap = gen_set_cmap,
+- .fb_pan_display =atafb_pan_display,
++ .fb_check_var = atafb_check_var,
++ .fb_set_par = atafb_set_par,
++ .fb_setcolreg = atafb_setcolreg,
+ .fb_blank = atafb_blank,
++ .fb_pan_display = atafb_pan_display,
++ .fb_fillrect = atafb_fillrect,
++ .fb_copyarea = atafb_copyarea,
++ .fb_imageblit = atafb_imageblit,
+ .fb_ioctl = atafb_ioctl,
+ };
+
+-static void
+-check_default_par( int detected_mode )
++static void check_default_par(int detected_mode)
+ {
+ char default_name[10];
+ int i;
+@@ -2642,199 +2794,41 @@ check_default_par( int detected_mode )
+
+ /* First try the user supplied mode */
+ if (default_par) {
+- var=atafb_predefined[default_par-1];
++ var = atafb_predefined[default_par - 1];
+ var.activate = FB_ACTIVATE_TEST;
+- if (do_fb_set_var(&var,1))
+- default_par=0; /* failed */
++ if (do_fb_set_var(&var, 1))
++ default_par = 0; /* failed */
+ }
+ /* Next is the autodetected one */
+- if (! default_par) {
+- var=atafb_predefined[detected_mode-1]; /* autodetect */
++ if (!default_par) {
++ var = atafb_predefined[detected_mode - 1]; /* autodetect */
+ var.activate = FB_ACTIVATE_TEST;
+- if (!do_fb_set_var(&var,1))
+- default_par=detected_mode;
++ if (!do_fb_set_var(&var, 1))
++ default_par = detected_mode;
+ }
+ /* If that also failed, try some default modes... */
+- if (! default_par) {
++ if (!default_par) {
+ /* try default1, default2... */
+- for (i=1 ; i < 10 ; i++) {
+- sprintf(default_name,"default%d",i);
+- default_par=get_video_mode(default_name);
+- if (! default_par)
++ for (i = 1; i < 10; i++) {
++ sprintf(default_name,"default%d", i);
++ default_par = get_video_mode(default_name);
++ if (!default_par)
+ panic("can't set default video mode");
+- var=atafb_predefined[default_par-1];
++ var = atafb_predefined[default_par - 1];
+ var.activate = FB_ACTIVATE_TEST;
+- if (! do_fb_set_var(&var,1))
++ if (!do_fb_set_var(&var,1))
+ break; /* ok */
+ }
+ }
+- min_mem=var.xres_virtual * var.yres_virtual * var.bits_per_pixel/8;
++ min_mem = var.xres_virtual * var.yres_virtual * var.bits_per_pixel / 8;
+ if (default_mem_req < min_mem)
+- default_mem_req=min_mem;
+-}
+-
+-static int
+-atafb_switch(int con, struct fb_info *info)
+-{
+- /* Do we have to save the colormap ? */
+- if (fb_display[info->currcon].cmap.len)
+- fb_get_cmap(&fb_display[info->currcon].cmap, 1, fbhw->getcolreg,
+- info);
+- do_fb_set_var(&fb_display[con].var,1);
+- info->currcon=con;
+- /* Install new colormap */
+- do_install_cmap(con, info);
+- return 0;
+-}
+-
+-int __init atafb_init(void)
+-{
+- int pad;
+- int detected_mode;
+- unsigned long mem_req;
+-
+- if (!MACH_IS_ATARI)
+- return -ENXIO;
+-
+- do {
+-#ifdef ATAFB_EXT
+- if (external_addr) {
+- fbhw = &ext_switch;
+- atafb_ops.fb_setcolreg = &ext_setcolreg;
+- break;
+- }
+-#endif
+-#ifdef ATAFB_TT
+- if (ATARIHW_PRESENT(TT_SHIFTER)) {
+- fbhw = &tt_switch;
+- atafb_ops.fb_setcolreg = &tt_setcolreg;
+- break;
+- }
+-#endif
+-#ifdef ATAFB_FALCON
+- if (ATARIHW_PRESENT(VIDEL_SHIFTER)) {
+- fbhw = &falcon_switch;
+- atafb_ops.fb_setcolreg = &falcon_setcolreg;
+- request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO,
+- "framebuffer/modeswitch", falcon_vbl_switcher);
+- break;
+- }
+-#endif
+-#ifdef ATAFB_STE
+- if (ATARIHW_PRESENT(STND_SHIFTER) ||
+- ATARIHW_PRESENT(EXTD_SHIFTER)) {
+- fbhw = &st_switch;
+- atafb_ops.fb_setcolreg = &stste_setcolreg;
+- break;
+- }
+- fbhw = &st_switch;
+- atafb_ops.fb_setcolreg = &stste_setcolreg;
+- printk("Cannot determine video hardware; defaulting to ST(e)\n");
+-#else /* ATAFB_STE */
+- /* no default driver included */
+- /* Nobody will ever see this message :-) */
+- panic("Cannot initialize video hardware");
+-#endif
+- } while (0);
+-
+- /* Multisync monitor capabilities */
+- /* Atari-TOS defaults if no boot option present */
+- if (fb_info.monspecs.hfmin == 0) {
+- fb_info.monspecs.hfmin = 31000;
+- fb_info.monspecs.hfmax = 32000;
+- fb_info.monspecs.vfmin = 58;
+- fb_info.monspecs.vfmax = 62;
+- }
+-
+- detected_mode = fbhw->detect();
+- check_default_par(detected_mode);
+-#ifdef ATAFB_EXT
+- if (!external_addr) {
+-#endif /* ATAFB_EXT */
+- mem_req = default_mem_req + ovsc_offset + ovsc_addlen;
+- mem_req = PAGE_ALIGN(mem_req) + PAGE_SIZE;
+- screen_base = atari_stram_alloc(mem_req, "atafb");
+- if (!screen_base)
+- panic("Cannot allocate screen memory");
+- memset(screen_base, 0, mem_req);
+- pad = -(unsigned long)screen_base & (PAGE_SIZE-1);
+- screen_base+=pad;
+- real_screen_base=screen_base+ovsc_offset;
+- screen_len = (mem_req - pad - ovsc_offset) & PAGE_MASK;
+- st_ovsc_switch();
+- if (CPU_IS_040_OR_060) {
+- /* On a '040+, the cache mode of video RAM must be set to
+- * write-through also for internal video hardware! */
+- cache_push(virt_to_phys(screen_base), screen_len);
+- kernel_set_cachemode(screen_base, screen_len,
+- IOMAP_WRITETHROUGH);
+- }
+-#ifdef ATAFB_EXT
+- }
+- else {
+- /* Map the video memory (physical address given) to somewhere
+- * in the kernel address space.
+- */
+- external_addr =
+- ioremap_writethrough((unsigned long)external_addr,
+- external_len);
+- if (external_vgaiobase)
+- external_vgaiobase =
+- (unsigned long)ioremap(external_vgaiobase, 0x10000);
+- screen_base =
+- real_screen_base = external_addr;
+- screen_len = external_len & PAGE_MASK;
+- memset (screen_base, 0, external_len);
+- }
+-#endif /* ATAFB_EXT */
+-
+- strcpy(fb_info.modename, "Atari Builtin ");
+- fb_info.changevar = NULL;
+- fb_info.fbops = &atafb_ops;
+- fb_info.disp = &disp;
+- fb_info.currcon = -1;
+- fb_info.switch_con = &atafb_switch;
+- fb_info.updatevar = &fb_update_var;
+- fb_info.flags = FBINFO_FLAG_DEFAULT;
+- do_fb_set_var(&atafb_predefined[default_par-1], 1);
+- strcat(fb_info.modename, fb_var_names[default_par-1][0]);
+-
+- atafb_get_var(&disp.var, -1, &fb_info);
+- atafb_set_disp(-1, &fb_info);
+- do_install_cmap(0, &fb_info);
+-
+- if (register_framebuffer(&fb_info) < 0) {
+-#ifdef ATAFB_EXT
+- if (external_addr) {
+- iounmap(external_addr);
+- external_addr = NULL;
+- }
+- if (external_vgaiobase) {
+- iounmap((void*)external_vgaiobase);
+- external_vgaiobase = 0;
+- }
+-#endif
+- return -EINVAL;
+- }
+-
+- printk("Determined %dx%d, depth %d\n",
+- disp.var.xres, disp.var.yres, disp.var.bits_per_pixel);
+- if ((disp.var.xres != disp.var.xres_virtual) ||
+- (disp.var.yres != disp.var.yres_virtual))
+- printk(" virtual %dx%d\n",
+- disp.var.xres_virtual, disp.var.yres_virtual);
+- printk("fb%d: %s frame buffer device, using %dK of video memory\n",
+- fb_info.node, fb_info.modename, screen_len>>10);
+-
+- /* TODO: This driver cannot be unloaded yet */
+- return 0;
++ default_mem_req = min_mem;
+ }
+
+-
+ #ifdef ATAFB_EXT
+ static void __init atafb_setup_ext(char *spec)
+ {
+- int xres, xres_virtual, yres, depth, planes;
++ int xres, xres_virtual, yres, depth, planes;
+ unsigned long addr, len;
+ char *p;
+
+@@ -2848,27 +2842,31 @@ static void __init atafb_setup_ext(char
+ *
+ * Even xres_virtual is available, we neither support panning nor hw-scrolling!
+ */
+- if (!(p = strsep(&spec, ";")) || !*p)
+- return;
++ p = strsep(&spec, ";");
++ if (!p || !*p)
++ return;
+ xres_virtual = xres = simple_strtoul(p, NULL, 10);
+ if (xres <= 0)
+- return;
++ return;
+
+- if (!(p = strsep(&spec, ";")) || !*p)
+- return;
++ p = strsep(&spec, ";");
++ if (!p || !*p)
++ return;
+ yres = simple_strtoul(p, NULL, 10);
+ if (yres <= 0)
+- return;
++ return;
+
+- if (!(p = strsep(&spec, ";")) || !*p)
+- return;
++ p = strsep(&spec, ";");
++ if (!p || !*p)
++ return;
+ depth = simple_strtoul(p, NULL, 10);
+ if (depth != 1 && depth != 2 && depth != 4 && depth != 8 &&
+- depth != 16 && depth != 24)
+- return;
++ depth != 16 && depth != 24)
++ return;
+
+- if (!(p = strsep(&spec, ";")) || !*p)
+- return;
++ p = strsep(&spec, ";");
++ if (!p || !*p)
++ return;
+ if (*p == 'i')
+ planes = FB_TYPE_INTERLEAVED_PLANES;
+ else if (*p == 'p')
+@@ -2876,25 +2874,27 @@ static void __init atafb_setup_ext(char
+ else if (*p == 'n')
+ planes = FB_TYPE_PLANES;
+ else if (*p == 't')
+- planes = -1; /* true color */
++ planes = -1; /* true color */
+ else
+ return;
+
+-
+- if (!(p = strsep(&spec, ";")) || !*p)
++ p = strsep(&spec, ";");
++ if (!p || !*p)
+ return;
+ addr = simple_strtoul(p, NULL, 0);
+
+- if (!(p = strsep(&spec, ";")) || !*p)
+- len = xres*yres*depth/8;
++ p = strsep(&spec, ";");
++ if (!p || !*p)
++ len = xres * yres * depth / 8;
+ else
+ len = simple_strtoul(p, NULL, 0);
+
+- if ((p = strsep(&spec, ";")) && *p) {
+- external_vgaiobase=simple_strtoul(p, NULL, 0);
+- }
++ p = strsep(&spec, ";");
++ if (p && *p)
++ external_vgaiobase = simple_strtoul(p, NULL, 0);
+
+- if ((p = strsep(&spec, ";")) && *p) {
++ p = strsep(&spec, ";");
++ if (p && *p) {
+ external_bitspercol = simple_strtoul(p, NULL, 0);
+ if (external_bitspercol > 8)
+ external_bitspercol = 8;
+@@ -2902,59 +2902,61 @@ static void __init atafb_setup_ext(char
+ external_bitspercol = 1;
+ }
+
+- if ((p = strsep(&spec, ";")) && *p) {
++ p = strsep(&spec, ";");
++ if (p && *p) {
+ if (!strcmp(p, "vga"))
+ external_card_type = IS_VGA;
+ if (!strcmp(p, "mv300"))
+ external_card_type = IS_MV300;
+ }
+
+- if ((p = strsep(&spec, ";")) && *p) {
++ p = strsep(&spec, ";");
++ if (p && *p) {
+ xres_virtual = simple_strtoul(p, NULL, 10);
+ if (xres_virtual < xres)
+ xres_virtual = xres;
+- if (xres_virtual*yres*depth/8 > len)
+- len=xres_virtual*yres*depth/8;
++ if (xres_virtual * yres * depth / 8 > len)
++ len = xres_virtual * yres * depth / 8;
+ }
+
+- external_xres = xres;
+- external_xres_virtual = xres_virtual;
+- external_yres = yres;
++ external_xres = xres;
++ external_xres_virtual = xres_virtual;
++ external_yres = yres;
+ external_depth = depth;
+ external_pmode = planes;
+- external_addr = (void *)addr;
+- external_len = len;
++ external_addr = (void *)addr;
++ external_len = len;
+
+- if (external_card_type == IS_MV300)
+- switch (external_depth) {
+- case 1:
+- MV300_reg = MV300_reg_1bit;
+- break;
+- case 4:
+- MV300_reg = MV300_reg_4bit;
+- break;
+- case 8:
+- MV300_reg = MV300_reg_8bit;
+- break;
+- }
++ if (external_card_type == IS_MV300) {
++ switch (external_depth) {
++ case 1:
++ MV300_reg = MV300_reg_1bit;
++ break;
++ case 4:
++ MV300_reg = MV300_reg_4bit;
++ break;
++ case 8:
++ MV300_reg = MV300_reg_8bit;
++ break;
++ }
++ }
+ }
+ #endif /* ATAFB_EXT */
+
+-
+ static void __init atafb_setup_int(char *spec)
+ {
+ /* Format to config extended internal video hardware like OverScan:
+- "internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>"
+- Explanation:
+- <xres>: x-resolution
+- <yres>: y-resolution
+- The following are only needed if you have an overscan which
+- needs a black border:
+- <xres_max>: max. length of a line in pixels your OverScan hardware would allow
+- <yres_max>: max. number of lines your OverScan hardware would allow
+- <offset>: Offset from physical beginning to visible beginning
+- of screen in bytes
+- */
++ * "internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>"
++ * Explanation:
++ * <xres>: x-resolution
++ * <yres>: y-resolution
++ * The following are only needed if you have an overscan which
++ * needs a black border:
++ * <xres_max>: max. length of a line in pixels your OverScan hardware would allow
++ * <yres_max>: max. number of lines your OverScan hardware would allow
++ * <offset>: Offset from physical beginning to visible beginning
++ * of screen in bytes
++ */
+ int xres;
+ char *p;
+
+@@ -2963,23 +2965,19 @@ static void __init atafb_setup_int(char
+ xres = simple_strtoul(p, NULL, 10);
+ if (!(p = strsep(&spec, ";")) || !*p)
+ return;
+- sttt_xres=xres;
+- tt_yres=st_yres=simple_strtoul(p, NULL, 10);
+- if ((p=strsep(&spec, ";")) && *p) {
+- sttt_xres_virtual=simple_strtoul(p, NULL, 10);
+- }
+- if ((p=strsep(&spec, ";")) && *p) {
+- sttt_yres_virtual=simple_strtoul(p, NULL, 0);
+- }
+- if ((p=strsep(&spec, ";")) && *p) {
+- ovsc_offset=simple_strtoul(p, NULL, 0);
+- }
++ sttt_xres = xres;
++ tt_yres = st_yres = simple_strtoul(p, NULL, 10);
++ if ((p = strsep(&spec, ";")) && *p)
++ sttt_xres_virtual = simple_strtoul(p, NULL, 10);
++ if ((p = strsep(&spec, ";")) && *p)
++ sttt_yres_virtual = simple_strtoul(p, NULL, 0);
++ if ((p = strsep(&spec, ";")) && *p)
++ ovsc_offset = simple_strtoul(p, NULL, 0);
+
+ if (ovsc_offset || (sttt_yres_virtual != st_yres))
+- use_hwscroll=0;
++ use_hwscroll = 0;
+ }
+
+-
+ #ifdef ATAFB_FALCON
+ static void __init atafb_setup_mcap(char *spec)
+ {
+@@ -3018,7 +3016,6 @@ static void __init atafb_setup_mcap(char
+ }
+ #endif /* ATAFB_FALCON */
+
+-
+ static void __init atafb_setup_user(char *spec)
+ {
+ /* Format of user defined video mode is: <xres>;<yres>;<depth>
+@@ -3026,81 +3023,257 @@ static void __init atafb_setup_user(char
+ char *p;
+ int xres, yres, depth, temp;
+
+- if (!(p = strsep(&spec, ";")) || !*p)
++ p = strsep(&spec, ";");
++ if (!p || !*p)
+ return;
+ xres = simple_strtoul(p, NULL, 10);
+- if (!(p = strsep(&spec, ";")) || !*p)
++ p = strsep(&spec, ";");
++ if (!p || !*p)
+ return;
+ yres = simple_strtoul(p, NULL, 10);
+- if (!(p = strsep(&spec, "")) || !*p)
++ p = strsep(&spec, "");
++ if (!p || !*p)
+ return;
+ depth = simple_strtoul(p, NULL, 10);
+- if ((temp=get_video_mode("user0"))) {
+- default_par=temp;
+- atafb_predefined[default_par-1].xres = xres;
+- atafb_predefined[default_par-1].yres = yres;
+- atafb_predefined[default_par-1].bits_per_pixel = depth;
++ temp = get_video_mode("user0");
++ if (temp) {
++ default_par = temp;
++ atafb_predefined[default_par - 1].xres = xres;
++ atafb_predefined[default_par - 1].yres = yres;
++ atafb_predefined[default_par - 1].bits_per_pixel = depth;
+ }
+ }
+
+-int __init atafb_setup( char *options )
++int __init atafb_setup(char *options)
+ {
+- char *this_opt;
+- int temp;
+-
+- fb_info.fontname[0] = '\0';
++ char *this_opt;
++ int temp;
+
+- if (!options || !*options)
++ if (!options || !*options)
+ return 0;
+-
+- while ((this_opt = strsep(&options, ",")) != NULL) {
+- if (!*this_opt) continue;
+- if ((temp=get_video_mode(this_opt)))
+- default_par=temp;
+- else if (! strcmp(this_opt, "inverse"))
+- inverse=1;
+- else if (!strncmp(this_opt, "font:", 5))
+- strcpy(fb_info.fontname, this_opt+5);
+- else if (! strncmp(this_opt, "hwscroll_",9)) {
+- hwscroll=simple_strtoul(this_opt+9, NULL, 10);
+- if (hwscroll < 0)
+- hwscroll = 0;
+- if (hwscroll > 200)
+- hwscroll = 200;
+- }
++
++ while ((this_opt = strsep(&options, ",")) != NULL) {
++ if (!*this_opt)
++ continue;
++ if ((temp = get_video_mode(this_opt))) {
++ default_par = temp;
++ mode_option = this_opt;
++ } else if (!strcmp(this_opt, "inverse"))
++ inverse = 1;
++ else if (!strncmp(this_opt, "hwscroll_", 9)) {
++ hwscroll = simple_strtoul(this_opt + 9, NULL, 10);
++ if (hwscroll < 0)
++ hwscroll = 0;
++ if (hwscroll > 200)
++ hwscroll = 200;
++ }
+ #ifdef ATAFB_EXT
+- else if (!strcmp(this_opt,"mv300")) {
+- external_bitspercol = 8;
+- external_card_type = IS_MV300;
++ else if (!strcmp(this_opt, "mv300")) {
++ external_bitspercol = 8;
++ external_card_type = IS_MV300;
++ } else if (!strncmp(this_opt, "external:", 9))
++ atafb_setup_ext(this_opt + 9);
++#endif
++ else if (!strncmp(this_opt, "internal:", 9))
++ atafb_setup_int(this_opt + 9);
++#ifdef ATAFB_FALCON
++ else if (!strncmp(this_opt, "eclock:", 7)) {
++ fext.f = simple_strtoul(this_opt + 7, NULL, 10);
++ /* external pixelclock in kHz --> ps */
++ fext.t = 1000000000 / fext.f;
++ fext.f *= 1000;
++ } else if (!strncmp(this_opt, "monitorcap:", 11))
++ atafb_setup_mcap(this_opt + 11);
++#endif
++ else if (!strcmp(this_opt, "keep"))
++ DontCalcRes = 1;
++ else if (!strncmp(this_opt, "R", 1))
++ atafb_setup_user(this_opt + 1);
+ }
+- else if (!strncmp(this_opt,"external:",9))
+- atafb_setup_ext(this_opt+9);
++ return 0;
++}
++
++int __init atafb_init(void)
++{
++ int pad;
++ int detected_mode;
++ unsigned int defmode = 0;
++ unsigned long mem_req;
++
++#ifndef MODULE
++ char *option = NULL;
++
++ if (fb_get_options("atafb", &option))
++ return -ENODEV;
++ atafb_setup(option);
++#endif
++ printk("atafb_init: start\n");
++
++ if (!MACH_IS_ATARI)
++ return -ENXIO;
++
++ do {
++#ifdef ATAFB_EXT
++ if (external_addr) {
++ printk("atafb_init: initializing external hw\n");
++ fbhw = &ext_switch;
++ atafb_ops.fb_setcolreg = &ext_setcolreg;
++ defmode = DEFMODE_EXT;
++ break;
++ }
++#endif
++#ifdef ATAFB_TT
++ if (ATARIHW_PRESENT(TT_SHIFTER)) {
++ printk("atafb_init: initializing TT hw\n");
++ fbhw = &tt_switch;
++ atafb_ops.fb_setcolreg = &tt_setcolreg;
++ defmode = DEFMODE_TT;
++ break;
++ }
+ #endif
+- else if (!strncmp(this_opt,"internal:",9))
+- atafb_setup_int(this_opt+9);
+ #ifdef ATAFB_FALCON
+- else if (!strncmp(this_opt, "eclock:", 7)) {
+- fext.f = simple_strtoul(this_opt+7, NULL, 10);
+- /* external pixelclock in kHz --> ps */
+- fext.t = 1000000000/fext.f;
+- fext.f *= 1000;
+- }
+- else if (!strncmp(this_opt, "monitorcap:", 11))
+- atafb_setup_mcap(this_opt+11);
+-#endif
+- else if (!strcmp(this_opt, "keep"))
+- DontCalcRes = 1;
+- else if (!strncmp(this_opt, "R", 1))
+- atafb_setup_user(this_opt+1);
+- }
+- return 0;
++ if (ATARIHW_PRESENT(VIDEL_SHIFTER)) {
++ printk("atafb_init: initializing Falcon hw\n");
++ fbhw = &falcon_switch;
++ atafb_ops.fb_setcolreg = &falcon_setcolreg;
++ request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO,
++ "framebuffer/modeswitch", falcon_vbl_switcher);
++ defmode = DEFMODE_F30;
++ break;
++ }
++#endif
++#ifdef ATAFB_STE
++ if (ATARIHW_PRESENT(STND_SHIFTER) ||
++ ATARIHW_PRESENT(EXTD_SHIFTER)) {
++ printk("atafb_init: initializing ST/E hw\n");
++ fbhw = &st_switch;
++ atafb_ops.fb_setcolreg = &stste_setcolreg;
++ defmode = DEFMODE_STE;
++ break;
++ }
++ fbhw = &st_switch;
++ atafb_ops.fb_setcolreg = &stste_setcolreg;
++ printk("Cannot determine video hardware; defaulting to ST(e)\n");
++#else /* ATAFB_STE */
++ /* no default driver included */
++ /* Nobody will ever see this message :-) */
++ panic("Cannot initialize video hardware");
++#endif
++ } while (0);
++
++ /* Multisync monitor capabilities */
++ /* Atari-TOS defaults if no boot option present */
++ if (fb_info.monspecs.hfmin == 0) {
++ fb_info.monspecs.hfmin = 31000;
++ fb_info.monspecs.hfmax = 32000;
++ fb_info.monspecs.vfmin = 58;
++ fb_info.monspecs.vfmax = 62;
++ }
++
++ detected_mode = fbhw->detect();
++ check_default_par(detected_mode);
++#ifdef ATAFB_EXT
++ if (!external_addr) {
++#endif /* ATAFB_EXT */
++ mem_req = default_mem_req + ovsc_offset + ovsc_addlen;
++ mem_req = PAGE_ALIGN(mem_req) + PAGE_SIZE;
++ screen_base = atari_stram_alloc(mem_req, "atafb");
++ if (!screen_base)
++ panic("Cannot allocate screen memory");
++ memset(screen_base, 0, mem_req);
++ pad = -(unsigned long)screen_base & (PAGE_SIZE - 1);
++ screen_base += pad;
++ real_screen_base = screen_base + ovsc_offset;
++ screen_len = (mem_req - pad - ovsc_offset) & PAGE_MASK;
++ st_ovsc_switch();
++ if (CPU_IS_040_OR_060) {
++ /* On a '040+, the cache mode of video RAM must be set to
++ * write-through also for internal video hardware! */
++ cache_push(virt_to_phys(screen_base), screen_len);
++ kernel_set_cachemode(screen_base, screen_len,
++ IOMAP_WRITETHROUGH);
++ }
++ printk("atafb: screen_base %p real_screen_base %p screen_len %d\n",
++ screen_base, real_screen_base, screen_len);
++#ifdef ATAFB_EXT
++ } else {
++ /* Map the video memory (physical address given) to somewhere
++ * in the kernel address space.
++ */
++ external_addr = ioremap_writethrough((unsigned long)external_addr,
++ external_len);
++ if (external_vgaiobase)
++ external_vgaiobase =
++ (unsigned long)ioremap(external_vgaiobase, 0x10000);
++ screen_base =
++ real_screen_base = external_addr;
++ screen_len = external_len & PAGE_MASK;
++ memset (screen_base, 0, external_len);
++ }
++#endif /* ATAFB_EXT */
++
++// strcpy(fb_info.mode->name, "Atari Builtin ");
++ fb_info.fbops = &atafb_ops;
++ // try to set default (detected; requested) var
++ do_fb_set_var(&atafb_predefined[default_par - 1], 1);
++ // reads hw state into current par, which may not be sane yet
++ ata_get_par(&current_par);
++ fb_info.par = &current_par;
++ // tries to read from HW which may not be initialized yet
++ // so set sane var first, then call atafb_set_par
++ atafb_get_var(&fb_info.var, &fb_info);
++ fb_info.flags = FBINFO_FLAG_DEFAULT;
++
++ if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, atafb_modedb,
++ NUM_TOTAL_MODES, &atafb_modedb[defmode],
++ fb_info.var.bits_per_pixel)) {
++ return -EINVAL;
++ }
++
++ atafb_set_disp(&fb_info);
++
++ fb_alloc_cmap(&(fb_info.cmap), 1 << fb_info.var.bits_per_pixel, 0);
++
++
++ printk("Determined %dx%d, depth %d\n",
++ fb_info.var.xres, fb_info.var.yres, fb_info.var.bits_per_pixel);
++ if ((fb_info.var.xres != fb_info.var.xres_virtual) ||
++ (fb_info.var.yres != fb_info.var.yres_virtual))
++ printk(" virtual %dx%d\n", fb_info.var.xres_virtual,
++ fb_info.var.yres_virtual);
++
++ if (register_framebuffer(&fb_info) < 0) {
++#ifdef ATAFB_EXT
++ if (external_addr) {
++ iounmap(external_addr);
++ external_addr = NULL;
++ }
++ if (external_vgaiobase) {
++ iounmap((void*)external_vgaiobase);
++ external_vgaiobase = 0;
++ }
++#endif
++ return -EINVAL;
++ }
++
++ // FIXME: mode needs setting!
++ //printk("fb%d: %s frame buffer device, using %dK of video memory\n",
++ // fb_info.node, fb_info.mode->name, screen_len>>10);
++ printk("fb%d: frame buffer device, using %dK of video memory\n",
++ fb_info.node, screen_len >> 10);
++
++ /* TODO: This driver cannot be unloaded yet */
++ return 0;
+ }
+
++module_init(atafb_init);
++
+ #ifdef MODULE
+ MODULE_LICENSE("GPL");
+
+-int init_module(void)
++int cleanup_module(void)
+ {
+- return atafb_init();
++ unregister_framebuffer(&fb_info);
++ return atafb_deinit();
+ }
+ #endif /* MODULE */
+--- /dev/null
++++ linux-m68k-2.6.21/drivers/video/atafb.h
+@@ -0,0 +1,36 @@
++#ifndef _VIDEO_ATAFB_H
++#define _VIDEO_ATAFB_H
++
++void atafb_mfb_copyarea(struct fb_info *info, u_long next_line, int sy, int sx, int dy,
++ int dx, int height, int width);
++void atafb_mfb_fillrect(struct fb_info *info, u_long next_line, u32 color,
++ int sy, int sx, int height, int width);
++void atafb_mfb_linefill(struct fb_info *info, u_long next_line,
++ int dy, int dx, u32 width,
++ const u8 *data, u32 bgcolor, u32 fgcolor);
++
++void atafb_iplan2p2_copyarea(struct fb_info *info, u_long next_line, int sy, int sx, int dy,
++ int dx, int height, int width);
++void atafb_iplan2p2_fillrect(struct fb_info *info, u_long next_line, u32 color,
++ int sy, int sx, int height, int width);
++void atafb_iplan2p2_linefill(struct fb_info *info, u_long next_line,
++ int dy, int dx, u32 width,
++ const u8 *data, u32 bgcolor, u32 fgcolor);
++
++void atafb_iplan2p4_copyarea(struct fb_info *info, u_long next_line, int sy, int sx, int dy,
++ int dx, int height, int width);
++void atafb_iplan2p4_fillrect(struct fb_info *info, u_long next_line, u32 color,
++ int sy, int sx, int height, int width);
++void atafb_iplan2p4_linefill(struct fb_info *info, u_long next_line,
++ int dy, int dx, u32 width,
++ const u8 *data, u32 bgcolor, u32 fgcolor);
++
++void atafb_iplan2p8_copyarea(struct fb_info *info, u_long next_line, int sy, int sx, int dy,
++ int dx, int height, int width);
++void atafb_iplan2p8_fillrect(struct fb_info *info, u_long next_line, u32 color,
++ int sy, int sx, int height, int width);
++void atafb_iplan2p8_linefill(struct fb_info *info, u_long next_line,
++ int dy, int dx, u32 width,
++ const u8 *data, u32 bgcolor, u32 fgcolor);
++
++#endif /* _VIDEO_ATAFB_H */
+--- /dev/null
++++ linux-m68k-2.6.21/drivers/video/atafb_iplan2p2.c
+@@ -0,0 +1,293 @@
++/*
++ * linux/drivers/video/iplan2p2.c -- Low level frame buffer operations for
++ * interleaved bitplanes à la Atari (2
++ * planes, 2 bytes interleave)
++ *
++ * Created 5 Apr 1997 by 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/module.h>
++#include <linux/string.h>
++#include <linux/fb.h>
++
++#include <asm/setup.h>
++
++#include "atafb.h"
++
++#define BPL 2
++#include "atafb_utils.h"
++
++void atafb_iplan2p2_copyarea(struct fb_info *info, u_long next_line,
++ int sy, int sx, int dy, int dx,
++ int height, int width)
++{
++ /* bmove() has to distinguish two major cases: If both, source and
++ * destination, start at even addresses or both are at odd
++ * addresses, just the first odd and last even column (if present)
++ * require special treatment (memmove_col()). The rest between
++ * then can be copied by normal operations, because all adjacent
++ * bytes are affected and are to be stored in the same order.
++ * The pathological case is when the move should go from an odd
++ * address to an even or vice versa. Since the bytes in the plane
++ * words must be assembled in new order, it seems wisest to make
++ * all movements by memmove_col().
++ */
++
++ u8 *src, *dst;
++ u32 *s, *d;
++ int w, l , i, j;
++ u_int colsize;
++ u_int upwards = (dy < sy) || (dy == sy && dx < sx);
++
++ colsize = height;
++ if (!((sx ^ dx) & 15)) {
++ /* odd->odd or even->even */
++
++ if (upwards) {
++ src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL);
++ dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL);
++ if (sx & 15) {
++ memmove32_col(dst, src, 0xff00ff, height, next_line - BPL * 2);
++ src += BPL * 2;
++ dst += BPL * 2;
++ width -= 8;
++ }
++ w = width >> 4;
++ if (w) {
++ s = (u32 *)src;
++ d = (u32 *)dst;
++ w *= BPL / 2;
++ l = next_line - w * 4;
++ for (j = height; j > 0; j--) {
++ for (i = w; i > 0; i--)
++ *d++ = *s++;
++ s = (u32 *)((u8 *)s + l);
++ d = (u32 *)((u8 *)d + l);
++ }
++ }
++ if (width & 15)
++ memmove32_col(dst + width / (8 / BPL), src + width / (8 / BPL),
++ 0xff00ff00, height, next_line - BPL * 2);
++ } else {
++ src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL);
++ dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL);
++
++ if ((sx + width) & 15) {
++ src -= BPL * 2;
++ dst -= BPL * 2;
++ memmove32_col(dst, src, 0xff00ff00, colsize, -next_line - BPL * 2);
++ width -= 8;
++ }
++ w = width >> 4;
++ if (w) {
++ s = (u32 *)src;
++ d = (u32 *)dst;
++ w *= BPL / 2;
++ l = next_line - w * 4;
++ for (j = height; j > 0; j--) {
++ for (i = w; i > 0; i--)
++ *--d = *--s;
++ s = (u32 *)((u8 *)s - l);
++ d = (u32 *)((u8 *)d - l);
++ }
++ }
++ if (sx & 15)
++ memmove32_col(dst - (width - 16) / (8 / BPL),
++ src - (width - 16) / (8 / BPL),
++ 0xff00ff, colsize, -next_line - BPL * 2);
++ }
++ } else {
++ /* odd->even or even->odd */
++ if (upwards) {
++ u32 *src32, *dst32;
++ u32 pval[4], v, v1, mask;
++ int i, j, w, f;
++
++ src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL);
++ dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL);
++
++ mask = 0xff00ff00;
++ f = 0;
++ w = width;
++ if (sx & 15) {
++ f = 1;
++ w += 8;
++ }
++ if ((sx + width) & 15)
++ f |= 2;
++ w >>= 4;
++ for (i = height; i; i--) {
++ src32 = (u32 *)src;
++ dst32 = (u32 *)dst;
++
++ if (f & 1) {
++ pval[0] = (*src32++ << 8) & mask;
++ } else {
++ pval[0] = dst32[0] & mask;
++ }
++
++ for (j = w; j > 0; j--) {
++ v = *src32++;
++ v1 = v & mask;
++ *dst32++ = pval[0] | (v1 >> 8);
++ pval[0] = (v ^ v1) << 8;
++ }
++
++ if (f & 2) {
++ dst32[0] = (dst32[0] & mask) | pval[0];
++ }
++
++ src += next_line;
++ dst += next_line;
++ }
++ } else {
++ u32 *src32, *dst32;
++ u32 pval[4], v, v1, mask;
++ int i, j, w, f;
++
++ src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL);
++ dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL);
++
++ mask = 0xff00ff;
++ f = 0;
++ w = width;
++ if ((dx + width) & 15)
++ f = 1;
++ if (sx & 15) {
++ f |= 2;
++ w += 8;
++ }
++ w >>= 4;
++ for (i = height; i; i--) {
++ src32 = (u32 *)src;
++ dst32 = (u32 *)dst;
++
++ if (f & 1) {
++ pval[0] = dst32[-1] & mask;
++ } else {
++ pval[0] = (*--src32 >> 8) & mask;
++ }
++
++ for (j = w; j > 0; j--) {
++ v = *--src32;
++ v1 = v & mask;
++ *--dst32 = pval[0] | (v1 << 8);
++ pval[0] = (v ^ v1) >> 8;
++ }
++
++ if (!(f & 2)) {
++ dst32[-1] = (dst32[-1] & mask) | pval[0];
++ }
++
++ src -= next_line;
++ dst -= next_line;
++ }
++ }
++ }
++}
++
++void atafb_iplan2p2_fillrect(struct fb_info *info, u_long next_line, u32 color,
++ int sy, int sx, int height, int width)
++{
++ u32 *dest;
++ int rows, i;
++ u32 cval[4];
++
++ dest = (u32 *)(info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL));
++ if (sx & 15) {
++ u8 *dest8 = (u8 *)dest + 1;
++
++ expand8_col2mask(color, cval);
++
++ for (i = height; i; i--) {
++ fill8_col(dest8, cval);
++ dest8 += next_line;
++ }
++ dest += BPL / 2;
++ width -= 8;
++ }
++
++ expand16_col2mask(color, cval);
++ rows = width >> 4;
++ if (rows) {
++ u32 *d = dest;
++ u32 off = next_line - rows * BPL * 2;
++ for (i = height; i; i--) {
++ d = fill16_col(d, rows, cval);
++ d = (u32 *)((long)d + off);
++ }
++ dest += rows * BPL / 2;
++ width &= 15;
++ }
++
++ if (width) {
++ u8 *dest8 = (u8 *)dest;
++
++ expand8_col2mask(color, cval);
++
++ for (i = height; i; i--) {
++ fill8_col(dest8, cval);
++ dest8 += next_line;
++ }
++ }
++}
++
++void atafb_iplan2p2_linefill(struct fb_info *info, u_long next_line,
++ int dy, int dx, u32 width,
++ const u8 *data, u32 bgcolor, u32 fgcolor)
++{
++ u32 *dest;
++ const u16 *data16;
++ int rows;
++ u32 fgm[4], bgm[4], m;
++
++ dest = (u32 *)(info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL));
++ if (dx & 15) {
++ fill8_2col((u8 *)dest + 1, fgcolor, bgcolor, *data++);
++ dest += BPL / 2;
++ width -= 8;
++ }
++
++ if (width >= 16) {
++ data16 = (const u16 *)data;
++ expand16_2col2mask(fgcolor, bgcolor, fgm, bgm);
++
++ for (rows = width / 16; rows; rows--) {
++ u16 d = *data16++;
++ m = d | ((u32)d << 16);
++ *dest++ = (m & fgm[0]) ^ bgm[0];
++ }
++
++ data = (const u8 *)data16;
++ width &= 15;
++ }
++
++ if (width)
++ fill8_2col((u8 *)dest, fgcolor, bgcolor, *data);
++}
++
++#ifdef MODULE
++MODULE_LICENSE("GPL");
++
++int init_module(void)
++{
++ return 0;
++}
++
++void cleanup_module(void)
++{
++}
++#endif /* MODULE */
++
++
++ /*
++ * Visible symbols for modules
++ */
++
++EXPORT_SYMBOL(atafb_iplan2p2_copyarea);
++EXPORT_SYMBOL(atafb_iplan2p2_fillrect);
++EXPORT_SYMBOL(atafb_iplan2p2_linefill);
+--- /dev/null
++++ linux-m68k-2.6.21/drivers/video/atafb_iplan2p4.c
+@@ -0,0 +1,308 @@
++/*
++ * linux/drivers/video/iplan2p4.c -- Low level frame buffer operations for
++ * interleaved bitplanes à la Atari (4
++ * planes, 2 bytes interleave)
++ *
++ * Created 5 Apr 1997 by 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/module.h>
++#include <linux/string.h>
++#include <linux/fb.h>
++
++#include <asm/setup.h>
++
++#include "atafb.h"
++
++#define BPL 4
++#include "atafb_utils.h"
++
++void atafb_iplan2p4_copyarea(struct fb_info *info, u_long next_line,
++ int sy, int sx, int dy, int dx,
++ int height, int width)
++{
++ /* bmove() has to distinguish two major cases: If both, source and
++ * destination, start at even addresses or both are at odd
++ * addresses, just the first odd and last even column (if present)
++ * require special treatment (memmove_col()). The rest between
++ * then can be copied by normal operations, because all adjacent
++ * bytes are affected and are to be stored in the same order.
++ * The pathological case is when the move should go from an odd
++ * address to an even or vice versa. Since the bytes in the plane
++ * words must be assembled in new order, it seems wisest to make
++ * all movements by memmove_col().
++ */
++
++ u8 *src, *dst;
++ u32 *s, *d;
++ int w, l , i, j;
++ u_int colsize;
++ u_int upwards = (dy < sy) || (dy == sy && dx < sx);
++
++ colsize = height;
++ if (!((sx ^ dx) & 15)) {
++ /* odd->odd or even->even */
++
++ if (upwards) {
++ src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL);
++ dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL);
++ if (sx & 15) {
++ memmove32_col(dst, src, 0xff00ff, height, next_line - BPL * 2);
++ src += BPL * 2;
++ dst += BPL * 2;
++ width -= 8;
++ }
++ w = width >> 4;
++ if (w) {
++ s = (u32 *)src;
++ d = (u32 *)dst;
++ w *= BPL / 2;
++ l = next_line - w * 4;
++ for (j = height; j > 0; j--) {
++ for (i = w; i > 0; i--)
++ *d++ = *s++;
++ s = (u32 *)((u8 *)s + l);
++ d = (u32 *)((u8 *)d + l);
++ }
++ }
++ if (width & 15)
++ memmove32_col(dst + width / (8 / BPL), src + width / (8 / BPL),
++ 0xff00ff00, height, next_line - BPL * 2);
++ } else {
++ src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL);
++ dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL);
++
++ if ((sx + width) & 15) {
++ src -= BPL * 2;
++ dst -= BPL * 2;
++ memmove32_col(dst, src, 0xff00ff00, colsize, -next_line - BPL * 2);
++ width -= 8;
++ }
++ w = width >> 4;
++ if (w) {
++ s = (u32 *)src;
++ d = (u32 *)dst;
++ w *= BPL / 2;
++ l = next_line - w * 4;
++ for (j = height; j > 0; j--) {
++ for (i = w; i > 0; i--)
++ *--d = *--s;
++ s = (u32 *)((u8 *)s - l);
++ d = (u32 *)((u8 *)d - l);
++ }
++ }
++ if (sx & 15)
++ memmove32_col(dst - (width - 16) / (8 / BPL),
++ src - (width - 16) / (8 / BPL),
++ 0xff00ff, colsize, -next_line - BPL * 2);
++ }
++ } else {
++ /* odd->even or even->odd */
++ if (upwards) {
++ u32 *src32, *dst32;
++ u32 pval[4], v, v1, mask;
++ int i, j, w, f;
++
++ src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL);
++ dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL);
++
++ mask = 0xff00ff00;
++ f = 0;
++ w = width;
++ if (sx & 15) {
++ f = 1;
++ w += 8;
++ }
++ if ((sx + width) & 15)
++ f |= 2;
++ w >>= 4;
++ for (i = height; i; i--) {
++ src32 = (u32 *)src;
++ dst32 = (u32 *)dst;
++
++ if (f & 1) {
++ pval[0] = (*src32++ << 8) & mask;
++ pval[1] = (*src32++ << 8) & mask;
++ } else {
++ pval[0] = dst32[0] & mask;
++ pval[1] = dst32[1] & mask;
++ }
++
++ for (j = w; j > 0; j--) {
++ v = *src32++;
++ v1 = v & mask;
++ *dst32++ = pval[0] | (v1 >> 8);
++ pval[0] = (v ^ v1) << 8;
++ v = *src32++;
++ v1 = v & mask;
++ *dst32++ = pval[1] | (v1 >> 8);
++ pval[1] = (v ^ v1) << 8;
++ }
++
++ if (f & 2) {
++ dst32[0] = (dst32[0] & mask) | pval[0];
++ dst32[1] = (dst32[1] & mask) | pval[1];
++ }
++
++ src += next_line;
++ dst += next_line;
++ }
++ } else {
++ u32 *src32, *dst32;
++ u32 pval[4], v, v1, mask;
++ int i, j, w, f;
++
++ src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL);
++ dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL);
++
++ mask = 0xff00ff;
++ f = 0;
++ w = width;
++ if ((dx + width) & 15)
++ f = 1;
++ if (sx & 15) {
++ f |= 2;
++ w += 8;
++ }
++ w >>= 4;
++ for (i = height; i; i--) {
++ src32 = (u32 *)src;
++ dst32 = (u32 *)dst;
++
++ if (f & 1) {
++ pval[0] = dst32[-1] & mask;
++ pval[1] = dst32[-2] & mask;
++ } else {
++ pval[0] = (*--src32 >> 8) & mask;
++ pval[1] = (*--src32 >> 8) & mask;
++ }
++
++ for (j = w; j > 0; j--) {
++ v = *--src32;
++ v1 = v & mask;
++ *--dst32 = pval[0] | (v1 << 8);
++ pval[0] = (v ^ v1) >> 8;
++ v = *--src32;
++ v1 = v & mask;
++ *--dst32 = pval[1] | (v1 << 8);
++ pval[1] = (v ^ v1) >> 8;
++ }
++
++ if (!(f & 2)) {
++ dst32[-1] = (dst32[-1] & mask) | pval[0];
++ dst32[-2] = (dst32[-2] & mask) | pval[1];
++ }
++
++ src -= next_line;
++ dst -= next_line;
++ }
++ }
++ }
++}
++
++void atafb_iplan2p4_fillrect(struct fb_info *info, u_long next_line, u32 color,
++ int sy, int sx, int height, int width)
++{
++ u32 *dest;
++ int rows, i;
++ u32 cval[4];
++
++ dest = (u32 *)(info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL));
++ if (sx & 15) {
++ u8 *dest8 = (u8 *)dest + 1;
++
++ expand8_col2mask(color, cval);
++
++ for (i = height; i; i--) {
++ fill8_col(dest8, cval);
++ dest8 += next_line;
++ }
++ dest += BPL / 2;
++ width -= 8;
++ }
++
++ expand16_col2mask(color, cval);
++ rows = width >> 4;
++ if (rows) {
++ u32 *d = dest;
++ u32 off = next_line - rows * BPL * 2;
++ for (i = height; i; i--) {
++ d = fill16_col(d, rows, cval);
++ d = (u32 *)((long)d + off);
++ }
++ dest += rows * BPL / 2;
++ width &= 15;
++ }
++
++ if (width) {
++ u8 *dest8 = (u8 *)dest;
++
++ expand8_col2mask(color, cval);
++
++ for (i = height; i; i--) {
++ fill8_col(dest8, cval);
++ dest8 += next_line;
++ }
++ }
++}
++
++void atafb_iplan2p4_linefill(struct fb_info *info, u_long next_line,
++ int dy, int dx, u32 width,
++ const u8 *data, u32 bgcolor, u32 fgcolor)
++{
++ u32 *dest;
++ const u16 *data16;
++ int rows;
++ u32 fgm[4], bgm[4], m;
++
++ dest = (u32 *)(info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL));
++ if (dx & 15) {
++ fill8_2col((u8 *)dest + 1, fgcolor, bgcolor, *data++);
++ dest += BPL / 2;
++ width -= 8;
++ }
++
++ if (width >= 16) {
++ data16 = (const u16 *)data;
++ expand16_2col2mask(fgcolor, bgcolor, fgm, bgm);
++
++ for (rows = width / 16; rows; rows--) {
++ u16 d = *data16++;
++ m = d | ((u32)d << 16);
++ *dest++ = (m & fgm[0]) ^ bgm[0];
++ *dest++ = (m & fgm[1]) ^ bgm[1];
++ }
++
++ data = (const u8 *)data16;
++ width &= 15;
++ }
++
++ if (width)
++ fill8_2col((u8 *)dest, fgcolor, bgcolor, *data);
++}
++
++#ifdef MODULE
++MODULE_LICENSE("GPL");
++
++int init_module(void)
++{
++ return 0;
++}
++
++void cleanup_module(void)
++{
++}
++#endif /* MODULE */
++
++
++ /*
++ * Visible symbols for modules
++ */
++
++EXPORT_SYMBOL(atafb_iplan2p4_copyarea);
++EXPORT_SYMBOL(atafb_iplan2p4_fillrect);
++EXPORT_SYMBOL(atafb_iplan2p4_linefill);
+--- /dev/null
++++ linux-m68k-2.6.21/drivers/video/atafb_iplan2p8.c
+@@ -0,0 +1,345 @@
++/*
++ * linux/drivers/video/iplan2p8.c -- Low level frame buffer operations for
++ * interleaved bitplanes à la Atari (8
++ * planes, 2 bytes interleave)
++ *
++ * Created 5 Apr 1997 by 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/module.h>
++#include <linux/string.h>
++#include <linux/fb.h>
++
++#include <asm/setup.h>
++
++#include "atafb.h"
++
++#define BPL 8
++#include "atafb_utils.h"
++
++
++/* Copies a 8 plane column from 's', height 'h', to 'd'. */
++
++/* This expands a 8 bit color into two longs for two movepl (8 plane)
++ * operations.
++ */
++
++void atafb_iplan2p8_copyarea(struct fb_info *info, u_long next_line,
++ int sy, int sx, int dy, int dx,
++ int height, int width)
++{
++ /* bmove() has to distinguish two major cases: If both, source and
++ * destination, start at even addresses or both are at odd
++ * addresses, just the first odd and last even column (if present)
++ * require special treatment (memmove_col()). The rest between
++ * then can be copied by normal operations, because all adjacent
++ * bytes are affected and are to be stored in the same order.
++ * The pathological case is when the move should go from an odd
++ * address to an even or vice versa. Since the bytes in the plane
++ * words must be assembled in new order, it seems wisest to make
++ * all movements by memmove_col().
++ */
++
++ u8 *src, *dst;
++ u32 *s, *d;
++ int w, l , i, j;
++ u_int colsize;
++ u_int upwards = (dy < sy) || (dy == sy && dx < sx);
++
++ colsize = height;
++ if (!((sx ^ dx) & 15)) {
++ /* odd->odd or even->even */
++
++ if (upwards) {
++ src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL);
++ dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL);
++ if (sx & 15) {
++ memmove32_col(dst, src, 0xff00ff, height, next_line - BPL * 2);
++ src += BPL * 2;
++ dst += BPL * 2;
++ width -= 8;
++ }
++ w = width >> 4;
++ if (w) {
++ s = (u32 *)src;
++ d = (u32 *)dst;
++ w *= BPL / 2;
++ l = next_line - w * 4;
++ for (j = height; j > 0; j--) {
++ for (i = w; i > 0; i--)
++ *d++ = *s++;
++ s = (u32 *)((u8 *)s + l);
++ d = (u32 *)((u8 *)d + l);
++ }
++ }
++ if (width & 15)
++ memmove32_col(dst + width / (8 / BPL), src + width / (8 / BPL),
++ 0xff00ff00, height, next_line - BPL * 2);
++ } else {
++ src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL);
++ dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL);
++
++ if ((sx + width) & 15) {
++ src -= BPL * 2;
++ dst -= BPL * 2;
++ memmove32_col(dst, src, 0xff00ff00, colsize, -next_line - BPL * 2);
++ width -= 8;
++ }
++ w = width >> 4;
++ if (w) {
++ s = (u32 *)src;
++ d = (u32 *)dst;
++ w *= BPL / 2;
++ l = next_line - w * 4;
++ for (j = height; j > 0; j--) {
++ for (i = w; i > 0; i--)
++ *--d = *--s;
++ s = (u32 *)((u8 *)s - l);
++ d = (u32 *)((u8 *)d - l);
++ }
++ }
++ if (sx & 15)
++ memmove32_col(dst - (width - 16) / (8 / BPL),
++ src - (width - 16) / (8 / BPL),
++ 0xff00ff, colsize, -next_line - BPL * 2);
++ }
++ } else {
++ /* odd->even or even->odd */
++ if (upwards) {
++ u32 *src32, *dst32;
++ u32 pval[4], v, v1, mask;
++ int i, j, w, f;
++
++ src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL);
++ dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL);
++
++ mask = 0xff00ff00;
++ f = 0;
++ w = width;
++ if (sx & 15) {
++ f = 1;
++ w += 8;
++ }
++ if ((sx + width) & 15)
++ f |= 2;
++ w >>= 4;
++ for (i = height; i; i--) {
++ src32 = (u32 *)src;
++ dst32 = (u32 *)dst;
++
++ if (f & 1) {
++ pval[0] = (*src32++ << 8) & mask;
++ pval[1] = (*src32++ << 8) & mask;
++ pval[2] = (*src32++ << 8) & mask;
++ pval[3] = (*src32++ << 8) & mask;
++ } else {
++ pval[0] = dst32[0] & mask;
++ pval[1] = dst32[1] & mask;
++ pval[2] = dst32[2] & mask;
++ pval[3] = dst32[3] & mask;
++ }
++
++ for (j = w; j > 0; j--) {
++ v = *src32++;
++ v1 = v & mask;
++ *dst32++ = pval[0] | (v1 >> 8);
++ pval[0] = (v ^ v1) << 8;
++ v = *src32++;
++ v1 = v & mask;
++ *dst32++ = pval[1] | (v1 >> 8);
++ pval[1] = (v ^ v1) << 8;
++ v = *src32++;
++ v1 = v & mask;
++ *dst32++ = pval[2] | (v1 >> 8);
++ pval[2] = (v ^ v1) << 8;
++ v = *src32++;
++ v1 = v & mask;
++ *dst32++ = pval[3] | (v1 >> 8);
++ pval[3] = (v ^ v1) << 8;
++ }
++
++ if (f & 2) {
++ dst32[0] = (dst32[0] & mask) | pval[0];
++ dst32[1] = (dst32[1] & mask) | pval[1];
++ dst32[2] = (dst32[2] & mask) | pval[2];
++ dst32[3] = (dst32[3] & mask) | pval[3];
++ }
++
++ src += next_line;
++ dst += next_line;
++ }
++ } else {
++ u32 *src32, *dst32;
++ u32 pval[4], v, v1, mask;
++ int i, j, w, f;
++
++ src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL);
++ dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL);
++
++ mask = 0xff00ff;
++ f = 0;
++ w = width;
++ if ((dx + width) & 15)
++ f = 1;
++ if (sx & 15) {
++ f |= 2;
++ w += 8;
++ }
++ w >>= 4;
++ for (i = height; i; i--) {
++ src32 = (u32 *)src;
++ dst32 = (u32 *)dst;
++
++ if (f & 1) {
++ pval[0] = dst32[-1] & mask;
++ pval[1] = dst32[-2] & mask;
++ pval[2] = dst32[-3] & mask;
++ pval[3] = dst32[-4] & mask;
++ } else {
++ pval[0] = (*--src32 >> 8) & mask;
++ pval[1] = (*--src32 >> 8) & mask;
++ pval[2] = (*--src32 >> 8) & mask;
++ pval[3] = (*--src32 >> 8) & mask;
++ }
++
++ for (j = w; j > 0; j--) {
++ v = *--src32;
++ v1 = v & mask;
++ *--dst32 = pval[0] | (v1 << 8);
++ pval[0] = (v ^ v1) >> 8;
++ v = *--src32;
++ v1 = v & mask;
++ *--dst32 = pval[1] | (v1 << 8);
++ pval[1] = (v ^ v1) >> 8;
++ v = *--src32;
++ v1 = v & mask;
++ *--dst32 = pval[2] | (v1 << 8);
++ pval[2] = (v ^ v1) >> 8;
++ v = *--src32;
++ v1 = v & mask;
++ *--dst32 = pval[3] | (v1 << 8);
++ pval[3] = (v ^ v1) >> 8;
++ }
++
++ if (!(f & 2)) {
++ dst32[-1] = (dst32[-1] & mask) | pval[0];
++ dst32[-2] = (dst32[-2] & mask) | pval[1];
++ dst32[-3] = (dst32[-3] & mask) | pval[2];
++ dst32[-4] = (dst32[-4] & mask) | pval[3];
++ }
++
++ src -= next_line;
++ dst -= next_line;
++ }
++ }
++ }
++}
++
++void atafb_iplan2p8_fillrect(struct fb_info *info, u_long next_line, u32 color,
++ int sy, int sx, int height, int width)
++{
++ u32 *dest;
++ int rows, i;
++ u32 cval[4];
++
++ dest = (u32 *)(info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL));
++ if (sx & 15) {
++ u8 *dest8 = (u8 *)dest + 1;
++
++ expand8_col2mask(color, cval);
++
++ for (i = height; i; i--) {
++ fill8_col(dest8, cval);
++ dest8 += next_line;
++ }
++ dest += BPL / 2;
++ width -= 8;
++ }
++
++ expand16_col2mask(color, cval);
++ rows = width >> 4;
++ if (rows) {
++ u32 *d = dest;
++ u32 off = next_line - rows * BPL * 2;
++ for (i = height; i; i--) {
++ d = fill16_col(d, rows, cval);
++ d = (u32 *)((long)d + off);
++ }
++ dest += rows * BPL / 2;
++ width &= 15;
++ }
++
++ if (width) {
++ u8 *dest8 = (u8 *)dest;
++
++ expand8_col2mask(color, cval);
++
++ for (i = height; i; i--) {
++ fill8_col(dest8, cval);
++ dest8 += next_line;
++ }
++ }
++}
++
++void atafb_iplan2p8_linefill(struct fb_info *info, u_long next_line,
++ int dy, int dx, u32 width,
++ const u8 *data, u32 bgcolor, u32 fgcolor)
++{
++ u32 *dest;
++ const u16 *data16;
++ int rows;
++ u32 fgm[4], bgm[4], m;
++
++ dest = (u32 *)(info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL));
++ if (dx & 15) {
++ fill8_2col((u8 *)dest + 1, fgcolor, bgcolor, *data++);
++ dest += BPL / 2;
++ width -= 8;
++ }
++
++ if (width >= 16) {
++ data16 = (const u16 *)data;
++ expand16_2col2mask(fgcolor, bgcolor, fgm, bgm);
++
++ for (rows = width / 16; rows; rows--) {
++ u16 d = *data16++;
++ m = d | ((u32)d << 16);
++ *dest++ = (m & fgm[0]) ^ bgm[0];
++ *dest++ = (m & fgm[1]) ^ bgm[1];
++ *dest++ = (m & fgm[2]) ^ bgm[2];
++ *dest++ = (m & fgm[3]) ^ bgm[3];
++ }
++
++ data = (const u8 *)data16;
++ width &= 15;
++ }
++
++ if (width)
++ fill8_2col((u8 *)dest, fgcolor, bgcolor, *data);
++}
++
++#ifdef MODULE
++MODULE_LICENSE("GPL");
++
++int init_module(void)
++{
++ return 0;
++}
++
++void cleanup_module(void)
++{
++}
++#endif /* MODULE */
++
++
++ /*
++ * Visible symbols for modules
++ */
++
++EXPORT_SYMBOL(atafb_iplan2p8_copyarea);
++EXPORT_SYMBOL(atafb_iplan2p8_fillrect);
++EXPORT_SYMBOL(atafb_iplan2p8_linefill);
+--- /dev/null
++++ linux-m68k-2.6.21/drivers/video/atafb_mfb.c
+@@ -0,0 +1,112 @@
++/*
++ * linux/drivers/video/mfb.c -- Low level frame buffer operations for
++ * monochrome
++ *
++ * Created 5 Apr 1997 by 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/module.h>
++#include <linux/string.h>
++#include <linux/fb.h>
++
++#include "atafb.h"
++#include "atafb_utils.h"
++
++
++ /*
++ * Monochrome
++ */
++
++void atafb_mfb_copyarea(struct fb_info *info, u_long next_line,
++ int sy, int sx, int dy, int dx,
++ int height, int width)
++{
++ u8 *src, *dest;
++ u_int rows;
++
++ if (sx == 0 && dx == 0 && width == next_line) {
++ src = (u8 *)info->screen_base + sy * (width >> 3);
++ dest = (u8 *)info->screen_base + dy * (width >> 3);
++ fb_memmove(dest, src, height * (width >> 3));
++ } else if (dy <= sy) {
++ src = (u8 *)info->screen_base + sy * next_line + (sx >> 3);
++ dest = (u8 *)info->screen_base + dy * next_line + (dx >> 3);
++ for (rows = height; rows--;) {
++ fb_memmove(dest, src, width >> 3);
++ src += next_line;
++ dest += next_line;
++ }
++ } else {
++ src = (u8 *)info->screen_base + (sy + height - 1) * next_line + (sx >> 3);
++ dest = (u8 *)info->screen_base + (dy + height - 1) * next_line + (dx >> 3);
++ for (rows = height; rows--;) {
++ fb_memmove(dest, src, width >> 3);
++ src -= next_line;
++ dest -= next_line;
++ }
++ }
++}
++
++void atafb_mfb_fillrect(struct fb_info *info, u_long next_line, u32 color,
++ int sy, int sx, int height, int width)
++{
++ u8 *dest;
++ u_int rows;
++
++ dest = (u8 *)info->screen_base + sy * next_line + (sx >> 3);
++
++ if (sx == 0 && width == next_line) {
++ if (color)
++ fb_memset255(dest, height * (width >> 3));
++ else
++ fb_memclear(dest, height * (width >> 3));
++ } else {
++ for (rows = height; rows--; dest += next_line) {
++ if (color)
++ fb_memset255(dest, width >> 3);
++ else
++ fb_memclear_small(dest, width >> 3);
++ }
++ }
++}
++
++void atafb_mfb_linefill(struct fb_info *info, u_long next_line,
++ int dy, int dx, u32 width,
++ const u8 *data, u32 bgcolor, u32 fgcolor)
++{
++ u8 *dest;
++ u_int rows;
++
++ dest = (u8 *)info->screen_base + dy * next_line + (dx >> 3);
++
++ for (rows = width / 8; rows--; /* check margins */ ) {
++ // use fast_memmove or fb_memmove
++ *dest++ = *data++;
++ }
++}
++
++#ifdef MODULE
++MODULE_LICENSE("GPL");
++
++int init_module(void)
++{
++ return 0;
++}
++
++void cleanup_module(void)
++{
++}
++#endif /* MODULE */
++
++
++ /*
++ * Visible symbols for modules
++ */
++
++EXPORT_SYMBOL(atafb_mfb_copyarea);
++EXPORT_SYMBOL(atafb_mfb_fillrect);
++EXPORT_SYMBOL(atafb_mfb_linefill);
+--- /dev/null
++++ linux-m68k-2.6.21/drivers/video/atafb_utils.h
+@@ -0,0 +1,400 @@
++#ifndef _VIDEO_ATAFB_UTILS_H
++#define _VIDEO_ATAFB_UTILS_H
++
++/* ================================================================= */
++/* Utility Assembler Functions */
++/* ================================================================= */
++
++/* ====================================================================== */
++
++/* Those of a delicate disposition might like to skip the next couple of
++ * pages.
++ *
++ * These functions are drop in replacements for memmove and
++ * memset(_, 0, _). However their five instances add at least a kilobyte
++ * to the object file. You have been warned.
++ *
++ * Not a great fan of assembler for the sake of it, but I think
++ * that these routines are at least 10 times faster than their C
++ * equivalents for large blits, and that's important to the lowest level of
++ * a graphics driver. Question is whether some scheme with the blitter
++ * would be faster. I suspect not for simple text system - not much
++ * asynchrony.
++ *
++ * Code is very simple, just gruesome expansion. Basic strategy is to
++ * increase data moved/cleared at each step to 16 bytes to reduce
++ * instruction per data move overhead. movem might be faster still
++ * For more than 15 bytes, we try to align the write direction on a
++ * longword boundary to get maximum speed. This is even more gruesome.
++ * Unaligned read/write used requires 68020+ - think this is a problem?
++ *
++ * Sorry!
++ */
++
++
++/* ++roman: I've optimized Robert's original versions in some minor
++ * aspects, e.g. moveq instead of movel, let gcc choose the registers,
++ * use movem in some places...
++ * For other modes than 1 plane, lots of more such assembler functions
++ * were needed (e.g. the ones using movep or expanding color values).
++ */
++
++/* ++andreas: more optimizations:
++ subl #65536,d0 replaced by clrw d0; subql #1,d0 for dbcc
++ addal is faster than addaw
++ movep is rather expensive compared to ordinary move's
++ some functions rewritten in C for clarity, no speed loss */
++
++static inline void *fb_memclear_small(void *s, size_t count)
++{
++ if (!count)
++ return 0;
++
++ asm volatile ("\n"
++ " lsr.l #1,%1 ; jcc 1f ; move.b %2,-(%0)\n"
++ "1: lsr.l #1,%1 ; jcc 1f ; move.w %2,-(%0)\n"
++ "1: lsr.l #1,%1 ; jcc 1f ; move.l %2,-(%0)\n"
++ "1: lsr.l #1,%1 ; jcc 1f ; move.l %2,-(%0) ; move.l %2,-(%0)\n"
++ "1:"
++ : "=a" (s), "=d" (count)
++ : "d" (0), "0" ((char *)s + count), "1" (count));
++ asm volatile ("\n"
++ " subq.l #1,%1\n"
++ " jcs 3f\n"
++ " move.l %2,%%d4; move.l %2,%%d5; move.l %2,%%d6\n"
++ "2: movem.l %2/%%d4/%%d5/%%d6,-(%0)\n"
++ " dbra %1,2b\n"
++ "3:"
++ : "=a" (s), "=d" (count)
++ : "d" (0), "0" (s), "1" (count)
++ : "d4", "d5", "d6"
++ );
++
++ return 0;
++}
++
++
++static inline void *fb_memclear(void *s, size_t count)
++{
++ if (!count)
++ return 0;
++
++ if (count < 16) {
++ asm volatile ("\n"
++ " lsr.l #1,%1 ; jcc 1f ; clr.b (%0)+\n"
++ "1: lsr.l #1,%1 ; jcc 1f ; clr.w (%0)+\n"
++ "1: lsr.l #1,%1 ; jcc 1f ; clr.l (%0)+\n"
++ "1: lsr.l #1,%1 ; jcc 1f ; clr.l (%0)+ ; clr.l (%0)+\n"
++ "1:"
++ : "=a" (s), "=d" (count)
++ : "0" (s), "1" (count));
++ } else {
++ long tmp;
++ asm volatile ("\n"
++ " move.l %1,%2\n"
++ " lsr.l #1,%2 ; jcc 1f ; clr.b (%0)+ ; subq.w #1,%1\n"
++ " lsr.l #1,%2 ; jcs 2f\n" /* %0 increased=>bit 2 switched*/
++ " clr.w (%0)+ ; subq.w #2,%1 ; jra 2f\n"
++ "1: lsr.l #1,%2 ; jcc 2f\n"
++ " clr.w (%0)+ ; subq.w #2,%1\n"
++ "2: move.w %1,%2; lsr.l #2,%1 ; jeq 6f\n"
++ " lsr.l #1,%1 ; jcc 3f ; clr.l (%0)+\n"
++ "3: lsr.l #1,%1 ; jcc 4f ; clr.l (%0)+ ; clr.l (%0)+\n"
++ "4: subq.l #1,%1 ; jcs 6f\n"
++ "5: clr.l (%0)+; clr.l (%0)+ ; clr.l (%0)+ ; clr.l (%0)+\n"
++ " dbra %1,5b ; clr.w %1; subq.l #1,%1; jcc 5b\n"
++ "6: move.w %2,%1; btst #1,%1 ; jeq 7f ; clr.w (%0)+\n"
++ "7: btst #0,%1 ; jeq 8f ; clr.b (%0)+\n"
++ "8:"
++ : "=a" (s), "=d" (count), "=d" (tmp)
++ : "0" (s), "1" (count));
++ }
++
++ return 0;
++}
++
++
++static inline void *fb_memset255(void *s, size_t count)
++{
++ if (!count)
++ return 0;
++
++ asm volatile ("\n"
++ " lsr.l #1,%1 ; jcc 1f ; move.b %2,-(%0)\n"
++ "1: lsr.l #1,%1 ; jcc 1f ; move.w %2,-(%0)\n"
++ "1: lsr.l #1,%1 ; jcc 1f ; move.l %2,-(%0)\n"
++ "1: lsr.l #1,%1 ; jcc 1f ; move.l %2,-(%0) ; move.l %2,-(%0)\n"
++ "1:"
++ : "=a" (s), "=d" (count)
++ : "d" (-1), "0" ((char *)s+count), "1" (count));
++ asm volatile ("\n"
++ " subq.l #1,%1 ; jcs 3f\n"
++ " move.l %2,%%d4; move.l %2,%%d5; move.l %2,%%d6\n"
++ "2: movem.l %2/%%d4/%%d5/%%d6,-(%0)\n"
++ " dbra %1,2b\n"
++ "3:"
++ : "=a" (s), "=d" (count)
++ : "d" (-1), "0" (s), "1" (count)
++ : "d4", "d5", "d6");
++
++ return 0;
++}
++
++
++static inline void *fb_memmove(void *d, const void *s, size_t count)
++{
++ if (d < s) {
++ if (count < 16) {
++ asm volatile ("\n"
++ " lsr.l #1,%2 ; jcc 1f ; move.b (%1)+,(%0)+\n"
++ "1: lsr.l #1,%2 ; jcc 1f ; move.w (%1)+,(%0)+\n"
++ "1: lsr.l #1,%2 ; jcc 1f ; move.l (%1)+,(%0)+\n"
++ "1: lsr.l #1,%2 ; jcc 1f ; move.l (%1)+,(%0)+ ; move.l (%1)+,(%0)+\n"
++ "1:"
++ : "=a" (d), "=a" (s), "=d" (count)
++ : "0" (d), "1" (s), "2" (count));
++ } else {
++ long tmp;
++ asm volatile ("\n"
++ " move.l %0,%3\n"
++ " lsr.l #1,%3 ; jcc 1f ; move.b (%1)+,(%0)+ ; subqw #1,%2\n"
++ " lsr.l #1,%3 ; jcs 2f\n" /* %0 increased=>bit 2 switched*/
++ " move.w (%1)+,(%0)+ ; subqw #2,%2 ; jra 2f\n"
++ "1: lsr.l #1,%3 ; jcc 2f\n"
++ " move.w (%1)+,(%0)+ ; subqw #2,%2\n"
++ "2: move.w %2,%-; lsr.l #2,%2 ; jeq 6f\n"
++ " lsr.l #1,%2 ; jcc 3f ; move.l (%1)+,(%0)+\n"
++ "3: lsr.l #1,%2 ; jcc 4f ; move.l (%1)+,(%0)+ ; move.l (%1)+,(%0)+\n"
++ "4: subq.l #1,%2 ; jcs 6f\n"
++ "5: move.l (%1)+,(%0)+; move.l (%1)+,(%0)+\n"
++ " move.l (%1)+,(%0)+; move.l (%1)+,(%0)+\n"
++ " dbra %2,5b ; clr.w %2; subq.l #1,%2; jcc 5b\n"
++ "6: move.w %+,%2; btst #1,%2 ; jeq 7f ; move.w (%1)+,(%0)+\n"
++ "7: btst #0,%2 ; jeq 8f ; move.b (%1)+,(%0)+\n"
++ "8:"
++ : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp)
++ : "0" (d), "1" (s), "2" (count));
++ }
++ } else {
++ if (count < 16) {
++ asm volatile ("\n"
++ " lsr.l #1,%2 ; jcc 1f ; move.b -(%1),-(%0)\n"
++ "1: lsr.l #1,%2 ; jcc 1f ; move.w -(%1),-(%0)\n"
++ "1: lsr.l #1,%2 ; jcc 1f ; move.l -(%1),-(%0)\n"
++ "1: lsr.l #1,%2 ; jcc 1f ; move.l -(%1),-(%0) ; move.l -(%1),-(%0)\n"
++ "1:"
++ : "=a" (d), "=a" (s), "=d" (count)
++ : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count));
++ } else {
++ long tmp;
++
++ asm volatile ("\n"
++ " move.l %0,%3\n"
++ " lsr.l #1,%3 ; jcc 1f ; move.b -(%1),-(%0) ; subqw #1,%2\n"
++ " lsr.l #1,%3 ; jcs 2f\n" /* %0 increased=>bit 2 switched*/
++ " move.w -(%1),-(%0) ; subqw #2,%2 ; jra 2f\n"
++ "1: lsr.l #1,%3 ; jcc 2f\n"
++ " move.w -(%1),-(%0) ; subqw #2,%2\n"
++ "2: move.w %2,%-; lsr.l #2,%2 ; jeq 6f\n"
++ " lsr.l #1,%2 ; jcc 3f ; move.l -(%1),-(%0)\n"
++ "3: lsr.l #1,%2 ; jcc 4f ; move.l -(%1),-(%0) ; move.l -(%1),-(%0)\n"
++ "4: subq.l #1,%2 ; jcs 6f\n"
++ "5: move.l -(%1),-(%0); move.l -(%1),-(%0)\n"
++ " move.l -(%1),-(%0); move.l -(%1),-(%0)\n"
++ " dbra %2,5b ; clr.w %2; subq.l #1,%2; jcc 5b\n"
++ "6: move.w %+,%2; btst #1,%2 ; jeq 7f ; move.w -(%1),-(%0)\n"
++ "7: btst #0,%2 ; jeq 8f ; move.b -(%1),-(%0)\n"
++ "8:"
++ : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp)
++ : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count));
++ }
++ }
++
++ return 0;
++}
++
++
++/* ++andreas: Simple and fast version of memmove, assumes size is
++ divisible by 16, suitable for moving the whole screen bitplane */
++static inline void fast_memmove(char *dst, const char *src, size_t size)
++{
++ if (!size)
++ return;
++ if (dst < src)
++ asm volatile ("\n"
++ "1: movem.l (%0)+,%%d0/%%d1/%%a0/%%a1\n"
++ " movem.l %%d0/%%d1/%%a0/%%a1,%1@\n"
++ " addq.l #8,%1; addq.l #8,%1\n"
++ " dbra %2,1b\n"
++ " clr.w %2; subq.l #1,%2\n"
++ " jcc 1b"
++ : "=a" (src), "=a" (dst), "=d" (size)
++ : "0" (src), "1" (dst), "2" (size / 16 - 1)
++ : "d0", "d1", "a0", "a1", "memory");
++ else
++ asm volatile ("\n"
++ "1: subq.l #8,%0; subq.l #8,%0\n"
++ " movem.l %0@,%%d0/%%d1/%%a0/%%a1\n"
++ " movem.l %%d0/%%d1/%%a0/%%a1,-(%1)\n"
++ " dbra %2,1b\n"
++ " clr.w %2; subq.l #1,%2\n"
++ " jcc 1b"
++ : "=a" (src), "=a" (dst), "=d" (size)
++ : "0" (src + size), "1" (dst + size), "2" (size / 16 - 1)
++ : "d0", "d1", "a0", "a1", "memory");
++}
++
++#ifdef BPL
++
++/*
++ * This expands a up to 8 bit color into two longs
++ * for movel operations.
++ */
++static const u32 four2long[] = {
++ 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff,
++ 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff,
++ 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff,
++ 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff,
++};
++
++static inline void expand8_col2mask(u8 c, u32 m[])
++{
++ m[0] = four2long[c & 15];
++#if BPL > 4
++ m[1] = four2long[c >> 4];
++#endif
++}
++
++static inline void expand8_2col2mask(u8 fg, u8 bg, u32 fgm[], u32 bgm[])
++{
++ fgm[0] = four2long[fg & 15] ^ (bgm[0] = four2long[bg & 15]);
++#if BPL > 4
++ fgm[1] = four2long[fg >> 4] ^ (bgm[1] = four2long[bg >> 4]);
++#endif
++}
++
++/*
++ * set an 8bit value to a color
++ */
++static inline void fill8_col(u8 *dst, u32 m[])
++{
++ u32 tmp = m[0];
++ dst[0] = tmp;
++ dst[2] = (tmp >>= 8);
++#if BPL > 2
++ dst[4] = (tmp >>= 8);
++ dst[6] = tmp >> 8;
++#endif
++#if BPL > 4
++ tmp = m[1];
++ dst[8] = tmp;
++ dst[10] = (tmp >>= 8);
++ dst[12] = (tmp >>= 8);
++ dst[14] = tmp >> 8;
++#endif
++}
++
++/*
++ * set an 8bit value according to foreground/background color
++ */
++static inline void fill8_2col(u8 *dst, u8 fg, u8 bg, u32 mask)
++{
++ u32 fgm[2], bgm[2], tmp;
++
++ expand8_2col2mask(fg, bg, fgm, bgm);
++
++ mask |= mask << 8;
++#if BPL > 2
++ mask |= mask << 16;
++#endif
++ tmp = (mask & fgm[0]) ^ bgm[0];
++ dst[0] = tmp;
++ dst[2] = (tmp >>= 8);
++#if BPL > 2
++ dst[4] = (tmp >>= 8);
++ dst[6] = tmp >> 8;
++#endif
++#if BPL > 4
++ tmp = (mask & fgm[1]) ^ bgm[1];
++ dst[8] = tmp;
++ dst[10] = (tmp >>= 8);
++ dst[12] = (tmp >>= 8);
++ dst[14] = tmp >> 8;
++#endif
++}
++
++static const u32 two2word[] = {
++ 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
++};
++
++static inline void expand16_col2mask(u8 c, u32 m[])
++{
++ m[0] = two2word[c & 3];
++#if BPL > 2
++ m[1] = two2word[(c >> 2) & 3];
++#endif
++#if BPL > 4
++ m[2] = two2word[(c >> 4) & 3];
++ m[3] = two2word[c >> 6];
++#endif
++}
++
++static inline void expand16_2col2mask(u8 fg, u8 bg, u32 fgm[], u32 bgm[])
++{
++ bgm[0] = two2word[bg & 3];
++ fgm[0] = two2word[fg & 3] ^ bgm[0];
++#if BPL > 2
++ bgm[1] = two2word[(bg >> 2) & 3];
++ fgm[1] = two2word[(fg >> 2) & 3] ^ bgm[1];
++#endif
++#if BPL > 4
++ bgm[2] = two2word[(bg >> 4) & 3];
++ fgm[2] = two2word[(fg >> 4) & 3] ^ bgm[2];
++ bgm[3] = two2word[bg >> 6];
++ fgm[3] = two2word[fg >> 6] ^ bgm[3];
++#endif
++}
++
++static inline u32 *fill16_col(u32 *dst, int rows, u32 m[])
++{
++ while (rows) {
++ *dst++ = m[0];
++#if BPL > 2
++ *dst++ = m[1];
++#endif
++#if BPL > 4
++ *dst++ = m[2];
++ *dst++ = m[3];
++#endif
++ rows--;
++ }
++ return dst;
++}
++
++static inline void memmove32_col(void *dst, void *src, u32 mask, u32 h, u32 bytes)
++{
++ u32 *s, *d, v;
++
++ s = src;
++ d = dst;
++ do {
++ v = (*s++ & mask) | (*d & ~mask);
++ *d++ = v;
++#if BPL > 2
++ v = (*s++ & mask) | (*d & ~mask);
++ *d++ = v;
++#endif
++#if BPL > 4
++ v = (*s++ & mask) | (*d & ~mask);
++ *d++ = v;
++ v = (*s++ & mask) | (*d & ~mask);
++ *d++ = v;
++#endif
++ d = (u32 *)((u8 *)d + bytes);
++ s = (u32 *)((u8 *)s + bytes);
++ } while (--h);
++}
++
++#endif
++
++#endif /* _VIDEO_ATAFB_UTILS_H */
diff --git a/debian/patches/bugfix/m68k/amiga-a2065-ariadne-stats.diff b/debian/patches/bugfix/m68k/amiga-a2065-ariadne-stats.diff
new file mode 100644
index 000000000000..d6cd97977ec4
--- /dev/null
+++ b/debian/patches/bugfix/m68k/amiga-a2065-ariadne-stats.diff
@@ -0,0 +1,42 @@
+Subject: [PATCH] m68k: Amiga A2065 and Ariadne TX statistics
+Cc: Jeff Garzik <jgarzik@pobox.com>, netdev@vger.kernel.org
+
+Add missing code to the Amiga A2065 and Ariadne drivers to update
+net_device_stats.tx_bytes.
+
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ drivers/net/a2065.c | 4 +---
+ drivers/net/ariadne.c | 1 +
+ 2 files changed, 2 insertions(+), 3 deletions(-)
+
+--- linux-m68k-2.6.21.orig/drivers/net/a2065.c
++++ linux-m68k-2.6.21/drivers/net/a2065.c
+@@ -563,7 +563,6 @@ static int lance_start_xmit (struct sk_b
+ volatile struct lance_init_block *ib = lp->init_block;
+ int entry, skblen, len;
+ int status = 0;
+- static int outs;
+ unsigned long flags;
+
+ skblen = skb->len;
+@@ -608,8 +607,7 @@ static int lance_start_xmit (struct sk_b
+ /* Now, give the packet to the lance */
+ ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN);
+ lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask;
+-
+- outs++;
++ lp->stats.tx_bytes += skblen;
+
+ if (TX_BUFFS_AVAIL <= 0)
+ netif_stop_queue(dev);
+--- linux-m68k-2.6.21.orig/drivers/net/ariadne.c
++++ linux-m68k-2.6.21/drivers/net/ariadne.c
+@@ -677,6 +677,7 @@ static int ariadne_start_xmit(struct sk_
+ priv->cur_tx -= TX_RING_SIZE;
+ priv->dirty_tx -= TX_RING_SIZE;
+ }
++ priv->stats.tx_bytes += len;
+
+ /* Trigger an immediate send poll. */
+ lance->RAP = CSR0; /* PCnet-ISA Controller Status */
diff --git a/debian/patches/bugfix/m68k/atari-aranym.diff b/debian/patches/bugfix/m68k/atari-aranym.diff
new file mode 100644
index 000000000000..b0579c114107
--- /dev/null
+++ b/debian/patches/bugfix/m68k/atari-aranym.diff
@@ -0,0 +1,542 @@
+Subject: [PATCH] m68k: Atari ARAnyM support
+
+From: Michael Schmitz <schmitz@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@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 | 292 +++++++++++++++++++++++++++++++++++++++++++++
+ arch/m68k/kernel/setup.c | 5
+ drivers/net/Kconfig | 8 +
+ include/asm-m68k/natfeat.h | 22 +++
+ 8 files changed, 463 insertions(+)
+
+--- linux-m68k-2.6.21.orig/arch/m68k/Kconfig
++++ linux-m68k-2.6.21/arch/m68k/Kconfig
+@@ -260,6 +260,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
+--- linux-m68k-2.6.21.orig/arch/m68k/Makefile
++++ linux-m68k-2.6.21/arch/m68k/Makefile
+@@ -75,6 +75,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
++++ linux-m68k-2.6.21/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
++++ linux-m68k-2.6.21/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@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 <asm/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;
++
++ printk("NatFeats found (%s, %lu.%lu)\n", buf,
++ version >> 16, version & 0xffff);
++
++ mach_power_off = nf_poweroff;
++}
+--- /dev/null
++++ linux-m68k-2.6.21/arch/m68k/emu/nfeth.c
+@@ -0,0 +1,292 @@
++/*
++ * 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>
++
++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)");
++*/
++
++#undef DEBUG
++
++static long nfEtherID;
++static int nfEtherIRQ;
++
++struct nfeth_private {
++ int ethX;
++ struct net_device_stats stats;
++ spinlock_t lock;
++};
++
++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));
++ spin_lock_init(&priv->lock);
++
++#ifdef DEBUG
++ printk(DRV_NAME ": open %d\n", res);
++#endif
++
++ /* 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);
++
++#ifdef DEBUG
++ printk(DRV_NAME ": recv_packet: %i\n", pktlen);
++#endif
++
++ if (!pktlen) {
++#ifdef DEBUG
++ printk(DRV_NAME ": recv_packet: pktlen == 0\n");
++#endif
++ priv->stats.rx_errors++;
++ return;
++ }
++
++ skb = dev_alloc_skb(pktlen + 2);
++ if (!skb) {
++#ifdef DEBUG
++ printk(DRV_NAME ": recv_packet: out of mem (buf_alloc failed)\n");
++#endif
++ 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;
++
++#ifdef DEBUG
++ printk(DRV_NAME ": send %d bytes\n", len);
++#endif
++ 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];
++ 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;
++
++ SET_MODULE_OWNER(dev);
++ 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));
++
++ printk(KERN_INFO "%s: nfeth addr:%s (%s) HWaddr:" MAC_FMT "\n",
++ dev->name, host_ip, local_ip, MAC_ARG(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);
++ printk("nfeth API %lu\n", ver);
++
++ nfEtherIRQ = nf_call(nfEtherID + XIF_INTLEVEL);
++ if (request_irq(nfEtherIRQ, nfeth_interrupt, IRQF_SHARED,
++ "eth emu", nfeth_interrupt)) {
++ printk("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);
+--- linux-m68k-2.6.21.orig/arch/m68k/kernel/setup.c
++++ linux-m68k-2.6.21/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;
+@@ -313,6 +314,10 @@ void __init setup_arch(char **cmdline_p)
+ panic("No configuration setup");
+ }
+
++#ifdef CONFIG_NATFEAT
++ nf_init();
++#endif
++
+ paging_init();
+
+ #ifndef CONFIG_SUN3
+--- linux-m68k-2.6.21.orig/drivers/net/Kconfig
++++ linux-m68k-2.6.21/drivers/net/Kconfig
+@@ -398,6 +398,14 @@ config ATARI_PAMSNET
+ ACSI port ("ACSI node"). The driver works (has to work...) with a
+ polled I/O scheme, so it's rather slow :-(
+
++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 NET_ETHERNET && (SUN3 || SUN3X)
+--- /dev/null
++++ linux-m68k-2.6.21/include/asm-m68k/natfeat.h
+@@ -0,0 +1,22 @@
++/*
++ * ARAnyM hardware support via Native Features (natfeats)
++ *
++ * Copyright (c) 2005 Petr Stehlik of ARAnyM dev team
++ *
++ * This software may be used and distributed according to the terms of
++ * the GNU General Public License (GPL), incorporated herein by reference.
++ */
++
++#ifndef _NATFEAT_H
++#define _NATFEAT_H
++
++long nf_get_id(const char *feature_name);
++long nf_call(long id, ...);
++
++void nf_init(void);
++void nf_shutdown(void);
++
++void nfprint(const char *fmt, ...)
++ __attribute__ ((format (printf, 1, 2)));
++
++# endif /* _NATFEAT_H */
diff --git a/debian/patches/bugfix/m68k/atari-ethernec.diff b/debian/patches/bugfix/m68k/atari-ethernec.diff
new file mode 100644
index 000000000000..9ddd4570479a
--- /dev/null
+++ b/debian/patches/bugfix/m68k/atari-ethernec.diff
@@ -0,0 +1,1106 @@
+Subject: [PATCH] m68k: Atari EtherNEC driver
+Cc: Jeff Garzik <jgarzik@pobox.com>, netdev@vger.kernel.org
+
+From: Michael Schmitz <schmitz@opal.biophys.uni-duesseldorf.de>
+
+Atari EtherNEC driver
+
+Signed-off-by: Michael Schmitz <schmitz@debian.org>
+Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ drivers/net/Makefile | 1
+ drivers/net/Space.c | 4
+ drivers/net/atari_ethernec.c | 1057 +++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 1062 insertions(+)
+
+--- linux-m68k-2.6.21.orig/drivers/net/Makefile
++++ linux-m68k-2.6.21/drivers/net/Makefile
+@@ -177,6 +177,7 @@ obj-$(CONFIG_DECLANCE) += declance.o
+ obj-$(CONFIG_ATARILANCE) += atarilance.o
+ obj-$(CONFIG_ATARI_BIONET) += atari_bionet.o
+ obj-$(CONFIG_ATARI_PAMSNET) += atari_pamsnet.o
++obj-$(CONFIG_ATARI_ETHERNEC) += atari_ethernec.o 8390.o
+ obj-$(CONFIG_A2065) += a2065.o
+ obj-$(CONFIG_HYDRA) += hydra.o
+ obj-$(CONFIG_ARIADNE) += ariadne.o
+--- linux-m68k-2.6.21.orig/drivers/net/Space.c
++++ linux-m68k-2.6.21/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);
+@@ -255,6 +256,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
++++ linux-m68k-2.6.21/drivers/net/atari_ethernec.c
+@@ -0,0 +1,1057 @@
++/*
++ * atari_ethernec.c: Atari cartridge port ethernet adapter
++ * (C) 2006 Michael Schmitz
++ *
++ * Modified after:
++ */
++
++/* ne.c: A general non-shared-memory NS8390 ethernet driver for linux. */
++/*
++ Written 1992-94 by Donald Becker.
++
++ Copyright 1993 United States Government as represented by the
++ Director, National Security Agency.
++
++ This software may be used and distributed according to the terms
++ of the GNU General Public License, incorporated herein by reference.
++
++ The author may be reached as becker@scyld.com, or C/O
++ Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403
++
++ This driver should work with many programmed-I/O 8390-based ethernet
++ boards. Currently it supports the NE1000, NE2000, many clones,
++ and some Cabletron products.
++
++ Changelog:
++
++ Paul Gortmaker : use ENISR_RDC to monitor Tx PIO uploads, made
++ sanity checks and bad clone support optional.
++ Paul Gortmaker : new reset code, reset card after probe at boot.
++ Paul Gortmaker : multiple card support for module users.
++ Paul Gortmaker : Support for PCI ne2k clones, similar to lance.c
++ Paul Gortmaker : Allow users with bad cards to avoid full probe.
++ Paul Gortmaker : PCI probe changes, more PCI cards supported.
++ rjohnson@analogic.com : Changed init order so an interrupt will only
++ occur after memory is allocated for dev->priv. Deallocated memory
++ last in cleanup_modue()
++ Richard Guenther : Added support for ISAPnP cards
++ Paul Gortmaker : Discontinued PCI support - use ne2k-pci.c instead.
++ Hayato Fujiwara : Add m32r support.
++
++*/
++
++/*
++ * From the driver distribution kit by Thomas Redelberger:
++ *
++ * Hardware circuit description (see directory ETHERNEC for schematics)
++ *
++ * As there is no reset line on the CP, a resistor and a capacitor are
++ * used to reset the NE card on power up.
++ *
++ * Reading from the NE card is done by a read cycle on the CP at address
++ * /ROM4 + 512*ISA address as the ISA address lines A0-A4 are connected
++ * to CP A9-A13. /ROM4 going low will start the ISA read cycle, enable
++ * the ISA bus buffers of the NE card and start decoding of the ISA IO
++ * address by the NE card. /ROM4 going high ends the cycle and the
++ * processor latches the data.
++ *
++ * Because the CP is read only writing to the NE card must be done with
++ * the trick to read from addresses that stand for the data. Dummy reads
++ * at /ROM3 base address + data*2 + ISA address*512 effect this. You
++ * might wonder why everything appears to be shifted up one bit. There is
++ * no CP "A0" address line. There are the signals /UDS and /LDS instead
++ * typical for the 68000 family. The original design which generated an
++ * "A0" worked on an ST and an STE but did not on a Falcon.
++ *
++ * The falling edge of /ROM3 enables the CP address lines A1-A8 onto the
++ * data bus and starts the ISA write cycle. The rising edge will end the
++ * ISA write cycle and the NE latches the data. The processor will also
++ * see and just read this same data but that is harmless.
++ * Elmar Hilgart reported that the bus buffer IC shall be an TTL F-type
++ * to keep up with the fast cycles on the Falcon.
++ *
++ * Base addresses:
++ * rom4 EQU $00fa0000 ; ROM4 base address
++ * rom3 EQU $00fb0000 ; ROM3 base address
++ *
++ */
++
++/* Routines for the NatSemi-based designs (NE[12]000). */
++
++static const char version1[] =
++"ne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com)\n";
++static const char version2[] =
++"atari_ethernec.c 11/10/06 Michael Schmitz (schmitz@debian.org)\n";
++
++
++#include <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 <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 work_struct tqueue;
++
++#ifdef ETHERNEC_USE_POLL
++static struct {
++ struct work_struct poll_queue;
++ struct timer_list poll_timer;
++ struct net_device *dev;
++} poll_ops;
++#endif
++
++static struct net_device *poll_dev = NULL;
++
++static void atari_ethernec_int(unsigned long dev_addr)
++{
++ 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 */
++}
++
++#ifdef ETHERNEC_USE_POLL
++static void atari_ethernec_poll_handler(unsigned long dev_addr)
++{
++ struct net_device *dev = poll_dev;
++
++ if (!dev || !dev->poll_controller)
++ return;
++
++ if (netif_running(dev))
++ dev->poll_controller(dev);
++
++ schedule_work(&poll_ops.poll_queue);
++ mod_timer(&poll_ops.poll_timer, jiffies + HZ / 100);
++}
++#endif
++
++static void atari_ethernec_start_poll(struct net_device *dev)
++{
++ poll_dev = dev;
++
++ init_waitqueue_head(&WaitQ);
++
++ INIT_WORK(&tqueue, (void (*)(void *))atari_ethernec_int, dev);
++ schedule_delayed_work(&tqueue, 1);
++#ifdef ETHERNEC_USE_POLL
++ if (!poll_ops.poll_queue.func ||
++ poll_ops.poll_queue.func == ei_interrupt) {
++ if (!poll_ops.poll_queue.func)
++ INIT_WORK(&poll_ops.poll_queue, ei_interrupt, dev);
++
++ init_timer(&poll_ops.poll_timer);
++ poll_ops.poll_timer.function = atari_ethernec_poll_handler;
++ poll_ops.poll_timer.expires = jiffies + HZ / 5;
++ poll_ops.poll_timer.data = (unsigned long)dev;
++ add_timer(&poll_ops.poll_timer);
++ }
++#endif
++}
++
++static void atari_ethernec_stop_poll(struct net_device *dev)
++{
++ poll_dev = NULL;
++
++ if (dev)
++ sleep_on(&WaitQ);
++
++#ifdef ETHERNEC_USE_POLL
++ if (poll_ops.poll_queue.func == ei_interrupt)
++ del_timer_sync(&poll_ops.poll_timer);
++#endif
++}
++
++
++/* 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
++
++ SET_MODULE_OWNER(dev);
++
++ /* 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 */
diff --git a/debian/patches/bugfix/m68k/atari-rom-isa.diff b/debian/patches/bugfix/m68k/atari-rom-isa.diff
new file mode 100644
index 000000000000..ce5fdffd6fef
--- /dev/null
+++ b/debian/patches/bugfix/m68k/atari-rom-isa.diff
@@ -0,0 +1,340 @@
+Subject: [PATCH] m68k: Atari ROM port ISA adapter support
+
+From: Michael Schmitz <schmitz@opal.biophys.uni-duesseldorf.de>
+
+Atari ROM port ISA adapter support
+
+Signed-off-by: Michael Schmitz <schmitz@debian.org>
+Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ arch/m68k/Kconfig | 10 ++++
+ include/asm-m68k/io.h | 101 ++++++++++++++++++++++++++++++++++++++++++++--
+ include/asm-m68k/raw_io.h | 98 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 205 insertions(+), 4 deletions(-)
+
+--- linux-m68k-2.6.21.orig/arch/m68k/Kconfig
++++ linux-m68k-2.6.21/arch/m68k/Kconfig
+@@ -143,6 +143,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
+--- linux-m68k-2.6.21.orig/include/asm-m68k/io.h
++++ linux-m68k-2.6.21/include/asm-m68k/io.h
+@@ -82,9 +82,21 @@ 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))
++
++#define MULTI_ISA 0
++#endif /* ATARI */
++
++
++#if defined(CONFIG_ISA) || defined(CONFIG_ATARI_ROM_ISA)
+
+ #if MULTI_ISA == 0
+ #undef MULTI_ISA
+@@ -93,6 +105,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
+@@ -106,6 +119,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;
+@@ -133,6 +150,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 */
+ }
+ }
+@@ -149,6 +169,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 */
+ }
+ }
+@@ -165,6 +188,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 */
+ }
+ }
+@@ -181,6 +207,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 */
+ }
+ }
+@@ -200,6 +229,19 @@ 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_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_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)
+@@ -213,6 +255,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 */
+ }
+ }
+@@ -234,10 +279,33 @@ static inline void isa_delay(void)
+ #define isa_outsw(port, buf, nr) \
+ (ISA_SEX ? raw_outsw(isa_itw(port), (u16 *)(buf), (nr)) : \
+ raw_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr)))
++
++#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_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)))
++
++#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
+@@ -306,7 +374,34 @@ static inline void isa_delay(void)
+ #endif
+ #endif /* CONFIG_PCI */
+
+-#if !defined(CONFIG_ISA) && !defined(CONFIG_PCI) && defined(CONFIG_HP300)
++#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 outsb isa_rom_outsb
++#define outsw isa_rom_outsw
++#endif
++
++#if !defined(CONFIG_ISA) && !defined(CONFIG_PCI) && !defined(CONFIG_ATARI_ROM_ISA) && defined(CONFIG_HP300)
+ /*
+ * We need to define dummy functions otherwise drivers/serial/8250.c doesn't link
+ */
+--- linux-m68k-2.6.21.orig/include/asm-m68k/raw_io.h
++++ linux-m68k-2.6.21/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 */
+@@ -54,6 +54,46 @@ extern void __iounmap(void *addr, unsign
+ #define raw_outw(val,port) out_be16((port),(val))
+ #define raw_outl(val,port) out_be32((port),(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;
+@@ -336,6 +376,62 @@ 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++);
++}
++#endif /* CONFIG_ATARI_ROM_ISA */
++
+ #define __raw_writel raw_outl
+
+ #endif /* __KERNEL__ */
diff --git a/debian/patches/bugfix/m68k/atari-scsi-compile-fixes.diff b/debian/patches/bugfix/m68k/atari-scsi-compile-fixes.diff
new file mode 100644
index 000000000000..3aa6f7bfb40f
--- /dev/null
+++ b/debian/patches/bugfix/m68k/atari-scsi-compile-fixes.diff
@@ -0,0 +1,340 @@
+Cc: James E.J. Bottomley <James.Bottomley@SteelEye.com>,
+ linux-scsi@vger.kernel.org
+Subject: [PATCH] m68k: Atari SCSI driver compile fixes
+
+From: Roman Zippel <zippel@linux-m68k.org>
+
+Atari SCSI driver compile fixes
+
+Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ drivers/scsi/atari_NCR5380.c | 33 +++++----
+ drivers/scsi/atari_scsi.c | 6 -
+ drivers/scsi/atari_scsi.h | 144 ++++++++-----------------------------------
+ 3 files changed, 49 insertions(+), 134 deletions(-)
+
+--- linux-m68k-2.6.21.orig/drivers/scsi/atari_NCR5380.c
++++ linux-m68k-2.6.21/drivers/scsi/atari_NCR5380.c
+@@ -272,8 +272,9 @@ static struct scsi_host_template *the_te
+ (struct NCR5380_hostdata *)(in)->hostdata
+ #define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata)
+
+-#define NEXT(cmd) ((cmd)->host_scribble)
+-#define NEXTADDR(cmd) ((Scsi_Cmnd **)&((cmd)->host_scribble))
++#define NEXT(cmd) ((Scsi_Cmnd *)(cmd)->host_scribble)
++#define SET_NEXT(cmd,next) ((cmd)->host_scribble = (void *)(next))
++#define NEXTADDR(cmd) ((Scsi_Cmnd **)&(cmd)->host_scribble)
+
+ #define HOSTNO instance->host_no
+ #define H_NO(cmd) (cmd)->device->host->host_no
+@@ -479,7 +480,7 @@ static void merge_contiguous_buffers(Scs
+ virt_to_phys(page_address(cmd->SCp.buffer[1].page) +
+ cmd->SCp.buffer[1].offset) == endaddr;) {
+ MER_PRINTK("VTOP(%p) == %08lx -> merging\n",
+- cmd->SCp.buffer[1].address, endaddr);
++ page_address(cmd->SCp.buffer[1].page), endaddr);
+ #if (NDEBUG & NDEBUG_MERGING)
+ ++cnt;
+ #endif
+@@ -1002,7 +1003,7 @@ static int NCR5380_queue_command(Scsi_Cm
+ * in a queue
+ */
+
+- NEXT(cmd) = NULL;
++ SET_NEXT(cmd, NULL);
+ cmd->scsi_done = done;
+
+ cmd->result = 0;
+@@ -1034,14 +1035,14 @@ static int NCR5380_queue_command(Scsi_Cm
+ }
+ if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+ LIST(cmd, hostdata->issue_queue);
+- NEXT(cmd) = hostdata->issue_queue;
++ SET_NEXT(cmd, hostdata->issue_queue);
+ hostdata->issue_queue = cmd;
+ } else {
+ for (tmp = (Scsi_Cmnd *)hostdata->issue_queue;
+ NEXT(tmp); tmp = NEXT(tmp))
+ ;
+ LIST(cmd, tmp);
+- NEXT(tmp) = cmd;
++ SET_NEXT(tmp, cmd);
+ }
+ local_irq_restore(flags);
+
+@@ -1149,12 +1150,12 @@ static void NCR5380_main(void *bl)
+ local_irq_disable();
+ if (prev) {
+ REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
+- NEXT(prev) = NEXT(tmp);
++ SET_NEXT(prev, NEXT(tmp));
+ } else {
+ REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp));
+ hostdata->issue_queue = NEXT(tmp);
+ }
+- NEXT(tmp) = NULL;
++ SET_NEXT(tmp, NULL);
+ falcon_dont_release++;
+
+ /* reenable interrupts after finding one */
+@@ -1192,7 +1193,7 @@ static void NCR5380_main(void *bl)
+ } else {
+ local_irq_disable();
+ LIST(tmp, hostdata->issue_queue);
+- NEXT(tmp) = hostdata->issue_queue;
++ SET_NEXT(tmp, hostdata->issue_queue);
+ hostdata->issue_queue = tmp;
+ #ifdef SUPPORT_TAGS
+ cmd_free_tag(tmp);
+@@ -2295,7 +2296,7 @@ static void NCR5380_information_transfer
+
+ local_irq_save(flags);
+ LIST(cmd,hostdata->issue_queue);
+- NEXT(cmd) = hostdata->issue_queue;
++ SET_NEXT(cmd, hostdata->issue_queue);
+ hostdata->issue_queue = (Scsi_Cmnd *) cmd;
+ local_irq_restore(flags);
+ QU_PRINTK("scsi%d: REQUEST SENSE added to head of "
+@@ -2357,7 +2358,7 @@ static void NCR5380_information_transfer
+ local_irq_save(flags);
+ cmd->device->disconnect = 1;
+ LIST(cmd,hostdata->disconnected_queue);
+- NEXT(cmd) = hostdata->disconnected_queue;
++ SET_NEXT(cmd, hostdata->disconnected_queue);
+ hostdata->connected = NULL;
+ hostdata->disconnected_queue = cmd;
+ local_irq_restore(flags);
+@@ -2632,12 +2633,12 @@ static void NCR5380_reselect(struct Scsi
+ falcon_dont_release++;
+ if (prev) {
+ REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
+- NEXT(prev) = NEXT(tmp);
++ SET_NEXT(prev, NEXT(tmp));
+ } else {
+ REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp));
+ hostdata->disconnected_queue = NEXT(tmp);
+ }
+- NEXT(tmp) = NULL;
++ SET_NEXT(tmp, NULL);
+ break;
+ }
+ }
+@@ -2769,7 +2770,7 @@ int NCR5380_abort(Scsi_Cmnd *cmd)
+ if (cmd == tmp) {
+ REMOVE(5, *prev, tmp, NEXT(tmp));
+ (*prev) = NEXT(tmp);
+- NEXT(tmp) = NULL;
++ SET_NEXT(tmp, NULL);
+ tmp->result = DID_ABORT << 16;
+ local_irq_restore(flags);
+ ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n",
+@@ -2844,7 +2845,7 @@ int NCR5380_abort(Scsi_Cmnd *cmd)
+ if (cmd == tmp) {
+ REMOVE(5, *prev, tmp, NEXT(tmp));
+ *prev = NEXT(tmp);
+- NEXT(tmp) = NULL;
++ SET_NEXT(tmp, NULL);
+ tmp->result = DID_ABORT << 16;
+ /* We must unlock the tag/LUN immediately here, since the
+ * target goes to BUS FREE and doesn't send us another
+@@ -2965,7 +2966,7 @@ static int NCR5380_bus_reset(Scsi_Cmnd *
+
+ for (i = 0; (cmd = disconnected_queue); ++i) {
+ disconnected_queue = NEXT(cmd);
+- NEXT(cmd) = NULL;
++ SET_NEXT(cmd, NULL);
+ cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
+ cmd->scsi_done(cmd);
+ }
+--- linux-m68k-2.6.21.orig/drivers/scsi/atari_scsi.c
++++ linux-m68k-2.6.21/drivers/scsi/atari_scsi.c
+@@ -69,9 +69,9 @@
+
+ #define NDEBUG (0)
+
+-#define NDEBUG_ABORT 0x800000
+-#define NDEBUG_TAGS 0x1000000
+-#define NDEBUG_MERGING 0x2000000
++#define NDEBUG_ABORT 0x00100000
++#define NDEBUG_TAGS 0x00200000
++#define NDEBUG_MERGING 0x00400000
+
+ #define AUTOSENSE
+ /* For the Atari version, use only polled IO or REAL_DMA */
+--- linux-m68k-2.6.21.orig/drivers/scsi/atari_scsi.h
++++ linux-m68k-2.6.21/drivers/scsi/atari_scsi.h
+@@ -113,144 +113,58 @@ int atari_scsi_release (struct Scsi_Host
+ *
+ */
+
+-#if NDEBUG & NDEBUG_ARBITRATION
++#define dprint(flg, format...) \
++({ \
++ if (NDEBUG & (flg)) \
++ printk(KERN_DEBUG format); \
++})
++
+ #define ARB_PRINTK(format, args...) \
+- printk(KERN_DEBUG format , ## args)
+-#else
+-#define ARB_PRINTK(format, args...)
+-#endif
+-#if NDEBUG & NDEBUG_AUTOSENSE
++ dprint(NDEBUG_ARBITRATION, format , ## args)
+ #define ASEN_PRINTK(format, args...) \
+- printk(KERN_DEBUG format , ## args)
+-#else
+-#define ASEN_PRINTK(format, args...)
+-#endif
+-#if NDEBUG & NDEBUG_DMA
++ dprint(NDEBUG_AUTOSENSE, format , ## args)
+ #define DMA_PRINTK(format, args...) \
+- printk(KERN_DEBUG format , ## args)
+-#else
+-#define DMA_PRINTK(format, args...)
+-#endif
+-#if NDEBUG & NDEBUG_HANDSHAKE
++ dprint(NDEBUG_DMA, format , ## args)
+ #define HSH_PRINTK(format, args...) \
+- printk(KERN_DEBUG format , ## args)
+-#else
+-#define HSH_PRINTK(format, args...)
+-#endif
+-#if NDEBUG & NDEBUG_INFORMATION
++ dprint(NDEBUG_HANDSHAKE, format , ## args)
+ #define INF_PRINTK(format, args...) \
+- printk(KERN_DEBUG format , ## args)
+-#else
+-#define INF_PRINTK(format, args...)
+-#endif
+-#if NDEBUG & NDEBUG_INIT
++ dprint(NDEBUG_INFORMATION, format , ## args)
+ #define INI_PRINTK(format, args...) \
+- printk(KERN_DEBUG format , ## args)
+-#else
+-#define INI_PRINTK(format, args...)
+-#endif
+-#if NDEBUG & NDEBUG_INTR
++ dprint(NDEBUG_INIT, format , ## args)
+ #define INT_PRINTK(format, args...) \
+- printk(KERN_DEBUG format , ## args)
+-#else
+-#define INT_PRINTK(format, args...)
+-#endif
+-#if NDEBUG & NDEBUG_LINKED
++ dprint(NDEBUG_INTR, format , ## args)
+ #define LNK_PRINTK(format, args...) \
+- printk(KERN_DEBUG format , ## args)
+-#else
+-#define LNK_PRINTK(format, args...)
+-#endif
+-#if NDEBUG & NDEBUG_MAIN
++ dprint(NDEBUG_LINKED, format , ## args)
+ #define MAIN_PRINTK(format, args...) \
+- printk(KERN_DEBUG format , ## args)
+-#else
+-#define MAIN_PRINTK(format, args...)
+-#endif
+-#if NDEBUG & NDEBUG_NO_DATAOUT
++ dprint(NDEBUG_MAIN, format , ## args)
+ #define NDAT_PRINTK(format, args...) \
+- printk(KERN_DEBUG format , ## args)
+-#else
+-#define NDAT_PRINTK(format, args...)
+-#endif
+-#if NDEBUG & NDEBUG_NO_WRITE
++ dprint(NDEBUG_NO_DATAOUT, format , ## args)
+ #define NWR_PRINTK(format, args...) \
+- printk(KERN_DEBUG format , ## args)
+-#else
+-#define NWR_PRINTK(format, args...)
+-#endif
+-#if NDEBUG & NDEBUG_PIO
++ dprint(NDEBUG_NO_WRITE, format , ## args)
+ #define PIO_PRINTK(format, args...) \
+- printk(KERN_DEBUG format , ## args)
+-#else
+-#define PIO_PRINTK(format, args...)
+-#endif
+-#if NDEBUG & NDEBUG_PSEUDO_DMA
++ dprint(NDEBUG_PIO, format , ## args)
+ #define PDMA_PRINTK(format, args...) \
+- printk(KERN_DEBUG format , ## args)
+-#else
+-#define PDMA_PRINTK(format, args...)
+-#endif
+-#if NDEBUG & NDEBUG_QUEUES
++ dprint(NDEBUG_PSEUDO_DMA, format , ## args)
+ #define QU_PRINTK(format, args...) \
+- printk(KERN_DEBUG format , ## args)
+-#else
+-#define QU_PRINTK(format, args...)
+-#endif
+-#if NDEBUG & NDEBUG_RESELECTION
++ dprint(NDEBUG_QUEUES, format , ## args)
+ #define RSL_PRINTK(format, args...) \
+- printk(KERN_DEBUG format , ## args)
+-#else
+-#define RSL_PRINTK(format, args...)
+-#endif
+-#if NDEBUG & NDEBUG_SELECTION
++ dprint(NDEBUG_RESELECTION, format , ## args)
+ #define SEL_PRINTK(format, args...) \
+- printk(KERN_DEBUG format , ## args)
+-#else
+-#define SEL_PRINTK(format, args...)
+-#endif
+-#if NDEBUG & NDEBUG_USLEEP
++ dprint(NDEBUG_SELECTION, format , ## args)
+ #define USL_PRINTK(format, args...) \
+- printk(KERN_DEBUG format , ## args)
+-#else
+-#define USL_PRINTK(format, args...)
+-#endif
+-#if NDEBUG & NDEBUG_LAST_BYTE_SENT
++ dprint(NDEBUG_USLEEP, format , ## args)
+ #define LBS_PRINTK(format, args...) \
+- printk(KERN_DEBUG format , ## args)
+-#else
+-#define LBS_PRINTK(format, args...)
+-#endif
+-#if NDEBUG & NDEBUG_RESTART_SELECT
++ dprint(NDEBUG_LAST_BYTE_SENT, format , ## args)
+ #define RSS_PRINTK(format, args...) \
+- printk(KERN_DEBUG format , ## args)
+-#else
+-#define RSS_PRINTK(format, args...)
+-#endif
+-#if NDEBUG & NDEBUG_EXTENDED
++ dprint(NDEBUG_RESTART_SELECT, format , ## args)
+ #define EXT_PRINTK(format, args...) \
+- printk(KERN_DEBUG format , ## args)
+-#else
+-#define EXT_PRINTK(format, args...)
+-#endif
+-#if NDEBUG & NDEBUG_ABORT
++ dprint(NDEBUG_EXTENDED, format , ## args)
+ #define ABRT_PRINTK(format, args...) \
+- printk(KERN_DEBUG format , ## args)
+-#else
+-#define ABRT_PRINTK(format, args...)
+-#endif
+-#if NDEBUG & NDEBUG_TAGS
++ dprint(NDEBUG_ABORT, format , ## args)
+ #define TAG_PRINTK(format, args...) \
+- printk(KERN_DEBUG format , ## args)
+-#else
+-#define TAG_PRINTK(format, args...)
+-#endif
+-#if NDEBUG & NDEBUG_MERGING
++ dprint(NDEBUG_TAGS, format , ## args)
+ #define MER_PRINTK(format, args...) \
+- printk(KERN_DEBUG format , ## args)
+-#else
+-#define MER_PRINTK(format, args...)
+-#endif
++ dprint(NDEBUG_MERGING, format , ## args)
+
+ /* conditional macros for NCR5380_print_{,phase,status} */
+
diff --git a/debian/patches/bugfix/m68k/atari-scsi-reformat.diff b/debian/patches/bugfix/m68k/atari-scsi-reformat.diff
new file mode 100644
index 000000000000..09afca506ae0
--- /dev/null
+++ b/debian/patches/bugfix/m68k/atari-scsi-reformat.diff
@@ -0,0 +1,5903 @@
+Cc: James E.J. Bottomley <James.Bottomley@SteelEye.com>,
+ linux-scsi@vger.kernel.org
+Subject: [PATCH] m68k: Reformat the Atari SCSI driver
+
+From: Roman Zippel <zippel@linux-m68k.org>
+
+Reformat the Atari SCSI driver
+
+Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ drivers/scsi/atari_NCR5380.c | 4433 +++++++++++++++++++++----------------------
+ drivers/scsi/atari_scsi.c | 363 +--
+ 2 files changed, 2397 insertions(+), 2399 deletions(-)
+
+--- linux-m68k-2.6.21.orig/drivers/scsi/atari_NCR5380.c
++++ linux-m68k-2.6.21/drivers/scsi/atari_NCR5380.c
+@@ -1,19 +1,19 @@
+-/*
++/*
+ * NCR 5380 generic driver routines. These should make it *trivial*
+- * to implement 5380 SCSI drivers under Linux with a non-trantor
++ * to implement 5380 SCSI drivers under Linux with a non-trantor
+ * architecture.
+ *
+ * Note that these routines also work with NR53c400 family chips.
+ *
+ * Copyright 1993, Drew Eckhardt
+- * Visionary Computing
++ * Visionary Computing
+ * (Unix and Linux consulting and custom programming)
+- * drew@colorado.edu
++ * drew@colorado.edu
+ * +1 (303) 666-5836
+ *
+- * DISTRIBUTION RELEASE 6.
++ * DISTRIBUTION RELEASE 6.
+ *
+- * For more information, please consult
++ * For more information, please consult
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+@@ -57,7 +57,7 @@
+ * - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA
+ * and USLEEP, because these were messing up readability and will never be
+ * needed for Atari SCSI.
+- *
++ *
+ * - I've revised the NCR5380_main() calling scheme (relax the 'main_running'
+ * stuff), and 'main' is executed in a bottom half if awoken by an
+ * interrupt.
+@@ -69,21 +69,29 @@
+ */
+
+ /*
+- * Further development / testing that should be done :
+- * 1. Test linked command handling code after Eric is ready with
++ * Further development / testing that should be done :
++ * 1. Test linked command handling code after Eric is ready with
+ * the high level code.
+ */
+ #include <scsi/scsi_dbg.h>
+ #include <scsi/scsi_transport_spi.h>
+
+ #if (NDEBUG & NDEBUG_LISTS)
+-#define LIST(x,y) \
+- { printk("LINE:%d Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); \
+- if ((x)==(y)) udelay(5); }
+-#define REMOVE(w,x,y,z) \
+- { printk("LINE:%d Removing: %p->%p %p->%p \n", __LINE__, \
+- (void*)(w), (void*)(x), (void*)(y), (void*)(z)); \
+- if ((x)==(y)) udelay(5); }
++#define LIST(x, y) \
++ do { \
++ printk("LINE:%d Adding %p to %p\n", \
++ __LINE__, (void*)(x), (void*)(y)); \
++ if ((x) == (y)) \
++ udelay(5); \
++ } while (0)
++#define REMOVE(w, x, y, z) \
++ do { \
++ printk("LINE:%d Removing: %p->%p %p->%p \n", \
++ __LINE__, (void*)(w), (void*)(x), \
++ (void*)(y), (void*)(z)); \
++ if ((x) == (y)) \
++ udelay(5); \
++ } while (0)
+ #else
+ #define LIST(x,y)
+ #define REMOVE(w,x,y,z)
+@@ -103,62 +111,62 @@
+ * more difficult than it has to be.
+ *
+ * Also, many of the SCSI drivers were written before the command queuing
+- * routines were implemented, meaning their implementations of queued
++ * routines were implemented, meaning their implementations of queued
+ * commands were hacked on rather than designed in from the start.
+ *
+- * When I designed the Linux SCSI drivers I figured that
++ * When I designed the Linux SCSI drivers I figured that
+ * while having two different SCSI boards in a system might be useful
+ * for debugging things, two of the same type wouldn't be used.
+ * Well, I was wrong and a number of users have mailed me about running
+ * multiple high-performance SCSI boards in a server.
+ *
+- * Finally, when I get questions from users, I have no idea what
++ * Finally, when I get questions from users, I have no idea what
+ * revision of my driver they are running.
+ *
+ * This driver attempts to address these problems :
+- * This is a generic 5380 driver. To use it on a different platform,
++ * This is a generic 5380 driver. To use it on a different platform,
+ * one simply writes appropriate system specific macros (ie, data
+- * transfer - some PC's will use the I/O bus, 68K's must use
++ * transfer - some PC's will use the I/O bus, 68K's must use
+ * memory mapped) and drops this file in their 'C' wrapper.
+ *
+- * As far as command queueing, two queues are maintained for
++ * As far as command queueing, two queues are maintained for
+ * each 5380 in the system - commands that haven't been issued yet,
+- * and commands that are currently executing. This means that an
+- * unlimited number of commands may be queued, letting
+- * more commands propagate from the higher driver levels giving higher
+- * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported,
+- * allowing multiple commands to propagate all the way to a SCSI-II device
++ * and commands that are currently executing. This means that an
++ * unlimited number of commands may be queued, letting
++ * more commands propagate from the higher driver levels giving higher
++ * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported,
++ * allowing multiple commands to propagate all the way to a SCSI-II device
+ * while a command is already executing.
+ *
+- * To solve the multiple-boards-in-the-same-system problem,
++ * To solve the multiple-boards-in-the-same-system problem,
+ * there is a separate instance structure for each instance
+ * of a 5380 in the system. So, multiple NCR5380 drivers will
+ * be able to coexist with appropriate changes to the high level
+- * SCSI code.
++ * SCSI code.
+ *
+ * A NCR5380_PUBLIC_REVISION macro is provided, with the release
+- * number (updated for each public release) printed by the
+- * NCR5380_print_options command, which should be called from the
++ * number (updated for each public release) printed by the
++ * NCR5380_print_options command, which should be called from the
+ * wrapper detect function, so that I know what release of the driver
+ * users are using.
+ *
+- * Issues specific to the NCR5380 :
++ * Issues specific to the NCR5380 :
+ *
+- * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead
+- * piece of hardware that requires you to sit in a loop polling for
+- * the REQ signal as long as you are connected. Some devices are
+- * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect
++ * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead
++ * piece of hardware that requires you to sit in a loop polling for
++ * the REQ signal as long as you are connected. Some devices are
++ * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect
+ * while doing long seek operations.
+- *
++ *
+ * The workaround for this is to keep track of devices that have
+ * disconnected. If the device hasn't disconnected, for commands that
+- * should disconnect, we do something like
++ * should disconnect, we do something like
+ *
+ * while (!REQ is asserted) { sleep for N usecs; poll for M usecs }
+- *
+- * Some tweaking of N and M needs to be done. An algorithm based
++ *
++ * Some tweaking of N and M needs to be done. An algorithm based
+ * on "time to data" would give the best results as long as short time
+- * to datas (ie, on the same track) were considered, however these
++ * to datas (ie, on the same track) were considered, however these
+ * broken devices are the exception rather than the rule and I'd rather
+ * spend my time optimizing for the normal case.
+ *
+@@ -167,9 +175,9 @@
+ * At the heart of the design is a coroutine, NCR5380_main,
+ * which is started when not running by the interrupt handler,
+ * timer, and queue command function. It attempts to establish
+- * I_T_L or I_T_L_Q nexuses by removing the commands from the
+- * issue queue and calling NCR5380_select() if a nexus
+- * is not established.
++ * I_T_L or I_T_L_Q nexuses by removing the commands from the
++ * issue queue and calling NCR5380_select() if a nexus
++ * is not established.
+ *
+ * Once a nexus is established, the NCR5380_information_transfer()
+ * phase goes through the various phases as instructed by the target.
+@@ -183,10 +191,10 @@
+ * calling NCR5380_intr() which will in turn call NCR5380_reselect
+ * to reestablish a nexus. This will run main if necessary.
+ *
+- * On command termination, the done function will be called as
++ * On command termination, the done function will be called as
+ * appropriate.
+ *
+- * SCSI pointers are maintained in the SCp field of SCSI command
++ * SCSI pointers are maintained in the SCp field of SCSI command
+ * structures, being initialized after the command is connected
+ * in NCR5380_select, and set as appropriate in NCR5380_information_transfer.
+ * Note that in violation of the standard, an implicit SAVE POINTERS operation
+@@ -196,12 +204,12 @@
+ /*
+ * Using this file :
+ * This file a skeleton Linux SCSI driver for the NCR 5380 series
+- * of chips. To use it, you write an architecture specific functions
++ * of chips. To use it, you write an architecture specific functions
+ * and macros and include this file in your driver.
+ *
+- * These macros control options :
++ * These macros control options :
+ * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
+- * for commands that return with a CHECK CONDITION status.
++ * for commands that return with a CHECK CONDITION status.
+ *
+ * LINKED - if defined, linked commands are supported.
+ *
+@@ -210,18 +218,18 @@
+ * SUPPORT_TAGS - if defined, SCSI-2 tagged queuing is used where possible
+ *
+ * These macros MUST be defined :
+- *
++ *
+ * NCR5380_read(register) - read from the specified register
+ *
+- * NCR5380_write(register, value) - write to the specific register
++ * NCR5380_write(register, value) - write to the specific register
+ *
+ * Either real DMA *or* pseudo DMA may be implemented
+- * REAL functions :
++ * REAL functions :
+ * NCR5380_REAL_DMA should be defined if real DMA is to be used.
+- * Note that the DMA setup functions should return the number of bytes
++ * Note that the DMA setup functions should return the number of bytes
+ * that they were able to program the controller for.
+ *
+- * Also note that generic i386/PC versions of these macros are
++ * Also note that generic i386/PC versions of these macros are
+ * available as NCR5380_i386_dma_write_setup,
+ * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
+ *
+@@ -234,14 +242,14 @@
+ * NCR5380_pread(instance, dst, count);
+ *
+ * If nothing specific to this implementation needs doing (ie, with external
+- * hardware), you must also define
+- *
++ * hardware), you must also define
++ *
+ * NCR5380_queue_command
+ * NCR5380_reset
+ * NCR5380_abort
+ * NCR5380_proc_info
+ *
+- * to be the global entry points into the specific driver, ie
++ * to be the global entry points into the specific driver, ie
+ * #define NCR5380_queue_command t128_queue_command.
+ *
+ * If this is not done, the routines will be defined as static functions
+@@ -249,7 +257,7 @@
+ * accessible wrapper function.
+ *
+ * The generic driver is initialized by calling NCR5380_init(instance),
+- * after setting the appropriate host specific fields and ID. If the
++ * after setting the appropriate host specific fields and ID. If the
+ * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance,
+ * possible) function may be used. Before the specific driver initialization
+ * code finishes, NCR5380_print_options should be called.
+@@ -312,34 +320,34 @@ static struct scsi_host_template *the_te
+ #define TAG_NONE 0xff
+
+ typedef struct {
+- DECLARE_BITMAP(allocated, MAX_TAGS);
+- int nr_allocated;
+- int queue_size;
++ DECLARE_BITMAP(allocated, MAX_TAGS);
++ int nr_allocated;
++ int queue_size;
+ } TAG_ALLOC;
+
+-static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */
++static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */
+
+
+-static void __init init_tags( void )
++static void __init init_tags(void)
+ {
+- int target, lun;
+- TAG_ALLOC *ta;
+-
+- if (!setup_use_tagged_queuing)
+- return;
+-
+- for( target = 0; target < 8; ++target ) {
+- for( lun = 0; lun < 8; ++lun ) {
+- ta = &TagAlloc[target][lun];
+- bitmap_zero(ta->allocated, MAX_TAGS);
+- ta->nr_allocated = 0;
+- /* At the beginning, assume the maximum queue size we could
+- * support (MAX_TAGS). This value will be decreased if the target
+- * returns QUEUE_FULL status.
+- */
+- ta->queue_size = MAX_TAGS;
++ int target, lun;
++ TAG_ALLOC *ta;
++
++ if (!setup_use_tagged_queuing)
++ return;
++
++ for (target = 0; target < 8; ++target) {
++ for (lun = 0; lun < 8; ++lun) {
++ ta = &TagAlloc[target][lun];
++ bitmap_zero(ta->allocated, MAX_TAGS);
++ ta->nr_allocated = 0;
++ /* At the beginning, assume the maximum queue size we could
++ * support (MAX_TAGS). This value will be decreased if the target
++ * returns QUEUE_FULL status.
++ */
++ ta->queue_size = MAX_TAGS;
++ }
+ }
+- }
+ }
+
+
+@@ -348,24 +356,24 @@ static void __init init_tags( void )
+ * check that there is a free tag and the target's queue won't overflow. This
+ * function should be called with interrupts disabled to avoid race
+ * conditions.
+- */
++ */
+
+-static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged )
++static int is_lun_busy(Scsi_Cmnd *cmd, int should_be_tagged)
+ {
+- SETUP_HOSTDATA(cmd->device->host);
++ SETUP_HOSTDATA(cmd->device->host);
+
+- if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun))
+- return( 1 );
+- if (!should_be_tagged ||
+- !setup_use_tagged_queuing || !cmd->device->tagged_supported)
+- return( 0 );
+- if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >=
+- TagAlloc[cmd->device->id][cmd->device->lun].queue_size ) {
+- TAG_PRINTK( "scsi%d: target %d lun %d: no free tags\n",
+- H_NO(cmd), cmd->device->id, cmd->device->lun );
+- return( 1 );
+- }
+- return( 0 );
++ if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun))
++ return 1;
++ if (!should_be_tagged ||
++ !setup_use_tagged_queuing || !cmd->device->tagged_supported)
++ return 0;
++ if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >=
++ TagAlloc[cmd->device->id][cmd->device->lun].queue_size) {
++ TAG_PRINTK("scsi%d: target %d lun %d: no free tags\n",
++ H_NO(cmd), cmd->device->id, cmd->device->lun);
++ return 1;
++ }
++ return 0;
+ }
+
+
+@@ -374,31 +382,30 @@ static int is_lun_busy( Scsi_Cmnd *cmd,
+ * untagged.
+ */
+
+-static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged )
++static void cmd_get_tag(Scsi_Cmnd *cmd, int should_be_tagged)
+ {
+- SETUP_HOSTDATA(cmd->device->host);
++ SETUP_HOSTDATA(cmd->device->host);
+
+- /* If we or the target don't support tagged queuing, allocate the LUN for
+- * an untagged command.
+- */
+- if (!should_be_tagged ||
+- !setup_use_tagged_queuing || !cmd->device->tagged_supported) {
+- cmd->tag = TAG_NONE;
+- hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+- TAG_PRINTK( "scsi%d: target %d lun %d now allocated by untagged "
+- "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun );
+- }
+- else {
+- TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
+-
+- cmd->tag = find_first_zero_bit( ta->allocated, MAX_TAGS );
+- set_bit( cmd->tag, ta->allocated );
+- ta->nr_allocated++;
+- TAG_PRINTK( "scsi%d: using tag %d for target %d lun %d "
+- "(now %d tags in use)\n",
+- H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun,
+- ta->nr_allocated );
+- }
++ /* If we or the target don't support tagged queuing, allocate the LUN for
++ * an untagged command.
++ */
++ if (!should_be_tagged ||
++ !setup_use_tagged_queuing || !cmd->device->tagged_supported) {
++ cmd->tag = TAG_NONE;
++ hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
++ TAG_PRINTK("scsi%d: target %d lun %d now allocated by untagged "
++ "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun);
++ } else {
++ TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
++
++ cmd->tag = find_first_zero_bit(ta->allocated, MAX_TAGS);
++ set_bit(cmd->tag, ta->allocated);
++ ta->nr_allocated++;
++ TAG_PRINTK("scsi%d: using tag %d for target %d lun %d "
++ "(now %d tags in use)\n",
++ H_NO(cmd), cmd->tag, cmd->device->id,
++ cmd->device->lun, ta->nr_allocated);
++ }
+ }
+
+
+@@ -406,44 +413,42 @@ static void cmd_get_tag( Scsi_Cmnd *cmd,
+ * unlock the LUN.
+ */
+
+-static void cmd_free_tag( Scsi_Cmnd *cmd )
++static void cmd_free_tag(Scsi_Cmnd *cmd)
+ {
+- SETUP_HOSTDATA(cmd->device->host);
++ SETUP_HOSTDATA(cmd->device->host);
+
+- if (cmd->tag == TAG_NONE) {
+- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+- TAG_PRINTK( "scsi%d: target %d lun %d untagged cmd finished\n",
+- H_NO(cmd), cmd->device->id, cmd->device->lun );
+- }
+- else if (cmd->tag >= MAX_TAGS) {
+- printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
+- H_NO(cmd), cmd->tag );
+- }
+- else {
+- TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
+- clear_bit( cmd->tag, ta->allocated );
+- ta->nr_allocated--;
+- TAG_PRINTK( "scsi%d: freed tag %d for target %d lun %d\n",
+- H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun );
+- }
++ if (cmd->tag == TAG_NONE) {
++ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
++ TAG_PRINTK("scsi%d: target %d lun %d untagged cmd finished\n",
++ H_NO(cmd), cmd->device->id, cmd->device->lun);
++ } else if (cmd->tag >= MAX_TAGS) {
++ printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
++ H_NO(cmd), cmd->tag);
++ } else {
++ TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
++ clear_bit(cmd->tag, ta->allocated);
++ ta->nr_allocated--;
++ TAG_PRINTK("scsi%d: freed tag %d for target %d lun %d\n",
++ H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun);
++ }
+ }
+
+
+-static void free_all_tags( void )
+-{
+- int target, lun;
+- TAG_ALLOC *ta;
+-
+- if (!setup_use_tagged_queuing)
+- return;
+-
+- for( target = 0; target < 8; ++target ) {
+- for( lun = 0; lun < 8; ++lun ) {
+- ta = &TagAlloc[target][lun];
+- bitmap_zero(ta->allocated, MAX_TAGS);
+- ta->nr_allocated = 0;
++static void free_all_tags(void)
++{
++ int target, lun;
++ TAG_ALLOC *ta;
++
++ if (!setup_use_tagged_queuing)
++ return;
++
++ for (target = 0; target < 8; ++target) {
++ for (lun = 0; lun < 8; ++lun) {
++ ta = &TagAlloc[target][lun];
++ bitmap_zero(ta->allocated, MAX_TAGS);
++ ta->nr_allocated = 0;
++ }
+ }
+- }
+ }
+
+ #endif /* SUPPORT_TAGS */
+@@ -461,89 +466,94 @@ static void free_all_tags( void )
+ * assumed to be already transfered into ptr/this_residual.
+ */
+
+-static void merge_contiguous_buffers( Scsi_Cmnd *cmd )
++static void merge_contiguous_buffers(Scsi_Cmnd *cmd)
+ {
+- unsigned long endaddr;
++ unsigned long endaddr;
+ #if (NDEBUG & NDEBUG_MERGING)
+- unsigned long oldlen = cmd->SCp.this_residual;
+- int cnt = 1;
++ unsigned long oldlen = cmd->SCp.this_residual;
++ int cnt = 1;
+ #endif
+
+- for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1;
+- cmd->SCp.buffers_residual &&
+- virt_to_phys(page_address(cmd->SCp.buffer[1].page)+
+- cmd->SCp.buffer[1].offset) == endaddr; ) {
+- MER_PRINTK("VTOP(%p) == %08lx -> merging\n",
+- cmd->SCp.buffer[1].address, endaddr);
++ for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1;
++ cmd->SCp.buffers_residual &&
++ virt_to_phys(page_address(cmd->SCp.buffer[1].page) +
++ cmd->SCp.buffer[1].offset) == endaddr;) {
++ MER_PRINTK("VTOP(%p) == %08lx -> merging\n",
++ cmd->SCp.buffer[1].address, endaddr);
+ #if (NDEBUG & NDEBUG_MERGING)
+- ++cnt;
++ ++cnt;
+ #endif
+- ++cmd->SCp.buffer;
+- --cmd->SCp.buffers_residual;
+- cmd->SCp.this_residual += cmd->SCp.buffer->length;
+- endaddr += cmd->SCp.buffer->length;
+- }
++ ++cmd->SCp.buffer;
++ --cmd->SCp.buffers_residual;
++ cmd->SCp.this_residual += cmd->SCp.buffer->length;
++ endaddr += cmd->SCp.buffer->length;
++ }
+ #if (NDEBUG & NDEBUG_MERGING)
+- if (oldlen != cmd->SCp.this_residual)
+- MER_PRINTK("merged %d buffers from %p, new length %08x\n",
+- cnt, cmd->SCp.ptr, cmd->SCp.this_residual);
++ if (oldlen != cmd->SCp.this_residual)
++ MER_PRINTK("merged %d buffers from %p, new length %08x\n",
++ cnt, cmd->SCp.ptr, cmd->SCp.this_residual);
+ #endif
+ }
+
+ /*
+ * Function : void initialize_SCp(Scsi_Cmnd *cmd)
+ *
+- * Purpose : initialize the saved data pointers for cmd to point to the
++ * Purpose : initialize the saved data pointers for cmd to point to the
+ * start of the buffer.
+ *
+ * Inputs : cmd - Scsi_Cmnd structure to have pointers reset.
+ */
+
+-static __inline__ void initialize_SCp(Scsi_Cmnd *cmd)
++static inline void initialize_SCp(Scsi_Cmnd *cmd)
+ {
+- /*
+- * Initialize the Scsi Pointer field so that all of the commands in the
+- * various queues are valid.
+- */
+-
+- if (cmd->use_sg) {
+- cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
+- cmd->SCp.buffers_residual = cmd->use_sg - 1;
+- cmd->SCp.ptr = (char *)page_address(cmd->SCp.buffer->page)+
+- cmd->SCp.buffer->offset;
+- cmd->SCp.this_residual = cmd->SCp.buffer->length;
+- /* ++roman: Try to merge some scatter-buffers if they are at
+- * contiguous physical addresses.
+- */
+- merge_contiguous_buffers( cmd );
+- } else {
+- cmd->SCp.buffer = NULL;
+- cmd->SCp.buffers_residual = 0;
+- cmd->SCp.ptr = (char *) cmd->request_buffer;
+- cmd->SCp.this_residual = cmd->request_bufflen;
+- }
++ /*
++ * Initialize the Scsi Pointer field so that all of the commands in the
++ * various queues are valid.
++ */
++
++ if (cmd->use_sg) {
++ cmd->SCp.buffer = (struct scatterlist *)cmd->request_buffer;
++ cmd->SCp.buffers_residual = cmd->use_sg - 1;
++ cmd->SCp.ptr = (char *)page_address(cmd->SCp.buffer->page) +
++ cmd->SCp.buffer->offset;
++ cmd->SCp.this_residual = cmd->SCp.buffer->length;
++ /* ++roman: Try to merge some scatter-buffers if they are at
++ * contiguous physical addresses.
++ */
++ merge_contiguous_buffers(cmd);
++ } else {
++ cmd->SCp.buffer = NULL;
++ cmd->SCp.buffers_residual = 0;
++ cmd->SCp.ptr = (char *)cmd->request_buffer;
++ cmd->SCp.this_residual = cmd->request_bufflen;
++ }
+ }
+
+ #include <linux/delay.h>
+
+ #if NDEBUG
+ static struct {
+- unsigned char mask;
+- const char * name;}
+-signals[] = {{ SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" },
+- { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD, "CD" }, { SR_IO, "IO" },
+- { SR_SEL, "SEL" }, {0, NULL}},
+-basrs[] = {{BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}},
+-icrs[] = {{ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"},
+- {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"},
+- {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"},
+- {0, NULL}},
+-mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"},
+- {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR,
+- "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"},
+- {MR_MONITOR_BSY, "MODE MONITOR BSY"},
+- {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"},
+- {0, NULL}};
++ unsigned char mask;
++ const char *name;
++} signals[] = {
++ { SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" },
++ { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD, "CD" }, { SR_IO, "IO" },
++ { SR_SEL, "SEL" }, {0, NULL}
++}, basrs[] = {
++ {BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}
++}, icrs[] = {
++ {ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"},
++ {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"},
++ {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"},
++ {0, NULL}
++}, mrs[] = {
++ {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"},
++ {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR,
++ "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"},
++ {MR_MONITOR_BSY, "MODE MONITOR BSY"},
++ {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"},
++ {0, NULL}
++};
+
+ /*
+ * Function : void NCR5380_print(struct Scsi_Host *instance)
+@@ -553,45 +563,47 @@ mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK
+ * Input : instance - which NCR5380
+ */
+
+-static void NCR5380_print(struct Scsi_Host *instance) {
+- unsigned char status, data, basr, mr, icr, i;
+- unsigned long flags;
+-
+- local_irq_save(flags);
+- data = NCR5380_read(CURRENT_SCSI_DATA_REG);
+- status = NCR5380_read(STATUS_REG);
+- mr = NCR5380_read(MODE_REG);
+- icr = NCR5380_read(INITIATOR_COMMAND_REG);
+- basr = NCR5380_read(BUS_AND_STATUS_REG);
+- local_irq_restore(flags);
+- printk("STATUS_REG: %02x ", status);
+- for (i = 0; signals[i].mask ; ++i)
+- if (status & signals[i].mask)
+- printk(",%s", signals[i].name);
+- printk("\nBASR: %02x ", basr);
+- for (i = 0; basrs[i].mask ; ++i)
+- if (basr & basrs[i].mask)
+- printk(",%s", basrs[i].name);
+- printk("\nICR: %02x ", icr);
+- for (i = 0; icrs[i].mask; ++i)
+- if (icr & icrs[i].mask)
+- printk(",%s", icrs[i].name);
+- printk("\nMODE: %02x ", mr);
+- for (i = 0; mrs[i].mask; ++i)
+- if (mr & mrs[i].mask)
+- printk(",%s", mrs[i].name);
+- printk("\n");
++static void NCR5380_print(struct Scsi_Host *instance)
++{
++ unsigned char status, data, basr, mr, icr, i;
++ unsigned long flags;
++
++ local_irq_save(flags);
++ data = NCR5380_read(CURRENT_SCSI_DATA_REG);
++ status = NCR5380_read(STATUS_REG);
++ mr = NCR5380_read(MODE_REG);
++ icr = NCR5380_read(INITIATOR_COMMAND_REG);
++ basr = NCR5380_read(BUS_AND_STATUS_REG);
++ local_irq_restore(flags);
++ printk("STATUS_REG: %02x ", status);
++ for (i = 0; signals[i].mask; ++i)
++ if (status & signals[i].mask)
++ printk(",%s", signals[i].name);
++ printk("\nBASR: %02x ", basr);
++ for (i = 0; basrs[i].mask; ++i)
++ if (basr & basrs[i].mask)
++ printk(",%s", basrs[i].name);
++ printk("\nICR: %02x ", icr);
++ for (i = 0; icrs[i].mask; ++i)
++ if (icr & icrs[i].mask)
++ printk(",%s", icrs[i].name);
++ printk("\nMODE: %02x ", mr);
++ for (i = 0; mrs[i].mask; ++i)
++ if (mr & mrs[i].mask)
++ printk(",%s", mrs[i].name);
++ printk("\n");
+ }
+
+ static struct {
+- unsigned char value;
+- const char *name;
++ unsigned char value;
++ const char *name;
+ } phases[] = {
+- {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"},
+- {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"},
+- {PHASE_UNKNOWN, "UNKNOWN"}};
++ {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"},
++ {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"},
++ {PHASE_UNKNOWN, "UNKNOWN"}
++};
+
+-/*
++/*
+ * Function : void NCR5380_print_phase(struct Scsi_Host *instance)
+ *
+ * Purpose : print the current SCSI phase for debugging purposes
+@@ -601,30 +613,35 @@ static struct {
+
+ static void NCR5380_print_phase(struct Scsi_Host *instance)
+ {
+- unsigned char status;
+- int i;
++ unsigned char status;
++ int i;
+
+- status = NCR5380_read(STATUS_REG);
+- if (!(status & SR_REQ))
+- printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
+- else {
+- for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&
+- (phases[i].value != (status & PHASE_MASK)); ++i);
+- printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name);
+- }
++ status = NCR5380_read(STATUS_REG);
++ if (!(status & SR_REQ))
++ printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
++ else {
++ for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&
++ (phases[i].value != (status & PHASE_MASK)); ++i)
++ ;
++ printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name);
++ }
+ }
+
+ #else /* !NDEBUG */
+
+ /* dummies... */
+-__inline__ void NCR5380_print(struct Scsi_Host *instance) { };
+-__inline__ void NCR5380_print_phase(struct Scsi_Host *instance) { };
++static inline void NCR5380_print(struct Scsi_Host *instance)
++{
++};
++static inline void NCR5380_print_phase(struct Scsi_Host *instance)
++{
++};
+
+ #endif
+
+ /*
+ * ++roman: New scheme of calling NCR5380_main()
+- *
++ *
+ * If we're not in an interrupt, we can call our main directly, it cannot be
+ * already running. Else, we queue it on a task queue, if not 'main_running'
+ * tells us that a lower level is already executing it. This way,
+@@ -638,33 +655,33 @@ __inline__ void NCR5380_print_phase(stru
+ #include <linux/workqueue.h>
+ #include <linux/interrupt.h>
+
+-static volatile int main_running = 0;
+-static DECLARE_WORK(NCR5380_tqueue, (void (*)(void*))NCR5380_main, NULL);
++static volatile int main_running;
++static DECLARE_WORK(NCR5380_tqueue, (void (*)(void *))NCR5380_main, NULL);
+
+-static __inline__ void queue_main(void)
++static inline void queue_main(void)
+ {
+- if (!main_running) {
+- /* If in interrupt and NCR5380_main() not already running,
+- queue it on the 'immediate' task queue, to be processed
+- immediately after the current interrupt processing has
+- finished. */
+- schedule_work(&NCR5380_tqueue);
+- }
+- /* else: nothing to do: the running NCR5380_main() will pick up
+- any newly queued command. */
++ if (!main_running) {
++ /* If in interrupt and NCR5380_main() not already running,
++ queue it on the 'immediate' task queue, to be processed
++ immediately after the current interrupt processing has
++ finished. */
++ schedule_work(&NCR5380_tqueue);
++ }
++ /* else: nothing to do: the running NCR5380_main() will pick up
++ any newly queued command. */
+ }
+
+
+-static inline void NCR5380_all_init (void)
++static inline void NCR5380_all_init(void)
+ {
+- static int done = 0;
+- if (!done) {
+- INI_PRINTK("scsi : NCR5380_all_init()\n");
+- done = 1;
+- }
++ static int done = 0;
++ if (!done) {
++ INI_PRINTK("scsi : NCR5380_all_init()\n");
++ done = 1;
++ }
+ }
+
+-
++
+ /*
+ * Function : void NCR58380_print_options (struct Scsi_Host *instance)
+ *
+@@ -674,23 +691,23 @@ static inline void NCR5380_all_init (voi
+ * Inputs : instance, pointer to this instance. Unused.
+ */
+
+-static void __init NCR5380_print_options (struct Scsi_Host *instance)
++static void __init NCR5380_print_options(struct Scsi_Host *instance)
+ {
+- printk(" generic options"
+-#ifdef AUTOSENSE
+- " AUTOSENSE"
++ printk(" generic options"
++#ifdef AUTOSENSE
++ " AUTOSENSE"
+ #endif
+ #ifdef REAL_DMA
+- " REAL DMA"
++ " REAL DMA"
+ #endif
+ #ifdef PARITY
+- " PARITY"
++ " PARITY"
+ #endif
+ #ifdef SUPPORT_TAGS
+- " SCSI-2 TAGGED QUEUING"
++ " SCSI-2 TAGGED QUEUING"
+ #endif
+- );
+- printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);
++ );
++ printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);
+ }
+
+ /*
+@@ -699,27 +716,27 @@ static void __init NCR5380_print_options
+ * Purpose : print commands in the various queues, called from
+ * NCR5380_abort and NCR5380_debug to aid debugging.
+ *
+- * Inputs : instance, pointer to this instance.
++ * Inputs : instance, pointer to this instance.
+ */
+
+-static void NCR5380_print_status (struct Scsi_Host *instance)
++static void NCR5380_print_status(struct Scsi_Host *instance)
+ {
+- char *pr_bfr;
+- char *start;
+- int len;
+-
+- NCR_PRINT(NDEBUG_ANY);
+- NCR_PRINT_PHASE(NDEBUG_ANY);
+-
+- pr_bfr = (char *) __get_free_page(GFP_ATOMIC);
+- if (!pr_bfr) {
+- printk("NCR5380_print_status: no memory for print buffer\n");
+- return;
+- }
+- len = NCR5380_proc_info(instance, pr_bfr, &start, 0, PAGE_SIZE, 0);
+- pr_bfr[len] = 0;
+- printk("\n%s\n", pr_bfr);
+- free_page((unsigned long) pr_bfr);
++ char *pr_bfr;
++ char *start;
++ int len;
++
++ NCR_PRINT(NDEBUG_ANY);
++ NCR_PRINT_PHASE(NDEBUG_ANY);
++
++ pr_bfr = (char *)__get_free_page(GFP_ATOMIC);
++ if (!pr_bfr) {
++ printk("NCR5380_print_status: no memory for print buffer\n");
++ return;
++ }
++ len = NCR5380_proc_info(instance, pr_bfr, &start, 0, PAGE_SIZE, 0);
++ pr_bfr[len] = 0;
++ printk("\n%s\n", pr_bfr);
++ free_page((unsigned long)pr_bfr);
+ }
+
+
+@@ -738,146 +755,144 @@ static void NCR5380_print_status (struct
+ */
+
+ #undef SPRINTF
+-#define SPRINTF(fmt,args...) \
+- do { if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \
+- pos += sprintf(pos, fmt , ## args); } while(0)
+-static
+-char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length);
+-
+-static
+-int NCR5380_proc_info (struct Scsi_Host *instance, char *buffer, char **start, off_t offset,
+- int length, int inout)
+-{
+- char *pos = buffer;
+- struct NCR5380_hostdata *hostdata;
+- Scsi_Cmnd *ptr;
+- unsigned long flags;
+- off_t begin = 0;
+-#define check_offset() \
+- do { \
+- if (pos - buffer < offset - begin) { \
+- begin += pos - buffer; \
+- pos = buffer; \
+- } \
+- } while (0)
+-
+- hostdata = (struct NCR5380_hostdata *)instance->hostdata;
+-
+- if (inout) { /* Has data been written to the file ? */
+- return(-ENOSYS); /* Currently this is a no-op */
+- }
+- SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
+- check_offset();
+- local_irq_save(flags);
+- SPRINTF("NCR5380: coroutine is%s running.\n", main_running ? "" : "n't");
+- check_offset();
+- if (!hostdata->connected)
+- SPRINTF("scsi%d: no currently connected command\n", HOSTNO);
+- else
+- pos = lprint_Scsi_Cmnd ((Scsi_Cmnd *) hostdata->connected,
+- pos, buffer, length);
+- SPRINTF("scsi%d: issue_queue\n", HOSTNO);
+- check_offset();
+- for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = NEXT(ptr)) {
+- pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
++#define SPRINTF(fmt,args...) \
++ do { \
++ if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \
++ pos += sprintf(pos, fmt , ## args); \
++ } while(0)
++static char *lprint_Scsi_Cmnd(Scsi_Cmnd *cmd, char *pos, char *buffer, int length);
++
++static int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer,
++ char **start, off_t offset, int length, int inout)
++{
++ char *pos = buffer;
++ struct NCR5380_hostdata *hostdata;
++ Scsi_Cmnd *ptr;
++ unsigned long flags;
++ off_t begin = 0;
++#define check_offset() \
++ do { \
++ if (pos - buffer < offset - begin) { \
++ begin += pos - buffer; \
++ pos = buffer; \
++ } \
++ } while (0)
++
++ hostdata = (struct NCR5380_hostdata *)instance->hostdata;
++
++ if (inout) /* Has data been written to the file ? */
++ return -ENOSYS; /* Currently this is a no-op */
++ SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
+ check_offset();
+- }
+-
+- SPRINTF("scsi%d: disconnected_queue\n", HOSTNO);
+- check_offset();
+- for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
+- ptr = NEXT(ptr)) {
+- pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
++ local_irq_save(flags);
++ SPRINTF("NCR5380: coroutine is%s running.\n",
++ main_running ? "" : "n't");
+ check_offset();
+- }
++ if (!hostdata->connected)
++ SPRINTF("scsi%d: no currently connected command\n", HOSTNO);
++ else
++ pos = lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected,
++ pos, buffer, length);
++ SPRINTF("scsi%d: issue_queue\n", HOSTNO);
++ check_offset();
++ for (ptr = (Scsi_Cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr)) {
++ pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length);
++ check_offset();
++ }
+
+- local_irq_restore(flags);
+- *start = buffer + (offset - begin);
+- if (pos - buffer < offset - begin)
+- return 0;
+- else if (pos - buffer - (offset - begin) < length)
+- return pos - buffer - (offset - begin);
+- return length;
+-}
++ SPRINTF("scsi%d: disconnected_queue\n", HOSTNO);
++ check_offset();
++ for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
++ ptr = NEXT(ptr)) {
++ pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length);
++ check_offset();
++ }
+
+-static char *
+-lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
+-{
+- int i, s;
+- unsigned char *command;
+- SPRINTF("scsi%d: destination target %d, lun %d\n",
+- H_NO(cmd), cmd->device->id, cmd->device->lun);
+- SPRINTF(" command = ");
+- command = cmd->cmnd;
+- SPRINTF("%2d (0x%02x)", command[0], command[0]);
+- for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
+- SPRINTF(" %02x", command[i]);
+- SPRINTF("\n");
+- return pos;
++ local_irq_restore(flags);
++ *start = buffer + (offset - begin);
++ if (pos - buffer < offset - begin)
++ return 0;
++ else if (pos - buffer - (offset - begin) < length)
++ return pos - buffer - (offset - begin);
++ return length;
++}
++
++static char *lprint_Scsi_Cmnd(Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
++{
++ int i, s;
++ unsigned char *command;
++ SPRINTF("scsi%d: destination target %d, lun %d\n",
++ H_NO(cmd), cmd->device->id, cmd->device->lun);
++ SPRINTF(" command = ");
++ command = cmd->cmnd;
++ SPRINTF("%2d (0x%02x)", command[0], command[0]);
++ for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
++ SPRINTF(" %02x", command[i]);
++ SPRINTF("\n");
++ return pos;
+ }
+
+
+-/*
++/*
+ * Function : void NCR5380_init (struct Scsi_Host *instance)
+ *
+ * Purpose : initializes *instance and corresponding 5380 chip.
+ *
+- * Inputs : instance - instantiation of the 5380 driver.
++ * Inputs : instance - instantiation of the 5380 driver.
+ *
+ * Notes : I assume that the host, hostno, and id bits have been
+- * set correctly. I don't care about the irq and other fields.
+- *
++ * set correctly. I don't care about the irq and other fields.
++ *
+ */
+
+-static int NCR5380_init (struct Scsi_Host *instance, int flags)
++static int NCR5380_init(struct Scsi_Host *instance, int flags)
+ {
+- int i;
+- SETUP_HOSTDATA(instance);
++ int i;
++ SETUP_HOSTDATA(instance);
+
+- NCR5380_all_init();
++ NCR5380_all_init();
+
+- hostdata->aborted = 0;
+- hostdata->id_mask = 1 << instance->this_id;
+- hostdata->id_higher_mask = 0;
+- for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
+- if (i > hostdata->id_mask)
+- hostdata->id_higher_mask |= i;
+- for (i = 0; i < 8; ++i)
+- hostdata->busy[i] = 0;
++ hostdata->aborted = 0;
++ hostdata->id_mask = 1 << instance->this_id;
++ hostdata->id_higher_mask = 0;
++ for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
++ if (i > hostdata->id_mask)
++ hostdata->id_higher_mask |= i;
++ for (i = 0; i < 8; ++i)
++ hostdata->busy[i] = 0;
+ #ifdef SUPPORT_TAGS
+- init_tags();
++ init_tags();
+ #endif
+ #if defined (REAL_DMA)
+- hostdata->dma_len = 0;
++ hostdata->dma_len = 0;
+ #endif
+- hostdata->targets_present = 0;
+- hostdata->connected = NULL;
+- hostdata->issue_queue = NULL;
+- hostdata->disconnected_queue = NULL;
+- hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT;
+-
+- if (!the_template) {
+- the_template = instance->hostt;
+- first_instance = instance;
+- }
+-
++ hostdata->targets_present = 0;
++ hostdata->connected = NULL;
++ hostdata->issue_queue = NULL;
++ hostdata->disconnected_queue = NULL;
++ hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT;
++
++ if (!the_template) {
++ the_template = instance->hostt;
++ first_instance = instance;
++ }
+
+ #ifndef AUTOSENSE
+- if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1))
+- printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n"
+- " without AUTOSENSE option, contingent allegiance conditions may\n"
+- " be incorrectly cleared.\n", HOSTNO);
++ if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1))
++ printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n"
++ " without AUTOSENSE option, contingent allegiance conditions may\n"
++ " be incorrectly cleared.\n", HOSTNO);
+ #endif /* def AUTOSENSE */
+
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+- NCR5380_write(MODE_REG, MR_BASE);
+- NCR5380_write(TARGET_COMMAND_REG, 0);
+- NCR5380_write(SELECT_ENABLE_REG, 0);
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
++ NCR5380_write(MODE_REG, MR_BASE);
++ NCR5380_write(TARGET_COMMAND_REG, 0);
++ NCR5380_write(SELECT_ENABLE_REG, 0);
+
+- return 0;
++ return 0;
+ }
+
+-/*
++/*
+ * our own old-style timeout update
+ */
+ /*
+@@ -890,331 +905,328 @@ static int NCR5380_init (struct Scsi_Hos
+
+ int atari_scsi_update_timeout(Scsi_Cmnd * SCset, int timeout)
+ {
+- int rtn;
++ int rtn;
+
+- /*
+- * We are using the new error handling code to actually register/deregister
+- * timers for timeout.
+- */
+-
+- if (!timer_pending(&SCset->eh_timeout)) {
+- rtn = 0;
+- } else {
+- rtn = SCset->eh_timeout.expires - jiffies;
+- }
+-
+- if (timeout == 0) {
+- del_timer(&SCset->eh_timeout);
+- SCset->eh_timeout.data = (unsigned long) NULL;
+- SCset->eh_timeout.expires = 0;
+- } else {
+- if (SCset->eh_timeout.data != (unsigned long) NULL)
+- del_timer(&SCset->eh_timeout);
+- SCset->eh_timeout.data = (unsigned long) SCset;
+- SCset->eh_timeout.expires = jiffies + timeout;
+- add_timer(&SCset->eh_timeout);
+- }
++ /*
++ * We are using the new error handling code to actually register/deregister
++ * timers for timeout.
++ */
++
++ if (!timer_pending(&SCset->eh_timeout))
++ rtn = 0;
++ else
++ rtn = SCset->eh_timeout.expires - jiffies;
++
++ if (timeout == 0) {
++ del_timer(&SCset->eh_timeout);
++ SCset->eh_timeout.data = (unsigned long)NULL;
++ SCset->eh_timeout.expires = 0;
++ } else {
++ if (SCset->eh_timeout.data != (unsigned long)NULL)
++ del_timer(&SCset->eh_timeout);
++ SCset->eh_timeout.data = (unsigned long)SCset;
++ SCset->eh_timeout.expires = jiffies + timeout;
++ add_timer(&SCset->eh_timeout);
++ }
+ return rtn;
+ }
+
+-/*
+- * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd,
+- * void (*done)(Scsi_Cmnd *))
++/*
++ * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd,
++ * void (*done)(Scsi_Cmnd *))
+ *
+ * Purpose : enqueues a SCSI command
+ *
+ * Inputs : cmd - SCSI command, done - function called on completion, with
+ * a pointer to the command descriptor.
+- *
++ *
+ * Returns : 0
+ *
+- * Side effects :
+- * cmd is added to the per instance issue_queue, with minor
+- * twiddling done to the host specific fields of cmd. If the
++ * Side effects :
++ * cmd is added to the per instance issue_queue, with minor
++ * twiddling done to the host specific fields of cmd. If the
+ * main coroutine is not running, it is restarted.
+ *
+ */
+
+-static
+-int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
++static int NCR5380_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+ {
+- SETUP_HOSTDATA(cmd->device->host);
+- Scsi_Cmnd *tmp;
+- int oldto;
+- unsigned long flags;
+- // extern int update_timeout(Scsi_Cmnd * SCset, int timeout);
++ SETUP_HOSTDATA(cmd->device->host);
++ Scsi_Cmnd *tmp;
++ int oldto;
++ unsigned long flags;
++ // extern int update_timeout(Scsi_Cmnd * SCset, int timeout);
+
+ #if (NDEBUG & NDEBUG_NO_WRITE)
+- switch (cmd->cmnd[0]) {
+- case WRITE_6:
+- case WRITE_10:
+- printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
+- H_NO(cmd));
+- cmd->result = (DID_ERROR << 16);
+- done(cmd);
+- return 0;
+- }
++ switch (cmd->cmnd[0]) {
++ case WRITE_6:
++ case WRITE_10:
++ printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
++ H_NO(cmd));
++ cmd->result = (DID_ERROR << 16);
++ done(cmd);
++ return 0;
++ }
+ #endif /* (NDEBUG & NDEBUG_NO_WRITE) */
+
+-
+ #ifdef NCR5380_STATS
+ # if 0
+- if (!hostdata->connected && !hostdata->issue_queue &&
+- !hostdata->disconnected_queue) {
+- hostdata->timebase = jiffies;
+- }
++ if (!hostdata->connected && !hostdata->issue_queue &&
++ !hostdata->disconnected_queue) {
++ hostdata->timebase = jiffies;
++ }
+ # endif
+ # ifdef NCR5380_STAT_LIMIT
+- if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
++ if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+ # endif
+- switch (cmd->cmnd[0])
+- {
+- case WRITE:
+- case WRITE_6:
+- case WRITE_10:
+- hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
+- hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
+- hostdata->pendingw++;
+- break;
+- case READ:
+- case READ_6:
+- case READ_10:
+- hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
+- hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
+- hostdata->pendingr++;
+- break;
+- }
+-#endif
+-
+- /*
+- * We use the host_scribble field as a pointer to the next command
+- * in a queue
+- */
+-
+- NEXT(cmd) = NULL;
+- cmd->scsi_done = done;
+-
+- cmd->result = 0;
+-
+-
+- /*
+- * Insert the cmd into the issue queue. Note that REQUEST SENSE
+- * commands are added to the head of the queue since any command will
+- * clear the contingent allegiance condition that exists and the
+- * sense data is only guaranteed to be valid while the condition exists.
+- */
+-
+- local_irq_save(flags);
+- /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA.
+- * Otherwise a running NCR5380_main may steal the lock.
+- * Lock before actually inserting due to fairness reasons explained in
+- * atari_scsi.c. If we insert first, then it's impossible for this driver
+- * to release the lock.
+- * Stop timer for this command while waiting for the lock, or timeouts
+- * may happen (and they really do), and it's no good if the command doesn't
+- * appear in any of the queues.
+- * ++roman: Just disabling the NCR interrupt isn't sufficient here,
+- * because also a timer int can trigger an abort or reset, which would
+- * alter queues and touch the lock.
+- */
+- if (!IS_A_TT()) {
+- oldto = atari_scsi_update_timeout(cmd, 0);
+- falcon_get_lock();
+- atari_scsi_update_timeout(cmd, oldto);
+- }
+- if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+- LIST(cmd, hostdata->issue_queue);
+- NEXT(cmd) = hostdata->issue_queue;
+- hostdata->issue_queue = cmd;
+- } else {
+- for (tmp = (Scsi_Cmnd *)hostdata->issue_queue;
+- NEXT(tmp); tmp = NEXT(tmp))
+- ;
+- LIST(cmd, tmp);
+- NEXT(tmp) = cmd;
+- }
+- local_irq_restore(flags);
+-
+- QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd),
+- (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
+-
+- /* If queue_command() is called from an interrupt (real one or bottom
+- * half), we let queue_main() do the job of taking care about main. If it
+- * is already running, this is a no-op, else main will be queued.
+- *
+- * If we're not in an interrupt, we can call NCR5380_main()
+- * unconditionally, because it cannot be already running.
+- */
+- if (in_interrupt() || ((flags >> 8) & 7) >= 6)
+- queue_main();
+- else
+- NCR5380_main(NULL);
+- return 0;
+-}
+-
+-/*
+- * Function : NCR5380_main (void)
+- *
+- * Purpose : NCR5380_main is a coroutine that runs as long as more work can
+- * be done on the NCR5380 host adapters in a system. Both
+- * NCR5380_queue_command() and NCR5380_intr() will try to start it
++ switch (cmd->cmnd[0]) {
++ case WRITE:
++ case WRITE_6:
++ case WRITE_10:
++ hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
++ hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
++ hostdata->pendingw++;
++ break;
++ case READ:
++ case READ_6:
++ case READ_10:
++ hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
++ hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
++ hostdata->pendingr++;
++ break;
++ }
++#endif
++
++ /*
++ * We use the host_scribble field as a pointer to the next command
++ * in a queue
++ */
++
++ NEXT(cmd) = NULL;
++ cmd->scsi_done = done;
++
++ cmd->result = 0;
++
++ /*
++ * Insert the cmd into the issue queue. Note that REQUEST SENSE
++ * commands are added to the head of the queue since any command will
++ * clear the contingent allegiance condition that exists and the
++ * sense data is only guaranteed to be valid while the condition exists.
++ */
++
++ local_irq_save(flags);
++ /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA.
++ * Otherwise a running NCR5380_main may steal the lock.
++ * Lock before actually inserting due to fairness reasons explained in
++ * atari_scsi.c. If we insert first, then it's impossible for this driver
++ * to release the lock.
++ * Stop timer for this command while waiting for the lock, or timeouts
++ * may happen (and they really do), and it's no good if the command doesn't
++ * appear in any of the queues.
++ * ++roman: Just disabling the NCR interrupt isn't sufficient here,
++ * because also a timer int can trigger an abort or reset, which would
++ * alter queues and touch the lock.
++ */
++ if (!IS_A_TT()) {
++ oldto = atari_scsi_update_timeout(cmd, 0);
++ falcon_get_lock();
++ atari_scsi_update_timeout(cmd, oldto);
++ }
++ if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
++ LIST(cmd, hostdata->issue_queue);
++ NEXT(cmd) = hostdata->issue_queue;
++ hostdata->issue_queue = cmd;
++ } else {
++ for (tmp = (Scsi_Cmnd *)hostdata->issue_queue;
++ NEXT(tmp); tmp = NEXT(tmp))
++ ;
++ LIST(cmd, tmp);
++ NEXT(tmp) = cmd;
++ }
++ local_irq_restore(flags);
++
++ QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd),
++ (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
++
++ /* If queue_command() is called from an interrupt (real one or bottom
++ * half), we let queue_main() do the job of taking care about main. If it
++ * is already running, this is a no-op, else main will be queued.
++ *
++ * If we're not in an interrupt, we can call NCR5380_main()
++ * unconditionally, because it cannot be already running.
++ */
++ if (in_interrupt() || ((flags >> 8) & 7) >= 6)
++ queue_main();
++ else
++ NCR5380_main(NULL);
++ return 0;
++}
++
++/*
++ * Function : NCR5380_main (void)
++ *
++ * Purpose : NCR5380_main is a coroutine that runs as long as more work can
++ * be done on the NCR5380 host adapters in a system. Both
++ * NCR5380_queue_command() and NCR5380_intr() will try to start it
+ * in case it is not running.
+- *
+- * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should
++ *
++ * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should
+ * reenable them. This prevents reentrancy and kernel stack overflow.
+- */
+-
+-static void NCR5380_main (void *bl)
+-{
+- Scsi_Cmnd *tmp, *prev;
+- struct Scsi_Host *instance = first_instance;
+- struct NCR5380_hostdata *hostdata = HOSTDATA(instance);
+- int done;
+- unsigned long flags;
+-
+- /*
+- * We run (with interrupts disabled) until we're sure that none of
+- * the host adapters have anything that can be done, at which point
+- * we set main_running to 0 and exit.
+- *
+- * Interrupts are enabled before doing various other internal
+- * instructions, after we've decided that we need to run through
+- * the loop again.
+- *
+- * this should prevent any race conditions.
+- *
+- * ++roman: Just disabling the NCR interrupt isn't sufficient here,
+- * because also a timer int can trigger an abort or reset, which can
+- * alter queues and touch the Falcon lock.
+- */
+-
+- /* Tell int handlers main() is now already executing. Note that
+- no races are possible here. If an int comes in before
+- 'main_running' is set here, and queues/executes main via the
+- task queue, it doesn't do any harm, just this instance of main
+- won't find any work left to do. */
+- if (main_running)
+- return;
+- main_running = 1;
+-
+- local_save_flags(flags);
+- do {
+- local_irq_disable(); /* Freeze request queues */
+- done = 1;
+-
+- if (!hostdata->connected) {
+- MAIN_PRINTK( "scsi%d: not connected\n", HOSTNO );
+- /*
+- * Search through the issue_queue for a command destined
+- * for a target that's not busy.
+- */
++ */
++
++static void NCR5380_main(void *bl)
++{
++ Scsi_Cmnd *tmp, *prev;
++ struct Scsi_Host *instance = first_instance;
++ struct NCR5380_hostdata *hostdata = HOSTDATA(instance);
++ int done;
++ unsigned long flags;
++
++ /*
++ * We run (with interrupts disabled) until we're sure that none of
++ * the host adapters have anything that can be done, at which point
++ * we set main_running to 0 and exit.
++ *
++ * Interrupts are enabled before doing various other internal
++ * instructions, after we've decided that we need to run through
++ * the loop again.
++ *
++ * this should prevent any race conditions.
++ *
++ * ++roman: Just disabling the NCR interrupt isn't sufficient here,
++ * because also a timer int can trigger an abort or reset, which can
++ * alter queues and touch the Falcon lock.
++ */
++
++ /* Tell int handlers main() is now already executing. Note that
++ no races are possible here. If an int comes in before
++ 'main_running' is set here, and queues/executes main via the
++ task queue, it doesn't do any harm, just this instance of main
++ won't find any work left to do. */
++ if (main_running)
++ return;
++ main_running = 1;
++
++ local_save_flags(flags);
++ do {
++ local_irq_disable(); /* Freeze request queues */
++ done = 1;
++
++ if (!hostdata->connected) {
++ MAIN_PRINTK("scsi%d: not connected\n", HOSTNO);
++ /*
++ * Search through the issue_queue for a command destined
++ * for a target that's not busy.
++ */
+ #if (NDEBUG & NDEBUG_LISTS)
+- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL;
+- tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp))
+- ;
+- /*printk("%p ", tmp);*/
+- if ((tmp == prev) && tmp) printk(" LOOP\n");/* else printk("\n");*/
++ for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL;
++ tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp))
++ ;
++ /*printk("%p ", tmp);*/
++ if ((tmp == prev) && tmp)
++ printk(" LOOP\n");
++ /* else printk("\n"); */
+ #endif
+- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue,
+- prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp) ) {
++ for (tmp = (Scsi_Cmnd *) hostdata->issue_queue,
++ prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp)) {
+
+ #if (NDEBUG & NDEBUG_LISTS)
+- if (prev != tmp)
+- printk("MAIN tmp=%p target=%d busy=%d lun=%d\n",
+- tmp, tmp->device->id, hostdata->busy[tmp->device->id],
+- tmp->device->lun);
+-#endif
+- /* When we find one, remove it from the issue queue. */
+- /* ++guenther: possible race with Falcon locking */
+- if (
++ if (prev != tmp)
++ printk("MAIN tmp=%p target=%d busy=%d lun=%d\n",
++ tmp, tmp->device->id, hostdata->busy[tmp->device->id],
++ tmp->device->lun);
++#endif
++ /* When we find one, remove it from the issue queue. */
++ /* ++guenther: possible race with Falcon locking */
++ if (
+ #ifdef SUPPORT_TAGS
+- !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE)
++ !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE)
+ #else
+- !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun))
++ !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun))
+ #endif
+- ) {
+- /* ++guenther: just to be sure, this must be atomic */
+- local_irq_disable();
+- if (prev) {
+- REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
+- NEXT(prev) = NEXT(tmp);
+- } else {
+- REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp));
+- hostdata->issue_queue = NEXT(tmp);
+- }
+- NEXT(tmp) = NULL;
+- falcon_dont_release++;
+-
+- /* reenable interrupts after finding one */
+- local_irq_restore(flags);
+-
+- /*
+- * Attempt to establish an I_T_L nexus here.
+- * On success, instance->hostdata->connected is set.
+- * On failure, we must add the command back to the
+- * issue queue so we can keep trying.
+- */
+- MAIN_PRINTK("scsi%d: main(): command for target %d "
+- "lun %d removed from issue_queue\n",
+- HOSTNO, tmp->device->id, tmp->device->lun);
+- /*
+- * REQUEST SENSE commands are issued without tagged
+- * queueing, even on SCSI-II devices because the
+- * contingent allegiance condition exists for the
+- * entire unit.
+- */
+- /* ++roman: ...and the standard also requires that
+- * REQUEST SENSE command are untagged.
+- */
+-
++ ) {
++ /* ++guenther: just to be sure, this must be atomic */
++ local_irq_disable();
++ if (prev) {
++ REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
++ NEXT(prev) = NEXT(tmp);
++ } else {
++ REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp));
++ hostdata->issue_queue = NEXT(tmp);
++ }
++ NEXT(tmp) = NULL;
++ falcon_dont_release++;
++
++ /* reenable interrupts after finding one */
++ local_irq_restore(flags);
++
++ /*
++ * Attempt to establish an I_T_L nexus here.
++ * On success, instance->hostdata->connected is set.
++ * On failure, we must add the command back to the
++ * issue queue so we can keep trying.
++ */
++ MAIN_PRINTK("scsi%d: main(): command for target %d "
++ "lun %d removed from issue_queue\n",
++ HOSTNO, tmp->device->id, tmp->device->lun);
++ /*
++ * REQUEST SENSE commands are issued without tagged
++ * queueing, even on SCSI-II devices because the
++ * contingent allegiance condition exists for the
++ * entire unit.
++ */
++ /* ++roman: ...and the standard also requires that
++ * REQUEST SENSE command are untagged.
++ */
++
+ #ifdef SUPPORT_TAGS
+- cmd_get_tag( tmp, tmp->cmnd[0] != REQUEST_SENSE );
++ cmd_get_tag(tmp, tmp->cmnd[0] != REQUEST_SENSE);
+ #endif
+- if (!NCR5380_select(instance, tmp,
+- (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE :
+- TAG_NEXT)) {
+- falcon_dont_release--;
+- /* release if target did not response! */
+- falcon_release_lock_if_possible( hostdata );
+- break;
+- } else {
+- local_irq_disable();
+- LIST(tmp, hostdata->issue_queue);
+- NEXT(tmp) = hostdata->issue_queue;
+- hostdata->issue_queue = tmp;
++ if (!NCR5380_select(instance, tmp,
++ (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE :
++ TAG_NEXT)) {
++ falcon_dont_release--;
++ /* release if target did not response! */
++ falcon_release_lock_if_possible(hostdata);
++ break;
++ } else {
++ local_irq_disable();
++ LIST(tmp, hostdata->issue_queue);
++ NEXT(tmp) = hostdata->issue_queue;
++ hostdata->issue_queue = tmp;
+ #ifdef SUPPORT_TAGS
+- cmd_free_tag( tmp );
++ cmd_free_tag(tmp);
+ #endif
+- falcon_dont_release--;
+- local_irq_restore(flags);
+- MAIN_PRINTK("scsi%d: main(): select() failed, "
+- "returned to issue_queue\n", HOSTNO);
+- if (hostdata->connected)
+- break;
+- }
+- } /* if target/lun/target queue is not busy */
+- } /* for issue_queue */
+- } /* if (!hostdata->connected) */
+-
+- if (hostdata->connected
++ falcon_dont_release--;
++ local_irq_restore(flags);
++ MAIN_PRINTK("scsi%d: main(): select() failed, "
++ "returned to issue_queue\n", HOSTNO);
++ if (hostdata->connected)
++ break;
++ }
++ } /* if target/lun/target queue is not busy */
++ } /* for issue_queue */
++ } /* if (!hostdata->connected) */
++
++ if (hostdata->connected
+ #ifdef REAL_DMA
+- && !hostdata->dma_len
++ && !hostdata->dma_len
+ #endif
+- ) {
+- local_irq_restore(flags);
+- MAIN_PRINTK("scsi%d: main: performing information transfer\n",
+- HOSTNO);
+- NCR5380_information_transfer(instance);
+- MAIN_PRINTK("scsi%d: main: done set false\n", HOSTNO);
+- done = 0;
+- }
+- } while (!done);
+-
+- /* Better allow ints _after_ 'main_running' has been cleared, else
+- an interrupt could believe we'll pick up the work it left for
+- us, but we won't see it anymore here... */
+- main_running = 0;
+- local_irq_restore(flags);
++ ) {
++ local_irq_restore(flags);
++ MAIN_PRINTK("scsi%d: main: performing information transfer\n",
++ HOSTNO);
++ NCR5380_information_transfer(instance);
++ MAIN_PRINTK("scsi%d: main: done set false\n", HOSTNO);
++ done = 0;
++ }
++ } while (!done);
++
++ /* Better allow ints _after_ 'main_running' has been cleared, else
++ an interrupt could believe we'll pick up the work it left for
++ us, but we won't see it anymore here... */
++ main_running = 0;
++ local_irq_restore(flags);
+ }
+
+
+@@ -1223,1441 +1235,1439 @@ static void NCR5380_main (void *bl)
+ * Function : void NCR5380_dma_complete (struct Scsi_Host *instance)
+ *
+ * Purpose : Called by interrupt handler when DMA finishes or a phase
+- * mismatch occurs (which would finish the DMA transfer).
++ * mismatch occurs (which would finish the DMA transfer).
+ *
+ * Inputs : instance - this instance of the NCR5380.
+ *
+ */
+
+-static void NCR5380_dma_complete( struct Scsi_Host *instance )
++static void NCR5380_dma_complete(struct Scsi_Host *instance)
+ {
+- SETUP_HOSTDATA(instance);
+- int transfered, saved_data = 0, overrun = 0, cnt, toPIO;
+- unsigned char **data, p;
+- volatile int *count;
+-
+- if (!hostdata->connected) {
+- printk(KERN_WARNING "scsi%d: received end of DMA interrupt with "
+- "no connected cmd\n", HOSTNO);
+- return;
+- }
+-
+- if (atari_read_overruns) {
+- p = hostdata->connected->SCp.phase;
+- if (p & SR_IO) {
+- udelay(10);
+- if ((((NCR5380_read(BUS_AND_STATUS_REG)) &
+- (BASR_PHASE_MATCH|BASR_ACK)) ==
+- (BASR_PHASE_MATCH|BASR_ACK))) {
+- saved_data = NCR5380_read(INPUT_DATA_REG);
+- overrun = 1;
+- DMA_PRINTK("scsi%d: read overrun handled\n", HOSTNO);
+- }
+- }
+- }
+-
+- DMA_PRINTK("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n",
+- HOSTNO, NCR5380_read(BUS_AND_STATUS_REG),
+- NCR5380_read(STATUS_REG));
+-
+- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+- NCR5380_write(MODE_REG, MR_BASE);
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+-
+- transfered = hostdata->dma_len - NCR5380_dma_residual(instance);
+- hostdata->dma_len = 0;
+-
+- data = (unsigned char **) &(hostdata->connected->SCp.ptr);
+- count = &(hostdata->connected->SCp.this_residual);
+- *data += transfered;
+- *count -= transfered;
+-
+- if (atari_read_overruns) {
+- if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) {
+- cnt = toPIO = atari_read_overruns;
+- if (overrun) {
+- DMA_PRINTK("Got an input overrun, using saved byte\n");
+- *(*data)++ = saved_data;
+- (*count)--;
+- cnt--;
+- toPIO--;
+- }
+- DMA_PRINTK("Doing %d-byte PIO to 0x%08lx\n", cnt, (long)*data);
+- NCR5380_transfer_pio(instance, &p, &cnt, data);
+- *count -= toPIO - cnt;
++ SETUP_HOSTDATA(instance);
++ int transfered, saved_data = 0, overrun = 0, cnt, toPIO;
++ unsigned char **data, p;
++ volatile int *count;
++
++ if (!hostdata->connected) {
++ printk(KERN_WARNING "scsi%d: received end of DMA interrupt with "
++ "no connected cmd\n", HOSTNO);
++ return;
++ }
++
++ if (atari_read_overruns) {
++ p = hostdata->connected->SCp.phase;
++ if (p & SR_IO) {
++ udelay(10);
++ if ((NCR5380_read(BUS_AND_STATUS_REG) &
++ (BASR_PHASE_MATCH|BASR_ACK)) ==
++ (BASR_PHASE_MATCH|BASR_ACK)) {
++ saved_data = NCR5380_read(INPUT_DATA_REG);
++ overrun = 1;
++ DMA_PRINTK("scsi%d: read overrun handled\n", HOSTNO);
++ }
++ }
++ }
++
++ DMA_PRINTK("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n",
++ HOSTNO, NCR5380_read(BUS_AND_STATUS_REG),
++ NCR5380_read(STATUS_REG));
++
++ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
++ NCR5380_write(MODE_REG, MR_BASE);
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
++
++ transfered = hostdata->dma_len - NCR5380_dma_residual(instance);
++ hostdata->dma_len = 0;
++
++ data = (unsigned char **)&hostdata->connected->SCp.ptr;
++ count = &hostdata->connected->SCp.this_residual;
++ *data += transfered;
++ *count -= transfered;
++
++ if (atari_read_overruns) {
++ if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) {
++ cnt = toPIO = atari_read_overruns;
++ if (overrun) {
++ DMA_PRINTK("Got an input overrun, using saved byte\n");
++ *(*data)++ = saved_data;
++ (*count)--;
++ cnt--;
++ toPIO--;
++ }
++ DMA_PRINTK("Doing %d-byte PIO to 0x%08lx\n", cnt, (long)*data);
++ NCR5380_transfer_pio(instance, &p, &cnt, data);
++ *count -= toPIO - cnt;
++ }
+ }
+- }
+ }
+ #endif /* REAL_DMA */
+
+
+ /*
+ * Function : void NCR5380_intr (int irq)
+- *
++ *
+ * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
+- * from the disconnected queue, and restarting NCR5380_main()
++ * from the disconnected queue, and restarting NCR5380_main()
+ * as required.
+ *
+ * Inputs : int irq, irq that caused this interrupt.
+ *
+ */
+
+-static irqreturn_t NCR5380_intr (int irq, void *dev_id)
++static irqreturn_t NCR5380_intr(int irq, void *dev_id)
+ {
+- struct Scsi_Host *instance = first_instance;
+- int done = 1, handled = 0;
+- unsigned char basr;
+-
+- INT_PRINTK("scsi%d: NCR5380 irq triggered\n", HOSTNO);
+-
+- /* Look for pending interrupts */
+- basr = NCR5380_read(BUS_AND_STATUS_REG);
+- INT_PRINTK("scsi%d: BASR=%02x\n", HOSTNO, basr);
+- /* dispatch to appropriate routine if found and done=0 */
+- if (basr & BASR_IRQ) {
+- NCR_PRINT(NDEBUG_INTR);
+- if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) {
+- done = 0;
+- ENABLE_IRQ();
+- INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO);
+- NCR5380_reselect(instance);
+- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+- }
+- else if (basr & BASR_PARITY_ERROR) {
+- INT_PRINTK("scsi%d: PARITY interrupt\n", HOSTNO);
+- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+- }
+- else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
+- INT_PRINTK("scsi%d: RESET interrupt\n", HOSTNO);
+- (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+- }
+- else {
+- /*
+- * The rest of the interrupt conditions can occur only during a
+- * DMA transfer
+- */
++ struct Scsi_Host *instance = first_instance;
++ int done = 1, handled = 0;
++ unsigned char basr;
++
++ INT_PRINTK("scsi%d: NCR5380 irq triggered\n", HOSTNO);
++
++ /* Look for pending interrupts */
++ basr = NCR5380_read(BUS_AND_STATUS_REG);
++ INT_PRINTK("scsi%d: BASR=%02x\n", HOSTNO, basr);
++ /* dispatch to appropriate routine if found and done=0 */
++ if (basr & BASR_IRQ) {
++ NCR_PRINT(NDEBUG_INTR);
++ if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) {
++ done = 0;
++ ENABLE_IRQ();
++ INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO);
++ NCR5380_reselect(instance);
++ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
++ } else if (basr & BASR_PARITY_ERROR) {
++ INT_PRINTK("scsi%d: PARITY interrupt\n", HOSTNO);
++ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
++ } else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
++ INT_PRINTK("scsi%d: RESET interrupt\n", HOSTNO);
++ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
++ } else {
++ /*
++ * The rest of the interrupt conditions can occur only during a
++ * DMA transfer
++ */
+
+ #if defined(REAL_DMA)
+- /*
+- * We should only get PHASE MISMATCH and EOP interrupts if we have
+- * DMA enabled, so do a sanity check based on the current setting
+- * of the MODE register.
+- */
+-
+- if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) &&
+- ((basr & BASR_END_DMA_TRANSFER) ||
+- !(basr & BASR_PHASE_MATCH))) {
+-
+- INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
+- NCR5380_dma_complete( instance );
+- done = 0;
+- ENABLE_IRQ();
+- } else
++ /*
++ * We should only get PHASE MISMATCH and EOP interrupts if we have
++ * DMA enabled, so do a sanity check based on the current setting
++ * of the MODE register.
++ */
++
++ if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) &&
++ ((basr & BASR_END_DMA_TRANSFER) ||
++ !(basr & BASR_PHASE_MATCH))) {
++
++ INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
++ NCR5380_dma_complete( instance );
++ done = 0;
++ ENABLE_IRQ();
++ } else
+ #endif /* REAL_DMA */
+- {
++ {
+ /* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */
+- if (basr & BASR_PHASE_MATCH)
+- printk(KERN_NOTICE "scsi%d: unknown interrupt, "
+- "BASR 0x%x, MR 0x%x, SR 0x%x\n",
+- HOSTNO, basr, NCR5380_read(MODE_REG),
+- NCR5380_read(STATUS_REG));
+- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+- }
+- } /* if !(SELECTION || PARITY) */
+- handled = 1;
+- } /* BASR & IRQ */
+- else {
+- printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, "
+- "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr,
+- NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
+- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+- }
+-
+- if (!done) {
+- INT_PRINTK("scsi%d: in int routine, calling main\n", HOSTNO);
+- /* Put a call to NCR5380_main() on the queue... */
+- queue_main();
+- }
+- return IRQ_RETVAL(handled);
++ if (basr & BASR_PHASE_MATCH)
++ printk(KERN_NOTICE "scsi%d: unknown interrupt, "
++ "BASR 0x%x, MR 0x%x, SR 0x%x\n",
++ HOSTNO, basr, NCR5380_read(MODE_REG),
++ NCR5380_read(STATUS_REG));
++ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
++ }
++ } /* if !(SELECTION || PARITY) */
++ handled = 1;
++ } /* BASR & IRQ */ else {
++ printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, "
++ "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr,
++ NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
++ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
++ }
++
++ if (!done) {
++ INT_PRINTK("scsi%d: in int routine, calling main\n", HOSTNO);
++ /* Put a call to NCR5380_main() on the queue... */
++ queue_main();
++ }
++ return IRQ_RETVAL(handled);
+ }
+
+ #ifdef NCR5380_STATS
+-static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd)
++static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd *cmd)
+ {
+ # ifdef NCR5380_STAT_LIMIT
+- if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
++ if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+ # endif
+- switch (cmd->cmnd[0])
+- {
+- case WRITE:
+- case WRITE_6:
+- case WRITE_10:
+- hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
+- /*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/
+- hostdata->pendingw--;
+- break;
+- case READ:
+- case READ_6:
+- case READ_10:
+- hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
+- /*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/
+- hostdata->pendingr--;
+- break;
+- }
++ switch (cmd->cmnd[0]) {
++ case WRITE:
++ case WRITE_6:
++ case WRITE_10:
++ hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
++ /*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/
++ hostdata->pendingw--;
++ break;
++ case READ:
++ case READ_6:
++ case READ_10:
++ hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
++ /*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/
++ hostdata->pendingr--;
++ break;
++ }
+ }
+ #endif
+
+-/*
+- * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd,
++/*
++ * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd,
+ * int tag);
+ *
+ * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
+- * including ARBITRATION, SELECTION, and initial message out for
+- * IDENTIFY and queue messages.
++ * including ARBITRATION, SELECTION, and initial message out for
++ * IDENTIFY and queue messages.
+ *
+- * Inputs : instance - instantiation of the 5380 driver on which this
+- * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for
+- * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for
++ * Inputs : instance - instantiation of the 5380 driver on which this
++ * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for
++ * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for
+ * the command that is presently connected.
+- *
++ *
+ * Returns : -1 if selection could not execute for some reason,
+- * 0 if selection succeeded or failed because the target
+- * did not respond.
++ * 0 if selection succeeded or failed because the target
++ * did not respond.
+ *
+- * Side effects :
+- * If bus busy, arbitration failed, etc, NCR5380_select() will exit
++ * Side effects :
++ * If bus busy, arbitration failed, etc, NCR5380_select() will exit
+ * with registers as they should have been on entry - ie
+ * SELECT_ENABLE will be set appropriately, the NCR5380
+ * will cease to drive any SCSI bus signals.
+ *
+- * If successful : I_T_L or I_T_L_Q nexus will be established,
+- * instance->connected will be set to cmd.
+- * SELECT interrupt will be disabled.
++ * If successful : I_T_L or I_T_L_Q nexus will be established,
++ * instance->connected will be set to cmd.
++ * SELECT interrupt will be disabled.
+ *
+- * If failed (no target) : cmd->scsi_done() will be called, and the
++ * If failed (no target) : cmd->scsi_done() will be called, and the
+ * cmd->result host byte set to DID_BAD_TARGET.
+ */
+
+-static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
++static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
+ {
+- SETUP_HOSTDATA(instance);
+- unsigned char tmp[3], phase;
+- unsigned char *data;
+- int len;
+- unsigned long timeout;
+- unsigned long flags;
+-
+- hostdata->restart_select = 0;
+- NCR_PRINT(NDEBUG_ARBITRATION);
+- ARB_PRINTK("scsi%d: starting arbitration, id = %d\n", HOSTNO,
+- instance->this_id);
+-
+- /*
+- * Set the phase bits to 0, otherwise the NCR5380 won't drive the
+- * data bus during SELECTION.
+- */
++ SETUP_HOSTDATA(instance);
++ unsigned char tmp[3], phase;
++ unsigned char *data;
++ int len;
++ unsigned long timeout;
++ unsigned long flags;
++
++ hostdata->restart_select = 0;
++ NCR_PRINT(NDEBUG_ARBITRATION);
++ ARB_PRINTK("scsi%d: starting arbitration, id = %d\n", HOSTNO,
++ instance->this_id);
++
++ /*
++ * Set the phase bits to 0, otherwise the NCR5380 won't drive the
++ * data bus during SELECTION.
++ */
+
+- local_irq_save(flags);
+- if (hostdata->connected) {
+- local_irq_restore(flags);
+- return -1;
+- }
+- NCR5380_write(TARGET_COMMAND_REG, 0);
++ local_irq_save(flags);
++ if (hostdata->connected) {
++ local_irq_restore(flags);
++ return -1;
++ }
++ NCR5380_write(TARGET_COMMAND_REG, 0);
+
++ /*
++ * Start arbitration.
++ */
+
+- /*
+- * Start arbitration.
+- */
+-
+- NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
+- NCR5380_write(MODE_REG, MR_ARBITRATE);
++ NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
++ NCR5380_write(MODE_REG, MR_ARBITRATE);
+
+- local_irq_restore(flags);
++ local_irq_restore(flags);
+
+- /* Wait for arbitration logic to complete */
++ /* Wait for arbitration logic to complete */
+ #if defined(NCR_TIMEOUT)
+- {
+- unsigned long timeout = jiffies + 2*NCR_TIMEOUT;
++ {
++ unsigned long timeout = jiffies + 2*NCR_TIMEOUT;
+
+- while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
+- && time_before(jiffies, timeout) && !hostdata->connected)
+- ;
+- if (time_after_eq(jiffies, timeout))
+- {
+- printk("scsi : arbitration timeout at %d\n", __LINE__);
+- NCR5380_write(MODE_REG, MR_BASE);
+- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+- return -1;
+- }
+- }
++ while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) &&
++ time_before(jiffies, timeout) && !hostdata->connected)
++ ;
++ if (time_after_eq(jiffies, timeout)) {
++ printk("scsi : arbitration timeout at %d\n", __LINE__);
++ NCR5380_write(MODE_REG, MR_BASE);
++ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
++ return -1;
++ }
++ }
+ #else /* NCR_TIMEOUT */
+- while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
+- && !hostdata->connected);
++ while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) &&
++ !hostdata->connected)
++ ;
+ #endif
+
+- ARB_PRINTK("scsi%d: arbitration complete\n", HOSTNO);
++ ARB_PRINTK("scsi%d: arbitration complete\n", HOSTNO);
+
+- if (hostdata->connected) {
+- NCR5380_write(MODE_REG, MR_BASE);
+- return -1;
+- }
+- /*
+- * The arbitration delay is 2.2us, but this is a minimum and there is
+- * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate
+- * the integral nature of udelay().
+- *
+- */
+-
+- udelay(3);
+-
+- /* Check for lost arbitration */
+- if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+- (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
+- (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+- hostdata->connected) {
+- NCR5380_write(MODE_REG, MR_BASE);
+- ARB_PRINTK("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n",
+- HOSTNO);
+- return -1;
+- }
+-
+- /* after/during arbitration, BSY should be asserted.
+- IBM DPES-31080 Version S31Q works now */
+- /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL |
+- ICR_ASSERT_BSY ) ;
+-
+- if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+- hostdata->connected) {
+- NCR5380_write(MODE_REG, MR_BASE);
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+- ARB_PRINTK("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n",
+- HOSTNO);
+- return -1;
+- }
+-
+- /*
+- * Again, bus clear + bus settle time is 1.2us, however, this is
+- * a minimum so we'll udelay ceil(1.2)
+- */
++ if (hostdata->connected) {
++ NCR5380_write(MODE_REG, MR_BASE);
++ return -1;
++ }
++ /*
++ * The arbitration delay is 2.2us, but this is a minimum and there is
++ * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate
++ * the integral nature of udelay().
++ *
++ */
++
++ udelay(3);
++
++ /* Check for lost arbitration */
++ if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
++ (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
++ (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
++ hostdata->connected) {
++ NCR5380_write(MODE_REG, MR_BASE);
++ ARB_PRINTK("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n",
++ HOSTNO);
++ return -1;
++ }
++
++ /* after/during arbitration, BSY should be asserted.
++ IBM DPES-31080 Version S31Q works now */
++ /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */
++ NCR5380_write(INITIATOR_COMMAND_REG,
++ ICR_BASE | ICR_ASSERT_SEL | ICR_ASSERT_BSY);
++
++ if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
++ hostdata->connected) {
++ NCR5380_write(MODE_REG, MR_BASE);
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
++ ARB_PRINTK("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n",
++ HOSTNO);
++ return -1;
++ }
++
++ /*
++ * Again, bus clear + bus settle time is 1.2us, however, this is
++ * a minimum so we'll udelay ceil(1.2)
++ */
+
+ #ifdef CONFIG_ATARI_SCSI_TOSHIBA_DELAY
+- /* ++roman: But some targets (see above :-) seem to need a bit more... */
+- udelay(15);
++ /* ++roman: But some targets (see above :-) seem to need a bit more... */
++ udelay(15);
+ #else
+- udelay(2);
++ udelay(2);
+ #endif
+-
+- if (hostdata->connected) {
++
++ if (hostdata->connected) {
++ NCR5380_write(MODE_REG, MR_BASE);
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
++ return -1;
++ }
++
++ ARB_PRINTK("scsi%d: won arbitration\n", HOSTNO);
++
++ /*
++ * Now that we have won arbitration, start Selection process, asserting
++ * the host and target ID's on the SCSI bus.
++ */
++
++ NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id)));
++
++ /*
++ * Raise ATN while SEL is true before BSY goes false from arbitration,
++ * since this is the only way to guarantee that we'll get a MESSAGE OUT
++ * phase immediately after selection.
++ */
++
++ NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY |
++ ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL ));
+ NCR5380_write(MODE_REG, MR_BASE);
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+- return -1;
+- }
+
+- ARB_PRINTK("scsi%d: won arbitration\n", HOSTNO);
++ /*
++ * Reselect interrupts must be turned off prior to the dropping of BSY,
++ * otherwise we will trigger an interrupt.
++ */
++
++ if (hostdata->connected) {
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
++ return -1;
++ }
++
++ NCR5380_write(SELECT_ENABLE_REG, 0);
+
+- /*
+- * Now that we have won arbitration, start Selection process, asserting
+- * the host and target ID's on the SCSI bus.
+- */
+-
+- NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id)));
+-
+- /*
+- * Raise ATN while SEL is true before BSY goes false from arbitration,
+- * since this is the only way to guarantee that we'll get a MESSAGE OUT
+- * phase immediately after selection.
+- */
+-
+- NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY |
+- ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL ));
+- NCR5380_write(MODE_REG, MR_BASE);
+-
+- /*
+- * Reselect interrupts must be turned off prior to the dropping of BSY,
+- * otherwise we will trigger an interrupt.
+- */
++ /*
++ * The initiator shall then wait at least two deskew delays and release
++ * the BSY signal.
++ */
++ udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */
+
+- if (hostdata->connected) {
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+- return -1;
+- }
++ /* Reset BSY */
++ NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA |
++ ICR_ASSERT_ATN | ICR_ASSERT_SEL));
++
++ /*
++ * Something weird happens when we cease to drive BSY - looks
++ * like the board/chip is letting us do another read before the
++ * appropriate propagation delay has expired, and we're confusing
++ * a BSY signal from ourselves as the target's response to SELECTION.
++ *
++ * A small delay (the 'C++' frontend breaks the pipeline with an
++ * unnecessary jump, making it work on my 386-33/Trantor T128, the
++ * tighter 'C' code breaks and requires this) solves the problem -
++ * the 1 us delay is arbitrary, and only used because this delay will
++ * be the same on other platforms and since it works here, it should
++ * work there.
++ *
++ * wingel suggests that this could be due to failing to wait
++ * one deskew delay.
++ */
++
++ udelay(1);
+
+- NCR5380_write(SELECT_ENABLE_REG, 0);
++ SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->device->id);
++
++ /*
++ * The SCSI specification calls for a 250 ms timeout for the actual
++ * selection.
++ */
+
+- /*
+- * The initiator shall then wait at least two deskew delays and release
+- * the BSY signal.
+- */
+- udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */
+-
+- /* Reset BSY */
+- NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA |
+- ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+-
+- /*
+- * Something weird happens when we cease to drive BSY - looks
+- * like the board/chip is letting us do another read before the
+- * appropriate propagation delay has expired, and we're confusing
+- * a BSY signal from ourselves as the target's response to SELECTION.
+- *
+- * A small delay (the 'C++' frontend breaks the pipeline with an
+- * unnecessary jump, making it work on my 386-33/Trantor T128, the
+- * tighter 'C' code breaks and requires this) solves the problem -
+- * the 1 us delay is arbitrary, and only used because this delay will
+- * be the same on other platforms and since it works here, it should
+- * work there.
+- *
+- * wingel suggests that this could be due to failing to wait
+- * one deskew delay.
+- */
+-
+- udelay(1);
+-
+- SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->device->id);
+-
+- /*
+- * The SCSI specification calls for a 250 ms timeout for the actual
+- * selection.
+- */
+-
+- timeout = jiffies + 25;
+-
+- /*
+- * XXX very interesting - we're seeing a bounce where the BSY we
+- * asserted is being reflected / still asserted (propagation delay?)
+- * and it's detecting as true. Sigh.
+- */
++ timeout = jiffies + 25;
++
++ /*
++ * XXX very interesting - we're seeing a bounce where the BSY we
++ * asserted is being reflected / still asserted (propagation delay?)
++ * and it's detecting as true. Sigh.
++ */
+
+ #if 0
+- /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert
+- * IO while SEL is true. But again, there are some disks out the in the
+- * world that do that nevertheless. (Somebody claimed that this announces
+- * reselection capability of the target.) So we better skip that test and
+- * only wait for BSY... (Famous german words: Der Klügere gibt nach :-)
+- */
+-
+- while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) &
+- (SR_BSY | SR_IO)));
+-
+- if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) ==
+- (SR_SEL | SR_IO)) {
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+- NCR5380_reselect(instance);
+- printk (KERN_ERR "scsi%d: reselection after won arbitration?\n",
+- HOSTNO);
+- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+- return -1;
+- }
++ /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert
++ * IO while SEL is true. But again, there are some disks out the in the
++ * world that do that nevertheless. (Somebody claimed that this announces
++ * reselection capability of the target.) So we better skip that test and
++ * only wait for BSY... (Famous german words: Der Klügere gibt nach :-)
++ */
++
++ while (time_before(jiffies, timeout) &&
++ !(NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO)))
++ ;
++
++ if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) {
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
++ NCR5380_reselect(instance);
++ printk(KERN_ERR "scsi%d: reselection after won arbitration?\n",
++ HOSTNO);
++ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
++ return -1;
++ }
+ #else
+- while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY));
++ while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY))
++ ;
+ #endif
+
+- /*
+- * No less than two deskew delays after the initiator detects the
+- * BSY signal is true, it shall release the SEL signal and may
+- * change the DATA BUS. -wingel
+- */
++ /*
++ * No less than two deskew delays after the initiator detects the
++ * BSY signal is true, it shall release the SEL signal and may
++ * change the DATA BUS. -wingel
++ */
+
+- udelay(1);
++ udelay(1);
+
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+
+- if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+- if (hostdata->targets_present & (1 << cmd->device->id)) {
+- printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO);
+- if (hostdata->restart_select)
+- printk(KERN_NOTICE "\trestart select\n");
+- NCR_PRINT(NDEBUG_ANY);
+- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+- return -1;
+- }
+- cmd->result = DID_BAD_TARGET << 16;
++ if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
++ if (hostdata->targets_present & (1 << cmd->device->id)) {
++ printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO);
++ if (hostdata->restart_select)
++ printk(KERN_NOTICE "\trestart select\n");
++ NCR_PRINT(NDEBUG_ANY);
++ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
++ return -1;
++ }
++ cmd->result = DID_BAD_TARGET << 16;
+ #ifdef NCR5380_STATS
+- collect_stats(hostdata, cmd);
++ collect_stats(hostdata, cmd);
+ #endif
+ #ifdef SUPPORT_TAGS
+- cmd_free_tag( cmd );
++ cmd_free_tag(cmd);
+ #endif
+- cmd->scsi_done(cmd);
+- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+- SEL_PRINTK("scsi%d: target did not respond within 250ms\n", HOSTNO);
+- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+- return 0;
+- }
++ cmd->scsi_done(cmd);
++ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
++ SEL_PRINTK("scsi%d: target did not respond within 250ms\n", HOSTNO);
++ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
++ return 0;
++ }
++
++ hostdata->targets_present |= (1 << cmd->device->id);
+
+- hostdata->targets_present |= (1 << cmd->device->id);
++ /*
++ * Since we followed the SCSI spec, and raised ATN while SEL
++ * was true but before BSY was false during selection, the information
++ * transfer phase should be a MESSAGE OUT phase so that we can send the
++ * IDENTIFY message.
++ *
++ * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG
++ * message (2 bytes) with a tag ID that we increment with every command
++ * until it wraps back to 0.
++ *
++ * XXX - it turns out that there are some broken SCSI-II devices,
++ * which claim to support tagged queuing but fail when more than
++ * some number of commands are issued at once.
++ */
++
++ /* Wait for start of REQ/ACK handshake */
++ while (!(NCR5380_read(STATUS_REG) & SR_REQ))
++ ;
+
+- /*
+- * Since we followed the SCSI spec, and raised ATN while SEL
+- * was true but before BSY was false during selection, the information
+- * transfer phase should be a MESSAGE OUT phase so that we can send the
+- * IDENTIFY message.
+- *
+- * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG
+- * message (2 bytes) with a tag ID that we increment with every command
+- * until it wraps back to 0.
+- *
+- * XXX - it turns out that there are some broken SCSI-II devices,
+- * which claim to support tagged queuing but fail when more than
+- * some number of commands are issued at once.
+- */
+-
+- /* Wait for start of REQ/ACK handshake */
+- while (!(NCR5380_read(STATUS_REG) & SR_REQ));
+-
+- SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
+- HOSTNO, cmd->device->id);
+- tmp[0] = IDENTIFY(1, cmd->device->lun);
++ SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
++ HOSTNO, cmd->device->id);
++ tmp[0] = IDENTIFY(1, cmd->device->lun);
+
+ #ifdef SUPPORT_TAGS
+- if (cmd->tag != TAG_NONE) {
+- tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG;
+- tmp[2] = cmd->tag;
+- len = 3;
+- } else
+- len = 1;
++ if (cmd->tag != TAG_NONE) {
++ tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG;
++ tmp[2] = cmd->tag;
++ len = 3;
++ } else
++ len = 1;
+ #else
+- len = 1;
+- cmd->tag=0;
++ len = 1;
++ cmd->tag = 0;
+ #endif /* SUPPORT_TAGS */
+
+- /* Send message(s) */
+- data = tmp;
+- phase = PHASE_MSGOUT;
+- NCR5380_transfer_pio(instance, &phase, &len, &data);
+- SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO);
+- /* XXX need to handle errors here */
+- hostdata->connected = cmd;
++ /* Send message(s) */
++ data = tmp;
++ phase = PHASE_MSGOUT;
++ NCR5380_transfer_pio(instance, &phase, &len, &data);
++ SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO);
++ /* XXX need to handle errors here */
++ hostdata->connected = cmd;
+ #ifndef SUPPORT_TAGS
+- hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+-#endif
+-
+- initialize_SCp(cmd);
++ hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
++#endif
+
++ initialize_SCp(cmd);
+
+- return 0;
++ return 0;
+ }
+
+-/*
+- * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance,
++/*
++ * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance,
+ * unsigned char *phase, int *count, unsigned char **data)
+ *
+ * Purpose : transfers data in given phase using polled I/O
+ *
+- * Inputs : instance - instance of driver, *phase - pointer to
+- * what phase is expected, *count - pointer to number of
++ * Inputs : instance - instance of driver, *phase - pointer to
++ * what phase is expected, *count - pointer to number of
+ * bytes to transfer, **data - pointer to data pointer.
+- *
++ *
+ * Returns : -1 when different phase is entered without transferring
+ * maximum number of bytes, 0 if all bytes are transfered or exit
+ * is in same phase.
+ *
+- * Also, *phase, *count, *data are modified in place.
++ * Also, *phase, *count, *data are modified in place.
+ *
+ * XXX Note : handling for bus free may be useful.
+ */
+
+ /*
+- * Note : this code is not as quick as it could be, however it
++ * Note : this code is not as quick as it could be, however it
+ * IS 100% reliable, and for the actual data transfer where speed
+ * counts, we will always do a pseudo DMA or DMA transfer.
+ */
+
+-static int NCR5380_transfer_pio( struct Scsi_Host *instance,
+- unsigned char *phase, int *count,
+- unsigned char **data)
+-{
+- register unsigned char p = *phase, tmp;
+- register int c = *count;
+- register unsigned char *d = *data;
+-
+- /*
+- * The NCR5380 chip will only drive the SCSI bus when the
+- * phase specified in the appropriate bits of the TARGET COMMAND
+- * REGISTER match the STATUS REGISTER
+- */
+-
+- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+-
+- do {
+- /*
+- * Wait for assertion of REQ, after which the phase bits will be
+- * valid
+- */
+- while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ));
+-
+- HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO);
+-
+- /* Check for phase mismatch */
+- if ((tmp & PHASE_MASK) != p) {
+- PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO);
+- NCR_PRINT_PHASE(NDEBUG_PIO);
+- break;
+- }
+-
+- /* Do actual transfer from SCSI bus to / from memory */
+- if (!(p & SR_IO))
+- NCR5380_write(OUTPUT_DATA_REG, *d);
+- else
+- *d = NCR5380_read(CURRENT_SCSI_DATA_REG);
+-
+- ++d;
+-
+- /*
+- * The SCSI standard suggests that in MSGOUT phase, the initiator
+- * should drop ATN on the last byte of the message phase
+- * after REQ has been asserted for the handshake but before
+- * the initiator raises ACK.
+- */
+-
+- if (!(p & SR_IO)) {
+- if (!((p & SR_MSG) && c > 1)) {
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+- ICR_ASSERT_DATA);
+- NCR_PRINT(NDEBUG_PIO);
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+- ICR_ASSERT_DATA | ICR_ASSERT_ACK);
+- } else {
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+- ICR_ASSERT_DATA | ICR_ASSERT_ATN);
+- NCR_PRINT(NDEBUG_PIO);
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+- ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+- }
+- } else {
+- NCR_PRINT(NDEBUG_PIO);
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
+- }
++static int NCR5380_transfer_pio(struct Scsi_Host *instance,
++ unsigned char *phase, int *count,
++ unsigned char **data)
++{
++ register unsigned char p = *phase, tmp;
++ register int c = *count;
++ register unsigned char *d = *data;
++
++ /*
++ * The NCR5380 chip will only drive the SCSI bus when the
++ * phase specified in the appropriate bits of the TARGET COMMAND
++ * REGISTER match the STATUS REGISTER
++ */
+
+- while (NCR5380_read(STATUS_REG) & SR_REQ);
++ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+
+- HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO);
++ do {
++ /*
++ * Wait for assertion of REQ, after which the phase bits will be
++ * valid
++ */
++ while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ))
++ ;
+
+-/*
+- * We have several special cases to consider during REQ/ACK handshaking :
+- * 1. We were in MSGOUT phase, and we are on the last byte of the
+- * message. ATN must be dropped as ACK is dropped.
+- *
+- * 2. We are in a MSGIN phase, and we are on the last byte of the
+- * message. We must exit with ACK asserted, so that the calling
+- * code may raise ATN before dropping ACK to reject the message.
+- *
+- * 3. ACK and ATN are clear and the target may proceed as normal.
+- */
+- if (!(p == PHASE_MSGIN && c == 1)) {
+- if (p == PHASE_MSGOUT && c > 1)
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+- else
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+- }
+- } while (--c);
++ HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO);
+
+- PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c);
++ /* Check for phase mismatch */
++ if ((tmp & PHASE_MASK) != p) {
++ PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO);
++ NCR_PRINT_PHASE(NDEBUG_PIO);
++ break;
++ }
+
+- *count = c;
+- *data = d;
+- tmp = NCR5380_read(STATUS_REG);
+- /* The phase read from the bus is valid if either REQ is (already)
+- * asserted or if ACK hasn't been released yet. The latter is the case if
+- * we're in MSGIN and all wanted bytes have been received. */
+- if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0))
+- *phase = tmp & PHASE_MASK;
+- else
+- *phase = PHASE_UNKNOWN;
++ /* Do actual transfer from SCSI bus to / from memory */
++ if (!(p & SR_IO))
++ NCR5380_write(OUTPUT_DATA_REG, *d);
++ else
++ *d = NCR5380_read(CURRENT_SCSI_DATA_REG);
+
+- if (!c || (*phase == p))
+- return 0;
+- else
+- return -1;
++ ++d;
++
++ /*
++ * The SCSI standard suggests that in MSGOUT phase, the initiator
++ * should drop ATN on the last byte of the message phase
++ * after REQ has been asserted for the handshake but before
++ * the initiator raises ACK.
++ */
++
++ if (!(p & SR_IO)) {
++ if (!((p & SR_MSG) && c > 1)) {
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
++ NCR_PRINT(NDEBUG_PIO);
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
++ ICR_ASSERT_DATA | ICR_ASSERT_ACK);
++ } else {
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
++ ICR_ASSERT_DATA | ICR_ASSERT_ATN);
++ NCR_PRINT(NDEBUG_PIO);
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
++ ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
++ }
++ } else {
++ NCR_PRINT(NDEBUG_PIO);
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
++ }
++
++ while (NCR5380_read(STATUS_REG) & SR_REQ)
++ ;
++
++ HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO);
++
++ /*
++ * We have several special cases to consider during REQ/ACK handshaking :
++ * 1. We were in MSGOUT phase, and we are on the last byte of the
++ * message. ATN must be dropped as ACK is dropped.
++ *
++ * 2. We are in a MSGIN phase, and we are on the last byte of the
++ * message. We must exit with ACK asserted, so that the calling
++ * code may raise ATN before dropping ACK to reject the message.
++ *
++ * 3. ACK and ATN are clear and the target may proceed as normal.
++ */
++ if (!(p == PHASE_MSGIN && c == 1)) {
++ if (p == PHASE_MSGOUT && c > 1)
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
++ else
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
++ }
++ } while (--c);
++
++ PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c);
++
++ *count = c;
++ *data = d;
++ tmp = NCR5380_read(STATUS_REG);
++ /* The phase read from the bus is valid if either REQ is (already)
++ * asserted or if ACK hasn't been released yet. The latter is the case if
++ * we're in MSGIN and all wanted bytes have been received.
++ */
++ if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0))
++ *phase = tmp & PHASE_MASK;
++ else
++ *phase = PHASE_UNKNOWN;
++
++ if (!c || (*phase == p))
++ return 0;
++ else
++ return -1;
+ }
+
+ /*
+ * Function : do_abort (Scsi_Host *host)
+- *
+- * Purpose : abort the currently established nexus. Should only be
+- * called from a routine which can drop into a
+- *
++ *
++ * Purpose : abort the currently established nexus. Should only be
++ * called from a routine which can drop into a
++ *
+ * Returns : 0 on success, -1 on failure.
+ */
+
+-static int do_abort (struct Scsi_Host *host)
++static int do_abort(struct Scsi_Host *host)
+ {
+- unsigned char tmp, *msgptr, phase;
+- int len;
+-
+- /* Request message out phase */
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
++ unsigned char tmp, *msgptr, phase;
++ int len;
+
+- /*
+- * Wait for the target to indicate a valid phase by asserting
+- * REQ. Once this happens, we'll have either a MSGOUT phase
+- * and can immediately send the ABORT message, or we'll have some
+- * other phase and will have to source/sink data.
+- *
+- * We really don't care what value was on the bus or what value
+- * the target sees, so we just handshake.
+- */
+-
+- while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ);
+-
+- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+-
+- if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
+- ICR_ASSERT_ACK);
+- while (NCR5380_read(STATUS_REG) & SR_REQ);
++ /* Request message out phase */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+- }
+-
+- tmp = ABORT;
+- msgptr = &tmp;
+- len = 1;
+- phase = PHASE_MSGOUT;
+- NCR5380_transfer_pio (host, &phase, &len, &msgptr);
+-
+- /*
+- * If we got here, and the command completed successfully,
+- * we're about to go into bus free state.
+- */
+
+- return len ? -1 : 0;
++ /*
++ * Wait for the target to indicate a valid phase by asserting
++ * REQ. Once this happens, we'll have either a MSGOUT phase
++ * and can immediately send the ABORT message, or we'll have some
++ * other phase and will have to source/sink data.
++ *
++ * We really don't care what value was on the bus or what value
++ * the target sees, so we just handshake.
++ */
++
++ while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ)
++ ;
++
++ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
++
++ if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
++ ICR_ASSERT_ACK);
++ while (NCR5380_read(STATUS_REG) & SR_REQ)
++ ;
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
++ }
++
++ tmp = ABORT;
++ msgptr = &tmp;
++ len = 1;
++ phase = PHASE_MSGOUT;
++ NCR5380_transfer_pio(host, &phase, &len, &msgptr);
++
++ /*
++ * If we got here, and the command completed successfully,
++ * we're about to go into bus free state.
++ */
++
++ return len ? -1 : 0;
+ }
+
+ #if defined(REAL_DMA)
+-/*
+- * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance,
++/*
++ * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance,
+ * unsigned char *phase, int *count, unsigned char **data)
+ *
+ * Purpose : transfers data in given phase using either real
+ * or pseudo DMA.
+ *
+- * Inputs : instance - instance of driver, *phase - pointer to
+- * what phase is expected, *count - pointer to number of
++ * Inputs : instance - instance of driver, *phase - pointer to
++ * what phase is expected, *count - pointer to number of
+ * bytes to transfer, **data - pointer to data pointer.
+- *
++ *
+ * Returns : -1 when different phase is entered without transferring
+ * maximum number of bytes, 0 if all bytes or transfered or exit
+ * is in same phase.
+ *
+- * Also, *phase, *count, *data are modified in place.
++ * Also, *phase, *count, *data are modified in place.
+ *
+ */
+
+
+-static int NCR5380_transfer_dma( struct Scsi_Host *instance,
+- unsigned char *phase, int *count,
+- unsigned char **data)
++static int NCR5380_transfer_dma(struct Scsi_Host *instance,
++ unsigned char *phase, int *count,
++ unsigned char **data)
+ {
+- SETUP_HOSTDATA(instance);
+- register int c = *count;
+- register unsigned char p = *phase;
+- register unsigned char *d = *data;
+- unsigned char tmp;
+- unsigned long flags;
++ SETUP_HOSTDATA(instance);
++ register int c = *count;
++ register unsigned char p = *phase;
++ register unsigned char *d = *data;
++ unsigned char tmp;
++ unsigned long flags;
+
+- if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
+- *phase = tmp;
+- return -1;
+- }
++ if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
++ *phase = tmp;
++ return -1;
++ }
+
+- if (atari_read_overruns && (p & SR_IO)) {
+- c -= atari_read_overruns;
+- }
++ if (atari_read_overruns && (p & SR_IO))
++ c -= atari_read_overruns;
+
+- DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n",
+- HOSTNO, (p & SR_IO) ? "reading" : "writing",
+- c, (p & SR_IO) ? "to" : "from", d);
++ DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n",
++ HOSTNO, (p & SR_IO) ? "reading" : "writing",
++ c, (p & SR_IO) ? "to" : "from", d);
+
+- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
++ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+
+ #ifdef REAL_DMA
+- NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
++ NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
+ #endif /* def REAL_DMA */
+
+- if (IS_A_TT()) {
+- /* On the Medusa, it is a must to initialize the DMA before
+- * starting the NCR. This is also the cleaner way for the TT.
+- */
+- local_irq_save(flags);
+- hostdata->dma_len = (p & SR_IO) ?
+- NCR5380_dma_read_setup(instance, d, c) :
+- NCR5380_dma_write_setup(instance, d, c);
+- local_irq_restore(flags);
+- }
+-
+- if (p & SR_IO)
+- NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
+- else {
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
+- NCR5380_write(START_DMA_SEND_REG, 0);
+- }
+-
+- if (!IS_A_TT()) {
+- /* On the Falcon, the DMA setup must be done after the last */
+- /* NCR access, else the DMA setup gets trashed!
+- */
+- local_irq_save(flags);
+- hostdata->dma_len = (p & SR_IO) ?
+- NCR5380_dma_read_setup(instance, d, c) :
+- NCR5380_dma_write_setup(instance, d, c);
+- local_irq_restore(flags);
+- }
+- return 0;
++ if (IS_A_TT()) {
++ /* On the Medusa, it is a must to initialize the DMA before
++ * starting the NCR. This is also the cleaner way for the TT.
++ */
++ local_irq_save(flags);
++ hostdata->dma_len = (p & SR_IO) ?
++ NCR5380_dma_read_setup(instance, d, c) :
++ NCR5380_dma_write_setup(instance, d, c);
++ local_irq_restore(flags);
++ }
++
++ if (p & SR_IO)
++ NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
++ else {
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
++ NCR5380_write(START_DMA_SEND_REG, 0);
++ }
++
++ if (!IS_A_TT()) {
++ /* On the Falcon, the DMA setup must be done after the last */
++ /* NCR access, else the DMA setup gets trashed!
++ */
++ local_irq_save(flags);
++ hostdata->dma_len = (p & SR_IO) ?
++ NCR5380_dma_read_setup(instance, d, c) :
++ NCR5380_dma_write_setup(instance, d, c);
++ local_irq_restore(flags);
++ }
++ return 0;
+ }
+ #endif /* defined(REAL_DMA) */
+
+ /*
+ * Function : NCR5380_information_transfer (struct Scsi_Host *instance)
+ *
+- * Purpose : run through the various SCSI phases and do as the target
+- * directs us to. Operates on the currently connected command,
++ * Purpose : run through the various SCSI phases and do as the target
++ * directs us to. Operates on the currently connected command,
+ * instance->connected.
+ *
+ * Inputs : instance, instance for which we are doing commands
+ *
+- * Side effects : SCSI things happen, the disconnected queue will be
++ * Side effects : SCSI things happen, the disconnected queue will be
+ * modified if a command disconnects, *instance->connected will
+ * change.
+ *
+- * XXX Note : we need to watch for bus free or a reset condition here
+- * to recover from an unexpected bus free condition.
++ * XXX Note : we need to watch for bus free or a reset condition here
++ * to recover from an unexpected bus free condition.
+ */
+-
+-static void NCR5380_information_transfer (struct Scsi_Host *instance)
++
++static void NCR5380_information_transfer(struct Scsi_Host *instance)
+ {
+- SETUP_HOSTDATA(instance);
+- unsigned long flags;
+- unsigned char msgout = NOP;
+- int sink = 0;
+- int len;
++ SETUP_HOSTDATA(instance);
++ unsigned long flags;
++ unsigned char msgout = NOP;
++ int sink = 0;
++ int len;
+ #if defined(REAL_DMA)
+- int transfersize;
+-#endif
+- unsigned char *data;
+- unsigned char phase, tmp, extended_msg[10], old_phase=0xff;
+- Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
+-
+- while (1) {
+- tmp = NCR5380_read(STATUS_REG);
+- /* We only have a valid SCSI phase when REQ is asserted */
+- if (tmp & SR_REQ) {
+- phase = (tmp & PHASE_MASK);
+- if (phase != old_phase) {
+- old_phase = phase;
+- NCR_PRINT_PHASE(NDEBUG_INFORMATION);
+- }
+-
+- if (sink && (phase != PHASE_MSGOUT)) {
+- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+-
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
+- ICR_ASSERT_ACK);
+- while (NCR5380_read(STATUS_REG) & SR_REQ);
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+- ICR_ASSERT_ATN);
+- sink = 0;
+- continue;
+- }
+-
+- switch (phase) {
+- case PHASE_DATAOUT:
+-#if (NDEBUG & NDEBUG_NO_DATAOUT)
+- printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT "
+- "aborted\n", HOSTNO);
+- sink = 1;
+- do_abort(instance);
+- cmd->result = DID_ERROR << 16;
+- cmd->done(cmd);
+- return;
++ int transfersize;
+ #endif
+- case PHASE_DATAIN:
+- /*
+- * If there is no room left in the current buffer in the
+- * scatter-gather list, move onto the next one.
+- */
++ unsigned char *data;
++ unsigned char phase, tmp, extended_msg[10], old_phase = 0xff;
++ Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
++
++ while (1) {
++ tmp = NCR5380_read(STATUS_REG);
++ /* We only have a valid SCSI phase when REQ is asserted */
++ if (tmp & SR_REQ) {
++ phase = (tmp & PHASE_MASK);
++ if (phase != old_phase) {
++ old_phase = phase;
++ NCR_PRINT_PHASE(NDEBUG_INFORMATION);
++ }
+
+- if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
+- ++cmd->SCp.buffer;
+- --cmd->SCp.buffers_residual;
+- cmd->SCp.this_residual = cmd->SCp.buffer->length;
+- cmd->SCp.ptr = page_address(cmd->SCp.buffer->page)+
+- cmd->SCp.buffer->offset;
+- /* ++roman: Try to merge some scatter-buffers if
+- * they are at contiguous physical addresses.
+- */
+- merge_contiguous_buffers( cmd );
+- INF_PRINTK("scsi%d: %d bytes and %d buffers left\n",
+- HOSTNO, cmd->SCp.this_residual,
+- cmd->SCp.buffers_residual);
+- }
++ if (sink && (phase != PHASE_MSGOUT)) {
++ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+
+- /*
+- * The preferred transfer method is going to be
+- * PSEUDO-DMA for systems that are strictly PIO,
+- * since we can let the hardware do the handshaking.
+- *
+- * For this to work, we need to know the transfersize
+- * ahead of time, since the pseudo-DMA code will sit
+- * in an unconditional loop.
+- */
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
++ ICR_ASSERT_ACK);
++ while (NCR5380_read(STATUS_REG) & SR_REQ)
++ ;
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
++ ICR_ASSERT_ATN);
++ sink = 0;
++ continue;
++ }
+
+-/* ++roman: I suggest, this should be
+- * #if def(REAL_DMA)
+- * instead of leaving REAL_DMA out.
+- */
++ switch (phase) {
++ case PHASE_DATAOUT:
++#if (NDEBUG & NDEBUG_NO_DATAOUT)
++ printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT "
++ "aborted\n", HOSTNO);
++ sink = 1;
++ do_abort(instance);
++ cmd->result = DID_ERROR << 16;
++ cmd->done(cmd);
++ return;
++#endif
++ case PHASE_DATAIN:
++ /*
++ * If there is no room left in the current buffer in the
++ * scatter-gather list, move onto the next one.
++ */
++
++ if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
++ ++cmd->SCp.buffer;
++ --cmd->SCp.buffers_residual;
++ cmd->SCp.this_residual = cmd->SCp.buffer->length;
++ cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) +
++ cmd->SCp.buffer->offset;
++ /* ++roman: Try to merge some scatter-buffers if
++ * they are at contiguous physical addresses.
++ */
++ merge_contiguous_buffers(cmd);
++ INF_PRINTK("scsi%d: %d bytes and %d buffers left\n",
++ HOSTNO, cmd->SCp.this_residual,
++ cmd->SCp.buffers_residual);
++ }
++
++ /*
++ * The preferred transfer method is going to be
++ * PSEUDO-DMA for systems that are strictly PIO,
++ * since we can let the hardware do the handshaking.
++ *
++ * For this to work, we need to know the transfersize
++ * ahead of time, since the pseudo-DMA code will sit
++ * in an unconditional loop.
++ */
++
++ /* ++roman: I suggest, this should be
++ * #if def(REAL_DMA)
++ * instead of leaving REAL_DMA out.
++ */
+
+ #if defined(REAL_DMA)
+- if (!cmd->device->borken &&
+- (transfersize = NCR5380_dma_xfer_len(instance,cmd,phase)) > 31) {
+- len = transfersize;
+- cmd->SCp.phase = phase;
+- if (NCR5380_transfer_dma(instance, &phase,
+- &len, (unsigned char **) &cmd->SCp.ptr)) {
+- /*
+- * If the watchdog timer fires, all future
+- * accesses to this device will use the
+- * polled-IO. */
+- printk(KERN_NOTICE "scsi%d: switching target %d "
+- "lun %d to slow handshake\n", HOSTNO,
+- cmd->device->id, cmd->device->lun);
+- cmd->device->borken = 1;
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+- ICR_ASSERT_ATN);
+- sink = 1;
+- do_abort(instance);
+- cmd->result = DID_ERROR << 16;
+- cmd->done(cmd);
+- /* XXX - need to source or sink data here, as appropriate */
+- } else {
++ if (!cmd->device->borken &&
++ (transfersize = NCR5380_dma_xfer_len(instance,cmd,phase)) > 31) {
++ len = transfersize;
++ cmd->SCp.phase = phase;
++ if (NCR5380_transfer_dma(instance, &phase,
++ &len, (unsigned char **)&cmd->SCp.ptr)) {
++ /*
++ * If the watchdog timer fires, all future
++ * accesses to this device will use the
++ * polled-IO. */
++ printk(KERN_NOTICE "scsi%d: switching target %d "
++ "lun %d to slow handshake\n", HOSTNO,
++ cmd->device->id, cmd->device->lun);
++ cmd->device->borken = 1;
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
++ ICR_ASSERT_ATN);
++ sink = 1;
++ do_abort(instance);
++ cmd->result = DID_ERROR << 16;
++ cmd->done(cmd);
++ /* XXX - need to source or sink data here, as appropriate */
++ } else {
+ #ifdef REAL_DMA
+- /* ++roman: When using real DMA,
+- * information_transfer() should return after
+- * starting DMA since it has nothing more to
+- * do.
+- */
+- return;
+-#else
+- cmd->SCp.this_residual -= transfersize - len;
++ /* ++roman: When using real DMA,
++ * information_transfer() should return after
++ * starting DMA since it has nothing more to
++ * do.
++ */
++ return;
++#else
++ cmd->SCp.this_residual -= transfersize - len;
+ #endif
+- }
+- } else
++ }
++ } else
+ #endif /* defined(REAL_DMA) */
+- NCR5380_transfer_pio(instance, &phase,
+- (int *) &cmd->SCp.this_residual, (unsigned char **)
+- &cmd->SCp.ptr);
+- break;
+- case PHASE_MSGIN:
+- len = 1;
+- data = &tmp;
+- NCR5380_write(SELECT_ENABLE_REG, 0); /* disable reselects */
+- NCR5380_transfer_pio(instance, &phase, &len, &data);
+- cmd->SCp.Message = tmp;
+-
+- switch (tmp) {
+- /*
+- * Linking lets us reduce the time required to get the
+- * next command out to the device, hopefully this will
+- * mean we don't waste another revolution due to the delays
+- * required by ARBITRATION and another SELECTION.
+- *
+- * In the current implementation proposal, low level drivers
+- * merely have to start the next command, pointed to by
+- * next_link, done() is called as with unlinked commands.
+- */
++ NCR5380_transfer_pio(instance, &phase,
++ (int *)&cmd->SCp.this_residual,
++ (unsigned char **)&cmd->SCp.ptr);
++ break;
++ case PHASE_MSGIN:
++ len = 1;
++ data = &tmp;
++ NCR5380_write(SELECT_ENABLE_REG, 0); /* disable reselects */
++ NCR5380_transfer_pio(instance, &phase, &len, &data);
++ cmd->SCp.Message = tmp;
++
++ switch (tmp) {
++ /*
++ * Linking lets us reduce the time required to get the
++ * next command out to the device, hopefully this will
++ * mean we don't waste another revolution due to the delays
++ * required by ARBITRATION and another SELECTION.
++ *
++ * In the current implementation proposal, low level drivers
++ * merely have to start the next command, pointed to by
++ * next_link, done() is called as with unlinked commands.
++ */
+ #ifdef LINKED
+- case LINKED_CMD_COMPLETE:
+- case LINKED_FLG_CMD_COMPLETE:
+- /* Accept message by clearing ACK */
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+-
+- LNK_PRINTK("scsi%d: target %d lun %d linked command "
+- "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun);
+-
+- /* Enable reselect interrupts */
+- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+- /*
+- * Sanity check : A linked command should only terminate
+- * with one of these messages if there are more linked
+- * commands available.
+- */
+-
+- if (!cmd->next_link) {
+- printk(KERN_NOTICE "scsi%d: target %d lun %d "
+- "linked command complete, no next_link\n",
+- HOSTNO, cmd->device->id, cmd->device->lun);
+- sink = 1;
+- do_abort (instance);
+- return;
+- }
+-
+- initialize_SCp(cmd->next_link);
+- /* The next command is still part of this process; copy it
+- * and don't free it! */
+- cmd->next_link->tag = cmd->tag;
+- cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+- LNK_PRINTK("scsi%d: target %d lun %d linked request "
+- "done, calling scsi_done().\n",
+- HOSTNO, cmd->device->id, cmd->device->lun);
++ case LINKED_CMD_COMPLETE:
++ case LINKED_FLG_CMD_COMPLETE:
++ /* Accept message by clearing ACK */
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
++
++ LNK_PRINTK("scsi%d: target %d lun %d linked command "
++ "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun);
++
++ /* Enable reselect interrupts */
++ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
++ /*
++ * Sanity check : A linked command should only terminate
++ * with one of these messages if there are more linked
++ * commands available.
++ */
++
++ if (!cmd->next_link) {
++ printk(KERN_NOTICE "scsi%d: target %d lun %d "
++ "linked command complete, no next_link\n",
++ HOSTNO, cmd->device->id, cmd->device->lun);
++ sink = 1;
++ do_abort(instance);
++ return;
++ }
++
++ initialize_SCp(cmd->next_link);
++ /* The next command is still part of this process; copy it
++ * and don't free it! */
++ cmd->next_link->tag = cmd->tag;
++ cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
++ LNK_PRINTK("scsi%d: target %d lun %d linked request "
++ "done, calling scsi_done().\n",
++ HOSTNO, cmd->device->id, cmd->device->lun);
+ #ifdef NCR5380_STATS
+- collect_stats(hostdata, cmd);
++ collect_stats(hostdata, cmd);
+ #endif
+- cmd->scsi_done(cmd);
+- cmd = hostdata->connected;
+- break;
++ cmd->scsi_done(cmd);
++ cmd = hostdata->connected;
++ break;
+ #endif /* def LINKED */
+- case ABORT:
+- case COMMAND_COMPLETE:
+- /* Accept message by clearing ACK */
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+- /* ++guenther: possible race with Falcon locking */
+- falcon_dont_release++;
+- hostdata->connected = NULL;
+- QU_PRINTK("scsi%d: command for target %d, lun %d "
+- "completed\n", HOSTNO, cmd->device->id, cmd->device->lun);
++ case ABORT:
++ case COMMAND_COMPLETE:
++ /* Accept message by clearing ACK */
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
++ /* ++guenther: possible race with Falcon locking */
++ falcon_dont_release++;
++ hostdata->connected = NULL;
++ QU_PRINTK("scsi%d: command for target %d, lun %d "
++ "completed\n", HOSTNO, cmd->device->id, cmd->device->lun);
+ #ifdef SUPPORT_TAGS
+- cmd_free_tag( cmd );
+- if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
+- /* Turn a QUEUE FULL status into BUSY, I think the
+- * mid level cannot handle QUEUE FULL :-( (The
+- * command is retried after BUSY). Also update our
+- * queue size to the number of currently issued
+- * commands now.
+- */
+- /* ++Andreas: the mid level code knows about
+- QUEUE_FULL now. */
+- TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
+- TAG_PRINTK("scsi%d: target %d lun %d returned "
+- "QUEUE_FULL after %d commands\n",
+- HOSTNO, cmd->device->id, cmd->device->lun,
+- ta->nr_allocated);
+- if (ta->queue_size > ta->nr_allocated)
+- ta->nr_allocated = ta->queue_size;
+- }
++ cmd_free_tag(cmd);
++ if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
++ /* Turn a QUEUE FULL status into BUSY, I think the
++ * mid level cannot handle QUEUE FULL :-( (The
++ * command is retried after BUSY). Also update our
++ * queue size to the number of currently issued
++ * commands now.
++ */
++ /* ++Andreas: the mid level code knows about
++ QUEUE_FULL now. */
++ TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
++ TAG_PRINTK("scsi%d: target %d lun %d returned "
++ "QUEUE_FULL after %d commands\n",
++ HOSTNO, cmd->device->id, cmd->device->lun,
++ ta->nr_allocated);
++ if (ta->queue_size > ta->nr_allocated)
++ ta->nr_allocated = ta->queue_size;
++ }
+ #else
+- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
++ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+ #endif
+- /* Enable reselect interrupts */
+- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
++ /* Enable reselect interrupts */
++ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+
+- /*
+- * I'm not sure what the correct thing to do here is :
+- *
+- * If the command that just executed is NOT a request
+- * sense, the obvious thing to do is to set the result
+- * code to the values of the stored parameters.
+- *
+- * If it was a REQUEST SENSE command, we need some way to
+- * differentiate between the failure code of the original
+- * and the failure code of the REQUEST sense - the obvious
+- * case is success, where we fall through and leave the
+- * result code unchanged.
+- *
+- * The non-obvious place is where the REQUEST SENSE failed
+- */
+-
+- if (cmd->cmnd[0] != REQUEST_SENSE)
+- cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+- else if (status_byte(cmd->SCp.Status) != GOOD)
+- cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+-
+-#ifdef AUTOSENSE
+- if ((cmd->cmnd[0] != REQUEST_SENSE) &&
+- (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
+- ASEN_PRINTK("scsi%d: performing request sense\n",
+- HOSTNO);
+- cmd->cmnd[0] = REQUEST_SENSE;
+- cmd->cmnd[1] &= 0xe0;
+- cmd->cmnd[2] = 0;
+- cmd->cmnd[3] = 0;
+- cmd->cmnd[4] = sizeof(cmd->sense_buffer);
+- cmd->cmnd[5] = 0;
+- cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+-
+- cmd->use_sg = 0;
+- /* this is initialized from initialize_SCp
+- cmd->SCp.buffer = NULL;
+- cmd->SCp.buffers_residual = 0;
+- */
+- cmd->request_buffer = (char *) cmd->sense_buffer;
+- cmd->request_bufflen = sizeof(cmd->sense_buffer);
++ /*
++ * I'm not sure what the correct thing to do here is :
++ *
++ * If the command that just executed is NOT a request
++ * sense, the obvious thing to do is to set the result
++ * code to the values of the stored parameters.
++ *
++ * If it was a REQUEST SENSE command, we need some way to
++ * differentiate between the failure code of the original
++ * and the failure code of the REQUEST sense - the obvious
++ * case is success, where we fall through and leave the
++ * result code unchanged.
++ *
++ * The non-obvious place is where the REQUEST SENSE failed
++ */
++
++ if (cmd->cmnd[0] != REQUEST_SENSE)
++ cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
++ else if (status_byte(cmd->SCp.Status) != GOOD)
++ cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+
+- local_irq_save(flags);
+- LIST(cmd,hostdata->issue_queue);
+- NEXT(cmd) = hostdata->issue_queue;
+- hostdata->issue_queue = (Scsi_Cmnd *) cmd;
+- local_irq_restore(flags);
+- QU_PRINTK("scsi%d: REQUEST SENSE added to head of "
+- "issue queue\n", H_NO(cmd));
+- } else
++#ifdef AUTOSENSE
++ if ((cmd->cmnd[0] != REQUEST_SENSE) &&
++ (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
++ ASEN_PRINTK("scsi%d: performing request sense\n", HOSTNO);
++ cmd->cmnd[0] = REQUEST_SENSE;
++ cmd->cmnd[1] &= 0xe0;
++ cmd->cmnd[2] = 0;
++ cmd->cmnd[3] = 0;
++ cmd->cmnd[4] = sizeof(cmd->sense_buffer);
++ cmd->cmnd[5] = 0;
++ cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
++
++ cmd->use_sg = 0;
++ /* this is initialized from initialize_SCp
++ cmd->SCp.buffer = NULL;
++ cmd->SCp.buffers_residual = 0;
++ */
++ cmd->request_buffer = (char *) cmd->sense_buffer;
++ cmd->request_bufflen = sizeof(cmd->sense_buffer);
++
++ local_irq_save(flags);
++ LIST(cmd,hostdata->issue_queue);
++ NEXT(cmd) = hostdata->issue_queue;
++ hostdata->issue_queue = (Scsi_Cmnd *) cmd;
++ local_irq_restore(flags);
++ QU_PRINTK("scsi%d: REQUEST SENSE added to head of "
++ "issue queue\n", H_NO(cmd));
++ } else
+ #endif /* def AUTOSENSE */
+- {
++ {
+ #ifdef NCR5380_STATS
+- collect_stats(hostdata, cmd);
++ collect_stats(hostdata, cmd);
+ #endif
+- cmd->scsi_done(cmd);
+- }
++ cmd->scsi_done(cmd);
++ }
+
+- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+- /*
+- * Restore phase bits to 0 so an interrupted selection,
+- * arbitration can resume.
+- */
+- NCR5380_write(TARGET_COMMAND_REG, 0);
+-
+- while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+- barrier();
+-
+- falcon_dont_release--;
+- /* ++roman: For Falcon SCSI, release the lock on the
+- * ST-DMA here if no other commands are waiting on the
+- * disconnected queue.
+- */
+- falcon_release_lock_if_possible( hostdata );
+- return;
+- case MESSAGE_REJECT:
+- /* Accept message by clearing ACK */
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+- /* Enable reselect interrupts */
+- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+- switch (hostdata->last_message) {
+- case HEAD_OF_QUEUE_TAG:
+- case ORDERED_QUEUE_TAG:
+- case SIMPLE_QUEUE_TAG:
+- /* The target obviously doesn't support tagged
+- * queuing, even though it announced this ability in
+- * its INQUIRY data ?!? (maybe only this LUN?) Ok,
+- * clear 'tagged_supported' and lock the LUN, since
+- * the command is treated as untagged further on.
+- */
+- cmd->device->tagged_supported = 0;
+- hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+- cmd->tag = TAG_NONE;
+- TAG_PRINTK("scsi%d: target %d lun %d rejected "
+- "QUEUE_TAG message; tagged queuing "
+- "disabled\n",
+- HOSTNO, cmd->device->id, cmd->device->lun);
+- break;
+- }
+- break;
+- case DISCONNECT:
+- /* Accept message by clearing ACK */
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+- local_irq_save(flags);
+- cmd->device->disconnect = 1;
+- LIST(cmd,hostdata->disconnected_queue);
+- NEXT(cmd) = hostdata->disconnected_queue;
+- hostdata->connected = NULL;
+- hostdata->disconnected_queue = cmd;
+- local_irq_restore(flags);
+- QU_PRINTK("scsi%d: command for target %d lun %d was "
+- "moved from connected to the "
+- "disconnected_queue\n", HOSTNO,
+- cmd->device->id, cmd->device->lun);
+- /*
+- * Restore phase bits to 0 so an interrupted selection,
+- * arbitration can resume.
+- */
+- NCR5380_write(TARGET_COMMAND_REG, 0);
+-
+- /* Enable reselect interrupts */
+- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+- /* Wait for bus free to avoid nasty timeouts */
+- while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+- barrier();
+- return;
+- /*
+- * The SCSI data pointer is *IMPLICITLY* saved on a disconnect
+- * operation, in violation of the SCSI spec so we can safely
+- * ignore SAVE/RESTORE pointers calls.
+- *
+- * Unfortunately, some disks violate the SCSI spec and
+- * don't issue the required SAVE_POINTERS message before
+- * disconnecting, and we have to break spec to remain
+- * compatible.
+- */
+- case SAVE_POINTERS:
+- case RESTORE_POINTERS:
+- /* Accept message by clearing ACK */
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+- /* Enable reselect interrupts */
+- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+- break;
+- case EXTENDED_MESSAGE:
+-/*
+- * Extended messages are sent in the following format :
+- * Byte
+- * 0 EXTENDED_MESSAGE == 1
+- * 1 length (includes one byte for code, doesn't
+- * include first two bytes)
+- * 2 code
+- * 3..length+1 arguments
+- *
+- * Start the extended message buffer with the EXTENDED_MESSAGE
+- * byte, since spi_print_msg() wants the whole thing.
+- */
+- extended_msg[0] = EXTENDED_MESSAGE;
+- /* Accept first byte by clearing ACK */
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+-
+- EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO);
+-
+- len = 2;
+- data = extended_msg + 1;
+- phase = PHASE_MSGIN;
+- NCR5380_transfer_pio(instance, &phase, &len, &data);
+- EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO,
+- (int)extended_msg[1], (int)extended_msg[2]);
+-
+- if (!len && extended_msg[1] <=
+- (sizeof (extended_msg) - 1)) {
+- /* Accept third byte by clearing ACK */
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+- len = extended_msg[1] - 1;
+- data = extended_msg + 3;
+- phase = PHASE_MSGIN;
+-
+- NCR5380_transfer_pio(instance, &phase, &len, &data);
+- EXT_PRINTK("scsi%d: message received, residual %d\n",
+- HOSTNO, len);
+-
+- switch (extended_msg[2]) {
+- case EXTENDED_SDTR:
+- case EXTENDED_WDTR:
+- case EXTENDED_MODIFY_DATA_POINTER:
+- case EXTENDED_EXTENDED_IDENTIFY:
+- tmp = 0;
+- }
+- } else if (len) {
+- printk(KERN_NOTICE "scsi%d: error receiving "
+- "extended message\n", HOSTNO);
+- tmp = 0;
+- } else {
+- printk(KERN_NOTICE "scsi%d: extended message "
+- "code %02x length %d is too long\n",
+- HOSTNO, extended_msg[2], extended_msg[1]);
+- tmp = 0;
+- }
+- /* Fall through to reject message */
+-
+- /*
+- * If we get something weird that we aren't expecting,
+- * reject it.
+- */
+- default:
+- if (!tmp) {
+- printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO);
+- spi_print_msg(extended_msg);
+- printk("\n");
+- } else if (tmp != EXTENDED_MESSAGE)
+- printk(KERN_DEBUG "scsi%d: rejecting unknown "
+- "message %02x from target %d, lun %d\n",
+- HOSTNO, tmp, cmd->device->id, cmd->device->lun);
+- else
+- printk(KERN_DEBUG "scsi%d: rejecting unknown "
+- "extended message "
+- "code %02x, length %d from target %d, lun %d\n",
+- HOSTNO, extended_msg[1], extended_msg[0],
+- cmd->device->id, cmd->device->lun);
+-
+-
+- msgout = MESSAGE_REJECT;
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+- ICR_ASSERT_ATN);
+- break;
+- } /* switch (tmp) */
+- break;
+- case PHASE_MSGOUT:
+- len = 1;
+- data = &msgout;
+- hostdata->last_message = msgout;
+- NCR5380_transfer_pio(instance, &phase, &len, &data);
+- if (msgout == ABORT) {
++ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
++ /*
++ * Restore phase bits to 0 so an interrupted selection,
++ * arbitration can resume.
++ */
++ NCR5380_write(TARGET_COMMAND_REG, 0);
++
++ while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
++ barrier();
++
++ falcon_dont_release--;
++ /* ++roman: For Falcon SCSI, release the lock on the
++ * ST-DMA here if no other commands are waiting on the
++ * disconnected queue.
++ */
++ falcon_release_lock_if_possible(hostdata);
++ return;
++ case MESSAGE_REJECT:
++ /* Accept message by clearing ACK */
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
++ /* Enable reselect interrupts */
++ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
++ switch (hostdata->last_message) {
++ case HEAD_OF_QUEUE_TAG:
++ case ORDERED_QUEUE_TAG:
++ case SIMPLE_QUEUE_TAG:
++ /* The target obviously doesn't support tagged
++ * queuing, even though it announced this ability in
++ * its INQUIRY data ?!? (maybe only this LUN?) Ok,
++ * clear 'tagged_supported' and lock the LUN, since
++ * the command is treated as untagged further on.
++ */
++ cmd->device->tagged_supported = 0;
++ hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
++ cmd->tag = TAG_NONE;
++ TAG_PRINTK("scsi%d: target %d lun %d rejected "
++ "QUEUE_TAG message; tagged queuing "
++ "disabled\n",
++ HOSTNO, cmd->device->id, cmd->device->lun);
++ break;
++ }
++ break;
++ case DISCONNECT:
++ /* Accept message by clearing ACK */
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
++ local_irq_save(flags);
++ cmd->device->disconnect = 1;
++ LIST(cmd,hostdata->disconnected_queue);
++ NEXT(cmd) = hostdata->disconnected_queue;
++ hostdata->connected = NULL;
++ hostdata->disconnected_queue = cmd;
++ local_irq_restore(flags);
++ QU_PRINTK("scsi%d: command for target %d lun %d was "
++ "moved from connected to the "
++ "disconnected_queue\n", HOSTNO,
++ cmd->device->id, cmd->device->lun);
++ /*
++ * Restore phase bits to 0 so an interrupted selection,
++ * arbitration can resume.
++ */
++ NCR5380_write(TARGET_COMMAND_REG, 0);
++
++ /* Enable reselect interrupts */
++ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
++ /* Wait for bus free to avoid nasty timeouts */
++ while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
++ barrier();
++ return;
++ /*
++ * The SCSI data pointer is *IMPLICITLY* saved on a disconnect
++ * operation, in violation of the SCSI spec so we can safely
++ * ignore SAVE/RESTORE pointers calls.
++ *
++ * Unfortunately, some disks violate the SCSI spec and
++ * don't issue the required SAVE_POINTERS message before
++ * disconnecting, and we have to break spec to remain
++ * compatible.
++ */
++ case SAVE_POINTERS:
++ case RESTORE_POINTERS:
++ /* Accept message by clearing ACK */
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
++ /* Enable reselect interrupts */
++ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
++ break;
++ case EXTENDED_MESSAGE:
++ /*
++ * Extended messages are sent in the following format :
++ * Byte
++ * 0 EXTENDED_MESSAGE == 1
++ * 1 length (includes one byte for code, doesn't
++ * include first two bytes)
++ * 2 code
++ * 3..length+1 arguments
++ *
++ * Start the extended message buffer with the EXTENDED_MESSAGE
++ * byte, since spi_print_msg() wants the whole thing.
++ */
++ extended_msg[0] = EXTENDED_MESSAGE;
++ /* Accept first byte by clearing ACK */
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
++
++ EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO);
++
++ len = 2;
++ data = extended_msg + 1;
++ phase = PHASE_MSGIN;
++ NCR5380_transfer_pio(instance, &phase, &len, &data);
++ EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO,
++ (int)extended_msg[1], (int)extended_msg[2]);
++
++ if (!len && extended_msg[1] <=
++ (sizeof(extended_msg) - 1)) {
++ /* Accept third byte by clearing ACK */
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
++ len = extended_msg[1] - 1;
++ data = extended_msg + 3;
++ phase = PHASE_MSGIN;
++
++ NCR5380_transfer_pio(instance, &phase, &len, &data);
++ EXT_PRINTK("scsi%d: message received, residual %d\n",
++ HOSTNO, len);
++
++ switch (extended_msg[2]) {
++ case EXTENDED_SDTR:
++ case EXTENDED_WDTR:
++ case EXTENDED_MODIFY_DATA_POINTER:
++ case EXTENDED_EXTENDED_IDENTIFY:
++ tmp = 0;
++ }
++ } else if (len) {
++ printk(KERN_NOTICE "scsi%d: error receiving "
++ "extended message\n", HOSTNO);
++ tmp = 0;
++ } else {
++ printk(KERN_NOTICE "scsi%d: extended message "
++ "code %02x length %d is too long\n",
++ HOSTNO, extended_msg[2], extended_msg[1]);
++ tmp = 0;
++ }
++ /* Fall through to reject message */
++
++ /*
++ * If we get something weird that we aren't expecting,
++ * reject it.
++ */
++ default:
++ if (!tmp) {
++ printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO);
++ spi_print_msg(extended_msg);
++ printk("\n");
++ } else if (tmp != EXTENDED_MESSAGE)
++ printk(KERN_DEBUG "scsi%d: rejecting unknown "
++ "message %02x from target %d, lun %d\n",
++ HOSTNO, tmp, cmd->device->id, cmd->device->lun);
++ else
++ printk(KERN_DEBUG "scsi%d: rejecting unknown "
++ "extended message "
++ "code %02x, length %d from target %d, lun %d\n",
++ HOSTNO, extended_msg[1], extended_msg[0],
++ cmd->device->id, cmd->device->lun);
++
++
++ msgout = MESSAGE_REJECT;
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
++ break;
++ } /* switch (tmp) */
++ break;
++ case PHASE_MSGOUT:
++ len = 1;
++ data = &msgout;
++ hostdata->last_message = msgout;
++ NCR5380_transfer_pio(instance, &phase, &len, &data);
++ if (msgout == ABORT) {
+ #ifdef SUPPORT_TAGS
+- cmd_free_tag( cmd );
++ cmd_free_tag(cmd);
+ #else
+- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
++ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+ #endif
+- hostdata->connected = NULL;
+- cmd->result = DID_ERROR << 16;
++ hostdata->connected = NULL;
++ cmd->result = DID_ERROR << 16;
+ #ifdef NCR5380_STATS
+- collect_stats(hostdata, cmd);
++ collect_stats(hostdata, cmd);
+ #endif
+- cmd->scsi_done(cmd);
+- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+- falcon_release_lock_if_possible( hostdata );
+- return;
+- }
+- msgout = NOP;
+- break;
+- case PHASE_CMDOUT:
+- len = cmd->cmd_len;
+- data = cmd->cmnd;
+- /*
+- * XXX for performance reasons, on machines with a
+- * PSEUDO-DMA architecture we should probably
+- * use the dma transfer function.
+- */
+- NCR5380_transfer_pio(instance, &phase, &len,
+- &data);
+- break;
+- case PHASE_STATIN:
+- len = 1;
+- data = &tmp;
+- NCR5380_transfer_pio(instance, &phase, &len, &data);
+- cmd->SCp.Status = tmp;
+- break;
+- default:
+- printk("scsi%d: unknown phase\n", HOSTNO);
+- NCR_PRINT(NDEBUG_ANY);
+- } /* switch(phase) */
+- } /* if (tmp * SR_REQ) */
+- } /* while (1) */
++ cmd->scsi_done(cmd);
++ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
++ falcon_release_lock_if_possible(hostdata);
++ return;
++ }
++ msgout = NOP;
++ break;
++ case PHASE_CMDOUT:
++ len = cmd->cmd_len;
++ data = cmd->cmnd;
++ /*
++ * XXX for performance reasons, on machines with a
++ * PSEUDO-DMA architecture we should probably
++ * use the dma transfer function.
++ */
++ NCR5380_transfer_pio(instance, &phase, &len, &data);
++ break;
++ case PHASE_STATIN:
++ len = 1;
++ data = &tmp;
++ NCR5380_transfer_pio(instance, &phase, &len, &data);
++ cmd->SCp.Status = tmp;
++ break;
++ default:
++ printk("scsi%d: unknown phase\n", HOSTNO);
++ NCR_PRINT(NDEBUG_ANY);
++ } /* switch(phase) */
++ } /* if (tmp * SR_REQ) */
++ } /* while (1) */
+ }
+
+ /*
+ * Function : void NCR5380_reselect (struct Scsi_Host *instance)
+ *
+- * Purpose : does reselection, initializing the instance->connected
+- * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q
++ * Purpose : does reselection, initializing the instance->connected
++ * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q
+ * nexus has been reestablished,
+- *
++ *
+ * Inputs : instance - this instance of the NCR5380.
+ *
+ */
+
+
+-static void NCR5380_reselect (struct Scsi_Host *instance)
++static void NCR5380_reselect(struct Scsi_Host *instance)
+ {
+- SETUP_HOSTDATA(instance);
+- unsigned char target_mask;
+- unsigned char lun, phase;
+- int len;
++ SETUP_HOSTDATA(instance);
++ unsigned char target_mask;
++ unsigned char lun, phase;
++ int len;
+ #ifdef SUPPORT_TAGS
+- unsigned char tag;
++ unsigned char tag;
+ #endif
+- unsigned char msg[3];
+- unsigned char *data;
+- Scsi_Cmnd *tmp = NULL, *prev;
+-/* unsigned long flags; */
+-
+- /*
+- * Disable arbitration, etc. since the host adapter obviously
+- * lost, and tell an interrupted NCR5380_select() to restart.
+- */
+-
+- NCR5380_write(MODE_REG, MR_BASE);
+- hostdata->restart_select = 1;
+-
+- target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
+-
+- RSL_PRINTK("scsi%d: reselect\n", HOSTNO);
+-
+- /*
+- * At this point, we have detected that our SCSI ID is on the bus,
+- * SEL is true and BSY was false for at least one bus settle delay
+- * (400 ns).
+- *
+- * We must assert BSY ourselves, until the target drops the SEL
+- * signal.
+- */
+-
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
+-
+- while (NCR5380_read(STATUS_REG) & SR_SEL);
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+-
+- /*
+- * Wait for target to go into MSGIN.
+- */
+-
+- while (!(NCR5380_read(STATUS_REG) & SR_REQ));
+-
+- len = 1;
+- data = msg;
+- phase = PHASE_MSGIN;
+- NCR5380_transfer_pio(instance, &phase, &len, &data);
+-
+- if (!(msg[0] & 0x80)) {
+- printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO);
+- spi_print_msg(msg);
+- do_abort(instance);
+- return;
+- }
+- lun = (msg[0] & 0x07);
++ unsigned char msg[3];
++ unsigned char *data;
++ Scsi_Cmnd *tmp = NULL, *prev;
++/* unsigned long flags; */
++
++ /*
++ * Disable arbitration, etc. since the host adapter obviously
++ * lost, and tell an interrupted NCR5380_select() to restart.
++ */
++
++ NCR5380_write(MODE_REG, MR_BASE);
++ hostdata->restart_select = 1;
++
++ target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
++
++ RSL_PRINTK("scsi%d: reselect\n", HOSTNO);
++
++ /*
++ * At this point, we have detected that our SCSI ID is on the bus,
++ * SEL is true and BSY was false for at least one bus settle delay
++ * (400 ns).
++ *
++ * We must assert BSY ourselves, until the target drops the SEL
++ * signal.
++ */
++
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
++
++ while (NCR5380_read(STATUS_REG) & SR_SEL)
++ ;
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
++
++ /*
++ * Wait for target to go into MSGIN.
++ */
++
++ while (!(NCR5380_read(STATUS_REG) & SR_REQ))
++ ;
++
++ len = 1;
++ data = msg;
++ phase = PHASE_MSGIN;
++ NCR5380_transfer_pio(instance, &phase, &len, &data);
++
++ if (!(msg[0] & 0x80)) {
++ printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO);
++ spi_print_msg(msg);
++ do_abort(instance);
++ return;
++ }
++ lun = (msg[0] & 0x07);
+
+ #ifdef SUPPORT_TAGS
+- /* If the phase is still MSGIN, the target wants to send some more
+- * messages. In case it supports tagged queuing, this is probably a
+- * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus.
+- */
+- tag = TAG_NONE;
+- if (phase == PHASE_MSGIN && setup_use_tagged_queuing) {
+- /* Accept previous IDENTIFY message by clearing ACK */
+- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
+- len = 2;
+- data = msg+1;
+- if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
+- msg[1] == SIMPLE_QUEUE_TAG)
+- tag = msg[2];
+- TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at "
+- "reselection\n", HOSTNO, target_mask, lun, tag);
+- }
+-#endif
+-
+- /*
+- * Find the command corresponding to the I_T_L or I_T_L_Q nexus we
+- * just reestablished, and remove it from the disconnected queue.
+- */
+-
+- for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL;
+- tmp; prev = tmp, tmp = NEXT(tmp) ) {
+- if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun)
++ /* If the phase is still MSGIN, the target wants to send some more
++ * messages. In case it supports tagged queuing, this is probably a
++ * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus.
++ */
++ tag = TAG_NONE;
++ if (phase == PHASE_MSGIN && setup_use_tagged_queuing) {
++ /* Accept previous IDENTIFY message by clearing ACK */
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
++ len = 2;
++ data = msg + 1;
++ if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
++ msg[1] == SIMPLE_QUEUE_TAG)
++ tag = msg[2];
++ TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at "
++ "reselection\n", HOSTNO, target_mask, lun, tag);
++ }
++#endif
++
++ /*
++ * Find the command corresponding to the I_T_L or I_T_L_Q nexus we
++ * just reestablished, and remove it from the disconnected queue.
++ */
++
++ for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL;
++ tmp; prev = tmp, tmp = NEXT(tmp)) {
++ if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun)
+ #ifdef SUPPORT_TAGS
+- && (tag == tmp->tag)
++ && (tag == tmp->tag)
+ #endif
+- ) {
+- /* ++guenther: prevent race with falcon_release_lock */
+- falcon_dont_release++;
+- if (prev) {
+- REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
+- NEXT(prev) = NEXT(tmp);
+- } else {
+- REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp));
+- hostdata->disconnected_queue = NEXT(tmp);
+- }
+- NEXT(tmp) = NULL;
+- break;
+- }
+- }
+-
+- if (!tmp) {
+- printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d "
++ ) {
++ /* ++guenther: prevent race with falcon_release_lock */
++ falcon_dont_release++;
++ if (prev) {
++ REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
++ NEXT(prev) = NEXT(tmp);
++ } else {
++ REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp));
++ hostdata->disconnected_queue = NEXT(tmp);
++ }
++ NEXT(tmp) = NULL;
++ break;
++ }
++ }
++
++ if (!tmp) {
++ printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d "
+ #ifdef SUPPORT_TAGS
+- "tag %d "
++ "tag %d "
+ #endif
+- "not in disconnected_queue.\n",
+- HOSTNO, target_mask, lun
++ "not in disconnected_queue.\n",
++ HOSTNO, target_mask, lun
+ #ifdef SUPPORT_TAGS
+- , tag
++ , tag
+ #endif
+- );
+- /*
+- * Since we have an established nexus that we can't do anything
+- * with, we must abort it.
+- */
+- do_abort(instance);
+- return;
+- }
+-
+- /* Accept message by clearing ACK */
+- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+-
+- hostdata->connected = tmp;
+- RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n",
+- HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag);
+- falcon_dont_release--;
++ );
++ /*
++ * Since we have an established nexus that we can't do anything
++ * with, we must abort it.
++ */
++ do_abort(instance);
++ return;
++ }
++
++ /* Accept message by clearing ACK */
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
++
++ hostdata->connected = tmp;
++ RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n",
++ HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag);
++ falcon_dont_release--;
+ }
+
+
+@@ -2666,362 +2676,361 @@ static void NCR5380_reselect (struct Scs
+ *
+ * Purpose : abort a command
+ *
+- * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the
+- * host byte of the result field to, if zero DID_ABORTED is
++ * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the
++ * host byte of the result field to, if zero DID_ABORTED is
+ * used.
+ *
+ * Returns : 0 - success, -1 on failure.
+ *
+- * XXX - there is no way to abort the command that is currently
+- * connected, you have to wait for it to complete. If this is
++ * XXX - there is no way to abort the command that is currently
++ * connected, you have to wait for it to complete. If this is
+ * a problem, we could implement longjmp() / setjmp(), setjmp()
+- * called where the loop started in NCR5380_main().
++ * called where the loop started in NCR5380_main().
+ */
+
+ static
+-int NCR5380_abort (Scsi_Cmnd *cmd)
++int NCR5380_abort(Scsi_Cmnd *cmd)
+ {
+- struct Scsi_Host *instance = cmd->device->host;
+- SETUP_HOSTDATA(instance);
+- Scsi_Cmnd *tmp, **prev;
+- unsigned long flags;
+-
+- printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO);
+- scsi_print_command(cmd);
+-
+- NCR5380_print_status (instance);
+-
+- local_irq_save(flags);
+-
+- if (!IS_A_TT() && !falcon_got_lock)
+- printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n",
+- HOSTNO);
+-
+- ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
+- NCR5380_read(BUS_AND_STATUS_REG),
+- NCR5380_read(STATUS_REG));
++ struct Scsi_Host *instance = cmd->device->host;
++ SETUP_HOSTDATA(instance);
++ Scsi_Cmnd *tmp, **prev;
++ unsigned long flags;
++
++ printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO);
++ scsi_print_command(cmd);
++
++ NCR5380_print_status(instance);
++
++ local_irq_save(flags);
++
++ if (!IS_A_TT() && !falcon_got_lock)
++ printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n",
++ HOSTNO);
++
++ ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
++ NCR5380_read(BUS_AND_STATUS_REG),
++ NCR5380_read(STATUS_REG));
+
+ #if 1
+-/*
+- * Case 1 : If the command is the currently executing command,
+- * we'll set the aborted flag and return control so that
+- * information transfer routine can exit cleanly.
+- */
++ /*
++ * Case 1 : If the command is the currently executing command,
++ * we'll set the aborted flag and return control so that
++ * information transfer routine can exit cleanly.
++ */
+
+- if (hostdata->connected == cmd) {
++ if (hostdata->connected == cmd) {
+
+- ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO);
+-/*
+- * We should perform BSY checking, and make sure we haven't slipped
+- * into BUS FREE.
+- */
++ ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO);
++ /*
++ * We should perform BSY checking, and make sure we haven't slipped
++ * into BUS FREE.
++ */
+
+-/* NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */
+-/*
+- * Since we can't change phases until we've completed the current
+- * handshake, we have to source or sink a byte of data if the current
+- * phase is not MSGOUT.
+- */
++ /* NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */
++ /*
++ * Since we can't change phases until we've completed the current
++ * handshake, we have to source or sink a byte of data if the current
++ * phase is not MSGOUT.
++ */
+
+-/*
+- * Return control to the executing NCR drive so we can clear the
+- * aborted flag and get back into our main loop.
+- */
++ /*
++ * Return control to the executing NCR drive so we can clear the
++ * aborted flag and get back into our main loop.
++ */
+
+- if (do_abort(instance) == 0) {
+- hostdata->aborted = 1;
+- hostdata->connected = NULL;
+- cmd->result = DID_ABORT << 16;
++ if (do_abort(instance) == 0) {
++ hostdata->aborted = 1;
++ hostdata->connected = NULL;
++ cmd->result = DID_ABORT << 16;
+ #ifdef SUPPORT_TAGS
+- cmd_free_tag( cmd );
++ cmd_free_tag(cmd);
+ #else
+- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
++ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
++#endif
++ local_irq_restore(flags);
++ cmd->scsi_done(cmd);
++ falcon_release_lock_if_possible(hostdata);
++ return SCSI_ABORT_SUCCESS;
++ } else {
++/* local_irq_restore(flags); */
++ printk("scsi%d: abort of connected command failed!\n", HOSTNO);
++ return SCSI_ABORT_ERROR;
++ }
++ }
+ #endif
+- local_irq_restore(flags);
+- cmd->scsi_done(cmd);
+- falcon_release_lock_if_possible( hostdata );
+- return SCSI_ABORT_SUCCESS;
+- } else {
+-/* local_irq_restore(flags); */
+- printk("scsi%d: abort of connected command failed!\n", HOSTNO);
+- return SCSI_ABORT_ERROR;
+- }
+- }
+-#endif
+-
+-/*
+- * Case 2 : If the command hasn't been issued yet, we simply remove it
+- * from the issue queue.
+- */
+- for (prev = (Scsi_Cmnd **) &(hostdata->issue_queue),
+- tmp = (Scsi_Cmnd *) hostdata->issue_queue;
+- tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
+- if (cmd == tmp) {
+- REMOVE(5, *prev, tmp, NEXT(tmp));
+- (*prev) = NEXT(tmp);
+- NEXT(tmp) = NULL;
+- tmp->result = DID_ABORT << 16;
+- local_irq_restore(flags);
+- ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n",
+- HOSTNO);
+- /* Tagged queuing note: no tag to free here, hasn't been assigned
+- * yet... */
+- tmp->scsi_done(tmp);
+- falcon_release_lock_if_possible( hostdata );
+- return SCSI_ABORT_SUCCESS;
+- }
+-
+-/*
+- * Case 3 : If any commands are connected, we're going to fail the abort
+- * and let the high level SCSI driver retry at a later time or
+- * issue a reset.
+- *
+- * Timeouts, and therefore aborted commands, will be highly unlikely
+- * and handling them cleanly in this situation would make the common
+- * case of noresets less efficient, and would pollute our code. So,
+- * we fail.
+- */
+
+- if (hostdata->connected) {
+- local_irq_restore(flags);
+- ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO);
+- return SCSI_ABORT_SNOOZE;
+- }
+-
+-/*
+- * Case 4: If the command is currently disconnected from the bus, and
+- * there are no connected commands, we reconnect the I_T_L or
+- * I_T_L_Q nexus associated with it, go into message out, and send
+- * an abort message.
+- *
+- * This case is especially ugly. In order to reestablish the nexus, we
+- * need to call NCR5380_select(). The easiest way to implement this
+- * function was to abort if the bus was busy, and let the interrupt
+- * handler triggered on the SEL for reselect take care of lost arbitrations
+- * where necessary, meaning interrupts need to be enabled.
+- *
+- * When interrupts are enabled, the queues may change - so we
+- * can't remove it from the disconnected queue before selecting it
+- * because that could cause a failure in hashing the nexus if that
+- * device reselected.
+- *
+- * Since the queues may change, we can't use the pointers from when we
+- * first locate it.
+- *
+- * So, we must first locate the command, and if NCR5380_select()
+- * succeeds, then issue the abort, relocate the command and remove
+- * it from the disconnected queue.
+- */
+-
+- for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
+- tmp = NEXT(tmp))
+- if (cmd == tmp) {
+- local_irq_restore(flags);
+- ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO);
+-
+- if (NCR5380_select (instance, cmd, (int) cmd->tag))
+- return SCSI_ABORT_BUSY;
+-
+- ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO);
+-
+- do_abort (instance);
+-
+- local_irq_save(flags);
+- for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue),
+- tmp = (Scsi_Cmnd *) hostdata->disconnected_queue;
+- tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
+- if (cmd == tmp) {
+- REMOVE(5, *prev, tmp, NEXT(tmp));
+- *prev = NEXT(tmp);
+- NEXT(tmp) = NULL;
+- tmp->result = DID_ABORT << 16;
+- /* We must unlock the tag/LUN immediately here, since the
+- * target goes to BUS FREE and doesn't send us another
+- * message (COMMAND_COMPLETE or the like)
+- */
++ /*
++ * Case 2 : If the command hasn't been issued yet, we simply remove it
++ * from the issue queue.
++ */
++ for (prev = (Scsi_Cmnd **)&(hostdata->issue_queue),
++ tmp = (Scsi_Cmnd *)hostdata->issue_queue;
++ tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) {
++ if (cmd == tmp) {
++ REMOVE(5, *prev, tmp, NEXT(tmp));
++ (*prev) = NEXT(tmp);
++ NEXT(tmp) = NULL;
++ tmp->result = DID_ABORT << 16;
++ local_irq_restore(flags);
++ ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n",
++ HOSTNO);
++ /* Tagged queuing note: no tag to free here, hasn't been assigned
++ * yet... */
++ tmp->scsi_done(tmp);
++ falcon_release_lock_if_possible(hostdata);
++ return SCSI_ABORT_SUCCESS;
++ }
++ }
++
++ /*
++ * Case 3 : If any commands are connected, we're going to fail the abort
++ * and let the high level SCSI driver retry at a later time or
++ * issue a reset.
++ *
++ * Timeouts, and therefore aborted commands, will be highly unlikely
++ * and handling them cleanly in this situation would make the common
++ * case of noresets less efficient, and would pollute our code. So,
++ * we fail.
++ */
++
++ if (hostdata->connected) {
++ local_irq_restore(flags);
++ ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO);
++ return SCSI_ABORT_SNOOZE;
++ }
++
++ /*
++ * Case 4: If the command is currently disconnected from the bus, and
++ * there are no connected commands, we reconnect the I_T_L or
++ * I_T_L_Q nexus associated with it, go into message out, and send
++ * an abort message.
++ *
++ * This case is especially ugly. In order to reestablish the nexus, we
++ * need to call NCR5380_select(). The easiest way to implement this
++ * function was to abort if the bus was busy, and let the interrupt
++ * handler triggered on the SEL for reselect take care of lost arbitrations
++ * where necessary, meaning interrupts need to be enabled.
++ *
++ * When interrupts are enabled, the queues may change - so we
++ * can't remove it from the disconnected queue before selecting it
++ * because that could cause a failure in hashing the nexus if that
++ * device reselected.
++ *
++ * Since the queues may change, we can't use the pointers from when we
++ * first locate it.
++ *
++ * So, we must first locate the command, and if NCR5380_select()
++ * succeeds, then issue the abort, relocate the command and remove
++ * it from the disconnected queue.
++ */
++
++ for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
++ tmp = NEXT(tmp)) {
++ if (cmd == tmp) {
++ local_irq_restore(flags);
++ ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO);
++
++ if (NCR5380_select(instance, cmd, (int)cmd->tag))
++ return SCSI_ABORT_BUSY;
++
++ ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO);
++
++ do_abort(instance);
++
++ local_irq_save(flags);
++ for (prev = (Scsi_Cmnd **)&(hostdata->disconnected_queue),
++ tmp = (Scsi_Cmnd *)hostdata->disconnected_queue;
++ tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) {
++ if (cmd == tmp) {
++ REMOVE(5, *prev, tmp, NEXT(tmp));
++ *prev = NEXT(tmp);
++ NEXT(tmp) = NULL;
++ tmp->result = DID_ABORT << 16;
++ /* We must unlock the tag/LUN immediately here, since the
++ * target goes to BUS FREE and doesn't send us another
++ * message (COMMAND_COMPLETE or the like)
++ */
+ #ifdef SUPPORT_TAGS
+- cmd_free_tag( tmp );
++ cmd_free_tag(tmp);
+ #else
+- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
++ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+ #endif
+- local_irq_restore(flags);
+- tmp->scsi_done(tmp);
+- falcon_release_lock_if_possible( hostdata );
+- return SCSI_ABORT_SUCCESS;
++ local_irq_restore(flags);
++ tmp->scsi_done(tmp);
++ falcon_release_lock_if_possible(hostdata);
++ return SCSI_ABORT_SUCCESS;
++ }
++ }
+ }
+ }
+
+-/*
+- * Case 5 : If we reached this point, the command was not found in any of
+- * the queues.
+- *
+- * We probably reached this point because of an unlikely race condition
+- * between the command completing successfully and the abortion code,
+- * so we won't panic, but we will notify the user in case something really
+- * broke.
+- */
++ /*
++ * Case 5 : If we reached this point, the command was not found in any of
++ * the queues.
++ *
++ * We probably reached this point because of an unlikely race condition
++ * between the command completing successfully and the abortion code,
++ * so we won't panic, but we will notify the user in case something really
++ * broke.
++ */
+
+- local_irq_restore(flags);
+- printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n"
+- KERN_INFO " before abortion\n", HOSTNO);
++ local_irq_restore(flags);
++ printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n"
++ KERN_INFO " before abortion\n", HOSTNO);
+
+-/* Maybe it is sufficient just to release the ST-DMA lock... (if
+- * possible at all) At least, we should check if the lock could be
+- * released after the abort, in case it is kept due to some bug.
+- */
+- falcon_release_lock_if_possible( hostdata );
++ /* Maybe it is sufficient just to release the ST-DMA lock... (if
++ * possible at all) At least, we should check if the lock could be
++ * released after the abort, in case it is kept due to some bug.
++ */
++ falcon_release_lock_if_possible(hostdata);
+
+- return SCSI_ABORT_NOT_RUNNING;
++ return SCSI_ABORT_NOT_RUNNING;
+ }
+
+
+-/*
++/*
+ * Function : int NCR5380_reset (Scsi_Cmnd *cmd)
+- *
++ *
+ * Purpose : reset the SCSI bus.
+ *
+ * Returns : SCSI_RESET_WAKEUP
+ *
+- */
++ */
+
+-static int NCR5380_bus_reset( Scsi_Cmnd *cmd)
++static int NCR5380_bus_reset(Scsi_Cmnd *cmd)
+ {
+- SETUP_HOSTDATA(cmd->device->host);
+- int i;
+- unsigned long flags;
++ SETUP_HOSTDATA(cmd->device->host);
++ int i;
++ unsigned long flags;
+ #if 1
+- Scsi_Cmnd *connected, *disconnected_queue;
++ Scsi_Cmnd *connected, *disconnected_queue;
+ #endif
+
+- if (!IS_A_TT() && !falcon_got_lock)
+- printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n",
+- H_NO(cmd) );
+-
+- NCR5380_print_status (cmd->device->host);
+-
+- /* get in phase */
+- NCR5380_write( TARGET_COMMAND_REG,
+- PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
+- /* assert RST */
+- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
+- udelay (40);
+- /* reset NCR registers */
+- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
+- NCR5380_write( MODE_REG, MR_BASE );
+- NCR5380_write( TARGET_COMMAND_REG, 0 );
+- NCR5380_write( SELECT_ENABLE_REG, 0 );
+- /* ++roman: reset interrupt condition! otherwise no interrupts don't get
+- * through anymore ... */
+- (void)NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+-
+-#if 1 /* XXX Should now be done by midlevel code, but it's broken XXX */
+- /* XXX see below XXX */
+-
+- /* MSch: old-style reset: actually abort all command processing here */
+-
+- /* After the reset, there are no more connected or disconnected commands
+- * and no busy units; to avoid problems with re-inserting the commands
+- * into the issue_queue (via scsi_done()), the aborted commands are
+- * remembered in local variables first.
+- */
+- local_irq_save(flags);
+- connected = (Scsi_Cmnd *)hostdata->connected;
+- hostdata->connected = NULL;
+- disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue;
+- hostdata->disconnected_queue = NULL;
++ if (!IS_A_TT() && !falcon_got_lock)
++ printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n",
++ H_NO(cmd));
++
++ NCR5380_print_status(cmd->device->host);
++
++ /* get in phase */
++ NCR5380_write(TARGET_COMMAND_REG,
++ PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG)));
++ /* assert RST */
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
++ udelay(40);
++ /* reset NCR registers */
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
++ NCR5380_write(MODE_REG, MR_BASE);
++ NCR5380_write(TARGET_COMMAND_REG, 0);
++ NCR5380_write(SELECT_ENABLE_REG, 0);
++ /* ++roman: reset interrupt condition! otherwise no interrupts don't get
++ * through anymore ... */
++ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
++
++#if 1 /* XXX Should now be done by midlevel code, but it's broken XXX */
++ /* XXX see below XXX */
++
++ /* MSch: old-style reset: actually abort all command processing here */
++
++ /* After the reset, there are no more connected or disconnected commands
++ * and no busy units; to avoid problems with re-inserting the commands
++ * into the issue_queue (via scsi_done()), the aborted commands are
++ * remembered in local variables first.
++ */
++ local_irq_save(flags);
++ connected = (Scsi_Cmnd *)hostdata->connected;
++ hostdata->connected = NULL;
++ disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue;
++ hostdata->disconnected_queue = NULL;
+ #ifdef SUPPORT_TAGS
+- free_all_tags();
++ free_all_tags();
+ #endif
+- for( i = 0; i < 8; ++i )
+- hostdata->busy[i] = 0;
++ for (i = 0; i < 8; ++i)
++ hostdata->busy[i] = 0;
+ #ifdef REAL_DMA
+- hostdata->dma_len = 0;
++ hostdata->dma_len = 0;
+ #endif
+- local_irq_restore(flags);
++ local_irq_restore(flags);
+
+- /* In order to tell the mid-level code which commands were aborted,
+- * set the command status to DID_RESET and call scsi_done() !!!
+- * This ultimately aborts processing of these commands in the mid-level.
+- */
+-
+- if ((cmd = connected)) {
+- ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
+- cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
+- cmd->scsi_done( cmd );
+- }
++ /* In order to tell the mid-level code which commands were aborted,
++ * set the command status to DID_RESET and call scsi_done() !!!
++ * This ultimately aborts processing of these commands in the mid-level.
++ */
+
+- for (i = 0; (cmd = disconnected_queue); ++i) {
+- disconnected_queue = NEXT(cmd);
+- NEXT(cmd) = NULL;
+- cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
+- cmd->scsi_done( cmd );
+- }
+- if (i > 0)
+- ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i);
+-
+-/* The Falcon lock should be released after a reset...
+- */
+-/* ++guenther: moved to atari_scsi_reset(), to prevent a race between
+- * unlocking and enabling dma interrupt.
+- */
+-/* falcon_release_lock_if_possible( hostdata );*/
+-
+- /* since all commands have been explicitly terminated, we need to tell
+- * the midlevel code that the reset was SUCCESSFUL, and there is no
+- * need to 'wake up' the commands by a request_sense
+- */
+- return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
++ if ((cmd = connected)) {
++ ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
++ cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
++ cmd->scsi_done(cmd);
++ }
++
++ for (i = 0; (cmd = disconnected_queue); ++i) {
++ disconnected_queue = NEXT(cmd);
++ NEXT(cmd) = NULL;
++ cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
++ cmd->scsi_done(cmd);
++ }
++ if (i > 0)
++ ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i);
++
++ /* The Falcon lock should be released after a reset...
++ */
++ /* ++guenther: moved to atari_scsi_reset(), to prevent a race between
++ * unlocking and enabling dma interrupt.
++ */
++/* falcon_release_lock_if_possible( hostdata );*/
++
++ /* since all commands have been explicitly terminated, we need to tell
++ * the midlevel code that the reset was SUCCESSFUL, and there is no
++ * need to 'wake up' the commands by a request_sense
++ */
++ return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
+ #else /* 1 */
+
+- /* MSch: new-style reset handling: let the mid-level do what it can */
++ /* MSch: new-style reset handling: let the mid-level do what it can */
++
++ /* ++guenther: MID-LEVEL IS STILL BROKEN.
++ * Mid-level is supposed to requeue all commands that were active on the
++ * various low-level queues. In fact it does this, but that's not enough
++ * because all these commands are subject to timeout. And if a timeout
++ * happens for any removed command, *_abort() is called but all queues
++ * are now empty. Abort then gives up the falcon lock, which is fatal,
++ * since the mid-level will queue more commands and must have the lock
++ * (it's all happening inside timer interrupt handler!!).
++ * Even worse, abort will return NOT_RUNNING for all those commands not
++ * on any queue, so they won't be retried ...
++ *
++ * Conclusion: either scsi.c disables timeout for all resetted commands
++ * immediately, or we lose! As of linux-2.0.20 it doesn't.
++ */
++
++ /* After the reset, there are no more connected or disconnected commands
++ * and no busy units; so clear the low-level status here to avoid
++ * conflicts when the mid-level code tries to wake up the affected
++ * commands!
++ */
++
++ if (hostdata->issue_queue)
++ ABRT_PRINTK("scsi%d: reset aborted issued command(s)\n", H_NO(cmd));
++ if (hostdata->connected)
++ ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
++ if (hostdata->disconnected_queue)
++ ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd));
+
+- /* ++guenther: MID-LEVEL IS STILL BROKEN.
+- * Mid-level is supposed to requeue all commands that were active on the
+- * various low-level queues. In fact it does this, but that's not enough
+- * because all these commands are subject to timeout. And if a timeout
+- * happens for any removed command, *_abort() is called but all queues
+- * are now empty. Abort then gives up the falcon lock, which is fatal,
+- * since the mid-level will queue more commands and must have the lock
+- * (it's all happening inside timer interrupt handler!!).
+- * Even worse, abort will return NOT_RUNNING for all those commands not
+- * on any queue, so they won't be retried ...
+- *
+- * Conclusion: either scsi.c disables timeout for all resetted commands
+- * immediately, or we lose! As of linux-2.0.20 it doesn't.
+- */
+-
+- /* After the reset, there are no more connected or disconnected commands
+- * and no busy units; so clear the low-level status here to avoid
+- * conflicts when the mid-level code tries to wake up the affected
+- * commands!
+- */
+-
+- if (hostdata->issue_queue)
+- ABRT_PRINTK("scsi%d: reset aborted issued command(s)\n", H_NO(cmd));
+- if (hostdata->connected)
+- ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
+- if (hostdata->disconnected_queue)
+- ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd));
+-
+- local_irq_save(flags);
+- hostdata->issue_queue = NULL;
+- hostdata->connected = NULL;
+- hostdata->disconnected_queue = NULL;
++ local_irq_save(flags);
++ hostdata->issue_queue = NULL;
++ hostdata->connected = NULL;
++ hostdata->disconnected_queue = NULL;
+ #ifdef SUPPORT_TAGS
+- free_all_tags();
++ free_all_tags();
+ #endif
+- for( i = 0; i < 8; ++i )
+- hostdata->busy[i] = 0;
++ for (i = 0; i < 8; ++i)
++ hostdata->busy[i] = 0;
+ #ifdef REAL_DMA
+- hostdata->dma_len = 0;
++ hostdata->dma_len = 0;
+ #endif
+- local_irq_restore(flags);
++ local_irq_restore(flags);
+
+- /* we did no complete reset of all commands, so a wakeup is required */
+- return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET;
++ /* we did no complete reset of all commands, so a wakeup is required */
++ return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET;
+ #endif /* 1 */
+ }
+-
+-/* Local Variables: */
+-/* tab-width: 8 */
+-/* End: */
+--- linux-m68k-2.6.21.orig/drivers/scsi/atari_scsi.c
++++ linux-m68k-2.6.21/drivers/scsi/atari_scsi.c
+@@ -186,38 +186,37 @@ static inline void DISABLE_IRQ(void)
+ /***************************** Prototypes *****************************/
+
+ #ifdef REAL_DMA
+-static int scsi_dma_is_ignored_buserr( unsigned char dma_stat );
+-static void atari_scsi_fetch_restbytes( void );
+-static long atari_scsi_dma_residual( struct Scsi_Host *instance );
+-static int falcon_classify_cmd( Scsi_Cmnd *cmd );
+-static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
+- Scsi_Cmnd *cmd, int write_flag );
+-#endif
+-static irqreturn_t scsi_tt_intr( int irq, void *dummy);
+-static irqreturn_t scsi_falcon_intr( int irq, void *dummy);
+-static void falcon_release_lock_if_possible( struct NCR5380_hostdata *
+- hostdata );
+-static void falcon_get_lock( void );
++static int scsi_dma_is_ignored_buserr(unsigned char dma_stat);
++static void atari_scsi_fetch_restbytes(void);
++static long atari_scsi_dma_residual(struct Scsi_Host *instance);
++static int falcon_classify_cmd(Scsi_Cmnd *cmd);
++static unsigned long atari_dma_xfer_len(unsigned long wanted_len,
++ Scsi_Cmnd *cmd, int write_flag);
++#endif
++static irqreturn_t scsi_tt_intr(int irq, void *dummy);
++static irqreturn_t scsi_falcon_intr(int irq, void *dummy);
++static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata);
++static void falcon_get_lock(void);
+ #ifdef CONFIG_ATARI_SCSI_RESET_BOOT
+-static void atari_scsi_reset_boot( void );
++static void atari_scsi_reset_boot(void);
+ #endif
+-static unsigned char atari_scsi_tt_reg_read( unsigned char reg );
+-static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value);
+-static unsigned char atari_scsi_falcon_reg_read( unsigned char reg );
+-static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value );
++static unsigned char atari_scsi_tt_reg_read(unsigned char reg);
++static void atari_scsi_tt_reg_write(unsigned char reg, unsigned char value);
++static unsigned char atari_scsi_falcon_reg_read(unsigned char reg);
++static void atari_scsi_falcon_reg_write(unsigned char reg, unsigned char value);
+
+ /************************* End of Prototypes **************************/
+
+
+-static struct Scsi_Host *atari_scsi_host = NULL;
+-static unsigned char (*atari_scsi_reg_read)( unsigned char reg );
+-static void (*atari_scsi_reg_write)( unsigned char reg, unsigned char value );
++static struct Scsi_Host *atari_scsi_host;
++static unsigned char (*atari_scsi_reg_read)(unsigned char reg);
++static void (*atari_scsi_reg_write)(unsigned char reg, unsigned char value);
+
+ #ifdef REAL_DMA
+ static unsigned long atari_dma_residual, atari_dma_startaddr;
+ static short atari_dma_active;
+ /* pointer to the dribble buffer */
+-static char *atari_dma_buffer = NULL;
++static char *atari_dma_buffer;
+ /* precalculated physical address of the dribble buffer */
+ static unsigned long atari_dma_phys_buffer;
+ /* != 0 tells the Falcon int handler to copy data from the dribble buffer */
+@@ -233,7 +232,7 @@ static char *atari_dma_orig_addr;
+ static unsigned long atari_dma_stram_mask;
+ #define STRAM_ADDR(a) (((a) & atari_dma_stram_mask) == 0)
+ /* number of bytes to cut from a transfer to handle NCR overruns */
+-static int atari_read_overruns = 0;
++static int atari_read_overruns;
+ #endif
+
+ static int setup_can_queue = -1;
+@@ -256,10 +255,10 @@ module_param(setup_hostid, int, 0);
+
+ #if defined(REAL_DMA)
+
+-static int scsi_dma_is_ignored_buserr( unsigned char dma_stat )
++static int scsi_dma_is_ignored_buserr(unsigned char dma_stat)
+ {
+ int i;
+- unsigned long addr = SCSI_DMA_READ_P( dma_addr ), end_addr;
++ unsigned long addr = SCSI_DMA_READ_P(dma_addr), end_addr;
+
+ if (dma_stat & 0x01) {
+
+@@ -267,15 +266,14 @@ static int scsi_dma_is_ignored_buserr( u
+ * physical memory chunk (DMA prefetch!), but that doesn't hurt.
+ * Check for this case:
+ */
+-
+- for( i = 0; i < m68k_num_memory; ++i ) {
+- end_addr = m68k_memory[i].addr +
+- m68k_memory[i].size;
++
++ for (i = 0; i < m68k_num_memory; ++i) {
++ end_addr = m68k_memory[i].addr + m68k_memory[i].size;
+ if (end_addr <= addr && addr <= end_addr + 4)
+- return( 1 );
++ return 1;
+ }
+ }
+- return( 0 );
++ return 0;
+ }
+
+
+@@ -284,28 +282,27 @@ static int scsi_dma_is_ignored_buserr( u
+ * end-of-DMA, both SCSI ints are triggered simultaneously, so the NCR int has
+ * to clear the DMA int pending bit before it allows other level 6 interrupts.
+ */
+-static void scsi_dma_buserr (int irq, void *dummy)
++static void scsi_dma_buserr(int irq, void *dummy)
+ {
+- unsigned char dma_stat = tt_scsi_dma.dma_ctrl;
++ unsigned char dma_stat = tt_scsi_dma.dma_ctrl;
+
+ /* Don't do anything if a NCR interrupt is pending. Probably it's just
+ * masked... */
+- if (atari_irq_pending( IRQ_TT_MFP_SCSI ))
++ if (atari_irq_pending(IRQ_TT_MFP_SCSI))
+ return;
+-
++
+ printk("Bad SCSI DMA interrupt! dma_addr=0x%08lx dma_stat=%02x dma_cnt=%08lx\n",
+ SCSI_DMA_READ_P(dma_addr), dma_stat, SCSI_DMA_READ_P(dma_cnt));
+ if (dma_stat & 0x80) {
+- if (!scsi_dma_is_ignored_buserr( dma_stat ))
+- printk( "SCSI DMA bus error -- bad DMA programming!\n" );
+- }
+- else {
++ if (!scsi_dma_is_ignored_buserr(dma_stat))
++ printk("SCSI DMA bus error -- bad DMA programming!\n");
++ } else {
+ /* Under normal circumstances we never should get to this point,
+ * since both interrupts are triggered simultaneously and the 5380
+ * int has higher priority. When this irq is handled, that DMA
+ * interrupt is cleared. So a warning message is printed here.
+ */
+- printk( "SCSI DMA intr ?? -- this shouldn't happen!\n" );
++ printk("SCSI DMA intr ?? -- this shouldn't happen!\n");
+ }
+ }
+ #endif
+@@ -313,7 +310,7 @@ static void scsi_dma_buserr (int irq, vo
+ #endif
+
+
+-static irqreturn_t scsi_tt_intr (int irq, void *dummy)
++static irqreturn_t scsi_tt_intr(int irq, void *dummy)
+ {
+ #ifdef REAL_DMA
+ int dma_stat;
+@@ -327,7 +324,7 @@ static irqreturn_t scsi_tt_intr (int irq
+ * is that a bus error occurred...
+ */
+ if (dma_stat & 0x80) {
+- if (!scsi_dma_is_ignored_buserr( dma_stat )) {
++ if (!scsi_dma_is_ignored_buserr(dma_stat)) {
+ printk(KERN_ERR "SCSI DMA caused bus error near 0x%08lx\n",
+ SCSI_DMA_READ_P(dma_addr));
+ printk(KERN_CRIT "SCSI DMA bus error -- bad DMA programming!");
+@@ -344,8 +341,7 @@ static irqreturn_t scsi_tt_intr (int irq
+ * data reg!
+ */
+ if ((dma_stat & 0x02) && !(dma_stat & 0x40)) {
+- atari_dma_residual = HOSTDATA_DMALEN - (SCSI_DMA_READ_P( dma_addr ) -
+- atari_dma_startaddr);
++ atari_dma_residual = HOSTDATA_DMALEN - (SCSI_DMA_READ_P(dma_addr) - atari_dma_startaddr);
+
+ DMA_PRINTK("SCSI DMA: There are %ld residual bytes.\n",
+ atari_dma_residual);
+@@ -353,28 +349,30 @@ static irqreturn_t scsi_tt_intr (int irq
+ if ((signed int)atari_dma_residual < 0)
+ atari_dma_residual = 0;
+ if ((dma_stat & 1) == 0) {
+- /* After read operations, we maybe have to
+- transport some rest bytes */
++ /*
++ * After read operations, we maybe have to
++ * transport some rest bytes
++ */
+ atari_scsi_fetch_restbytes();
+- }
+- else {
+- /* There seems to be a nasty bug in some SCSI-DMA/NCR
+- combinations: If a target disconnects while a write
+- operation is going on, the address register of the
+- DMA may be a few bytes farer than it actually read.
+- This is probably due to DMA prefetching and a delay
+- between DMA and NCR. Experiments showed that the
+- dma_addr is 9 bytes to high, but this could vary.
+- The problem is, that the residual is thus calculated
+- wrong and the next transfer will start behind where
+- it should. So we round up the residual to the next
+- multiple of a sector size, if it isn't already a
+- multiple and the originally expected transfer size
+- was. The latter condition is there to ensure that
+- the correction is taken only for "real" data
+- transfers and not for, e.g., the parameters of some
+- other command. These shouldn't disconnect anyway.
+- */
++ } else {
++ /*
++ * There seems to be a nasty bug in some SCSI-DMA/NCR
++ * combinations: If a target disconnects while a write
++ * operation is going on, the address register of the
++ * DMA may be a few bytes farer than it actually read.
++ * This is probably due to DMA prefetching and a delay
++ * between DMA and NCR. Experiments showed that the
++ * dma_addr is 9 bytes to high, but this could vary.
++ * The problem is, that the residual is thus calculated
++ * wrong and the next transfer will start behind where
++ * it should. So we round up the residual to the next
++ * multiple of a sector size, if it isn't already a
++ * multiple and the originally expected transfer size
++ * was. The latter condition is there to ensure that
++ * the correction is taken only for "real" data
++ * transfers and not for, e.g., the parameters of some
++ * other command. These shouldn't disconnect anyway.
++ */
+ if (atari_dma_residual & 0x1ff) {
+ DMA_PRINTK("SCSI DMA: DMA bug corrected, "
+ "difference %ld bytes\n",
+@@ -394,18 +392,18 @@ static irqreturn_t scsi_tt_intr (int irq
+ }
+
+ #endif /* REAL_DMA */
+-
++
+ NCR5380_intr(0, 0);
+
+ #if 0
+ /* To be sure the int is not masked */
+- atari_enable_irq( IRQ_TT_MFP_SCSI );
++ atari_enable_irq(IRQ_TT_MFP_SCSI);
+ #endif
+ return IRQ_HANDLED;
+ }
+
+
+-static irqreturn_t scsi_falcon_intr (int irq, void *dummy)
++static irqreturn_t scsi_falcon_intr(int irq, void *dummy)
+ {
+ #ifdef REAL_DMA
+ int dma_stat;
+@@ -430,7 +428,7 @@ static irqreturn_t scsi_falcon_intr (int
+ * bytes are stuck in the ST-DMA fifo (there's no way to reach them!)
+ */
+ if (atari_dma_active && (dma_stat & 0x02)) {
+- unsigned long transferred;
++ unsigned long transferred;
+
+ transferred = SCSI_DMA_GETADR() - atari_dma_startaddr;
+ /* The ST-DMA address is incremented in 2-byte steps, but the
+@@ -445,8 +443,7 @@ static irqreturn_t scsi_falcon_intr (int
+ atari_dma_residual = HOSTDATA_DMALEN - transferred;
+ DMA_PRINTK("SCSI DMA: There are %ld residual bytes.\n",
+ atari_dma_residual);
+- }
+- else
++ } else
+ atari_dma_residual = 0;
+ atari_dma_active = 0;
+
+@@ -467,7 +464,7 @@ static irqreturn_t scsi_falcon_intr (int
+
+
+ #ifdef REAL_DMA
+-static void atari_scsi_fetch_restbytes( void )
++static void atari_scsi_fetch_restbytes(void)
+ {
+ int nr;
+ char *src, *dst;
+@@ -505,19 +502,17 @@ static int falcon_dont_release = 0;
+ * again (but others waiting longer more probably will win).
+ */
+
+-static void
+-falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata )
++static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata)
+ {
+ unsigned long flags;
+-
+- if (IS_A_TT()) return;
+-
++
++ if (IS_A_TT())
++ return;
++
+ local_irq_save(flags);
+
+- if (falcon_got_lock &&
+- !hostdata->disconnected_queue &&
+- !hostdata->issue_queue &&
+- !hostdata->connected) {
++ if (falcon_got_lock && !hostdata->disconnected_queue &&
++ !hostdata->issue_queue && !hostdata->connected) {
+
+ if (falcon_dont_release) {
+ #if 0
+@@ -528,7 +523,7 @@ falcon_release_lock_if_possible( struct
+ }
+ falcon_got_lock = 0;
+ stdma_release();
+- wake_up( &falcon_fairness_wait );
++ wake_up(&falcon_fairness_wait);
+ }
+
+ local_irq_restore(flags);
+@@ -549,31 +544,31 @@ falcon_release_lock_if_possible( struct
+ * Complicated, complicated.... Sigh...
+ */
+
+-static void falcon_get_lock( void )
++static void falcon_get_lock(void)
+ {
+ unsigned long flags;
+
+- if (IS_A_TT()) return;
++ if (IS_A_TT())
++ return;
+
+ local_irq_save(flags);
+
+ while (!in_irq() && falcon_got_lock && stdma_others_waiting())
+- sleep_on( &falcon_fairness_wait );
++ sleep_on(&falcon_fairness_wait);
+
+ while (!falcon_got_lock) {
+ if (in_irq())
+- panic( "Falcon SCSI hasn't ST-DMA lock in interrupt" );
++ panic("Falcon SCSI hasn't ST-DMA lock in interrupt");
+ if (!falcon_trying_lock) {
+ falcon_trying_lock = 1;
+ stdma_lock(scsi_falcon_intr, NULL);
+ falcon_got_lock = 1;
+ falcon_trying_lock = 0;
+- wake_up( &falcon_try_wait );
+- }
+- else {
+- sleep_on( &falcon_try_wait );
++ wake_up(&falcon_try_wait);
++ } else {
++ sleep_on(&falcon_try_wait);
+ }
+- }
++ }
+
+ local_irq_restore(flags);
+ if (!falcon_got_lock)
+@@ -587,18 +582,18 @@ static void falcon_get_lock( void )
+ */
+
+ #if 0
+-int atari_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
++int atari_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+ {
+ /* falcon_get_lock();
+ * ++guenther: moved to NCR5380_queue_command() to prevent
+ * race condition, see there for an explanation.
+ */
+- return( NCR5380_queue_command( cmd, done ) );
++ return NCR5380_queue_command(cmd, done);
+ }
+ #endif
+
+
+-int atari_scsi_detect (struct scsi_host_template *host)
++int atari_scsi_detect(struct scsi_host_template *host)
+ {
+ static int called = 0;
+ struct Scsi_Host *instance;
+@@ -606,7 +601,7 @@ int atari_scsi_detect (struct scsi_host_
+ if (!MACH_IS_ATARI ||
+ (!ATARIHW_PRESENT(ST_SCSI) && !ATARIHW_PRESENT(TT_SCSI)) ||
+ called)
+- return( 0 );
++ return 0;
+
+ host->proc_name = "Atari";
+
+@@ -655,32 +650,33 @@ int atari_scsi_detect (struct scsi_host_
+ !ATARIHW_PRESENT(EXTD_DMA) && m68k_num_memory > 1) {
+ atari_dma_buffer = atari_stram_alloc(STRAM_BUFFER_SIZE, "SCSI");
+ if (!atari_dma_buffer) {
+- printk( KERN_ERR "atari_scsi_detect: can't allocate ST-RAM "
+- "double buffer\n" );
+- return( 0 );
++ printk(KERN_ERR "atari_scsi_detect: can't allocate ST-RAM "
++ "double buffer\n");
++ return 0;
+ }
+- atari_dma_phys_buffer = virt_to_phys( atari_dma_buffer );
++ atari_dma_phys_buffer = virt_to_phys(atari_dma_buffer);
+ atari_dma_orig_addr = 0;
+ }
+ #endif
+- instance = scsi_register (host, sizeof (struct NCR5380_hostdata));
+- if(instance == NULL)
+- {
++ instance = scsi_register(host, sizeof(struct NCR5380_hostdata));
++ if (instance == NULL) {
+ atari_stram_free(atari_dma_buffer);
+ atari_dma_buffer = 0;
+ return 0;
+ }
+ atari_scsi_host = instance;
+- /* Set irq to 0, to avoid that the mid-level code disables our interrupt
+- * during queue_command calls. This is completely unnecessary, and even
+- * worse causes bad problems on the Falcon, where the int is shared with
+- * IDE and floppy! */
++ /*
++ * Set irq to 0, to avoid that the mid-level code disables our interrupt
++ * during queue_command calls. This is completely unnecessary, and even
++ * worse causes bad problems on the Falcon, where the int is shared with
++ * IDE and floppy!
++ */
+ instance->irq = 0;
+
+ #ifdef CONFIG_ATARI_SCSI_RESET_BOOT
+ atari_scsi_reset_boot();
+ #endif
+- NCR5380_init (instance, 0);
++ NCR5380_init(instance, 0);
+
+ if (IS_A_TT()) {
+
+@@ -727,11 +723,10 @@ int atari_scsi_detect (struct scsi_host_
+ * the rest data bug is fixed, this can be lowered to 1.
+ */
+ atari_read_overruns = 4;
+- }
++ }
+ #endif /*REAL_DMA*/
+- }
+- else { /* ! IS_A_TT */
+-
++ } else { /* ! IS_A_TT */
++
+ /* Nothing to do for the interrupt: the ST-DMA is initialized
+ * already by atari_init_INTS()
+ */
+@@ -756,19 +751,19 @@ int atari_scsi_detect (struct scsi_host_
+ setup_use_tagged_queuing ? "yes" : "no",
+ #endif
+ instance->hostt->this_id );
+- NCR5380_print_options (instance);
+- printk ("\n");
++ NCR5380_print_options(instance);
++ printk("\n");
+
+ called = 1;
+- return( 1 );
++ return 1;
+ }
+
+-int atari_scsi_release (struct Scsi_Host *sh)
++int atari_scsi_release(struct Scsi_Host *sh)
+ {
+ if (IS_A_TT())
+ free_irq(IRQ_TT_MFP_SCSI, scsi_tt_intr);
+ if (atari_dma_buffer)
+- atari_stram_free (atari_dma_buffer);
++ atari_stram_free(atari_dma_buffer);
+ return 1;
+ }
+
+@@ -779,9 +774,9 @@ void __init atari_scsi_setup(char *str,
+ * Defaults depend on TT or Falcon, hostid determined at run time.
+ * Negative values mean don't change.
+ */
+-
++
+ if (ints[0] < 1) {
+- printk( "atari_scsi_setup: no arguments!\n" );
++ printk("atari_scsi_setup: no arguments!\n");
+ return;
+ }
+
+@@ -807,7 +802,7 @@ void __init atari_scsi_setup(char *str,
+ if (ints[4] >= 0 && ints[4] <= 7)
+ setup_hostid = ints[4];
+ else if (ints[4] > 7)
+- printk( "atari_scsi_setup: invalid host ID %d !\n", ints[4] );
++ printk("atari_scsi_setup: invalid host ID %d !\n", ints[4]);
+ }
+ #ifdef SUPPORT_TAGS
+ if (ints[0] >= 5) {
+@@ -819,7 +814,7 @@ void __init atari_scsi_setup(char *str,
+
+ int atari_scsi_bus_reset(Scsi_Cmnd *cmd)
+ {
+- int rv;
++ int rv;
+ struct NCR5380_hostdata *hostdata =
+ (struct NCR5380_hostdata *)cmd->device->host->hostdata;
+
+@@ -829,13 +824,12 @@ int atari_scsi_bus_reset(Scsi_Cmnd *cmd)
+ */
+ /* And abort a maybe active DMA transfer */
+ if (IS_A_TT()) {
+- atari_turnoff_irq( IRQ_TT_MFP_SCSI );
++ atari_turnoff_irq(IRQ_TT_MFP_SCSI);
+ #ifdef REAL_DMA
+ tt_scsi_dma.dma_ctrl = 0;
+ #endif /* REAL_DMA */
+- }
+- else {
+- atari_turnoff_irq( IRQ_MFP_FSCSI );
++ } else {
++ atari_turnoff_irq(IRQ_MFP_FSCSI);
+ #ifdef REAL_DMA
+ st_dma.dma_mode_status = 0x90;
+ atari_dma_active = 0;
+@@ -847,52 +841,51 @@ int atari_scsi_bus_reset(Scsi_Cmnd *cmd)
+
+ /* Re-enable ints */
+ if (IS_A_TT()) {
+- atari_turnon_irq( IRQ_TT_MFP_SCSI );
+- }
+- else {
+- atari_turnon_irq( IRQ_MFP_FSCSI );
++ atari_turnon_irq(IRQ_TT_MFP_SCSI);
++ } else {
++ atari_turnon_irq(IRQ_MFP_FSCSI);
+ }
+ if ((rv & SCSI_RESET_ACTION) == SCSI_RESET_SUCCESS)
+ falcon_release_lock_if_possible(hostdata);
+
+- return( rv );
++ return rv;
+ }
+
+-
++
+ #ifdef CONFIG_ATARI_SCSI_RESET_BOOT
+ static void __init atari_scsi_reset_boot(void)
+ {
+ unsigned long end;
+-
++
+ /*
+ * Do a SCSI reset to clean up the bus during initialization. No messing
+ * with the queues, interrupts, or locks necessary here.
+ */
+
+- printk( "Atari SCSI: resetting the SCSI bus..." );
++ printk("Atari SCSI: resetting the SCSI bus...");
+
+ /* get in phase */
+- NCR5380_write( TARGET_COMMAND_REG,
+- PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
++ NCR5380_write(TARGET_COMMAND_REG,
++ PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG)));
+
+ /* assert RST */
+- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
+ /* The min. reset hold time is 25us, so 40us should be enough */
+- udelay( 50 );
++ udelay(50);
+ /* reset RST and interrupt */
+- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
+- NCR5380_read( RESET_PARITY_INTERRUPT_REG );
++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
++ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+
+ end = jiffies + AFTER_RESET_DELAY;
+ while (time_before(jiffies, end))
+ barrier();
+
+- printk( " done\n" );
++ printk(" done\n");
+ }
+ #endif
+
+
+-const char * atari_scsi_info (struct Scsi_Host *host)
++const char *atari_scsi_info(struct Scsi_Host *host)
+ {
+ /* atari_scsi_detect() is verbose enough... */
+ static const char string[] = "Atari native SCSI";
+@@ -902,10 +895,10 @@ const char * atari_scsi_info (struct Scs
+
+ #if defined(REAL_DMA)
+
+-unsigned long atari_scsi_dma_setup( struct Scsi_Host *instance, void *data,
+- unsigned long count, int dir )
++unsigned long atari_scsi_dma_setup(struct Scsi_Host *instance, void *data,
++ unsigned long count, int dir)
+ {
+- unsigned long addr = virt_to_phys( data );
++ unsigned long addr = virt_to_phys(data);
+
+ DMA_PRINTK("scsi%d: setting up dma, data = %p, phys = %lx, count = %ld, "
+ "dir = %d\n", instance->host_no, data, addr, count, dir);
+@@ -917,38 +910,37 @@ unsigned long atari_scsi_dma_setup( stru
+ * wanted address.
+ */
+ if (dir)
+- memcpy( atari_dma_buffer, data, count );
++ memcpy(atari_dma_buffer, data, count);
+ else
+ atari_dma_orig_addr = data;
+ addr = atari_dma_phys_buffer;
+ }
+-
++
+ atari_dma_startaddr = addr; /* Needed for calculating residual later. */
+-
++
+ /* Cache cleanup stuff: On writes, push any dirty cache out before sending
+ * it to the peripheral. (Must be done before DMA setup, since at least
+ * the ST-DMA begins to fill internal buffers right after setup. For
+ * reads, invalidate any cache, may be altered after DMA without CPU
+ * knowledge.
+- *
++ *
+ * ++roman: For the Medusa, there's no need at all for that cache stuff,
+ * because the hardware does bus snooping (fine!).
+ */
+- dma_cache_maintenance( addr, count, dir );
++ dma_cache_maintenance(addr, count, dir);
+
+ if (count == 0)
+ printk(KERN_NOTICE "SCSI warning: DMA programmed for 0 bytes !\n");
+
+ if (IS_A_TT()) {
+ tt_scsi_dma.dma_ctrl = dir;
+- SCSI_DMA_WRITE_P( dma_addr, addr );
+- SCSI_DMA_WRITE_P( dma_cnt, count );
++ SCSI_DMA_WRITE_P(dma_addr, addr);
++ SCSI_DMA_WRITE_P(dma_cnt, count);
+ tt_scsi_dma.dma_ctrl = dir | 2;
+- }
+- else { /* ! IS_A_TT */
+-
++ } else { /* ! IS_A_TT */
++
+ /* set address */
+- SCSI_DMA_SETADR( addr );
++ SCSI_DMA_SETADR(addr);
+
+ /* toggle direction bit to clear FIFO and set DMA direction */
+ dir <<= 8;
+@@ -966,13 +958,13 @@ unsigned long atari_scsi_dma_setup( stru
+ atari_dma_active = 1;
+ }
+
+- return( count );
++ return count;
+ }
+
+
+-static long atari_scsi_dma_residual( struct Scsi_Host *instance )
++static long atari_scsi_dma_residual(struct Scsi_Host *instance)
+ {
+- return( atari_dma_residual );
++ return atari_dma_residual;
+ }
+
+
+@@ -980,13 +972,13 @@ static long atari_scsi_dma_residual( str
+ #define CMD_SURELY_BYTE_MODE 1
+ #define CMD_MODE_UNKNOWN 2
+
+-static int falcon_classify_cmd( Scsi_Cmnd *cmd )
++static int falcon_classify_cmd(Scsi_Cmnd *cmd)
+ {
+ unsigned char opcode = cmd->cmnd[0];
+-
++
+ if (opcode == READ_DEFECT_DATA || opcode == READ_LONG ||
+- opcode == READ_BUFFER)
+- return( CMD_SURELY_BYTE_MODE );
++ opcode == READ_BUFFER)
++ return CMD_SURELY_BYTE_MODE;
+ else if (opcode == READ_6 || opcode == READ_10 ||
+ opcode == 0xa8 /* READ_12 */ || opcode == READ_REVERSE ||
+ opcode == RECOVER_BUFFERED_DATA) {
+@@ -994,12 +986,11 @@ static int falcon_classify_cmd( Scsi_Cmn
+ * needed here: The transfer is block-mode only if the 'fixed' bit is
+ * set! */
+ if (cmd->device->type == TYPE_TAPE && !(cmd->cmnd[1] & 1))
+- return( CMD_SURELY_BYTE_MODE );
++ return CMD_SURELY_BYTE_MODE;
+ else
+- return( CMD_SURELY_BLOCK_MODE );
+- }
+- else
+- return( CMD_MODE_UNKNOWN );
++ return CMD_SURELY_BLOCK_MODE;
++ } else
++ return CMD_MODE_UNKNOWN;
+ }
+
+
+@@ -1012,19 +1003,18 @@ static int falcon_classify_cmd( Scsi_Cmn
+ * the overrun problem, so this question is academic :-)
+ */
+
+-static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
+- Scsi_Cmnd *cmd,
+- int write_flag )
++static unsigned long atari_dma_xfer_len(unsigned long wanted_len,
++ Scsi_Cmnd *cmd, int write_flag)
+ {
+ unsigned long possible_len, limit;
+ #ifndef CONFIG_TT_DMA_EMUL
+ if (MACH_IS_HADES)
+ /* Hades has no SCSI DMA at all :-( Always force use of PIO */
+- return( 0 );
+-#endif
++ return 0;
++#endif
+ if (IS_A_TT())
+ /* TT SCSI DMA can transfer arbitrary #bytes */
+- return( wanted_len );
++ return wanted_len;
+
+ /* ST DMA chip is stupid -- only multiples of 512 bytes! (and max.
+ * 255*512 bytes, but this should be enough)
+@@ -1060,8 +1050,7 @@ static unsigned long atari_dma_xfer_len(
+ * this).
+ */
+ possible_len = wanted_len;
+- }
+- else {
++ } else {
+ /* Read operations: if the wanted transfer length is not a multiple of
+ * 512, we cannot use DMA, since the ST-DMA cannot split transfers
+ * (no interrupt on DMA finished!)
+@@ -1071,15 +1060,15 @@ static unsigned long atari_dma_xfer_len(
+ else {
+ /* Now classify the command (see above) and decide whether it is
+ * allowed to do DMA at all */
+- switch( falcon_classify_cmd( cmd )) {
+- case CMD_SURELY_BLOCK_MODE:
++ switch (falcon_classify_cmd(cmd)) {
++ case CMD_SURELY_BLOCK_MODE:
+ possible_len = wanted_len;
+ break;
+- case CMD_SURELY_BYTE_MODE:
++ case CMD_SURELY_BYTE_MODE:
+ possible_len = 0; /* DMA prohibited */
+ break;
+- case CMD_MODE_UNKNOWN:
+- default:
++ case CMD_MODE_UNKNOWN:
++ default:
+ /* For unknown commands assume block transfers if the transfer
+ * size/allocation length is >= 1024 */
+ possible_len = (wanted_len < 1024) ? 0 : wanted_len;
+@@ -1087,9 +1076,9 @@ static unsigned long atari_dma_xfer_len(
+ }
+ }
+ }
+-
++
+ /* Last step: apply the hard limit on DMA transfers */
+- limit = (atari_dma_buffer && !STRAM_ADDR( virt_to_phys(cmd->SCp.ptr) )) ?
++ limit = (atari_dma_buffer && !STRAM_ADDR(virt_to_phys(cmd->SCp.ptr))) ?
+ STRAM_BUFFER_SIZE : 255*512;
+ if (possible_len > limit)
+ possible_len = limit;
+@@ -1098,7 +1087,7 @@ static unsigned long atari_dma_xfer_len(
+ DMA_PRINTK("Sorry, must cut DMA transfer size to %ld bytes "
+ "instead of %ld\n", possible_len, wanted_len);
+
+- return( possible_len );
++ return possible_len;
+ }
+
+
+@@ -1112,23 +1101,23 @@ static unsigned long atari_dma_xfer_len(
+ * NCR5380_write call these functions via function pointers.
+ */
+
+-static unsigned char atari_scsi_tt_reg_read( unsigned char reg )
++static unsigned char atari_scsi_tt_reg_read(unsigned char reg)
+ {
+- return( tt_scsi_regp[reg * 2] );
++ return tt_scsi_regp[reg * 2];
+ }
+
+-static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value )
++static void atari_scsi_tt_reg_write(unsigned char reg, unsigned char value)
+ {
+ tt_scsi_regp[reg * 2] = value;
+ }
+
+-static unsigned char atari_scsi_falcon_reg_read( unsigned char reg )
++static unsigned char atari_scsi_falcon_reg_read(unsigned char reg)
+ {
+ dma_wd.dma_mode_status= (u_short)(0x88 + reg);
+- return( (u_char)dma_wd.fdc_acces_seccount );
++ return (u_char)dma_wd.fdc_acces_seccount;
+ }
+
+-static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value )
++static void atari_scsi_falcon_reg_write(unsigned char reg, unsigned char value)
+ {
+ dma_wd.dma_mode_status = (u_short)(0x88 + reg);
+ dma_wd.fdc_acces_seccount = (u_short)value;
diff --git a/debian/patches/bugfix/m68k/atari_NCR5380-work.diff b/debian/patches/bugfix/m68k/atari_NCR5380-work.diff
new file mode 100644
index 000000000000..d49bdfdcb786
--- /dev/null
+++ b/debian/patches/bugfix/m68k/atari_NCR5380-work.diff
@@ -0,0 +1,31 @@
+Cc: James E.J. Bottomley <James.Bottomley@SteelEye.com>,
+ linux-scsi@vger.kernel.org
+Subject: [PATCH] m68k: Atari SCSI workqueue updates
+
+Workqueue updates for the Atari SCSI driver
+
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ drivers/scsi/atari_NCR5380.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- linux-m68k-2.6.21.orig/drivers/scsi/atari_NCR5380.c
++++ linux-m68k-2.6.21/drivers/scsi/atari_NCR5380.c
+@@ -657,7 +657,7 @@ static inline void NCR5380_print_phase(s
+ #include <linux/interrupt.h>
+
+ static volatile int main_running;
+-static DECLARE_WORK(NCR5380_tqueue, (void (*)(void *))NCR5380_main, NULL);
++static DECLARE_WORK(NCR5380_tqueue, NCR5380_main);
+
+ static inline void queue_main(void)
+ {
+@@ -1075,7 +1075,7 @@ static int NCR5380_queue_command(Scsi_Cm
+ * reenable them. This prevents reentrancy and kernel stack overflow.
+ */
+
+-static void NCR5380_main(void *bl)
++static void NCR5380_main(struct work_struct *work)
+ {
+ Scsi_Cmnd *tmp, *prev;
+ struct Scsi_Host *instance = first_instance;
diff --git a/debian/patches/bugfix/m68k/early-param.diff b/debian/patches/bugfix/m68k/early-param.diff
new file mode 100644
index 000000000000..59d9f3768214
--- /dev/null
+++ b/debian/patches/bugfix/m68k/early-param.diff
@@ -0,0 +1,468 @@
+Subject: [PATCH] m68k: early parameter support
+
+From: Roman Zippel <zippel@linux-m68k.org>
+
+Add early parameter support and convert current users to it.
+
+Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ arch/m68k/amiga/config.c | 41 ++++++++++++++++++++++-------------------
+ arch/m68k/atari/config.c | 17 +++++++++--------
+ arch/m68k/atari/debug.c | 24 ++++++++++++++----------
+ arch/m68k/kernel/setup.c | 39 +--------------------------------------
+ arch/m68k/mac/config.c | 8 --------
+ arch/m68k/mac/debug.c | 20 ++++++++++----------
+ arch/m68k/q40/config.c | 23 ++++++++++++++---------
+ arch/m68k/sun3x/prom.c | 11 +++++++----
+ 8 files changed, 77 insertions(+), 106 deletions(-)
+
+--- linux-m68k-2.6.21.orig/arch/m68k/amiga/config.c
++++ linux-m68k-2.6.21/arch/m68k/amiga/config.c
+@@ -79,8 +79,6 @@ static char *amiga_models[] __initdata =
+
+ static char amiga_model_name[13] = "Amiga ";
+
+-extern char m68k_debug_device[];
+-
+ static void amiga_sched_init(irq_handler_t handler);
+ /* amiga specific irq functions */
+ extern void amiga_init_IRQ(void);
+@@ -95,12 +93,10 @@ static unsigned int amiga_get_ss(void);
+ extern void amiga_mksound(unsigned int count, unsigned int ticks);
+ static void amiga_reset(void);
+ extern void amiga_init_sound(void);
+-static void amiga_savekmsg_init(void);
+ static void amiga_mem_console_write(struct console *co, const char *b,
+ unsigned int count);
+ void amiga_serial_console_write(struct console *co, const char *s,
+ unsigned int count);
+-static void amiga_debug_init(void);
+ #ifdef CONFIG_HEARTBEAT
+ static void amiga_heartbeat(int on);
+ #endif
+@@ -370,7 +366,6 @@ void __init config_amiga(void)
+ {
+ int i;
+
+- amiga_debug_init();
+ amiga_identify();
+
+ /* Yuk, we don't have PCI memory */
+@@ -458,17 +453,6 @@ void __init config_amiga(void)
+ /* initialize chipram allocator */
+ amiga_chip_init();
+
+- /* debugging using chipram */
+- if (!strcmp(m68k_debug_device, "mem")) {
+- if (!AMIGAHW_PRESENT(CHIP_RAM))
+- printk("Warning: no chipram present for debugging\n");
+- else {
+- amiga_savekmsg_init();
+- amiga_console_driver.write = amiga_mem_console_write;
+- register_console(&amiga_console_driver);
+- }
+- }
+-
+ /* our beloved beeper */
+ if (AMIGAHW_PRESENT(AMI_AUDIO))
+ amiga_init_sound();
+@@ -787,17 +771,33 @@ static void amiga_mem_console_write(stru
+ }
+ }
+
+-static void amiga_savekmsg_init(void)
++static int __init amiga_savekmsg_setup(char *arg)
+ {
+ 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;
+ savekmsg->magicptr = ZTWO_PADDR(savekmsg);
+ savekmsg->size = 0;
++
++ amiga_console_driver.write = amiga_mem_console_write;
++ register_console(&amiga_console_driver);
++
++done:
++ return 0;
+ }
+
++early_param("debug", amiga_savekmsg_setup);
++
+ static void amiga_serial_putc(char c)
+ {
+ amiga_custom.serdat = (unsigned char)c | 0x100;
+@@ -872,15 +872,18 @@ void amiga_serial_gets(struct console *c
+ }
+ #endif
+
+-static void __init amiga_debug_init(void)
++static int __init amiga_debug_setup(char *arg)
+ {
+- if (!strcmp(m68k_debug_device, "ser" )) {
++ if (MACH_IS_AMIGA && !strcmp(arg, "ser")) {
+ /* no initialization required (?) */
+ amiga_console_driver.write = amiga_serial_console_write;
+ register_console(&amiga_console_driver);
+ }
++ return 0;
+ }
+
++early_param("debug", amiga_debug_setup);
++
+ #ifdef CONFIG_HEARTBEAT
+ static void amiga_heartbeat(int on)
+ {
+--- linux-m68k-2.6.21.orig/arch/m68k/atari/config.c
++++ linux-m68k-2.6.21/arch/m68k/atari/config.c
+@@ -69,9 +69,6 @@ extern int atari_tt_hwclk (int, struct r
+ extern int atari_mste_set_clock_mmss (unsigned long);
+ extern int atari_tt_set_clock_mmss (unsigned long);
+
+-/* atari specific debug functions (in debug.c) */
+-extern void atari_debug_init(void);
+-
+
+ /* ++roman: This is a more elaborate test for an SCC chip, since the plain
+ * Medusa board generates DTACK at the SCC's standard addresses, but a SCC
+@@ -137,15 +134,18 @@ int __init atari_parse_bootinfo(const st
+
+
+ /* Parse the Atari-specific switches= option. */
+-void __init atari_switches_setup(const char *str, unsigned len)
++static int __init atari_switches_setup(char *str)
+ {
+- char switches[len+1];
++ char switches[strlen(str) + 1];
+ char *p;
+ int ovsc_shift;
+ char *args = switches;
+
++ if (!MACH_IS_ATARI)
++ return 0;
++
+ /* copy string to local array, strsep works destructively... */
+- strlcpy(switches, str, sizeof(switches));
++ strcpy(switches, str);
+ atari_switches = 0;
+
+ /* parse the options */
+@@ -170,8 +170,11 @@ void __init atari_switches_setup(const c
+ atari_switches |= ATARI_SWITCH_SND7 << ovsc_shift;
+ }
+ }
++ return 0;
+ }
+
++early_param("switches", atari_switches_setup);
++
+
+ /*
+ * Setup the Atari configuration info
+@@ -183,8 +186,6 @@ void __init config_atari(void)
+
+ memset(&atari_hw_present, 0, sizeof(atari_hw_present));
+
+- atari_debug_init();
+-
+ /* Change size of I/O space from 64KB to 4GB. */
+ ioport_resource.end = 0xFFFFFFFF;
+
+--- linux-m68k-2.6.21.orig/arch/m68k/atari/debug.c
++++ linux-m68k-2.6.21/arch/m68k/atari/debug.c
+@@ -19,8 +19,6 @@
+ #include <asm/atarihw.h>
+ #include <asm/atariints.h>
+
+-extern char m68k_debug_device[];
+-
+ /* Flag that Modem1 port is already initialized and used */
+ int atari_MFP_init_done;
+ /* Flag that Modem1 port is already initialized and used */
+@@ -305,26 +303,28 @@ void atari_init_midi_port(int cflag)
+ ACIA_RHTID : ACIA_RLTID);
+ }
+
+-void __init atari_debug_init(void)
++static int __init atari_debug_setup(char *arg)
+ {
+- if (!strcmp(m68k_debug_device, "ser")) {
++ if (!MACH_IS_ATARI)
++ return 0;
++
++ if (!strcmp(arg, "ser"))
+ /* defaults to ser2 for a Falcon and ser1 otherwise */
+- strcpy(m68k_debug_device, MACH_IS_FALCON ? "ser2" : "ser1");
+- }
++ arg = MACH_IS_FALCON ? "ser2" : "ser1";
+
+- if (!strcmp(m68k_debug_device, "ser1")) {
++ if (!strcmp(arg, "ser1")) {
+ /* ST-MFP Modem1 serial port */
+ atari_init_mfp_port(B9600|CS8);
+ atari_console_driver.write = atari_mfp_console_write;
+- } else if (!strcmp(m68k_debug_device, "ser2")) {
++ } else if (!strcmp(arg, "ser2")) {
+ /* SCC Modem2 serial port */
+ atari_init_scc_port(B9600|CS8);
+ atari_console_driver.write = atari_scc_console_write;
+- } else if (!strcmp(m68k_debug_device, "midi")) {
++ } else if (!strcmp(arg, "midi")) {
+ /* MIDI port */
+ atari_init_midi_port(B9600|CS8);
+ atari_console_driver.write = atari_midi_console_write;
+- } else if (!strcmp(m68k_debug_device, "par")) {
++ } else if (!strcmp(arg, "par")) {
+ /* parallel printer */
+ atari_turnoff_irq(IRQ_MFP_BUSY); /* avoid ints */
+ sound_ym.rd_data_reg_sel = 7; /* select mixer control */
+@@ -337,4 +337,8 @@ void __init atari_debug_init(void)
+ }
+ if (atari_console_driver.write)
+ register_console(&atari_console_driver);
++
++ return 0;
+ }
++
++early_param("debug", atari_debug_setup);
+--- linux-m68k-2.6.21.orig/arch/m68k/kernel/setup.c
++++ linux-m68k-2.6.21/arch/m68k/kernel/setup.c
+@@ -71,9 +71,6 @@ static struct mem_info m68k_ramdisk;
+
+ static char m68k_command_line[CL_SIZE];
+
+-char m68k_debug_device[6] = "";
+-EXPORT_SYMBOL(m68k_debug_device);
+-
+ void (*mach_sched_init) (irq_handler_t handler) __initdata = NULL;
+ /* machine dependent irq functions */
+ void (*mach_init_IRQ) (void) __initdata = NULL;
+@@ -215,7 +212,6 @@ void __init setup_arch(char **cmdline_p)
+ unsigned long endmem, startmem;
+ #endif
+ int i;
+- char *p, *q;
+
+ /* The bootinfo is located right after the kernel bss */
+ m68k_parse_bootinfo((const struct bi_record *)&_end);
+@@ -258,40 +254,7 @@ void __init setup_arch(char **cmdline_p)
+ *cmdline_p = m68k_command_line;
+ memcpy(boot_command_line, *cmdline_p, CL_SIZE);
+
+- /* Parse the command line for arch-specific options.
+- * For the m68k, this is currently only "debug=xxx" to enable printing
+- * certain kernel messages to some machine-specific device.
+- */
+- for (p = *cmdline_p; p && *p;) {
+- i = 0;
+- if (!strncmp(p, "debug=", 6)) {
+- strlcpy(m68k_debug_device, p+6, sizeof(m68k_debug_device));
+- q = strchr(m68k_debug_device, ' ');
+- if (q)
+- *q = 0;
+- i = 1;
+- }
+-#ifdef CONFIG_ATARI
+- /* This option must be parsed very early */
+- if (!strncmp(p, "switches=", 9)) {
+- extern void atari_switches_setup(const char *, int);
+- q = strchr(p + 9, ' ');
+- atari_switches_setup(p + 9, q ? (q - (p + 9)) : strlen(p + 9));
+- i = 1;
+- }
+-#endif
+-
+- if (i) {
+- /* option processed, delete it */
+- if ((q = strchr(p, ' ')))
+- strcpy(p, q + 1);
+- else
+- *p = 0;
+- } else {
+- if ((p = strchr(p, ' ')))
+- ++p;
+- }
+- }
++ parse_early_param();
+
+ #ifdef CONFIG_DUMMY_CONSOLE
+ conswitchp = &dummy_con;
+--- linux-m68k-2.6.21.orig/arch/m68k/mac/config.c
++++ linux-m68k-2.6.21/arch/m68k/mac/config.c
+@@ -82,10 +82,6 @@ extern void mac_mksound(unsigned int, un
+
+ extern void nubus_sweep_video(void);
+
+-/* Mac specific debug functions (in debug.c) */
+-extern void mac_debug_init(void);
+-extern void mac_debugging_long(int, long);
+-
+ static void mac_get_model(char *str);
+
+ static void mac_sched_init(irq_handler_t vector)
+@@ -180,9 +176,6 @@ void __init config_mac(void)
+ mach_halt = mac_poweroff;
+ mach_power_off = mac_poweroff;
+ mach_max_dma_address = 0xffffffff;
+-#if 0
+- mach_debug_init = mac_debug_init;
+-#endif
+ #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
+ mach_beep = mac_mksound;
+ #endif
+@@ -802,7 +795,6 @@ void mac_identify(void)
+ /* the serial ports set to "Faster" mode in MacOS. */
+
+ iop_preinit();
+- mac_debug_init();
+
+ printk(KERN_INFO "Detected Macintosh model: %d \n", model);
+
+--- linux-m68k-2.6.21.orig/arch/m68k/mac/debug.c
++++ linux-m68k-2.6.21/arch/m68k/mac/debug.c
+@@ -27,10 +27,6 @@
+ #include <asm/machw.h>
+ #include <asm/macints.h>
+
+-extern char m68k_debug_device[];
+-
+-extern struct compat_bootinfo compat_boot_info;
+-
+ extern unsigned long mac_videobase;
+ extern unsigned long mac_videodepth;
+ extern unsigned long mac_rowbytes;
+@@ -360,16 +356,18 @@ void mac_init_sccb_port(int cflag)
+ mac_init_scc_port(cflag, 1);
+ }
+
+-void __init mac_debug_init(void)
++static int __init mac_debug_setup(char *arg)
+ {
++ if (!MACH_IS_MAC)
++ return 0;
++
+ #ifdef DEBUG_SERIAL
+- if (!strcmp(m68k_debug_device, "ser") ||
+- !strcmp(m68k_debug_device, "ser1")) {
++ if (!strcmp(arg, "ser") || !strcmp(arg, "ser1")) {
+ /* Mac modem port */
+ mac_init_scc_port(B9600|CS8, 0);
+ mac_console_driver.write = mac_scca_console_write;
+ scc_port = 0;
+- } else if (!strcmp(m68k_debug_device, "ser2")) {
++ } else if (!strcmp(arg, "ser2")) {
+ /* Mac printer port */
+ mac_init_scc_port(B9600|CS8, 1);
+ mac_console_driver.write = mac_sccb_console_write;
+@@ -377,12 +375,14 @@ void __init mac_debug_init(void)
+ }
+ #endif
+ #ifdef DEBUG_HEADS
+- if (!strcmp(m68k_debug_device, "scn") ||
+- !strcmp(m68k_debug_device, "con")) {
++ if (!strcmp(arg, "scn") || !strcmp(arg, "con")) {
+ /* display, using head.S console routines */
+ mac_console_driver.write = mac_debug_console_write;
+ }
+ #endif
+ if (mac_console_driver.write)
+ register_console(&mac_console_driver);
++ return 0;
+ }
++
++early_param("debug", mac_debug_setup);
+--- linux-m68k-2.6.21.orig/arch/m68k/q40/config.c
++++ linux-m68k-2.6.21/arch/m68k/q40/config.c
+@@ -54,7 +54,6 @@ void q40_set_vectors(void);
+
+ extern void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/);
+
+-extern char m68k_debug_device[];
+ static void q40_mem_console_write(struct console *co, const char *b,
+ unsigned int count);
+
+@@ -62,6 +61,7 @@ extern int ql_ticks;
+
+ static struct console q40_console_driver = {
+ .name = "debug",
++ .write = q40_mem_console_write,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ };
+@@ -85,6 +85,19 @@ static void q40_mem_console_write(struct
+ }
+ }
+
++static int __init q40_debug_setup(char *arg)
++{
++ /* useful for early debugging stages - writes kernel messages into SRAM */
++ if (MACH_IS_Q40 && !strncmp(arg, "mem", 3)) {
++ /*printk("using NVRAM debug, q40_mem_cptr=%p\n",q40_mem_cptr);*/
++ _cpleft = 2000 - ((long)q40_mem_cptr-0xff020000) / 4;
++ register_console(&q40_console_driver);
++ }
++ return 0;
++}
++
++early_param("debug", q40_debug_setup);
++
+ #if 0
+ void printq40(char *str)
+ {
+@@ -194,14 +207,6 @@ void __init config_q40(void)
+ * all physical RAM fits into the boundary - otherwise
+ * allocator may play costly and useless tricks */
+ mach_max_dma_address = 1024*1024*1024;
+-
+- /* useful for early debugging stages - writes kernel messages into SRAM */
+- if (!strncmp( m68k_debug_device,"mem", 3)) {
+- /*printk("using NVRAM debug, q40_mem_cptr=%p\n",q40_mem_cptr);*/
+- _cpleft = 2000 - ((long)q40_mem_cptr-0xff020000) / 4;
+- q40_console_driver.write = q40_mem_console_write;
+- register_console(&q40_console_driver);
+- }
+ }
+
+
+--- linux-m68k-2.6.21.orig/arch/m68k/sun3x/prom.c
++++ linux-m68k-2.6.21/arch/m68k/sun3x/prom.c
+@@ -73,8 +73,6 @@ void sun3x_reboot(void)
+ (*romvec->pv_reboot)("vmlinux");
+ }
+
+-extern char m68k_debug_device[];
+-
+ static void sun3x_prom_write(struct console *co, const char *s,
+ unsigned int count)
+ {
+@@ -119,13 +117,18 @@ void sun3x_prom_init(void)
+ * XXX this is futile since we restore the vbr first - oops
+ */
+ vectors[VEC_TRAP14] = sun3x_prom_abort;
++}
+
++static int __init sun3x_debug_setup(char *arg)
++{
+ /* If debug=prom was specified, start the debug console */
+-
+- if (!strcmp(m68k_debug_device, "prom"))
++ if (MACH_IS_SUN3X && !strcmp(arg, "prom"))
+ register_console(&sun3x_debug);
++ return 0;
+ }
+
++early_param("debug", sun3x_debug_setup);
++
+ /* some prom functions to export */
+ int prom_getintdefault(int node, char *property, int deflt)
+ {
diff --git a/debian/patches/bugfix/m68k/ethernec-kill-ETHERNEC_USE_POLL.diff b/debian/patches/bugfix/m68k/ethernec-kill-ETHERNEC_USE_POLL.diff
new file mode 100644
index 000000000000..763f24e83c58
--- /dev/null
+++ b/debian/patches/bugfix/m68k/ethernec-kill-ETHERNEC_USE_POLL.diff
@@ -0,0 +1,76 @@
+---
+ drivers/net/atari_ethernec.c | 42 ------------------------------------------
+ 1 file changed, 42 deletions(-)
+
+--- linux-m68k-2.6.21.orig/drivers/net/atari_ethernec.c
++++ linux-m68k-2.6.21/drivers/net/atari_ethernec.c
+@@ -225,14 +225,6 @@ static wait_queue_head_t WaitQ;
+
+ static struct delayed_work tqueue;
+
+-#ifdef ETHERNEC_USE_POLL
+-static struct {
+- struct work_struct poll_queue;
+- struct timer_list poll_timer;
+- struct net_device *dev;
+-} poll_ops;
+-#endif
+-
+ static struct net_device *poll_dev = NULL;
+
+ static void atari_ethernec_int(struct work_struct *work)
+@@ -260,22 +252,6 @@ static void atari_ethernec_int(struct wo
+ schedule_delayed_work(&tqueue, 0); /* reduced delay from 1 */
+ }
+
+-#ifdef ETHERNEC_USE_POLL
+-static void atari_ethernec_poll_handler(unsigned long dev_addr)
+-{
+- struct net_device *dev = poll_dev;
+-
+- if (!dev || !dev->poll_controller)
+- return;
+-
+- if (netif_running(dev))
+- dev->poll_controller(dev);
+-
+- schedule_work(&poll_ops.poll_queue);
+- mod_timer(&poll_ops.poll_timer, jiffies + HZ / 100);
+-}
+-#endif
+-
+ static void atari_ethernec_start_poll(struct net_device *dev)
+ {
+ poll_dev = dev;
+@@ -284,19 +260,6 @@ static void atari_ethernec_start_poll(st
+
+ INIT_DELAYED_WORK(&tqueue, atari_ethernec_int);
+ schedule_delayed_work(&tqueue, 1);
+-#ifdef ETHERNEC_USE_POLL
+- if (!poll_ops.poll_queue.func ||
+- poll_ops.poll_queue.func == ei_interrupt) {
+- if (!poll_ops.poll_queue.func)
+- INIT_WORK(&poll_ops.poll_queue, ei_interrupt, dev);
+-
+- init_timer(&poll_ops.poll_timer);
+- poll_ops.poll_timer.function = atari_ethernec_poll_handler;
+- poll_ops.poll_timer.expires = jiffies + HZ / 5;
+- poll_ops.poll_timer.data = (unsigned long)dev;
+- add_timer(&poll_ops.poll_timer);
+- }
+-#endif
+ }
+
+ static void atari_ethernec_stop_poll(struct net_device *dev)
+@@ -305,11 +268,6 @@ static void atari_ethernec_stop_poll(str
+
+ if (dev)
+ sleep_on(&WaitQ);
+-
+-#ifdef ETHERNEC_USE_POLL
+- if (poll_ops.poll_queue.func == ei_interrupt)
+- del_timer_sync(&poll_ops.poll_timer);
+-#endif
+ }
+
+
diff --git a/debian/patches/bugfix/m68k/ethernec-work.diff b/debian/patches/bugfix/m68k/ethernec-work.diff
new file mode 100644
index 000000000000..d0a291f58c62
--- /dev/null
+++ b/debian/patches/bugfix/m68k/ethernec-work.diff
@@ -0,0 +1,46 @@
+Subject: [PATCH] m68k: Atari EtherNEC workqueue updates
+
+Workqueue updates for the Atari EtherNEC driver
+
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ drivers/net/atari_ethernec.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- linux-m68k-2.6.21.orig/drivers/net/atari_ethernec.c
++++ linux-m68k-2.6.21/drivers/net/atari_ethernec.c
+@@ -96,6 +96,7 @@ static const char version2[] =
+ #include <linux/netdevice.h>
+ #include <linux/etherdevice.h>
+ #include <linux/jiffies.h>
++#include <linux/workqueue.h>
+
+ #include <asm/system.h>
+ #include <asm/atarihw.h>
+@@ -222,7 +223,7 @@ static int use_poll;
+ */
+ static wait_queue_head_t WaitQ;
+
+-static struct work_struct tqueue;
++static struct delayed_work tqueue;
+
+ #ifdef ETHERNEC_USE_POLL
+ static struct {
+@@ -234,7 +235,7 @@ static struct {
+
+ static struct net_device *poll_dev = NULL;
+
+-static void atari_ethernec_int(unsigned long dev_addr)
++static void atari_ethernec_int(struct work_struct *work)
+ {
+ struct net_device *dev = poll_dev;
+
+@@ -281,7 +282,7 @@ static void atari_ethernec_start_poll(st
+
+ init_waitqueue_head(&WaitQ);
+
+- INIT_WORK(&tqueue, (void (*)(void *))atari_ethernec_int, dev);
++ INIT_DELAYED_WORK(&tqueue, atari_ethernec_int);
+ schedule_delayed_work(&tqueue, 1);
+ #ifdef ETHERNEC_USE_POLL
+ if (!poll_ops.poll_queue.func ||
diff --git a/debian/patches/bugfix/m68k/falconide_intr_lock-reentrant.diff b/debian/patches/bugfix/m68k/falconide_intr_lock-reentrant.diff
new file mode 100644
index 000000000000..f632f831f7f5
--- /dev/null
+++ b/debian/patches/bugfix/m68k/falconide_intr_lock-reentrant.diff
@@ -0,0 +1,41 @@
+Subject: [PATCH] m68k: make Atari IDE lock reentrant
+
+From Roman Zippel <zippel@linux-m68k.org>
+
+Make the Atari IDE lock reentrant, as the new request is started in the
+interrupt before the last one is completely released.
+
+Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ include/asm-m68k/ide.h | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- linux-m68k-2.6.21.orig/include/asm-m68k/ide.h
++++ linux-m68k-2.6.21/include/asm-m68k/ide.h
+@@ -117,8 +117,8 @@ static __inline__ void ide_release_lock
+ printk("ide_release_lock: bug\n");
+ return;
+ }
+- falconide_intr_lock = 0;
+- stdma_release();
++ if (!--falconide_intr_lock)
++ stdma_release();
+ }
+ }
+
+@@ -126,12 +126,12 @@ static __inline__ void
+ ide_get_lock(irq_handler_t handler, void *data)
+ {
+ if (MACH_IS_ATARI) {
+- if (falconide_intr_lock == 0) {
++ if (!falconide_intr_lock) {
+ if (in_interrupt() > 0)
+ panic( "Falcon IDE hasn't ST-DMA lock in interrupt" );
+ stdma_lock(handler, data);
+- falconide_intr_lock = 1;
+ }
++ falconide_intr_lock++;
+ }
+ }
+ #endif /* CONFIG_BLK_DEV_FALCON_IDE */
diff --git a/debian/patches/bugfix/m68k/hilkbd-warning.diff b/debian/patches/bugfix/m68k/hilkbd-warning.diff
new file mode 100644
index 000000000000..caacc2c0dde8
--- /dev/null
+++ b/debian/patches/bugfix/m68k/hilkbd-warning.diff
@@ -0,0 +1,21 @@
+Cc: parisc-linux@parisc-linux.org
+Subject: [PATCH] hilkbd: Kill compiler warning and fix comment dyslexia
+
+hilkbd: Kill compiler warning and fix comment dyslexia
+
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ drivers/input/keyboard/hilkbd.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- linux-m68k-2.6.21.orig/drivers/input/keyboard/hilkbd.c
++++ linux-m68k-2.6.21/drivers/input/keyboard/hilkbd.c
+@@ -52,7 +52,7 @@ MODULE_LICENSE("GPL v2");
+
+ #elif defined(CONFIG_HP300)
+
+- #define HILBASE 0xf0428000 /* HP300 (m86k) port address */
++ #define HILBASE 0xf0428000UL /* HP300 (m68k) port address */
+ #define HIL_DATA 0x1
+ #define HIL_CMD 0x3
+ #define HIL_IRQ 2
diff --git a/debian/patches/bugfix/m68k/irq_lockdep.diff b/debian/patches/bugfix/m68k/irq_lockdep.diff
new file mode 100644
index 000000000000..1d3542fa64c4
--- /dev/null
+++ b/debian/patches/bugfix/m68k/irq_lockdep.diff
@@ -0,0 +1,30 @@
+Subject: [PATCH] lockdep: Add missing disable/enable irq variant
+
+From: Roman Zippel <zippel@linux-m68k.org>
+
+Add missing disable/enable irq variant
+
+Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ include/linux/interrupt.h | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- linux-m68k-2.6.21.orig/include/linux/interrupt.h
++++ linux-m68k-2.6.21/include/linux/interrupt.h
+@@ -185,10 +185,14 @@ static inline int disable_irq_wake(unsig
+ * validator need to define the methods below in their asm/irq.h
+ * files, under an #ifdef CONFIG_LOCKDEP section.
+ */
+-# ifndef CONFIG_LOCKDEP
++#ifndef CONFIG_LOCKDEP
+ # define disable_irq_nosync_lockdep(irq) disable_irq_nosync(irq)
++# define disable_irq_nosync_lockdep_irqsave(irq, flags) \
++ disable_irq_nosync(irq)
+ # define disable_irq_lockdep(irq) disable_irq(irq)
+ # define enable_irq_lockdep(irq) enable_irq(irq)
++# define enable_irq_lockdep_irqrestore(irq, flags) \
++ enable_irq(irq)
+ # endif
+
+ #endif /* CONFIG_GENERIC_HARDIRQS */
diff --git a/debian/patches/bugfix/m68k/kmap_atomic-inline.diff b/debian/patches/bugfix/m68k/kmap_atomic-inline.diff
new file mode 100644
index 000000000000..3f6c50f5e50b
--- /dev/null
+++ b/debian/patches/bugfix/m68k/kmap_atomic-inline.diff
@@ -0,0 +1,30 @@
+Subject: [PATCH] Convert non-highmem kmap_atomic() to static inline function
+
+Convert kmap_atomic() in the non-highmem case from a macro to a static
+inline function, for better type-checking and the ability to pass void
+pointers instead of struct page pointers.
+
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ include/linux/highmem.h | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+--- linux-m68k-2.6.21.orig/include/linux/highmem.h
++++ linux-m68k-2.6.21/include/linux/highmem.h
+@@ -42,8 +42,14 @@ static inline void *kmap(struct page *pa
+
+ #define kunmap(page) do { (void) (page); } while (0)
+
+-#define kmap_atomic(page, idx) \
+- ({ pagefault_disable(); page_address(page); })
++#include <asm/kmap_types.h>
++
++static inline void *kmap_atomic(struct page *page, enum km_type idx)
++{
++ pagefault_disable();
++ return page_address(page);
++}
++
+ #define kunmap_atomic(addr, idx) do { pagefault_enable(); } while (0)
+ #define kmap_atomic_pfn(pfn, idx) kmap_atomic(pfn_to_page(pfn), (idx))
+ #define kmap_atomic_to_page(ptr) virt_to_page(ptr)
diff --git a/debian/patches/bugfix/m68k/m68k-53c700-scsi.diff b/debian/patches/bugfix/m68k/m68k-53c700-scsi.diff
new file mode 100644
index 000000000000..29ad0e2d972a
--- /dev/null
+++ b/debian/patches/bugfix/m68k/m68k-53c700-scsi.diff
@@ -0,0 +1,1155 @@
+From jongk@linux-m68k.org Tue Oct 31 22:46:33 2006
+Date: Tue, 31 Oct 2006 22:47:04 +0100
+From: Kars de Jong <jongk@linux-m68k.org>
+To: Christoph Hellwig <hch@infradead.org>
+Cc: Richard Hirst <rhirst@levanta.com>, Matthew Wilcox <matthew@wil.cx>, linux-scsi@vger.kernel.org, linux-m68k@vger.kernel.org, Geert Uytterhoeven <geert@linux-m68k.org>
+Subject: [RFC PATCH] m68k: switch to 53c700 driver
+
+On ma, 2006-10-30 at 11:13 +0000, Christoph Hellwig wrote:
+> Any updates? Honestly, I do not plan to touch the current 53c7xx/etc
+> mess in the upoming request_buffer transition, and unless the m68k
+> folks provide the new 53c700-based driver I'll just submit a patch to
+> rip 53c7xx and users out without replacement.
+
+OK, here's the patch, without the m68k generic iomap changes.
+
+If there are no objections, I will commit it to our CVS repository so
+Geert can send it upstream (with proper Signed-Off-By: headers and
+everything).
+
+Kars.
+
+---
+ arch/m68k/configs/amiga_defconfig | 2
+ arch/m68k/configs/bvme6000_defconfig | 2
+ arch/m68k/configs/mvme16x_defconfig | 2
+ arch/m68k/defconfig | 2
+ drivers/scsi/53c700.c | 20 +-
+ drivers/scsi/53c700.h | 5
+ drivers/scsi/Kconfig | 26 +-
+ drivers/scsi/Makefile | 15 -
+ drivers/scsi/amiga7xx.c | 344 +++++++++++++++++++++++++----------
+ drivers/scsi/amiga7xx.h | 23 --
+ drivers/scsi/bvme6000.h | 24 --
+ drivers/scsi/bvme6000_scsi.c | 158 ++++++++++------
+ drivers/scsi/mvme16x.h | 24 --
+ drivers/scsi/mvme16x_scsi.c | 183 +++++++++++++-----
+ 14 files changed, 525 insertions(+), 305 deletions(-)
+
+--- linux-m68k-2.6.21.orig/arch/m68k/configs/amiga_defconfig
++++ linux-m68k-2.6.21/arch/m68k/configs/amiga_defconfig
+@@ -249,7 +249,9 @@ CONFIG_CYBERSTORMII_SCSI=y
+ CONFIG_BLZ2060_SCSI=y
+ CONFIG_BLZ1230_SCSI=y
+ CONFIG_FASTLANE_SCSI=y
++CONFIG_SCSI_AMIGA7XX=y
+ CONFIG_OKTAGON_SCSI=y
++CONFIG_SCSI_NCR53C7xx_FAST=y
+
+ #
+ # Old CD-ROM drivers (not SCSI, not IDE)
+--- linux-m68k-2.6.21.orig/arch/m68k/configs/bvme6000_defconfig
++++ linux-m68k-2.6.21/arch/m68k/configs/bvme6000_defconfig
+@@ -185,6 +185,8 @@ CONFIG_SCSI_CONSTANTS=y
+ #
+ # CONFIG_SCSI_SATA is not set
+ # CONFIG_SCSI_DEBUG is not set
++CONFIG_BVME6000_SCSI=y
++CONFIG_SCSI_NCR53C7xx_FAST=y
+
+ #
+ # Multi-device support (RAID and LVM)
+--- linux-m68k-2.6.21.orig/arch/m68k/configs/mvme16x_defconfig
++++ linux-m68k-2.6.21/arch/m68k/configs/mvme16x_defconfig
+@@ -185,6 +185,8 @@ CONFIG_SCSI_CONSTANTS=y
+ #
+ # CONFIG_SCSI_SATA is not set
+ # CONFIG_SCSI_DEBUG is not set
++CONFIG_MVME16x_SCSI=y
++CONFIG_SCSI_NCR53C7xx_FAST=y
+
+ #
+ # Multi-device support (RAID and LVM)
+--- linux-m68k-2.6.21.orig/arch/m68k/defconfig
++++ linux-m68k-2.6.21/arch/m68k/defconfig
+@@ -186,7 +186,9 @@ CONFIG_GVP11_SCSI=y
+ # CONFIG_BLZ2060_SCSI is not set
+ # CONFIG_BLZ1230_SCSI is not set
+ # CONFIG_FASTLANE_SCSI is not set
++CONFIG_SCSI_AMIGA7XX=y
+ # CONFIG_OKTAGON_SCSI is not set
++CONFIG_SCSI_NCR53C7xx_FAST=y
+
+ #
+ # Multi-device support (RAID and LVM)
+--- linux-m68k-2.6.21.orig/drivers/scsi/53c700.c
++++ linux-m68k-2.6.21/drivers/scsi/53c700.c
+@@ -661,7 +661,6 @@ NCR_700_chip_setup(struct Scsi_Host *hos
+ {
+ struct NCR_700_Host_Parameters *hostdata =
+ (struct NCR_700_Host_Parameters *)host->hostdata[0];
+- __u32 dcntl_extra = 0;
+ __u8 min_period;
+ __u8 min_xferp = (hostdata->chip710 ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP);
+
+@@ -686,13 +685,14 @@ NCR_700_chip_setup(struct Scsi_Host *hos
+ burst_disable = BURST_DISABLE;
+ break;
+ }
+- dcntl_extra = COMPAT_700_MODE;
++ hostdata->dcntl_extra |= COMPAT_700_MODE;
+
+- NCR_700_writeb(dcntl_extra, host, DCNTL_REG);
++ NCR_700_writeb(hostdata->dcntl_extra, host, DCNTL_REG);
+ NCR_700_writeb(burst_length | hostdata->dmode_extra,
+ host, DMODE_710_REG);
+- NCR_700_writeb(burst_disable | (hostdata->differential ?
+- DIFF : 0), host, CTEST7_REG);
++ NCR_700_writeb(burst_disable | hostdata->ctest7_extra |
++ (hostdata->differential ? DIFF : 0),
++ host, CTEST7_REG);
+ NCR_700_writeb(BTB_TIMER_DISABLE, host, CTEST0_REG);
+ NCR_700_writeb(FULL_ARBITRATION | ENABLE_PARITY | PARITY
+ | AUTO_ATN, host, SCNTL0_REG);
+@@ -727,13 +727,13 @@ NCR_700_chip_setup(struct Scsi_Host *hos
+ * of spec: sync divider 2, async divider 3 */
+ DEBUG(("53c700: sync 2 async 3\n"));
+ NCR_700_writeb(SYNC_DIV_2_0, host, SBCL_REG);
+- NCR_700_writeb(ASYNC_DIV_3_0 | dcntl_extra, host, DCNTL_REG);
++ NCR_700_writeb(ASYNC_DIV_3_0 | hostdata->dcntl_extra, host, DCNTL_REG);
+ hostdata->sync_clock = hostdata->clock/2;
+ } else if(hostdata->clock > 50 && hostdata->clock <= 75) {
+ /* sync divider 1.5, async divider 3 */
+ DEBUG(("53c700: sync 1.5 async 3\n"));
+ NCR_700_writeb(SYNC_DIV_1_5, host, SBCL_REG);
+- NCR_700_writeb(ASYNC_DIV_3_0 | dcntl_extra, host, DCNTL_REG);
++ NCR_700_writeb(ASYNC_DIV_3_0 | hostdata->dcntl_extra, host, DCNTL_REG);
+ hostdata->sync_clock = hostdata->clock*2;
+ hostdata->sync_clock /= 3;
+
+@@ -741,18 +741,18 @@ NCR_700_chip_setup(struct Scsi_Host *hos
+ /* sync divider 1, async divider 2 */
+ DEBUG(("53c700: sync 1 async 2\n"));
+ NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG);
+- NCR_700_writeb(ASYNC_DIV_2_0 | dcntl_extra, host, DCNTL_REG);
++ NCR_700_writeb(ASYNC_DIV_2_0 | hostdata->dcntl_extra, host, DCNTL_REG);
+ hostdata->sync_clock = hostdata->clock;
+ } else if(hostdata->clock > 25 && hostdata->clock <=37) {
+ /* sync divider 1, async divider 1.5 */
+ DEBUG(("53c700: sync 1 async 1.5\n"));
+ NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG);
+- NCR_700_writeb(ASYNC_DIV_1_5 | dcntl_extra, host, DCNTL_REG);
++ NCR_700_writeb(ASYNC_DIV_1_5 | hostdata->dcntl_extra, host, DCNTL_REG);
+ hostdata->sync_clock = hostdata->clock;
+ } else {
+ DEBUG(("53c700: sync 1 async 1\n"));
+ NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG);
+- NCR_700_writeb(ASYNC_DIV_1_0 | dcntl_extra, host, DCNTL_REG);
++ NCR_700_writeb(ASYNC_DIV_1_0 | hostdata->dcntl_extra, host, DCNTL_REG);
+ /* sync divider 1, async divider 1 */
+ hostdata->sync_clock = hostdata->clock;
+ }
+--- linux-m68k-2.6.21.orig/drivers/scsi/53c700.h
++++ linux-m68k-2.6.21/drivers/scsi/53c700.h
+@@ -177,6 +177,7 @@ struct NCR_700_command_slot {
+ __u8 state;
+ #define NCR_700_FLAG_AUTOSENSE 0x01
+ __u8 flags;
++ __u8 pad1[2]; /* Needed for m68k where min alignment is 2 bytes */
+ int tag;
+ __u32 resume_offset;
+ struct scsi_cmnd *cmnd;
+@@ -196,6 +197,8 @@ struct NCR_700_Host_Parameters {
+ void __iomem *base; /* the base for the port (copied to host) */
+ struct device *dev;
+ __u32 dmode_extra; /* adjustable bus settings */
++ __u32 dcntl_extra; /* adjustable bus settings */
++ __u32 ctest7_extra; /* adjustable bus settings */
+ __u32 differential:1; /* if we are differential */
+ #ifdef CONFIG_53C700_LE_ON_BE
+ /* This option is for HP only. Set it if your chip is wired for
+@@ -352,6 +355,7 @@ struct NCR_700_Host_Parameters {
+ #define SEL_TIMEOUT_DISABLE 0x10 /* 710 only */
+ #define DFP 0x08
+ #define EVP 0x04
++#define CTEST7_TT1 0x02
+ #define DIFF 0x01
+ #define CTEST6_REG 0x1A
+ #define TEMP_REG 0x1C
+@@ -385,6 +389,7 @@ struct NCR_700_Host_Parameters {
+ #define SOFTWARE_RESET 0x01
+ #define COMPAT_700_MODE 0x01
+ #define SCRPTS_16BITS 0x20
++#define EA_710 0x20
+ #define ASYNC_DIV_2_0 0x00
+ #define ASYNC_DIV_1_5 0x40
+ #define ASYNC_DIV_1_0 0x80
+--- linux-m68k-2.6.21.orig/drivers/scsi/Kconfig
++++ linux-m68k-2.6.21/drivers/scsi/Kconfig
+@@ -1000,6 +1000,11 @@ config SCSI_STEX
+ To compile this driver as a module, choose M here: the
+ module will be called stex.
+
++config 53C700_BE_BUS
++ bool
++ depends on SCSI_AMIGA7XX || MVME16x_SCSI || BVME6000_SCSI
++ default y
++
+ config SCSI_SYM53C8XX_2
+ tristate "SYM53C8XX Version 2 SCSI support"
+ depends on PCI && SCSI
+@@ -1620,8 +1625,9 @@ config FASTLANE_SCSI
+ one in the near future, say Y to this question. Otherwise, say N.
+
+ config SCSI_AMIGA7XX
+- bool "Amiga NCR53c710 SCSI support (EXPERIMENTAL)"
+- depends on AMIGA && SCSI && EXPERIMENTAL && BROKEN
++ tristate "Amiga NCR53c710 SCSI support (EXPERIMENTAL)"
++ depends on AMIGA && SCSI && EXPERIMENTAL
++ select SCSI_SPI_ATTRS
+ help
+ Support for various NCR53c710-based SCSI controllers on the Amiga.
+ This includes:
+@@ -1720,8 +1726,8 @@ config MVME147_SCSI
+ single-board computer.
+
+ config MVME16x_SCSI
+- bool "NCR53C710 SCSI driver for MVME16x"
+- depends on MVME16x && SCSI && BROKEN
++ tristate "NCR53C710 SCSI driver for MVME16x"
++ depends on MVME16x && SCSI
+ select SCSI_SPI_ATTRS
+ help
+ The Motorola MVME162, 166, 167, 172 and 177 boards use the NCR53C710
+@@ -1729,22 +1735,14 @@ config MVME16x_SCSI
+ will want to say Y to this question.
+
+ config BVME6000_SCSI
+- bool "NCR53C710 SCSI driver for BVME6000"
+- depends on BVME6000 && SCSI && BROKEN
++ tristate "NCR53C710 SCSI driver for BVME6000"
++ depends on BVME6000 && SCSI
+ select SCSI_SPI_ATTRS
+ help
+ The BVME4000 and BVME6000 boards from BVM Ltd use the NCR53C710
+ SCSI controller chip. Almost everyone using one of these boards
+ will want to say Y to this question.
+
+-config SCSI_NCR53C7xx_FAST
+- bool "allow FAST-SCSI [10MHz]"
+- depends on SCSI_AMIGA7XX || MVME16x_SCSI || BVME6000_SCSI
+- help
+- This will enable 10MHz FAST-SCSI transfers with your host
+- adapter. Some systems have problems with that speed, so it's safest
+- to say N here.
+-
+ config SUN3_SCSI
+ tristate "Sun3 NCR5380 SCSI"
+ depends on SUN3 && SCSI
+--- linux-m68k-2.6.21.orig/drivers/scsi/Makefile
++++ linux-m68k-2.6.21/drivers/scsi/Makefile
+@@ -37,7 +37,7 @@ obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas/
+
+ obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o
+ obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o
+-obj-$(CONFIG_SCSI_AMIGA7XX) += amiga7xx.o 53c7xx.o
++obj-$(CONFIG_SCSI_AMIGA7XX) += 53c700.o amiga7xx.o
+ obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o
+ obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o
+ obj-$(CONFIG_GVP11_SCSI) += gvp11.o wd33c93.o
+@@ -53,8 +53,8 @@ obj-$(CONFIG_ATARI_SCSI) += atari_scsi.o
+ obj-$(CONFIG_MAC_SCSI) += mac_scsi.o
+ obj-$(CONFIG_SCSI_MAC_ESP) += mac_esp.o NCR53C9x.o
+ obj-$(CONFIG_SUN3_SCSI) += sun3_scsi.o sun3_scsi_vme.o
+-obj-$(CONFIG_MVME16x_SCSI) += mvme16x_scsi.o 53c7xx.o
+-obj-$(CONFIG_BVME6000_SCSI) += bvme6000_scsi.o 53c7xx.o
++obj-$(CONFIG_MVME16x_SCSI) += 53c700.o mvme16x_scsi.o
++obj-$(CONFIG_BVME6000_SCSI) += 53c700.o bvme6000_scsi.o
+ obj-$(CONFIG_SCSI_SIM710) += 53c700.o sim710.o
+ obj-$(CONFIG_SCSI_ADVANSYS) += advansys.o
+ obj-$(CONFIG_SCSI_PSI240I) += psi240i.o
+@@ -168,10 +168,8 @@ NCR_Q720_mod-objs := NCR_Q720.o ncr53c8x
+ oktagon_esp_mod-objs := oktagon_esp.o oktagon_io.o
+
+ # Files generated that shall be removed upon make clean
+-clean-files := 53c7xx_d.h 53c700_d.h \
+- 53c7xx_u.h 53c700_u.h
++clean-files := 53c700_d.h 53c700_u.h
+
+-$(obj)/53c7xx.o: $(obj)/53c7xx_d.h $(obj)/53c7xx_u.h
+ $(obj)/53c700.o $(MODVERDIR)/$(obj)/53c700.ver: $(obj)/53c700_d.h
+
+ # If you want to play with the firmware, uncomment
+@@ -179,11 +177,6 @@ $(obj)/53c700.o $(MODVERDIR)/$(obj)/53c7
+
+ ifdef GENERATE_FIRMWARE
+
+-$(obj)/53c7xx_d.h: $(src)/53c7xx.scr $(src)/script_asm.pl
+- $(CPP) -traditional -DCHIP=710 - < $< | grep -v '^#' | $(PERL) -s $(src)/script_asm.pl -ncr7x0_family $@ $(@:_d.h=_u.h)
+-
+-$(obj)/53c7xx_u.h: $(obj)/53c7xx_d.h
+-
+ $(obj)/53c700_d.h: $(src)/53c700.scr $(src)/script_asm.pl
+ $(PERL) -s $(src)/script_asm.pl -ncr7x0_family $@ $(@:_d.h=_u.h) < $<
+
+--- linux-m68k-2.6.21.orig/drivers/scsi/amiga7xx.c
++++ linux-m68k-2.6.21/drivers/scsi/amiga7xx.c
+@@ -6,133 +6,287 @@
+ *
+ * Written 1997 by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ * plus modifications of the 53c7xx.c driver to support the Amiga.
++ *
++ * Rewritten to use 53c700.c by Kars de Jong <jongk@linux-m68k.org>
+ */
+-#include <linux/types.h>
+-#include <linux/mm.h>
++
++#include <linux/module.h>
+ #include <linux/blkdev.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
+ #include <linux/zorro.h>
+-#include <linux/stat.h>
+-
+-#include <asm/setup.h>
+-#include <asm/page.h>
+-#include <asm/pgtable.h>
+-#include <asm/amigaints.h>
+ #include <asm/amigahw.h>
+-#include <asm/dma.h>
+-#include <asm/irq.h>
+-
+-#include "scsi.h"
++#include <asm/amigaints.h>
+ #include <scsi/scsi_host.h>
+-#include "53c7xx.h"
+-#include "amiga7xx.h"
++#include <scsi/scsi_device.h>
++#include <scsi/scsi_transport.h>
++#include <scsi/scsi_transport_spi.h>
++
++#include "53c700.h"
++
++MODULE_AUTHOR("Alan Hourihane <alanh@fairlite.demon.co.uk> / Kars de Jong <jongk@linux-m68k.org>");
++MODULE_DESCRIPTION("Amiga NCR53C710 driver");
++MODULE_LICENSE("GPL");
++
++static struct scsi_host_template amiga7xx_scsi_driver_template = {
++ .name = "A4000T builtin SCSI",
++ .proc_name = "Amiga7xx",
++ .this_id = 7,
++ .module = THIS_MODULE,
++};
++
++static struct platform_device *a4000t_scsi_device;
++
++#ifdef CONFIG_ZORRO
++
++static struct zorro_driver_data {
++ const char *name;
++ unsigned long offset;
++ int absolute; /* offset is absolute address */
++} amiga7xx_driver_data[] __devinitdata = {
++ { .name = "PowerUP 603e+", .offset = 0xf40000, .absolute = 1 },
++ { .name = "WarpEngine 40xx", .offset = 0x40000 },
++ { .name = "A4091", .offset = 0x800000 },
++ { .name = "GForce 040/060", .offset = 0x40000 },
++ { 0 }
++};
+
++static struct zorro_device_id amiga7xx_zorro_tbl[] __devinitdata = {
++ {
++ .id = ZORRO_PROD_PHASE5_BLIZZARD_603E_PLUS,
++ .driver_data = (unsigned long)&amiga7xx_driver_data[0],
++ },
++ {
++ .id = ZORRO_PROD_MACROSYSTEMS_WARP_ENGINE_40xx,
++ .driver_data = (unsigned long)&amiga7xx_driver_data[1],
++ },
++ {
++ .id = ZORRO_PROD_CBM_A4091_1,
++ .driver_data = (unsigned long)&amiga7xx_driver_data[2],
++ },
++ {
++ .id = ZORRO_PROD_CBM_A4091_2,
++ .driver_data = (unsigned long)&amiga7xx_driver_data[2],
++ },
++ {
++ .id = ZORRO_PROD_GVP_GFORCE_040_060,
++ .driver_data = (unsigned long)&amiga7xx_driver_data[3],
++ },
++ { 0 }
++};
+
+-static int amiga7xx_register_one(struct scsi_host_template *tpnt,
+- unsigned long address)
++static int __devinit amiga7xx_init_one(struct zorro_dev *z,
++ const struct zorro_device_id *ent)
+ {
+- long long options;
+- int clock;
++ struct Scsi_Host * host = NULL;
++ struct NCR_700_Host_Parameters *hostdata;
++ struct zorro_driver_data *zdd;
++ unsigned long board, ioaddr;
++
++ board = zorro_resource_start(z);
++ zdd = (struct zorro_driver_data *)ent->driver_data;
++
++ if (zdd->absolute) {
++ ioaddr = zdd->offset;
++ } else {
++ ioaddr = board + zdd->offset;
++ }
++
++ if (!zorro_request_device(z, zdd->name)) {
++ printk(KERN_ERR "amiga7xx: cannot reserve region 0x%lx, abort\n",
++ board);
++ return -EBUSY;
++ }
++
++ hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
++
++ if (hostdata == NULL) {
++ printk(KERN_ERR "amiga7xx: Failed to allocate host data\n");
++ goto out_release;
++ }
++
++ memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
++
++ /* Fill in the required pieces of hostdata */
++ if (ioaddr > 0x01000000)
++ hostdata->base = ioremap(ioaddr, zorro_resource_len(z));
++ else
++ hostdata->base = (void __iomem *)ZTWO_VADDR(ioaddr);
+
+- if (!request_mem_region(address, 0x1000, "ncr53c710"))
+- return 0;
++ hostdata->clock = 50;
++ hostdata->chip710 = 1;
+
+- address = (unsigned long)z_ioremap(address, 0x1000);
+- options = OPTION_MEMORY_MAPPED | OPTION_DEBUG_TEST1 | OPTION_INTFLY |
+- OPTION_SYNCHRONOUS | OPTION_ALWAYS_SYNCHRONOUS |
+- OPTION_DISCONNECT;
+- clock = 50000000; /* 50 MHz SCSI Clock */
+- ncr53c7xx_init(tpnt, 0, 710, address, 0, IRQ_AMIGA_PORTS, DMA_NONE,
+- options, clock);
+- return 1;
+-}
++ /* Settings for at least WarpEngine 40xx */
++ hostdata->ctest7_extra = CTEST7_TT1;
+
++ amiga7xx_scsi_driver_template.name = zdd->name;
+
+-#ifdef CONFIG_ZORRO
++ /* and register the chip */
++ if ((host = NCR_700_detect(&amiga7xx_scsi_driver_template, hostdata, &z->dev))
++ == NULL) {
++ printk(KERN_ERR "amiga7xx-scsi: No host detected; board configuration problem?\n");
++ goto out_free;
++ }
+
+-static struct {
+- zorro_id id;
+- unsigned long offset;
+- int absolute; /* offset is absolute address */
+-} amiga7xx_table[] = {
+- { .id = ZORRO_PROD_PHASE5_BLIZZARD_603E_PLUS, .offset = 0xf40000,
+- .absolute = 1 },
+- { .id = ZORRO_PROD_MACROSYSTEMS_WARP_ENGINE_40xx, .offset = 0x40000 },
+- { .id = ZORRO_PROD_CBM_A4091_1, .offset = 0x800000 },
+- { .id = ZORRO_PROD_CBM_A4091_2, .offset = 0x800000 },
+- { .id = ZORRO_PROD_GVP_GFORCE_040_060, .offset = 0x40000 },
+- { 0 }
+-};
++ host->this_id = 7;
++ host->base = ioaddr;
++ host->irq = IRQ_AMIGA_PORTS;
++
++ if (request_irq(host->irq, NCR_700_intr, IRQF_SHARED, "amiga7xx-scsi", host)) {
++ printk(KERN_ERR "amiga7xx-scsi: request_irq failed\n");
++ goto out_put_host;
++ }
++
++ scsi_scan_host(host);
++
++ return 0;
++
++ out_put_host:
++ scsi_host_put(host);
++ out_free:
++ if (ioaddr > 0x01000000)
++ iounmap(hostdata->base);
++ kfree(hostdata);
++ out_release:
++ zorro_release_device(z);
++
++ return -ENODEV;
++}
+
+-static int __init amiga7xx_zorro_detect(struct scsi_host_template *tpnt)
++static __devexit void amiga7xx_remove_one(struct zorro_dev *z)
+ {
+- int num = 0, i;
+- struct zorro_dev *z = NULL;
+- unsigned long address;
+-
+- while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
+- for (i = 0; amiga7xx_table[i].id; i++)
+- if (z->id == amiga7xx_table[i].id)
+- break;
+- if (!amiga7xx_table[i].id)
+- continue;
+- if (amiga7xx_table[i].absolute)
+- address = amiga7xx_table[i].offset;
+- else
+- address = z->resource.start + amiga7xx_table[i].offset;
+- num += amiga7xx_register_one(tpnt, address);
+- }
+- return num;
++ struct Scsi_Host *host = dev_to_shost(&z->dev);
++ struct NCR_700_Host_Parameters *hostdata =
++ (struct NCR_700_Host_Parameters *)host->hostdata[0];
++
++ scsi_remove_host(host);
++
++ NCR_700_release(host);
++ kfree(hostdata);
++ free_irq(host->irq, host);
++ zorro_release_device(z);
+ }
+
++static struct zorro_driver amiga7xx_driver = {
++ .name = "amiga7xx-scsi",
++ .id_table = amiga7xx_zorro_tbl,
++ .probe = amiga7xx_init_one,
++ .remove = __devexit_p(amiga7xx_remove_one),
++};
++
+ #endif /* CONFIG_ZORRO */
+
++#define A4000T_SCSI_ADDR 0xdd0040
+
+-int __init amiga7xx_detect(struct scsi_host_template *tpnt)
++static int __devinit a4000t_probe(struct device *dev)
+ {
+- static unsigned char called = 0;
+- int num = 0;
++ struct Scsi_Host * host = NULL;
++ struct NCR_700_Host_Parameters *hostdata;
+
+- if (called || !MACH_IS_AMIGA)
+- return 0;
++ if (!(MACH_IS_AMIGA && AMIGAHW_PRESENT(A4000_SCSI)))
++ goto out;
+
+- tpnt->proc_name = "Amiga7xx";
++ if (!request_mem_region(A4000T_SCSI_ADDR, 0x1000, "A4000T builtin SCSI"))
++ goto out;
+
+- if (AMIGAHW_PRESENT(A4000_SCSI))
+- num += amiga7xx_register_one(tpnt, 0xdd0040);
++ hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
++ if (hostdata == NULL) {
++ printk(KERN_ERR "a4000t-scsi: Failed to allocate host data\n");
++ goto out_release;
++ }
++ memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
++
++ /* Fill in the required pieces of hostdata */
++ hostdata->base = (void __iomem *)ZTWO_VADDR(A4000T_SCSI_ADDR);
++ hostdata->clock = 50;
++ hostdata->chip710 = 1;
++ hostdata->dmode_extra = DMODE_FC2;
++ hostdata->dcntl_extra = EA_710;
++
++ /* and register the chip */
++ if ((host = NCR_700_detect(&amiga7xx_scsi_driver_template, hostdata, dev))
++ == NULL) {
++ printk(KERN_ERR "a4000t-scsi: No host detected; board configuration problem?\n");
++ goto out_free;
++ }
++
++ host->this_id = 7;
++ host->base = A4000T_SCSI_ADDR;
++ host->irq = IRQ_AMIGA_PORTS;
++
++ if (request_irq(host->irq, NCR_700_intr, IRQF_SHARED, "a4000t-scsi", host)) {
++ printk(KERN_ERR "a4000t-scsi: request_irq failed\n");
++ goto out_put_host;
++ }
+
+-#ifdef CONFIG_ZORRO
+- num += amiga7xx_zorro_detect(tpnt);
+-#endif
++ scsi_scan_host(host);
++
++ return 0;
+
+- called = 1;
+- return num;
++ out_put_host:
++ scsi_host_put(host);
++ out_free:
++ kfree(hostdata);
++ out_release:
++ release_mem_region(A4000T_SCSI_ADDR, 0x1000);
++ out:
++ return -ENODEV;
+ }
+
+-static int amiga7xx_release(struct Scsi_Host *shost)
++static __devexit int a4000t_device_remove(struct device *dev)
+ {
+- if (shost->irq)
+- free_irq(shost->irq, NULL);
+- if (shost->dma_channel != 0xff)
+- free_dma(shost->dma_channel);
+- if (shost->io_port && shost->n_io_port)
+- release_region(shost->io_port, shost->n_io_port);
+- scsi_unregister(shost);
++ struct Scsi_Host *host = dev_to_shost(dev);
++ struct NCR_700_Host_Parameters *hostdata =
++ (struct NCR_700_Host_Parameters *)host->hostdata[0];
++
++ scsi_remove_host(host);
++
++ NCR_700_release(host);
++ kfree(hostdata);
++ free_irq(host->irq, host);
++ release_mem_region(A4000T_SCSI_ADDR, 0x1000);
++
+ return 0;
+ }
+
+-static struct scsi_host_template driver_template = {
+- .name = "Amiga NCR53c710 SCSI",
+- .detect = amiga7xx_detect,
+- .release = amiga7xx_release,
+- .queuecommand = NCR53c7xx_queue_command,
+- .abort = NCR53c7xx_abort,
+- .reset = NCR53c7xx_reset,
+- .can_queue = 24,
+- .this_id = 7,
+- .sg_tablesize = 63,
+- .cmd_per_lun = 3,
+- .use_clustering = DISABLE_CLUSTERING
++static struct device_driver a4000t_scsi_driver = {
++ .name = "a4000t-scsi",
++ .bus = &platform_bus_type,
++ .probe = a4000t_probe,
++ .remove = __devexit_p(a4000t_device_remove),
+ };
+
++static int __init amiga7xx_scsi_init(void)
++{
++ int err;
++
++ if ((err = driver_register(&a4000t_scsi_driver)))
++ return err;
++
++ a4000t_scsi_device = platform_device_register_simple("a4000t-scsi", -1, NULL, 0);
++
++ if (IS_ERR(a4000t_scsi_device)) {
++ driver_unregister(&a4000t_scsi_driver);
++ return PTR_ERR(a4000t_scsi_device);
++ }
++
++#ifdef CONFIG_ZORRO
++ err = zorro_register_driver(&amiga7xx_driver);
++#endif
++
++ return err;
++}
++
++static void __exit amiga7xx_scsi_exit(void)
++{
++ platform_device_unregister(a4000t_scsi_device);
++ driver_unregister(&a4000t_scsi_driver);
++#ifdef CONFIG_ZORRO
++ zorro_unregister_driver(&amiga7xx_driver);
++#endif
++}
+
+-#include "scsi_module.c"
++module_init(amiga7xx_scsi_init);
++module_exit(amiga7xx_scsi_exit);
+--- linux-m68k-2.6.21.orig/drivers/scsi/amiga7xx.h
++++ /dev/null
+@@ -1,23 +0,0 @@
+-#ifndef AMIGA7XX_H
+-
+-#include <linux/types.h>
+-
+-int amiga7xx_detect(struct scsi_host_template *);
+-const char *NCR53c7x0_info(void);
+-int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+-int NCR53c7xx_abort(Scsi_Cmnd *);
+-int NCR53c7x0_release (struct Scsi_Host *);
+-int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
+-void NCR53c7x0_intr(int irq, void *dev_id);
+-
+-#ifndef CMD_PER_LUN
+-#define CMD_PER_LUN 3
+-#endif
+-
+-#ifndef CAN_QUEUE
+-#define CAN_QUEUE 24
+-#endif
+-
+-#include <scsi/scsicam.h>
+-
+-#endif /* AMIGA7XX_H */
+--- linux-m68k-2.6.21.orig/drivers/scsi/bvme6000.h
++++ /dev/null
+@@ -1,24 +0,0 @@
+-#ifndef BVME6000_SCSI_H
+-#define BVME6000_SCSI_H
+-
+-#include <linux/types.h>
+-
+-int bvme6000_scsi_detect(struct scsi_host_template *);
+-const char *NCR53c7x0_info(void);
+-int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+-int NCR53c7xx_abort(Scsi_Cmnd *);
+-int NCR53c7x0_release (struct Scsi_Host *);
+-int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
+-void NCR53c7x0_intr(int irq, void *dev_id);
+-
+-#ifndef CMD_PER_LUN
+-#define CMD_PER_LUN 3
+-#endif
+-
+-#ifndef CAN_QUEUE
+-#define CAN_QUEUE 24
+-#endif
+-
+-#include <scsi/scsicam.h>
+-
+-#endif /* BVME6000_SCSI_H */
+--- linux-m68k-2.6.21.orig/drivers/scsi/bvme6000_scsi.c
++++ linux-m68k-2.6.21/drivers/scsi/bvme6000_scsi.c
+@@ -1,76 +1,132 @@
+ /*
+ * Detection routine for the NCR53c710 based BVME6000 SCSI Controllers for Linux.
+ *
+- * Based on work by Alan Hourihane
++ * Based on work by Alan Hourihane and Kars de Jong
++ *
++ * Rewritten to use 53c700.c by Richard Hirst <richard@sleepie.demon.co.uk>
+ */
+-#include <linux/types.h>
+-#include <linux/mm.h>
+-#include <linux/blkdev.h>
+-#include <linux/zorro.h>
+
+-#include <asm/setup.h>
+-#include <asm/page.h>
+-#include <asm/pgtable.h>
++#include <linux/module.h>
++#include <linux/blkdev.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
+ #include <asm/bvme6000hw.h>
+-#include <asm/irq.h>
+-
+-#include "scsi.h"
+ #include <scsi/scsi_host.h>
+-#include "53c7xx.h"
+-#include "bvme6000.h"
++#include <scsi/scsi_device.h>
++#include <scsi/scsi_transport.h>
++#include <scsi/scsi_transport_spi.h>
+
+-#include<linux/stat.h>
++#include "53c700.h"
+
++MODULE_AUTHOR("Richard Hirst <richard@sleepie.demon.co.uk>");
++MODULE_DESCRIPTION("BVME6000 NCR53C710 driver");
++MODULE_LICENSE("GPL");
+
+-int bvme6000_scsi_detect(struct scsi_host_template *tpnt)
++static struct scsi_host_template bvme6000_scsi_driver_template = {
++ .name = "BVME6000 NCR53c710 SCSI",
++ .proc_name = "BVME6000",
++ .this_id = 7,
++ .module = THIS_MODULE,
++};
++
++static struct platform_device *bvme6000_scsi_device;
++
++static __devinit int
++bvme6000_probe(struct device *dev)
+ {
+- static unsigned char called = 0;
+- int clock;
+- long long options;
++ struct Scsi_Host * host = NULL;
++ struct NCR_700_Host_Parameters *hostdata;
+
+- if (called)
+- return 0;
+- if (!MACH_IS_BVME6000)
+- return 0;
++ if (!MACH_IS_BVME6000)
++ goto out;
+
+- tpnt->proc_name = "BVME6000";
++ hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
++ if (hostdata == NULL) {
++ printk(KERN_ERR "bvme6000-scsi: Failed to allocate host data\n");
++ goto out;
++ }
++ memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
++
++ /* Fill in the required pieces of hostdata */
++ hostdata->base = (void __iomem *)BVME_NCR53C710_BASE;
++ hostdata->clock = 40; /* XXX - depends on the CPU clock! */
++ hostdata->chip710 = 1;
++ hostdata->dmode_extra = DMODE_FC2;
++ hostdata->dcntl_extra = EA_710;
++ hostdata->ctest7_extra = CTEST7_TT1;
++
++ /* and register the chip */
++ if ((host = NCR_700_detect(&bvme6000_scsi_driver_template, hostdata, dev))
++ == NULL) {
++ printk(KERN_ERR "bvme6000-scsi: No host detected; board configuration problem?\n");
++ goto out_free;
++ }
++ host->base = BVME_NCR53C710_BASE;
++ host->this_id = 7;
++ host->irq = BVME_IRQ_SCSI;
++ if (request_irq(BVME_IRQ_SCSI, NCR_700_intr, 0, "bvme6000-scsi", host)) {
++ printk(KERN_ERR "bvme6000-scsi: request_irq failed\n");
++ goto out_put_host;
++ }
+
+- options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
++ scsi_scan_host(host);
+
+- clock = 40000000; /* 66MHz SCSI Clock */
++ return 0;
+
+- ncr53c7xx_init(tpnt, 0, 710, (unsigned long)BVME_NCR53C710_BASE,
+- 0, BVME_IRQ_SCSI, DMA_NONE,
+- options, clock);
+- called = 1;
+- return 1;
++ out_put_host:
++ scsi_host_put(host);
++ out_free:
++ kfree(hostdata);
++ out:
++ return -ENODEV;
+ }
+
+-static int bvme6000_scsi_release(struct Scsi_Host *shost)
++static __devexit int
++bvme6000_device_remove(struct device *dev)
+ {
+- if (shost->irq)
+- free_irq(shost->irq, NULL);
+- if (shost->dma_channel != 0xff)
+- free_dma(shost->dma_channel);
+- if (shost->io_port && shost->n_io_port)
+- release_region(shost->io_port, shost->n_io_port);
+- scsi_unregister(shost);
++ struct Scsi_Host *host = dev_to_shost(dev);
++ struct NCR_700_Host_Parameters *hostdata =
++ (struct NCR_700_Host_Parameters *)host->hostdata[0];
++
++ scsi_remove_host(host);
++ NCR_700_release(host);
++ kfree(hostdata);
++ free_irq(host->irq, host);
++
+ return 0;
+ }
+
+-static struct scsi_host_template driver_template = {
+- .name = "BVME6000 NCR53c710 SCSI",
+- .detect = bvme6000_scsi_detect,
+- .release = bvme6000_scsi_release,
+- .queuecommand = NCR53c7xx_queue_command,
+- .abort = NCR53c7xx_abort,
+- .reset = NCR53c7xx_reset,
+- .can_queue = 24,
+- .this_id = 7,
+- .sg_tablesize = 63,
+- .cmd_per_lun = 3,
+- .use_clustering = DISABLE_CLUSTERING
++static struct device_driver bvme6000_scsi_driver = {
++ .name = "bvme6000-scsi",
++ .bus = &platform_bus_type,
++ .probe = bvme6000_probe,
++ .remove = __devexit_p(bvme6000_device_remove),
+ };
+
++static int __init bvme6000_scsi_init(void)
++{
++ int err;
++
++ if ((err = driver_register(&bvme6000_scsi_driver)))
++ return err;
++
++ bvme6000_scsi_device = platform_device_register_simple("bvme6000-scsi", -1, NULL, 0);
++
++ if (IS_ERR(bvme6000_scsi_device)) {
++ driver_unregister(&bvme6000_scsi_driver);
++ return PTR_ERR(bvme6000_scsi_device);
++ }
++
++ return 0;
++}
++
++static void __exit bvme6000_scsi_exit(void)
++{
++ platform_device_unregister(bvme6000_scsi_device);
++ driver_unregister(&bvme6000_scsi_driver);
++}
+
+-#include "scsi_module.c"
++module_init(bvme6000_scsi_init);
++module_exit(bvme6000_scsi_exit);
+--- linux-m68k-2.6.21.orig/drivers/scsi/mvme16x.h
++++ /dev/null
+@@ -1,24 +0,0 @@
+-#ifndef MVME16x_SCSI_H
+-#define MVME16x_SCSI_H
+-
+-#include <linux/types.h>
+-
+-int mvme16x_scsi_detect(struct scsi_host_template *);
+-const char *NCR53c7x0_info(void);
+-int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+-int NCR53c7xx_abort(Scsi_Cmnd *);
+-int NCR53c7x0_release (struct Scsi_Host *);
+-int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
+-void NCR53c7x0_intr(int irq, void *dev_id);
+-
+-#ifndef CMD_PER_LUN
+-#define CMD_PER_LUN 3
+-#endif
+-
+-#ifndef CAN_QUEUE
+-#define CAN_QUEUE 24
+-#endif
+-
+-#include <scsi/scsicam.h>
+-
+-#endif /* MVME16x_SCSI_H */
+--- linux-m68k-2.6.21.orig/drivers/scsi/mvme16x_scsi.c
++++ linux-m68k-2.6.21/drivers/scsi/mvme16x_scsi.c
+@@ -2,77 +2,154 @@
+ * Detection routine for the NCR53c710 based MVME16x SCSI Controllers for Linux.
+ *
+ * Based on work by Alan Hourihane
++ *
++ * Rewritten to use 53c700.c by Kars de Jong <jongk@linux-m68k.org>
+ */
+-#include <linux/types.h>
+-#include <linux/mm.h>
+-#include <linux/blkdev.h>
+
+-#include <asm/page.h>
+-#include <asm/pgtable.h>
++#include <linux/module.h>
++#include <linux/blkdev.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
+ #include <asm/mvme16xhw.h>
+-#include <asm/irq.h>
+-
+-#include "scsi.h"
+ #include <scsi/scsi_host.h>
+-#include "53c7xx.h"
+-#include "mvme16x.h"
++#include <scsi/scsi_device.h>
++#include <scsi/scsi_transport.h>
++#include <scsi/scsi_transport_spi.h>
+
+-#include<linux/stat.h>
++#include "53c700.h"
+
++MODULE_AUTHOR("Kars de Jong <jongk@linux-m68k.org>");
++MODULE_DESCRIPTION("MVME16x NCR53C710 driver");
++MODULE_LICENSE("GPL");
+
+-int mvme16x_scsi_detect(struct scsi_host_template *tpnt)
++static struct scsi_host_template mvme16x_scsi_driver_template = {
++ .name = "MVME16x NCR53c710 SCSI",
++ .proc_name = "MVME16x",
++ .this_id = 7,
++ .module = THIS_MODULE,
++};
++
++static struct platform_device *mvme16x_scsi_device;
++
++static __devinit int
++mvme16x_probe(struct device *dev)
+ {
+- static unsigned char called = 0;
+- int clock;
+- long long options;
+-
+- if (!MACH_IS_MVME16x)
+- return 0;
+- if (mvme16x_config & MVME16x_CONFIG_NO_SCSICHIP) {
+- printk ("SCSI detection disabled, SCSI chip not present\n");
+- return 0;
+- }
+- if (called)
+- return 0;
++ struct Scsi_Host * host = NULL;
++ struct NCR_700_Host_Parameters *hostdata;
++
++ if (!MACH_IS_MVME16x)
++ goto out;
+
+- tpnt->proc_name = "MVME16x";
++ if (mvme16x_config & MVME16x_CONFIG_NO_SCSICHIP) {
++ printk(KERN_INFO "mvme16x-scsi: detection disabled, SCSI chip not present\n");
++ goto out;
++ }
++
++ hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
++ if (hostdata == NULL) {
++ printk(KERN_ERR "mvme16x-scsi: Failed to allocate host data\n");
++ goto out;
++ }
++ memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
++
++ /* Fill in the required pieces of hostdata */
++ hostdata->base = (void __iomem *)0xfff47000UL;
++ hostdata->clock = 50; /* XXX - depends on the CPU clock! */
++ hostdata->chip710 = 1;
++ hostdata->dmode_extra = DMODE_FC2;
++ hostdata->dcntl_extra = EA_710;
++ hostdata->ctest7_extra = CTEST7_TT1;
++
++ /* and register the chip */
++ if ((host = NCR_700_detect(&mvme16x_scsi_driver_template, hostdata, dev))
++ == NULL) {
++ printk(KERN_ERR "mvme16x-scsi: No host detected; board configuration problem?\n");
++ goto out_free;
++ }
++ host->this_id = 7;
++ host->base = 0xfff47000UL;
++ host->irq = MVME16x_IRQ_SCSI;
++ if (request_irq(host->irq, NCR_700_intr, 0, "mvme16x-scsi", host)) {
++ printk(KERN_ERR "mvme16x-scsi: request_irq failed\n");
++ goto out_put_host;
++ }
++
++ /* Enable scsi chip ints */
++ {
++ volatile unsigned long v;
++
++ /* Enable scsi interrupts at level 4 in PCCchip2 */
++ v = in_be32(0xfff4202c);
++ v = (v & ~0xff) | 0x10 | 4;
++ out_be32(0xfff4202c, v);
++ }
+
+- options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
++ scsi_scan_host(host);
+
+- clock = 66000000; /* 66MHz SCSI Clock */
++ return 0;
+
+- ncr53c7xx_init(tpnt, 0, 710, (unsigned long)0xfff47000,
+- 0, MVME16x_IRQ_SCSI, DMA_NONE,
+- options, clock);
+- called = 1;
+- return 1;
++ out_put_host:
++ scsi_host_put(host);
++ out_free:
++ kfree(hostdata);
++ out:
++ return -ENODEV;
+ }
+
+-static int mvme16x_scsi_release(struct Scsi_Host *shost)
++static __devexit int
++mvme16x_device_remove(struct device *dev)
+ {
+- if (shost->irq)
+- free_irq(shost->irq, NULL);
+- if (shost->dma_channel != 0xff)
+- free_dma(shost->dma_channel);
+- if (shost->io_port && shost->n_io_port)
+- release_region(shost->io_port, shost->n_io_port);
+- scsi_unregister(shost);
++ struct Scsi_Host *host = dev_to_shost(dev);
++ struct NCR_700_Host_Parameters *hostdata =
++ (struct NCR_700_Host_Parameters *)host->hostdata[0];
++
++ /* Disable scsi chip ints */
++ {
++ volatile unsigned long v;
++
++ v = in_be32(0xfff4202c);
++ v &= ~0x10;
++ out_be32(0xfff4202c, v);
++ }
++ scsi_remove_host(host);
++ NCR_700_release(host);
++ kfree(hostdata);
++ free_irq(host->irq, host);
++
+ return 0;
+ }
+
+-static struct scsi_host_template driver_template = {
+- .name = "MVME16x NCR53c710 SCSI",
+- .detect = mvme16x_scsi_detect,
+- .release = mvme16x_scsi_release,
+- .queuecommand = NCR53c7xx_queue_command,
+- .abort = NCR53c7xx_abort,
+- .reset = NCR53c7xx_reset,
+- .can_queue = 24,
+- .this_id = 7,
+- .sg_tablesize = 63,
+- .cmd_per_lun = 3,
+- .use_clustering = DISABLE_CLUSTERING
++static struct device_driver mvme16x_scsi_driver = {
++ .name = "mvme16x-scsi",
++ .bus = &platform_bus_type,
++ .probe = mvme16x_probe,
++ .remove = __devexit_p(mvme16x_device_remove),
+ };
+
++static int __init mvme16x_scsi_init(void)
++{
++ int err;
++
++ if ((err = driver_register(&mvme16x_scsi_driver)))
++ return err;
++
++ mvme16x_scsi_device = platform_device_register_simple("mvme16x-scsi", -1, NULL, 0);
++
++ if (IS_ERR(mvme16x_scsi_device)) {
++ driver_unregister(&mvme16x_scsi_driver);
++ return PTR_ERR(mvme16x_scsi_device);
++ }
++
++ return 0;
++}
++
++static void __exit mvme16x_scsi_exit(void)
++{
++ platform_device_unregister(mvme16x_scsi_device);
++ driver_unregister(&mvme16x_scsi_driver);
++}
+
+-#include "scsi_module.c"
++module_init(mvme16x_scsi_init);
++module_exit(mvme16x_scsi_exit);
diff --git a/debian/patches/bugfix/m68k/m68k-as.patch b/debian/patches/bugfix/m68k/m68k-as.patch
new file mode 100644
index 000000000000..f228e6d3090b
--- /dev/null
+++ b/debian/patches/bugfix/m68k/m68k-as.patch
@@ -0,0 +1,308 @@
+From: Al Viro <viro@zeniv.linux.org.uk>
+Date: 1134413482 -0500
+
+recent as(1) doesn't think that . terminates a macro name, so
+getuser.l is _not_ treated as invoking getuser with .l as the
+first argument.
+
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+
+---
+
+ arch/m68k/math-emu/fp_cond.S | 2 +-
+ arch/m68k/math-emu/fp_decode.h | 4 ++--
+ arch/m68k/math-emu/fp_move.S | 14 +++++++-------
+ arch/m68k/math-emu/fp_movem.S | 16 ++++++++--------
+ arch/m68k/math-emu/fp_scan.S | 22 +++++++++++-----------
+ arch/m68k/math-emu/fp_util.S | 16 ++++++++--------
+ 6 files changed, 37 insertions(+), 37 deletions(-)
+
+3c4ab44571b5a46917ad28620995c326e386a909
+diff --git a/arch/m68k/math-emu/fp_cond.S b/arch/m68k/math-emu/fp_cond.S
+index ddae8b1..1cddeb0 100644
+--- a/arch/m68k/math-emu/fp_cond.S
++++ b/arch/m68k/math-emu/fp_cond.S
+@@ -163,7 +163,7 @@ fp_absolute_long:
+
+ fp_do_scc:
+ swap %d1
+- putuser.b %d1,(%a0),fp_err_ua1,%a0
++ putuser .b,%d1,(%a0),fp_err_ua1,%a0
+ printf PDECODE,"\n"
+ jra fp_end
+
+diff --git a/arch/m68k/math-emu/fp_decode.h b/arch/m68k/math-emu/fp_decode.h
+index 759679d..a2595d9 100644
+--- a/arch/m68k/math-emu/fp_decode.h
++++ b/arch/m68k/math-emu/fp_decode.h
+@@ -311,7 +311,7 @@ debug move.l "(%sp)+,%d1"
+ btst #2,%d2
+ jne 1f
+ printf PDECODE,")@("
+- getuser.l (%a1),%a1,fp_err_ua1,%a1
++ getuser .l,(%a1),%a1,fp_err_ua1,%a1
+ debug jra "2f"
+ 1: printf PDECODE,","
+ 2:
+@@ -322,7 +322,7 @@ debug jra "2f"
+ btst #2,%d2
+ jeq 1f
+ printf PDECODE,")@("
+- getuser.l (%a1),%a1,fp_err_ua1,%a1
++ getuser .l,(%a1),%a1,fp_err_ua1,%a1
+ debug jra "2f"
+ 1: printf PDECODE,","
+ 2:
+diff --git a/arch/m68k/math-emu/fp_move.S b/arch/m68k/math-emu/fp_move.S
+index 71bdf83..9bd0334 100644
+--- a/arch/m68k/math-emu/fp_move.S
++++ b/arch/m68k/math-emu/fp_move.S
+@@ -200,12 +200,12 @@ fp_putdest:
+
+ fp_format_long:
+ jsr fp_conv_ext2long
+- putuser.l %d0,(%a1),fp_err_ua1,%a1
++ putuser .l,%d0,(%a1),fp_err_ua1,%a1
+ jra fp_finish_move
+
+ fp_format_single:
+ jsr fp_conv_ext2single
+- putuser.l %d0,(%a1),fp_err_ua1,%a1
++ putuser .l,%d0,(%a1),fp_err_ua1,%a1
+ jra fp_finish_move
+
+ fp_format_extended:
+@@ -213,11 +213,11 @@ fp_format_extended:
+ lsl.w #1,%d0
+ lsl.l #7,%d0
+ lsl.l #8,%d0
+- putuser.l %d0,(%a1)+,fp_err_ua1,%a1
++ putuser .l,%d0,(%a1)+,fp_err_ua1,%a1
+ move.l (%a0)+,%d0
+- putuser.l %d0,(%a1)+,fp_err_ua1,%a1
++ putuser .l,%d0,(%a1)+,fp_err_ua1,%a1
+ move.l (%a0),%d0
+- putuser.l %d0,(%a1),fp_err_ua1,%a1
++ putuser .l,%d0,(%a1),fp_err_ua1,%a1
+ jra fp_finish_move
+
+ fp_format_packed:
+@@ -227,7 +227,7 @@ fp_format_packed:
+
+ fp_format_word:
+ jsr fp_conv_ext2short
+- putuser.w %d0,(%a1),fp_err_ua1,%a1
++ putuser .w,%d0,(%a1),fp_err_ua1,%a1
+ jra fp_finish_move
+
+ fp_format_double:
+@@ -236,7 +236,7 @@ fp_format_double:
+
+ fp_format_byte:
+ jsr fp_conv_ext2byte
+- putuser.b %d0,(%a1),fp_err_ua1,%a1
++ putuser .b,%d0,(%a1),fp_err_ua1,%a1
+ | jra fp_finish_move
+
+ fp_finish_move:
+diff --git a/arch/m68k/math-emu/fp_movem.S b/arch/m68k/math-emu/fp_movem.S
+index 8354d39..9c74134 100644
+--- a/arch/m68k/math-emu/fp_movem.S
++++ b/arch/m68k/math-emu/fp_movem.S
+@@ -141,14 +141,14 @@ fpr_do_movem:
+ | move register from memory into fpu
+ jra 3f
+ 1: printf PMOVEM,"(%p>%p)",2,%a0,%a1
+- getuser.l (%a0)+,%d2,fp_err_ua1,%a0
++ getuser .l,(%a0)+,%d2,fp_err_ua1,%a0
+ lsr.l #8,%d2
+ lsr.l #7,%d2
+ lsr.w #1,%d2
+ move.l %d2,(%a1)+
+- getuser.l (%a0)+,%d2,fp_err_ua1,%a0
++ getuser .l,(%a0)+,%d2,fp_err_ua1,%a0
+ move.l %d2,(%a1)+
+- getuser.l (%a0),%d2,fp_err_ua1,%a0
++ getuser .l,(%a0),%d2,fp_err_ua1,%a0
+ move.l %d2,(%a1)
+ subq.l #8,%a0
+ subq.l #8,%a1
+@@ -164,11 +164,11 @@ fpr_do_movem:
+ lsl.w #1,%d2
+ lsl.l #7,%d2
+ lsl.l #8,%d2
+- putuser.l %d2,(%a0)+,fp_err_ua1,%a0
++ putuser .l,%d2,(%a0)+,fp_err_ua1,%a0
+ move.l (%a1)+,%d2
+- putuser.l %d2,(%a0)+,fp_err_ua1,%a0
++ putuser .l,%d2,(%a0)+,fp_err_ua1,%a0
+ move.l (%a1),%d2
+- putuser.l %d2,(%a0),fp_err_ua1,%a0
++ putuser .l,%d2,(%a0),fp_err_ua1,%a0
+ subq.l #8,%a1
+ subq.l #8,%a0
+ add.l %d0,%a0
+@@ -325,7 +325,7 @@ fpc_do_movem:
+ | move register from memory into fpu
+ jra 3f
+ 1: printf PMOVEM,"(%p>%p)",2,%a0,%a1
+- getuser.l (%a0)+,%d0,fp_err_ua1,%a0
++ getuser .l,(%a0)+,%d0,fp_err_ua1,%a0
+ move.l %d0,(%a1)
+ 2: addq.l #4,%a1
+ 3: lsl.b #1,%d1
+@@ -336,7 +336,7 @@ fpc_do_movem:
+ | move register from fpu into memory
+ 1: printf PMOVEM,"(%p>%p)",2,%a1,%a0
+ move.l (%a1),%d0
+- putuser.l %d0,(%a0)+,fp_err_ua1,%a0
++ putuser .l,%d0,(%a0)+,fp_err_ua1,%a0
+ 2: addq.l #4,%a1
+ 4: lsl.b #1,%d1
+ jcs 1b
+diff --git a/arch/m68k/math-emu/fp_scan.S b/arch/m68k/math-emu/fp_scan.S
+index e4146ed..5f49b93 100644
+--- a/arch/m68k/math-emu/fp_scan.S
++++ b/arch/m68k/math-emu/fp_scan.S
+@@ -64,7 +64,7 @@ fp_scan:
+ | normal fpu instruction? (this excludes fsave/frestore)
+ fp_get_pc %a0
+ printf PDECODE,"%08x: ",1,%a0
+- getuser.b (%a0),%d0,fp_err_ua1,%a0
++ getuser .b,(%a0),%d0,fp_err_ua1,%a0
+ #if 1
+ cmp.b #0xf2,%d0 | cpid = 1
+ #else
+@@ -72,7 +72,7 @@ fp_scan:
+ #endif
+ jne fp_nonstd
+ | first two instruction words are kept in %d2
+- getuser.l (%a0)+,%d2,fp_err_ua1,%a0
++ getuser .l,(%a0)+,%d2,fp_err_ua1,%a0
+ fp_put_pc %a0
+ fp_decode_cond: | separate conditional instr
+ fp_decode_cond_instr_type
+@@ -230,7 +230,7 @@ fp_immediate:
+ movel %a0,%a1
+ clr.l %d1
+ jra 2f
+-1: getuser.b (%a1)+,%d1,fp_err_ua1,%a1
++1: getuser .b,(%a1)+,%d1,fp_err_ua1,%a1
+ printf PDECODE,"%02x",1,%d1
+ 2: dbra %d0,1b
+ movem.l (%sp)+,%d0/%d1
+@@ -252,24 +252,24 @@ fp_fetchsource:
+ .long fp_byte, fp_ill
+
+ fp_long:
+- getuser.l (%a1),%d0,fp_err_ua1,%a1
++ getuser .l,(%a1),%d0,fp_err_ua1,%a1
+ jsr fp_conv_long2ext
+ jra fp_getdest
+
+ fp_single:
+- getuser.l (%a1),%d0,fp_err_ua1,%a1
++ getuser .l,(%a1),%d0,fp_err_ua1,%a1
+ jsr fp_conv_single2ext
+ jra fp_getdest
+
+ fp_ext:
+- getuser.l (%a1)+,%d0,fp_err_ua1,%a1
++ getuser .l,(%a1)+,%d0,fp_err_ua1,%a1
+ lsr.l #8,%d0
+ lsr.l #7,%d0
+ lsr.w #1,%d0
+ move.l %d0,(%a0)+
+- getuser.l (%a1)+,%d0,fp_err_ua1,%a1
++ getuser .l,(%a1)+,%d0,fp_err_ua1,%a1
+ move.l %d0,(%a0)+
+- getuser.l (%a1),%d0,fp_err_ua1,%a1
++ getuser .l,(%a1),%d0,fp_err_ua1,%a1
+ move.l %d0,(%a0)
+ subq.l #8,%a0
+ jra fp_getdest
+@@ -279,7 +279,7 @@ fp_pack:
+ jra fp_ill
+
+ fp_word:
+- getuser.w (%a1),%d0,fp_err_ua1,%a1
++ getuser .w,(%a1),%d0,fp_err_ua1,%a1
+ ext.l %d0
+ jsr fp_conv_long2ext
+ jra fp_getdest
+@@ -289,7 +289,7 @@ fp_double:
+ jra fp_getdest
+
+ fp_byte:
+- getuser.b (%a1),%d0,fp_err_ua1,%a1
++ getuser .b,(%a1),%d0,fp_err_ua1,%a1
+ extb.l %d0
+ jsr fp_conv_long2ext
+ | jra fp_getdest
+@@ -465,7 +465,7 @@ fp_fdsub:
+
+ fp_nonstd:
+ fp_get_pc %a0
+- getuser.l (%a0),%d0,fp_err_ua1,%a0
++ getuser .l,(%a0),%d0,fp_err_ua1,%a0
+ printf ,"nonstd ((%08x)=%08x)\n",2,%a0,%d0
+ moveq #-1,%d0
+ rts
+diff --git a/arch/m68k/math-emu/fp_util.S b/arch/m68k/math-emu/fp_util.S
+index a9f7f01..f9f24d5 100644
+--- a/arch/m68k/math-emu/fp_util.S
++++ b/arch/m68k/math-emu/fp_util.S
+@@ -160,11 +160,11 @@ fp_s2e_large:
+
+ fp_conv_double2ext:
+ #ifdef FPU_EMU_DEBUG
+- getuser.l %a1@(0),%d0,fp_err_ua2,%a1
+- getuser.l %a1@(4),%d1,fp_err_ua2,%a1
++ getuser .l,%a1@(0),%d0,fp_err_ua2,%a1
++ getuser .l,%a1@(4),%d1,fp_err_ua2,%a1
+ printf PCONV,"d2e: %p%p -> %p(",3,%d0,%d1,%a0
+ #endif
+- getuser.l (%a1)+,%d0,fp_err_ua2,%a1
++ getuser .l,(%a1)+,%d0,fp_err_ua2,%a1
+ move.l %d0,%d1
+ lsl.l #8,%d0 | shift high mantissa
+ lsl.l #3,%d0
+@@ -178,7 +178,7 @@ fp_conv_double2ext:
+ add.w #0x3fff-0x3ff,%d1 | re-bias the exponent.
+ 9: move.l %d1,(%a0)+ | fp_ext.sign, fp_ext.exp
+ move.l %d0,(%a0)+
+- getuser.l (%a1)+,%d0,fp_err_ua2,%a1
++ getuser .l,(%a1)+,%d0,fp_err_ua2,%a1
+ move.l %d0,%d1
+ lsl.l #8,%d0
+ lsl.l #3,%d0
+@@ -1287,17 +1287,17 @@ fp_conv_ext2double:
+ lsr.l #4,%d0
+ lsr.l #8,%d0
+ or.l %d2,%d0
+- putuser.l %d0,(%a1)+,fp_err_ua2,%a1
++ putuser .l,%d0,(%a1)+,fp_err_ua2,%a1
+ moveq #21,%d0
+ lsl.l %d0,%d1
+ move.l (%a0),%d0
+ lsr.l #4,%d0
+ lsr.l #7,%d0
+ or.l %d1,%d0
+- putuser.l %d0,(%a1),fp_err_ua2,%a1
++ putuser .l,%d0,(%a1),fp_err_ua2,%a1
+ #ifdef FPU_EMU_DEBUG
+- getuser.l %a1@(-4),%d0,fp_err_ua2,%a1
+- getuser.l %a1@(0),%d1,fp_err_ua2,%a1
++ getuser .l,%a1@(-4),%d0,fp_err_ua2,%a1
++ getuser .l,%a1@(0),%d1,fp_err_ua2,%a1
+ printf PCONV,"%p(%08x%08x)\n",3,%a1,%d0,%d1
+ #endif
+ rts
+--
+0.99.9.GIT
+
+-
+To unsubscribe from this list: send the line "unsubscribe linux-m68k" in
+the body of a message to majordomo@vger.kernel.org
+More majordomo info at http://vger.kernel.org/majordomo-info.html
+
diff --git a/debian/patches/bugfix/m68k/m68k-generic-io.diff b/debian/patches/bugfix/m68k/m68k-generic-io.diff
new file mode 100644
index 000000000000..da0ad5558022
--- /dev/null
+++ b/debian/patches/bugfix/m68k/m68k-generic-io.diff
@@ -0,0 +1,234 @@
+From jongk@linux-m68k.org Fri Nov 3 10:12:53 2006
+Date: Fri, 03 Nov 2006 00:06:13 +0100
+From: Kars de Jong <jongk@linux-m68k.org>
+To: Geert Uytterhoeven <geert@linux-m68k.org>
+Cc: linux-m68k@vger.kernel.org
+Subject: [RFC PATCH] m68k: GENERIC_IOMAP support
+
+On do, 2006-11-02 at 22:34 +0100, Geert Uytterhoeven wrote:
+> > OK, here's the patch, without the m68k generic iomap changes.
+>
+> Ah, the missing io{read,write}*() stuff :-)
+
+And here is the proposed patch to add iomap support. I think we need to
+rethink our I/O support when we want to support all our I/O buses
+properly, but that has been discussed before. I will commit my Amiga
+PCMCIA support soon, I promise!
+
+I'm personally in favour of dropping the "generic" m68k kernel support.
+Even a specific 2.6.18 kernel with only MVME167 support and the bare
+essentials is already 2.5 MBytes these days. I don't even dare to think
+of the size of a generic m68k kernel these days.
+
+Since Debian also builds "specific" kernels these days, I wonder if we
+still need "generic" installation type kernels. Dropping that support
+does make implementing some of the I/O stuff a lot easier, IMO, since it
+can then be done at compile time.
+
+On vr, 2006-11-03 at 00:06 +0100, Kars de Jong wrote:
+> On do, 2006-11-02 at 22:34 +0100, Geert Uytterhoeven wrote:
+> > > OK, here's the patch, without the m68k generic iomap changes.
+> >
+> > Ah, the missing io{read,write}*() stuff :-)
+>
+> And here is the proposed patch to add iomap support. I think we need to
+> rethink our I/O support when we want to support all our I/O buses
+> properly, but that has been discussed before. I will commit my Amiga
+> PCMCIA support soon, I promise!
+
+Here's the updated version of this patch. It should now work with Amiga
+and Q40 defconfig.
+
+I don't think the CONFIG_ATARI_ROM_ISA definitions are complete yet, the
+32-bit variants are missing.
+
+Kind regards,
+
+Kars.
+
+---
+ arch/m68k/Kconfig | 4 ++
+ include/asm-m68k/io.h | 63 +++++++++++++++++++++++++++++++++++++---------
+ include/asm-m68k/raw_io.h | 8 ++++-
+ 3 files changed, 61 insertions(+), 14 deletions(-)
+
+--- linux-m68k-2.6.21.orig/arch/m68k/Kconfig
++++ linux-m68k-2.6.21/arch/m68k/Kconfig
+@@ -37,6 +37,10 @@ config TIME_LOW_RES
+ bool
+ default y
+
++config GENERIC_IOMAP
++ bool
++ default y
++
+ config ARCH_MAY_HAVE_PC_FDC
+ bool
+ depends on Q40 || (BROKEN && SUN3X)
+--- linux-m68k-2.6.21.orig/include/asm-m68k/io.h
++++ linux-m68k-2.6.21/include/asm-m68k/io.h
+@@ -27,6 +27,7 @@
+ #include <asm/raw_io.h>
+ #include <asm/virtconvert.h>
+
++#include <asm-generic/iomap.h>
+
+ #ifdef CONFIG_ATARI
+ #include <asm/atarihw.h>
+@@ -175,6 +176,16 @@ static inline u16 __iomem *isa_itw(unsig
+ default: return NULL; /* avoid warnings, just in case */
+ }
+ }
++static inline u32 __iomem *isa_itl(unsigned long addr)
++{
++ switch(ISA_TYPE)
++ {
++#ifdef CONFIG_AMIGA_PCMCIA
++ case AG_ISA: return (u32 *)AG_ISA_IO_W(addr);
++#endif
++ default: return 0; /* avoid warnings, just in case */
++ }
++}
+ static inline u8 __iomem *isa_mtb(unsigned long addr)
+ {
+ switch(ISA_TYPE)
+@@ -217,8 +228,10 @@ static inline u16 __iomem *isa_mtw(unsig
+
+ #define isa_inb(port) in_8(isa_itb(port))
+ #define isa_inw(port) (ISA_SEX ? in_be16(isa_itw(port)) : in_le16(isa_itw(port)))
++#define isa_inl(port) (ISA_SEX ? in_be32(isa_itl(port)) : in_le32(isa_itl(port)))
+ #define isa_outb(val,port) out_8(isa_itb(port),(val))
+ #define isa_outw(val,port) (ISA_SEX ? out_be16(isa_itw(port),(val)) : out_le16(isa_itw(port),(val)))
++#define isa_outl(val,port) (ISA_SEX ? out_be32(isa_itl(port),(val)) : out_le32(isa_itl(port),(val)))
+
+ #define isa_readb(p) in_8(isa_mtb((unsigned long)(p)))
+ #define isa_readw(p) \
+@@ -280,6 +293,14 @@ static inline void isa_delay(void)
+ (ISA_SEX ? raw_outsw(isa_itw(port), (u16 *)(buf), (nr)) : \
+ raw_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr)))
+
++#define isa_insl(port, buf, nr) \
++ (ISA_SEX ? raw_insl(isa_itl(port), (u32 *)(buf), (nr)) : \
++ raw_insw_swapw(isa_itw(port), (u16 *)(buf), (nr)<<1))
++
++#define isa_outsl(port, buf, nr) \
++ (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; })
+@@ -314,14 +335,16 @@ static inline void isa_delay(void)
+ #define inw_p isa_inw_p
+ #define outw isa_outw
+ #define outw_p isa_outw_p
+-#define inl isa_inw
+-#define inl_p isa_inw_p
+-#define outl isa_outw
+-#define outl_p isa_outw_p
++#define inl isa_inl
++#define inl_p isa_inl_p
++#define outl isa_outl
++#define outl_p isa_outl_p
+ #define insb isa_insb
+ #define insw isa_insw
++#define insl isa_insl
+ #define outsb isa_outsb
+ #define outsw isa_outsw
++#define outsl isa_outsl
+ #define readb isa_readb
+ #define readw isa_readw
+ #define writeb isa_writeb
+@@ -330,8 +353,6 @@ static inline void isa_delay(void)
+
+ #if defined(CONFIG_PCI)
+
+-#define inl(port) in_le32(port)
+-#define outl(val,port) out_le32((port),(val))
+ #define readl(addr) in_le32(addr)
+ #define writel(val,addr) out_le32((addr),(val))
+
+@@ -346,10 +367,13 @@ static inline void isa_delay(void)
+ #define readl_relaxed(addr) readl(addr)
+
+ #ifndef CONFIG_ISA
++
+ #define inb(port) in_8(port)
+ #define outb(val,port) out_8((port),(val))
+ #define inw(port) in_le16(port)
+ #define outw(val,port) out_le16((port),(val))
++#define inl(port) in_le32(port)
++#define outl(val,port) out_le32((port),(val))
+
+ #else
+ /*
+@@ -401,20 +425,35 @@ static inline void isa_delay(void)
+ #define outsw isa_rom_outsw
+ #endif
+
+-#if !defined(CONFIG_ISA) && !defined(CONFIG_PCI) && !defined(CONFIG_ATARI_ROM_ISA) && defined(CONFIG_HP300)
++#if !defined(CONFIG_ISA) && !defined(CONFIG_PCI) && !defined(CONFIG_ATARI_ROM_ISA)
+ /*
+- * We need to define dummy functions otherwise drivers/serial/8250.c doesn't link
++ * We need to define dummy functions for GENERIC_IOMAP support.
+ */
+-#define inb(port) 0xff
+-#define inb_p(port) 0xff
+-#define outb(val,port) do { } while (0)
+-#define outb_p(val,port) do { } while (0)
++#define inb(port) 0xff
++#define inb_p(port) 0xff
++#define outb(val,port) do { } while (0)
++#define outb_p(val,port) do { } while (0)
++#define inw(port) 0xffff
++#define outw(val,port) do { } while (0)
++#define inl(port) 0xffffffffUL
++#define outl(val,port) do { } while (0)
++
++#define insb(port,buf,nr) do { } while (0)
++#define outsb(port,buf,nr) do { } while (0)
++#define insw(port,buf,nr) do { } while (0)
++#define outsw(port,buf,nr) do { } while (0)
++#define insl(port,buf,nr) do { } while (0)
++#define outsl(port,buf,nr) do { } while (0)
+
+ /*
+ * These should be valid on any ioremap()ed region
+ */
+ #define readb(addr) in_8(addr)
+ #define writeb(val,addr) out_8((addr),(val))
++#define readw(addr) in_le16(addr)
++#define writew(val,addr) out_le16((addr),(val))
++#endif /* !CONFIG_ISA && !CONFIG_PCI && !CONFIG_ATARI_ROM_ISA */
++#if !defined(CONFIG_PCI)
+ #define readl(addr) in_le32(addr)
+ #define writel(val,addr) out_le32((addr),(val))
+ #endif
+--- linux-m68k-2.6.21.orig/include/asm-m68k/raw_io.h
++++ linux-m68k-2.6.21/include/asm-m68k/raw_io.h
+@@ -49,10 +49,16 @@ extern void __iounmap(void *addr, unsign
+ #define raw_inb in_8
+ #define raw_inw in_be16
+ #define raw_inl in_be32
++#define __raw_readb in_8
++#define __raw_readw in_be16
++#define __raw_readl in_be32
+
+ #define raw_outb(val,port) out_8((port),(val))
+ #define raw_outw(val,port) out_be16((port),(val))
+ #define raw_outl(val,port) out_be32((port),(val))
++#define __raw_writeb(val,addr) out_8((addr),(val))
++#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
+@@ -432,8 +438,6 @@ static inline void raw_rom_outsw_swapw(v
+ }
+ #endif /* CONFIG_ATARI_ROM_ISA */
+
+-#define __raw_writel raw_outl
+-
+ #endif /* __KERNEL__ */
+
+ #endif /* _RAW_IO_H */
diff --git a/debian/patches/bugfix/m68k/m68k-linux-gnu-crosscompile.diff b/debian/patches/bugfix/m68k/m68k-linux-gnu-crosscompile.diff
new file mode 100644
index 000000000000..b300da1ac064
--- /dev/null
+++ b/debian/patches/bugfix/m68k/m68k-linux-gnu-crosscompile.diff
@@ -0,0 +1,20 @@
+Subject: [PATCH] m68k: CROSS_COMPILE = m68k-linux-gnu-
+
+Recent cross-compilers are called m68k-linux-gnu-gcc instead of m68k-linux-gcc
+
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ arch/m68k/Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- linux-m68k-2.6.21.orig/arch/m68k/Makefile
++++ linux-m68k-2.6.21/arch/m68k/Makefile
+@@ -21,7 +21,7 @@ AS += -m68020
+ LDFLAGS := -m m68kelf
+ ifneq ($(COMPILE_ARCH),$(ARCH))
+ # prefix for cross-compiling binaries
+- CROSS_COMPILE = m68k-linux-
++ CROSS_COMPILE = m68k-linux-gnu-
+ endif
+
+ ifdef CONFIG_SUN3
diff --git a/debian/patches/bugfix/m68k/m68k-mvme-scsi-rename.diff b/debian/patches/bugfix/m68k/m68k-mvme-scsi-rename.diff
new file mode 100644
index 000000000000..988f73472fad
--- /dev/null
+++ b/debian/patches/bugfix/m68k/m68k-mvme-scsi-rename.diff
@@ -0,0 +1,348 @@
+Subject: [PATCH] m68k: BVME6000 and MVME16x SCSI driver rename
+
+Rename the source files for the BVME6000 and MVME16x SCSI drivers from *.c to
+*_scsi.c
+
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+
+---
+ drivers/scsi/Makefile | 4 +-
+ drivers/scsi/bvme6000.c | 76 -----------------------------------------
+ drivers/scsi/bvme6000_scsi.c | 76 +++++++++++++++++++++++++++++++++++++++++
+ drivers/scsi/mvme16x.c | 78 -------------------------------------------
+ drivers/scsi/mvme16x_scsi.c | 78 +++++++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 156 insertions(+), 156 deletions(-)
+
+--- linux-m68k-2.6.21.orig/drivers/scsi/Makefile
++++ linux-m68k-2.6.21/drivers/scsi/Makefile
+@@ -53,8 +53,8 @@ obj-$(CONFIG_ATARI_SCSI) += atari_scsi.o
+ obj-$(CONFIG_MAC_SCSI) += mac_scsi.o
+ obj-$(CONFIG_SCSI_MAC_ESP) += mac_esp.o NCR53C9x.o
+ obj-$(CONFIG_SUN3_SCSI) += sun3_scsi.o sun3_scsi_vme.o
+-obj-$(CONFIG_MVME16x_SCSI) += mvme16x.o 53c7xx.o
+-obj-$(CONFIG_BVME6000_SCSI) += bvme6000.o 53c7xx.o
++obj-$(CONFIG_MVME16x_SCSI) += mvme16x_scsi.o 53c7xx.o
++obj-$(CONFIG_BVME6000_SCSI) += bvme6000_scsi.o 53c7xx.o
+ obj-$(CONFIG_SCSI_SIM710) += 53c700.o sim710.o
+ obj-$(CONFIG_SCSI_ADVANSYS) += advansys.o
+ obj-$(CONFIG_SCSI_PSI240I) += psi240i.o
+--- linux-m68k-2.6.21.orig/drivers/scsi/bvme6000.c
++++ /dev/null
+@@ -1,76 +0,0 @@
+-/*
+- * Detection routine for the NCR53c710 based BVME6000 SCSI Controllers for Linux.
+- *
+- * Based on work by Alan Hourihane
+- */
+-#include <linux/types.h>
+-#include <linux/mm.h>
+-#include <linux/blkdev.h>
+-#include <linux/zorro.h>
+-
+-#include <asm/setup.h>
+-#include <asm/page.h>
+-#include <asm/pgtable.h>
+-#include <asm/bvme6000hw.h>
+-#include <asm/irq.h>
+-
+-#include "scsi.h"
+-#include <scsi/scsi_host.h>
+-#include "53c7xx.h"
+-#include "bvme6000.h"
+-
+-#include<linux/stat.h>
+-
+-
+-int bvme6000_scsi_detect(struct scsi_host_template *tpnt)
+-{
+- static unsigned char called = 0;
+- int clock;
+- long long options;
+-
+- if (called)
+- return 0;
+- if (!MACH_IS_BVME6000)
+- return 0;
+-
+- tpnt->proc_name = "BVME6000";
+-
+- options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
+-
+- clock = 40000000; /* 66MHz SCSI Clock */
+-
+- ncr53c7xx_init(tpnt, 0, 710, (unsigned long)BVME_NCR53C710_BASE,
+- 0, BVME_IRQ_SCSI, DMA_NONE,
+- options, clock);
+- called = 1;
+- return 1;
+-}
+-
+-static int bvme6000_scsi_release(struct Scsi_Host *shost)
+-{
+- if (shost->irq)
+- free_irq(shost->irq, NULL);
+- if (shost->dma_channel != 0xff)
+- free_dma(shost->dma_channel);
+- if (shost->io_port && shost->n_io_port)
+- release_region(shost->io_port, shost->n_io_port);
+- scsi_unregister(shost);
+- return 0;
+-}
+-
+-static struct scsi_host_template driver_template = {
+- .name = "BVME6000 NCR53c710 SCSI",
+- .detect = bvme6000_scsi_detect,
+- .release = bvme6000_scsi_release,
+- .queuecommand = NCR53c7xx_queue_command,
+- .abort = NCR53c7xx_abort,
+- .reset = NCR53c7xx_reset,
+- .can_queue = 24,
+- .this_id = 7,
+- .sg_tablesize = 63,
+- .cmd_per_lun = 3,
+- .use_clustering = DISABLE_CLUSTERING
+-};
+-
+-
+-#include "scsi_module.c"
+--- /dev/null
++++ linux-m68k-2.6.21/drivers/scsi/bvme6000_scsi.c
+@@ -0,0 +1,76 @@
++/*
++ * Detection routine for the NCR53c710 based BVME6000 SCSI Controllers for Linux.
++ *
++ * Based on work by Alan Hourihane
++ */
++#include <linux/types.h>
++#include <linux/mm.h>
++#include <linux/blkdev.h>
++#include <linux/zorro.h>
++
++#include <asm/setup.h>
++#include <asm/page.h>
++#include <asm/pgtable.h>
++#include <asm/bvme6000hw.h>
++#include <asm/irq.h>
++
++#include "scsi.h"
++#include <scsi/scsi_host.h>
++#include "53c7xx.h"
++#include "bvme6000.h"
++
++#include<linux/stat.h>
++
++
++int bvme6000_scsi_detect(struct scsi_host_template *tpnt)
++{
++ static unsigned char called = 0;
++ int clock;
++ long long options;
++
++ if (called)
++ return 0;
++ if (!MACH_IS_BVME6000)
++ return 0;
++
++ tpnt->proc_name = "BVME6000";
++
++ options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
++
++ clock = 40000000; /* 66MHz SCSI Clock */
++
++ ncr53c7xx_init(tpnt, 0, 710, (unsigned long)BVME_NCR53C710_BASE,
++ 0, BVME_IRQ_SCSI, DMA_NONE,
++ options, clock);
++ called = 1;
++ return 1;
++}
++
++static int bvme6000_scsi_release(struct Scsi_Host *shost)
++{
++ if (shost->irq)
++ free_irq(shost->irq, NULL);
++ if (shost->dma_channel != 0xff)
++ free_dma(shost->dma_channel);
++ if (shost->io_port && shost->n_io_port)
++ release_region(shost->io_port, shost->n_io_port);
++ scsi_unregister(shost);
++ return 0;
++}
++
++static struct scsi_host_template driver_template = {
++ .name = "BVME6000 NCR53c710 SCSI",
++ .detect = bvme6000_scsi_detect,
++ .release = bvme6000_scsi_release,
++ .queuecommand = NCR53c7xx_queue_command,
++ .abort = NCR53c7xx_abort,
++ .reset = NCR53c7xx_reset,
++ .can_queue = 24,
++ .this_id = 7,
++ .sg_tablesize = 63,
++ .cmd_per_lun = 3,
++ .use_clustering = DISABLE_CLUSTERING
++};
++
++
++#include "scsi_module.c"
+--- linux-m68k-2.6.21.orig/drivers/scsi/mvme16x.c
++++ /dev/null
+@@ -1,78 +0,0 @@
+-/*
+- * Detection routine for the NCR53c710 based MVME16x SCSI Controllers for Linux.
+- *
+- * Based on work by Alan Hourihane
+- */
+-#include <linux/types.h>
+-#include <linux/mm.h>
+-#include <linux/blkdev.h>
+-
+-#include <asm/page.h>
+-#include <asm/pgtable.h>
+-#include <asm/mvme16xhw.h>
+-#include <asm/irq.h>
+-
+-#include "scsi.h"
+-#include <scsi/scsi_host.h>
+-#include "53c7xx.h"
+-#include "mvme16x.h"
+-
+-#include<linux/stat.h>
+-
+-
+-int mvme16x_scsi_detect(struct scsi_host_template *tpnt)
+-{
+- static unsigned char called = 0;
+- int clock;
+- long long options;
+-
+- if (!MACH_IS_MVME16x)
+- return 0;
+- if (mvme16x_config & MVME16x_CONFIG_NO_SCSICHIP) {
+- printk ("SCSI detection disabled, SCSI chip not present\n");
+- return 0;
+- }
+- if (called)
+- return 0;
+-
+- tpnt->proc_name = "MVME16x";
+-
+- options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
+-
+- clock = 66000000; /* 66MHz SCSI Clock */
+-
+- ncr53c7xx_init(tpnt, 0, 710, (unsigned long)0xfff47000,
+- 0, MVME16x_IRQ_SCSI, DMA_NONE,
+- options, clock);
+- called = 1;
+- return 1;
+-}
+-
+-static int mvme16x_scsi_release(struct Scsi_Host *shost)
+-{
+- if (shost->irq)
+- free_irq(shost->irq, NULL);
+- if (shost->dma_channel != 0xff)
+- free_dma(shost->dma_channel);
+- if (shost->io_port && shost->n_io_port)
+- release_region(shost->io_port, shost->n_io_port);
+- scsi_unregister(shost);
+- return 0;
+-}
+-
+-static struct scsi_host_template driver_template = {
+- .name = "MVME16x NCR53c710 SCSI",
+- .detect = mvme16x_scsi_detect,
+- .release = mvme16x_scsi_release,
+- .queuecommand = NCR53c7xx_queue_command,
+- .abort = NCR53c7xx_abort,
+- .reset = NCR53c7xx_reset,
+- .can_queue = 24,
+- .this_id = 7,
+- .sg_tablesize = 63,
+- .cmd_per_lun = 3,
+- .use_clustering = DISABLE_CLUSTERING
+-};
+-
+-
+-#include "scsi_module.c"
+--- /dev/null
++++ linux-m68k-2.6.21/drivers/scsi/mvme16x_scsi.c
+@@ -0,0 +1,78 @@
++/*
++ * Detection routine for the NCR53c710 based MVME16x SCSI Controllers for Linux.
++ *
++ * Based on work by Alan Hourihane
++ */
++#include <linux/types.h>
++#include <linux/mm.h>
++#include <linux/blkdev.h>
++
++#include <asm/page.h>
++#include <asm/pgtable.h>
++#include <asm/mvme16xhw.h>
++#include <asm/irq.h>
++
++#include "scsi.h"
++#include <scsi/scsi_host.h>
++#include "53c7xx.h"
++#include "mvme16x.h"
++
++#include<linux/stat.h>
++
++
++int mvme16x_scsi_detect(struct scsi_host_template *tpnt)
++{
++ static unsigned char called = 0;
++ int clock;
++ long long options;
++
++ if (!MACH_IS_MVME16x)
++ return 0;
++ if (mvme16x_config & MVME16x_CONFIG_NO_SCSICHIP) {
++ printk ("SCSI detection disabled, SCSI chip not present\n");
++ return 0;
++ }
++ if (called)
++ return 0;
++
++ tpnt->proc_name = "MVME16x";
++
++ options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
++
++ clock = 66000000; /* 66MHz SCSI Clock */
++
++ ncr53c7xx_init(tpnt, 0, 710, (unsigned long)0xfff47000,
++ 0, MVME16x_IRQ_SCSI, DMA_NONE,
++ options, clock);
++ called = 1;
++ return 1;
++}
++
++static int mvme16x_scsi_release(struct Scsi_Host *shost)
++{
++ if (shost->irq)
++ free_irq(shost->irq, NULL);
++ if (shost->dma_channel != 0xff)
++ free_dma(shost->dma_channel);
++ if (shost->io_port && shost->n_io_port)
++ release_region(shost->io_port, shost->n_io_port);
++ scsi_unregister(shost);
++ return 0;
++}
++
++static struct scsi_host_template driver_template = {
++ .name = "MVME16x NCR53c710 SCSI",
++ .detect = mvme16x_scsi_detect,
++ .release = mvme16x_scsi_release,
++ .queuecommand = NCR53c7xx_queue_command,
++ .abort = NCR53c7xx_abort,
++ .reset = NCR53c7xx_reset,
++ .can_queue = 24,
++ .this_id = 7,
++ .sg_tablesize = 63,
++ .cmd_per_lun = 3,
++ .use_clustering = DISABLE_CLUSTERING
++};
++
++
++#include "scsi_module.c"
diff --git a/debian/patches/bugfix/m68k/m68k-reformat.diff b/debian/patches/bugfix/m68k/m68k-reformat.diff
new file mode 100644
index 000000000000..d218533dd0c5
--- /dev/null
+++ b/debian/patches/bugfix/m68k/m68k-reformat.diff
@@ -0,0 +1,4818 @@
+Subject: [PATCH] m68k: reformat various m68k files
+
+From: Roman Zippel <zippel@linux-m68k.org>
+
+Reformat various m68k files, so they actually look like Linux sources.
+
+Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ arch/m68k/amiga/config.c | 1062 +++++++++++++++++++++++------------------------
+ arch/m68k/atari/config.c | 983 ++++++++++++++++++++-----------------------
+ arch/m68k/atari/debug.c | 470 ++++++++++----------
+ arch/m68k/kernel/entry.S | 2
+ arch/m68k/kernel/head.S | 2
+ arch/m68k/kernel/setup.c | 381 ++++++++--------
+ arch/m68k/mac/config.c | 161 +++----
+ arch/m68k/mac/debug.c | 331 +++++++-------
+ arch/m68k/q40/config.c | 259 +++++------
+ arch/m68k/sun3x/prom.c | 121 ++---
+ 10 files changed, 1856 insertions(+), 1916 deletions(-)
+
+--- linux-m68k-2.6.21.orig/arch/m68k/amiga/config.c
++++ linux-m68k-2.6.21/arch/m68k/amiga/config.c
+@@ -22,9 +22,7 @@
+ #include <linux/vt_kern.h>
+ #include <linux/delay.h>
+ #include <linux/interrupt.h>
+-#ifdef CONFIG_ZORRO
+ #include <linux/zorro.h>
+-#endif
+
+ #include <asm/bootinfo.h>
+ #include <asm/setup.h>
+@@ -62,21 +60,21 @@ static char s_cdtv[] __initdata = "CDTV"
+ static char s_cd32[] __initdata = "CD32";
+ static char s_draco[] __initdata = "Draco";
+ static char *amiga_models[] __initdata = {
+- [AMI_500-AMI_500] = s_a500,
+- [AMI_500PLUS-AMI_500] = s_a500p,
+- [AMI_600-AMI_500] = s_a600,
+- [AMI_1000-AMI_500] = s_a1000,
+- [AMI_1200-AMI_500] = s_a1200,
+- [AMI_2000-AMI_500] = s_a2000,
+- [AMI_2500-AMI_500] = s_a2500,
+- [AMI_3000-AMI_500] = s_a3000,
+- [AMI_3000T-AMI_500] = s_a3000t,
+- [AMI_3000PLUS-AMI_500] = s_a3000p,
+- [AMI_4000-AMI_500] = s_a4000,
+- [AMI_4000T-AMI_500] = s_a4000t,
+- [AMI_CDTV-AMI_500] = s_cdtv,
+- [AMI_CD32-AMI_500] = s_cd32,
+- [AMI_DRACO-AMI_500] = s_draco,
++ [AMI_500-AMI_500] = s_a500,
++ [AMI_500PLUS-AMI_500] = s_a500p,
++ [AMI_600-AMI_500] = s_a600,
++ [AMI_1000-AMI_500] = s_a1000,
++ [AMI_1200-AMI_500] = s_a1200,
++ [AMI_2000-AMI_500] = s_a2000,
++ [AMI_2500-AMI_500] = s_a2500,
++ [AMI_3000-AMI_500] = s_a3000,
++ [AMI_3000T-AMI_500] = s_a3000t,
++ [AMI_3000PLUS-AMI_500] = s_a3000p,
++ [AMI_4000-AMI_500] = s_a4000,
++ [AMI_4000T-AMI_500] = s_a4000t,
++ [AMI_CDTV-AMI_500] = s_cdtv,
++ [AMI_CD32-AMI_500] = s_cd32,
++ [AMI_DRACO-AMI_500] = s_draco,
+ };
+
+ static char amiga_model_name[13] = "Amiga ";
+@@ -85,17 +83,17 @@ extern char m68k_debug_device[];
+
+ static void amiga_sched_init(irq_handler_t handler);
+ /* amiga specific irq functions */
+-extern void amiga_init_IRQ (void);
++extern void amiga_init_IRQ(void);
+ static void amiga_get_model(char *model);
+ static int amiga_get_hardware_list(char *buffer);
+ /* amiga specific timer functions */
+-static unsigned long amiga_gettimeoffset (void);
+-static int a3000_hwclk (int, struct rtc_time *);
+-static int a2000_hwclk (int, struct rtc_time *);
+-static int amiga_set_clock_mmss (unsigned long);
+-static unsigned int amiga_get_ss (void);
+-extern void amiga_mksound( unsigned int count, unsigned int ticks );
+-static void amiga_reset (void);
++static unsigned long amiga_gettimeoffset(void);
++static int a3000_hwclk(int, struct rtc_time *);
++static int a2000_hwclk(int, struct rtc_time *);
++static int amiga_set_clock_mmss(unsigned long);
++static unsigned int amiga_get_ss(void);
++extern void amiga_mksound(unsigned int count, unsigned int ticks);
++static void amiga_reset(void);
+ extern void amiga_init_sound(void);
+ static void amiga_savekmsg_init(void);
+ static void amiga_mem_console_write(struct console *co, const char *b,
+@@ -108,9 +106,9 @@ static void amiga_heartbeat(int on);
+ #endif
+
+ static struct console amiga_console_driver = {
+- .name = "debug",
+- .flags = CON_PRINTBUFFER,
+- .index = -1,
++ .name = "debug",
++ .flags = CON_PRINTBUFFER,
++ .index = -1,
+ };
+
+
+@@ -119,24 +117,24 @@ static struct console amiga_console_driv
+ */
+
+ static struct {
+- struct resource _ciab, _ciaa, _custom, _kickstart;
++ struct resource _ciab, _ciaa, _custom, _kickstart;
+ } mb_resources = {
+- ._ciab = {
+- .name = "CIA B", .start = 0x00bfd000, .end = 0x00bfdfff
+- },
+- ._ciaa = {
+- .name = "CIA A", .start = 0x00bfe000, .end = 0x00bfefff
+- },
+- ._custom = {
+- .name = "Custom I/O", .start = 0x00dff000, .end = 0x00dfffff
+- },
+- ._kickstart = {
+- .name = "Kickstart ROM", .start = 0x00f80000, .end = 0x00ffffff
+- }
++ ._ciab = {
++ .name = "CIA B", .start = 0x00bfd000, .end = 0x00bfdfff
++ },
++ ._ciaa = {
++ .name = "CIA A", .start = 0x00bfe000, .end = 0x00bfefff
++ },
++ ._custom = {
++ .name = "Custom I/O", .start = 0x00dff000, .end = 0x00dfffff
++ },
++ ._kickstart = {
++ .name = "Kickstart ROM", .start = 0x00f80000, .end = 0x00ffffff
++ }
+ };
+
+ static struct resource rtc_resource = {
+- .start = 0x00dc0000, .end = 0x00dcffff
++ .start = 0x00dc0000, .end = 0x00dcffff
+ };
+
+ static struct resource ram_resource[NUM_MEMINFO];
+@@ -148,57 +146,57 @@ static struct resource ram_resource[NUM_
+
+ int amiga_parse_bootinfo(const struct bi_record *record)
+ {
+- int unknown = 0;
+- const unsigned long *data = record->data;
++ int unknown = 0;
++ const unsigned long *data = record->data;
+
+- switch (record->tag) {
++ switch (record->tag) {
+ case BI_AMIGA_MODEL:
+- amiga_model = *data;
+- break;
++ amiga_model = *data;
++ break;
+
+ case BI_AMIGA_ECLOCK:
+- amiga_eclock = *data;
+- break;
++ amiga_eclock = *data;
++ break;
+
+ case BI_AMIGA_CHIPSET:
+- amiga_chipset = *data;
+- break;
++ amiga_chipset = *data;
++ break;
+
+ case BI_AMIGA_CHIP_SIZE:
+- amiga_chip_size = *(const int *)data;
+- break;
++ amiga_chip_size = *(const int *)data;
++ break;
+
+ case BI_AMIGA_VBLANK:
+- amiga_vblank = *(const unsigned char *)data;
+- break;
++ amiga_vblank = *(const unsigned char *)data;
++ break;
+
+ case BI_AMIGA_PSFREQ:
+- amiga_psfreq = *(const unsigned char *)data;
+- break;
++ amiga_psfreq = *(const unsigned char *)data;
++ break;
+
+ case BI_AMIGA_AUTOCON:
+ #ifdef CONFIG_ZORRO
+- if (zorro_num_autocon < ZORRO_NUM_AUTO) {
+- const struct ConfigDev *cd = (struct ConfigDev *)data;
+- struct zorro_dev *dev = &zorro_autocon[zorro_num_autocon++];
+- dev->rom = cd->cd_Rom;
+- dev->slotaddr = cd->cd_SlotAddr;
+- dev->slotsize = cd->cd_SlotSize;
+- dev->resource.start = (unsigned long)cd->cd_BoardAddr;
+- dev->resource.end = dev->resource.start+cd->cd_BoardSize-1;
+- } else
+- printk("amiga_parse_bootinfo: too many AutoConfig devices\n");
++ if (zorro_num_autocon < ZORRO_NUM_AUTO) {
++ const struct ConfigDev *cd = (struct ConfigDev *)data;
++ struct zorro_dev *dev = &zorro_autocon[zorro_num_autocon++];
++ dev->rom = cd->cd_Rom;
++ dev->slotaddr = cd->cd_SlotAddr;
++ dev->slotsize = cd->cd_SlotSize;
++ dev->resource.start = (unsigned long)cd->cd_BoardAddr;
++ dev->resource.end = dev->resource.start + cd->cd_BoardSize - 1;
++ } else
++ printk("amiga_parse_bootinfo: too many AutoConfig devices\n");
+ #endif /* CONFIG_ZORRO */
+- break;
++ break;
+
+ case BI_AMIGA_SERPER:
+- /* serial port period: ignored here */
+- break;
++ /* serial port period: ignored here */
++ break;
+
+ default:
+- unknown = 1;
+- }
+- return(unknown);
++ unknown = 1;
++ }
++ return unknown;
+ }
+
+ /*
+@@ -207,159 +205,159 @@ int amiga_parse_bootinfo(const struct bi
+
+ static void __init amiga_identify(void)
+ {
+- /* Fill in some default values, if necessary */
+- if (amiga_eclock == 0)
+- amiga_eclock = 709379;
+-
+- memset(&amiga_hw_present, 0, sizeof(amiga_hw_present));
+-
+- printk("Amiga hardware found: ");
+- if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) {
+- printk("[%s] ", amiga_models[amiga_model-AMI_500]);
+- strcat(amiga_model_name, amiga_models[amiga_model-AMI_500]);
+- }
+-
+- switch(amiga_model) {
+- case AMI_UNKNOWN:
+- goto Generic;
+-
+- case AMI_600:
+- case AMI_1200:
+- AMIGAHW_SET(A1200_IDE);
+- AMIGAHW_SET(PCMCIA);
+- case AMI_500:
+- case AMI_500PLUS:
+- case AMI_1000:
+- case AMI_2000:
+- case AMI_2500:
+- AMIGAHW_SET(A2000_CLK); /* Is this correct for all models? */
+- goto Generic;
+-
+- case AMI_3000:
+- case AMI_3000T:
+- AMIGAHW_SET(AMBER_FF);
+- AMIGAHW_SET(MAGIC_REKICK);
+- /* fall through */
+- case AMI_3000PLUS:
+- AMIGAHW_SET(A3000_SCSI);
+- AMIGAHW_SET(A3000_CLK);
+- AMIGAHW_SET(ZORRO3);
+- goto Generic;
+-
+- case AMI_4000T:
+- AMIGAHW_SET(A4000_SCSI);
+- /* fall through */
+- case AMI_4000:
+- AMIGAHW_SET(A4000_IDE);
+- AMIGAHW_SET(A3000_CLK);
+- AMIGAHW_SET(ZORRO3);
+- goto Generic;
+-
+- case AMI_CDTV:
+- case AMI_CD32:
+- AMIGAHW_SET(CD_ROM);
+- AMIGAHW_SET(A2000_CLK); /* Is this correct? */
+- goto Generic;
+-
+- Generic:
+- AMIGAHW_SET(AMI_VIDEO);
+- AMIGAHW_SET(AMI_BLITTER);
+- AMIGAHW_SET(AMI_AUDIO);
+- AMIGAHW_SET(AMI_FLOPPY);
+- AMIGAHW_SET(AMI_KEYBOARD);
+- AMIGAHW_SET(AMI_MOUSE);
+- AMIGAHW_SET(AMI_SERIAL);
+- AMIGAHW_SET(AMI_PARALLEL);
+- AMIGAHW_SET(CHIP_RAM);
+- AMIGAHW_SET(PAULA);
+-
+- switch(amiga_chipset) {
+- case CS_OCS:
+- case CS_ECS:
+- case CS_AGA:
+- switch (amiga_custom.deniseid & 0xf) {
+- case 0x0c:
+- AMIGAHW_SET(DENISE_HR);
+- break;
+- case 0x08:
+- AMIGAHW_SET(LISA);
+- break;
+- }
+- break;
+- default:
+- AMIGAHW_SET(DENISE);
+- break;
+- }
+- switch ((amiga_custom.vposr>>8) & 0x7f) {
+- case 0x00:
+- AMIGAHW_SET(AGNUS_PAL);
+- break;
+- case 0x10:
+- AMIGAHW_SET(AGNUS_NTSC);
+- break;
+- case 0x20:
+- case 0x21:
+- AMIGAHW_SET(AGNUS_HR_PAL);
+- break;
+- case 0x30:
+- case 0x31:
+- AMIGAHW_SET(AGNUS_HR_NTSC);
+- break;
+- case 0x22:
+- case 0x23:
+- AMIGAHW_SET(ALICE_PAL);
+- break;
+- case 0x32:
+- case 0x33:
+- AMIGAHW_SET(ALICE_NTSC);
+- break;
+- }
+- AMIGAHW_SET(ZORRO);
+- break;
+-
+- case AMI_DRACO:
+- panic("No support for Draco yet");
+-
+- default:
+- panic("Unknown Amiga Model");
+- }
++ /* Fill in some default values, if necessary */
++ if (amiga_eclock == 0)
++ amiga_eclock = 709379;
++
++ memset(&amiga_hw_present, 0, sizeof(amiga_hw_present));
++
++ printk("Amiga hardware found: ");
++ if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) {
++ printk("[%s] ", amiga_models[amiga_model-AMI_500]);
++ strcat(amiga_model_name, amiga_models[amiga_model-AMI_500]);
++ }
++
++ switch (amiga_model) {
++ case AMI_UNKNOWN:
++ goto Generic;
++
++ case AMI_600:
++ case AMI_1200:
++ AMIGAHW_SET(A1200_IDE);
++ AMIGAHW_SET(PCMCIA);
++ case AMI_500:
++ case AMI_500PLUS:
++ case AMI_1000:
++ case AMI_2000:
++ case AMI_2500:
++ AMIGAHW_SET(A2000_CLK); /* Is this correct for all models? */
++ goto Generic;
++
++ case AMI_3000:
++ case AMI_3000T:
++ AMIGAHW_SET(AMBER_FF);
++ AMIGAHW_SET(MAGIC_REKICK);
++ /* fall through */
++ case AMI_3000PLUS:
++ AMIGAHW_SET(A3000_SCSI);
++ AMIGAHW_SET(A3000_CLK);
++ AMIGAHW_SET(ZORRO3);
++ goto Generic;
++
++ case AMI_4000T:
++ AMIGAHW_SET(A4000_SCSI);
++ /* fall through */
++ case AMI_4000:
++ AMIGAHW_SET(A4000_IDE);
++ AMIGAHW_SET(A3000_CLK);
++ AMIGAHW_SET(ZORRO3);
++ goto Generic;
++
++ case AMI_CDTV:
++ case AMI_CD32:
++ AMIGAHW_SET(CD_ROM);
++ AMIGAHW_SET(A2000_CLK); /* Is this correct? */
++ goto Generic;
++
++ Generic:
++ AMIGAHW_SET(AMI_VIDEO);
++ AMIGAHW_SET(AMI_BLITTER);
++ AMIGAHW_SET(AMI_AUDIO);
++ AMIGAHW_SET(AMI_FLOPPY);
++ AMIGAHW_SET(AMI_KEYBOARD);
++ AMIGAHW_SET(AMI_MOUSE);
++ AMIGAHW_SET(AMI_SERIAL);
++ AMIGAHW_SET(AMI_PARALLEL);
++ AMIGAHW_SET(CHIP_RAM);
++ AMIGAHW_SET(PAULA);
++
++ switch (amiga_chipset) {
++ case CS_OCS:
++ case CS_ECS:
++ case CS_AGA:
++ switch (amiga_custom.deniseid & 0xf) {
++ case 0x0c:
++ AMIGAHW_SET(DENISE_HR);
++ break;
++ case 0x08:
++ AMIGAHW_SET(LISA);
++ break;
++ }
++ break;
++ default:
++ AMIGAHW_SET(DENISE);
++ break;
++ }
++ switch ((amiga_custom.vposr>>8) & 0x7f) {
++ case 0x00:
++ AMIGAHW_SET(AGNUS_PAL);
++ break;
++ case 0x10:
++ AMIGAHW_SET(AGNUS_NTSC);
++ break;
++ case 0x20:
++ case 0x21:
++ AMIGAHW_SET(AGNUS_HR_PAL);
++ break;
++ case 0x30:
++ case 0x31:
++ AMIGAHW_SET(AGNUS_HR_NTSC);
++ break;
++ case 0x22:
++ case 0x23:
++ AMIGAHW_SET(ALICE_PAL);
++ break;
++ case 0x32:
++ case 0x33:
++ AMIGAHW_SET(ALICE_NTSC);
++ break;
++ }
++ AMIGAHW_SET(ZORRO);
++ break;
+
+-#define AMIGAHW_ANNOUNCE(name, str) \
+- if (AMIGAHW_PRESENT(name)) \
+- printk(str)
++ case AMI_DRACO:
++ panic("No support for Draco yet");
++
++ default:
++ panic("Unknown Amiga Model");
++ }
+
+- AMIGAHW_ANNOUNCE(AMI_VIDEO, "VIDEO ");
+- AMIGAHW_ANNOUNCE(AMI_BLITTER, "BLITTER ");
+- AMIGAHW_ANNOUNCE(AMBER_FF, "AMBER_FF ");
+- AMIGAHW_ANNOUNCE(AMI_AUDIO, "AUDIO ");
+- AMIGAHW_ANNOUNCE(AMI_FLOPPY, "FLOPPY ");
+- AMIGAHW_ANNOUNCE(A3000_SCSI, "A3000_SCSI ");
+- AMIGAHW_ANNOUNCE(A4000_SCSI, "A4000_SCSI ");
+- AMIGAHW_ANNOUNCE(A1200_IDE, "A1200_IDE ");
+- AMIGAHW_ANNOUNCE(A4000_IDE, "A4000_IDE ");
+- AMIGAHW_ANNOUNCE(CD_ROM, "CD_ROM ");
+- AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "KEYBOARD ");
+- AMIGAHW_ANNOUNCE(AMI_MOUSE, "MOUSE ");
+- AMIGAHW_ANNOUNCE(AMI_SERIAL, "SERIAL ");
+- AMIGAHW_ANNOUNCE(AMI_PARALLEL, "PARALLEL ");
+- AMIGAHW_ANNOUNCE(A2000_CLK, "A2000_CLK ");
+- AMIGAHW_ANNOUNCE(A3000_CLK, "A3000_CLK ");
+- AMIGAHW_ANNOUNCE(CHIP_RAM, "CHIP_RAM ");
+- AMIGAHW_ANNOUNCE(PAULA, "PAULA ");
+- AMIGAHW_ANNOUNCE(DENISE, "DENISE ");
+- AMIGAHW_ANNOUNCE(DENISE_HR, "DENISE_HR ");
+- AMIGAHW_ANNOUNCE(LISA, "LISA ");
+- AMIGAHW_ANNOUNCE(AGNUS_PAL, "AGNUS_PAL ");
+- AMIGAHW_ANNOUNCE(AGNUS_NTSC, "AGNUS_NTSC ");
+- AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "AGNUS_HR_PAL ");
+- AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "AGNUS_HR_NTSC ");
+- AMIGAHW_ANNOUNCE(ALICE_PAL, "ALICE_PAL ");
+- AMIGAHW_ANNOUNCE(ALICE_NTSC, "ALICE_NTSC ");
+- AMIGAHW_ANNOUNCE(MAGIC_REKICK, "MAGIC_REKICK ");
+- AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA ");
+- if (AMIGAHW_PRESENT(ZORRO))
+- printk("ZORRO%s ", AMIGAHW_PRESENT(ZORRO3) ? "3" : "");
+- printk("\n");
++#define AMIGAHW_ANNOUNCE(name, str) \
++ if (AMIGAHW_PRESENT(name)) \
++ printk(str)
++
++ AMIGAHW_ANNOUNCE(AMI_VIDEO, "VIDEO ");
++ AMIGAHW_ANNOUNCE(AMI_BLITTER, "BLITTER ");
++ AMIGAHW_ANNOUNCE(AMBER_FF, "AMBER_FF ");
++ AMIGAHW_ANNOUNCE(AMI_AUDIO, "AUDIO ");
++ AMIGAHW_ANNOUNCE(AMI_FLOPPY, "FLOPPY ");
++ AMIGAHW_ANNOUNCE(A3000_SCSI, "A3000_SCSI ");
++ AMIGAHW_ANNOUNCE(A4000_SCSI, "A4000_SCSI ");
++ AMIGAHW_ANNOUNCE(A1200_IDE, "A1200_IDE ");
++ AMIGAHW_ANNOUNCE(A4000_IDE, "A4000_IDE ");
++ AMIGAHW_ANNOUNCE(CD_ROM, "CD_ROM ");
++ AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "KEYBOARD ");
++ AMIGAHW_ANNOUNCE(AMI_MOUSE, "MOUSE ");
++ AMIGAHW_ANNOUNCE(AMI_SERIAL, "SERIAL ");
++ AMIGAHW_ANNOUNCE(AMI_PARALLEL, "PARALLEL ");
++ AMIGAHW_ANNOUNCE(A2000_CLK, "A2000_CLK ");
++ AMIGAHW_ANNOUNCE(A3000_CLK, "A3000_CLK ");
++ AMIGAHW_ANNOUNCE(CHIP_RAM, "CHIP_RAM ");
++ AMIGAHW_ANNOUNCE(PAULA, "PAULA ");
++ AMIGAHW_ANNOUNCE(DENISE, "DENISE ");
++ AMIGAHW_ANNOUNCE(DENISE_HR, "DENISE_HR ");
++ AMIGAHW_ANNOUNCE(LISA, "LISA ");
++ AMIGAHW_ANNOUNCE(AGNUS_PAL, "AGNUS_PAL ");
++ AMIGAHW_ANNOUNCE(AGNUS_NTSC, "AGNUS_NTSC ");
++ AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "AGNUS_HR_PAL ");
++ AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "AGNUS_HR_NTSC ");
++ AMIGAHW_ANNOUNCE(ALICE_PAL, "ALICE_PAL ");
++ AMIGAHW_ANNOUNCE(ALICE_NTSC, "ALICE_NTSC ");
++ AMIGAHW_ANNOUNCE(MAGIC_REKICK, "MAGIC_REKICK ");
++ AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA ");
++ if (AMIGAHW_PRESENT(ZORRO))
++ printk("ZORRO%s ", AMIGAHW_PRESENT(ZORRO3) ? "3" : "");
++ printk("\n");
+
+ #undef AMIGAHW_ANNOUNCE
+ }
+@@ -370,119 +368,117 @@ static void __init amiga_identify(void)
+
+ void __init config_amiga(void)
+ {
+- int i;
++ int i;
++
++ amiga_debug_init();
++ amiga_identify();
+
+- amiga_debug_init();
+- amiga_identify();
++ /* Yuk, we don't have PCI memory */
++ iomem_resource.name = "Memory";
++ for (i = 0; i < 4; i++)
++ request_resource(&iomem_resource, &((struct resource *)&mb_resources)[i]);
++
++ mach_sched_init = amiga_sched_init;
++ mach_init_IRQ = amiga_init_IRQ;
++ mach_get_model = amiga_get_model;
++ mach_get_hardware_list = amiga_get_hardware_list;
++ mach_gettimeoffset = amiga_gettimeoffset;
++ if (AMIGAHW_PRESENT(A3000_CLK)) {
++ mach_hwclk = a3000_hwclk;
++ rtc_resource.name = "A3000 RTC";
++ request_resource(&iomem_resource, &rtc_resource);
++ } else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ {
++ mach_hwclk = a2000_hwclk;
++ rtc_resource.name = "A2000 RTC";
++ request_resource(&iomem_resource, &rtc_resource);
++ }
+
+- /* Yuk, we don't have PCI memory */
+- iomem_resource.name = "Memory";
+- for (i = 0; i < 4; i++)
+- request_resource(&iomem_resource, &((struct resource *)&mb_resources)[i]);
+-
+- mach_sched_init = amiga_sched_init;
+- mach_init_IRQ = amiga_init_IRQ;
+- mach_get_model = amiga_get_model;
+- mach_get_hardware_list = amiga_get_hardware_list;
+- mach_gettimeoffset = amiga_gettimeoffset;
+- if (AMIGAHW_PRESENT(A3000_CLK)){
+- mach_hwclk = a3000_hwclk;
+- rtc_resource.name = "A3000 RTC";
+- request_resource(&iomem_resource, &rtc_resource);
+- }
+- else{ /* if (AMIGAHW_PRESENT(A2000_CLK)) */
+- mach_hwclk = a2000_hwclk;
+- rtc_resource.name = "A2000 RTC";
+- request_resource(&iomem_resource, &rtc_resource);
+- }
+-
+- mach_max_dma_address = 0xffffffff; /*
+- * default MAX_DMA=0xffffffff
+- * on all machines. If we don't
+- * do so, the SCSI code will not
+- * be able to allocate any mem
+- * for transfers, unless we are
+- * dealing with a Z2 mem only
+- * system. /Jes
+- */
+-
+- mach_set_clock_mmss = amiga_set_clock_mmss;
+- mach_get_ss = amiga_get_ss;
+- mach_reset = amiga_reset;
++ /*
++ * default MAX_DMA=0xffffffff on all machines. If we don't do so, the SCSI
++ * code will not be able to allocate any mem for transfers, unless we are
++ * dealing with a Z2 mem only system. /Jes
++ */
++ mach_max_dma_address = 0xffffffff;
++
++ mach_set_clock_mmss = amiga_set_clock_mmss;
++ mach_get_ss = amiga_get_ss;
++ mach_reset = amiga_reset;
+ #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
+- mach_beep = amiga_mksound;
++ mach_beep = amiga_mksound;
+ #endif
+
+ #ifdef CONFIG_HEARTBEAT
+- mach_heartbeat = amiga_heartbeat;
++ mach_heartbeat = amiga_heartbeat;
+ #endif
+
+- /* Fill in the clock values (based on the 700 kHz E-Clock) */
+- amiga_masterclock = 40*amiga_eclock; /* 28 MHz */
+- amiga_colorclock = 5*amiga_eclock; /* 3.5 MHz */
+-
+- /* clear all DMA bits */
+- amiga_custom.dmacon = DMAF_ALL;
+- /* ensure that the DMA master bit is set */
+- amiga_custom.dmacon = DMAF_SETCLR | DMAF_MASTER;
+-
+- /* don't use Z2 RAM as system memory on Z3 capable machines */
+- if (AMIGAHW_PRESENT(ZORRO3)) {
+- int i, j;
+- u32 disabled_z2mem = 0;
+- for (i = 0; i < m68k_num_memory; i++)
+- if (m68k_memory[i].addr < 16*1024*1024) {
+- if (i == 0) {
+- /* don't cut off the branch we're sitting on */
+- printk("Warning: kernel runs in Zorro II memory\n");
+- continue;
+- }
+- disabled_z2mem += m68k_memory[i].size;
+- m68k_num_memory--;
+- for (j = i; j < m68k_num_memory; j++)
+- m68k_memory[j] = m68k_memory[j+1];
+- i--;
+- }
+- if (disabled_z2mem)
+- printk("%dK of Zorro II memory will not be used as system memory\n",
+- disabled_z2mem>>10);
+- }
+-
+- /* request all RAM */
+- for (i = 0; i < m68k_num_memory; i++) {
+- ram_resource[i].name =
+- (m68k_memory[i].addr >= 0x01000000) ? "32-bit Fast RAM" :
+- (m68k_memory[i].addr < 0x00c00000) ? "16-bit Fast RAM" :
+- "16-bit Slow RAM";
+- ram_resource[i].start = m68k_memory[i].addr;
+- ram_resource[i].end = m68k_memory[i].addr+m68k_memory[i].size-1;
+- request_resource(&iomem_resource, &ram_resource[i]);
+- }
+-
+- /* initialize chipram allocator */
+- amiga_chip_init ();
+-
+- /* debugging using chipram */
+- if (!strcmp( m68k_debug_device, "mem" )){
+- if (!AMIGAHW_PRESENT(CHIP_RAM))
+- printk("Warning: no chipram present for debugging\n");
+- else {
+- amiga_savekmsg_init();
+- amiga_console_driver.write = amiga_mem_console_write;
+- register_console(&amiga_console_driver);
+- }
+- }
+-
+- /* our beloved beeper */
+- if (AMIGAHW_PRESENT(AMI_AUDIO))
+- amiga_init_sound();
+-
+- /*
+- * if it is an A3000, set the magic bit that forces
+- * a hard rekick
+- */
+- if (AMIGAHW_PRESENT(MAGIC_REKICK))
+- *(unsigned char *)ZTWO_VADDR(0xde0002) |= 0x80;
++ /* Fill in the clock values (based on the 700 kHz E-Clock) */
++ amiga_masterclock = 40*amiga_eclock; /* 28 MHz */
++ amiga_colorclock = 5*amiga_eclock; /* 3.5 MHz */
++
++ /* clear all DMA bits */
++ amiga_custom.dmacon = DMAF_ALL;
++ /* ensure that the DMA master bit is set */
++ amiga_custom.dmacon = DMAF_SETCLR | DMAF_MASTER;
++
++ /* don't use Z2 RAM as system memory on Z3 capable machines */
++ if (AMIGAHW_PRESENT(ZORRO3)) {
++ int i, j;
++ u32 disabled_z2mem = 0;
++
++ for (i = 0; i < m68k_num_memory; i++) {
++ if (m68k_memory[i].addr < 16*1024*1024) {
++ if (i == 0) {
++ /* don't cut off the branch we're sitting on */
++ printk("Warning: kernel runs in Zorro II memory\n");
++ continue;
++ }
++ disabled_z2mem += m68k_memory[i].size;
++ m68k_num_memory--;
++ for (j = i; j < m68k_num_memory; j++)
++ m68k_memory[j] = m68k_memory[j+1];
++ i--;
++ }
++ }
++ if (disabled_z2mem)
++ printk("%dK of Zorro II memory will not be used as system memory\n",
++ disabled_z2mem>>10);
++ }
++
++ /* request all RAM */
++ for (i = 0; i < m68k_num_memory; i++) {
++ ram_resource[i].name =
++ (m68k_memory[i].addr >= 0x01000000) ? "32-bit Fast RAM" :
++ (m68k_memory[i].addr < 0x00c00000) ? "16-bit Fast RAM" :
++ "16-bit Slow RAM";
++ ram_resource[i].start = m68k_memory[i].addr;
++ ram_resource[i].end = m68k_memory[i].addr+m68k_memory[i].size-1;
++ request_resource(&iomem_resource, &ram_resource[i]);
++ }
++
++ /* initialize chipram allocator */
++ amiga_chip_init();
++
++ /* debugging using chipram */
++ if (!strcmp(m68k_debug_device, "mem")) {
++ if (!AMIGAHW_PRESENT(CHIP_RAM))
++ printk("Warning: no chipram present for debugging\n");
++ else {
++ amiga_savekmsg_init();
++ amiga_console_driver.write = amiga_mem_console_write;
++ register_console(&amiga_console_driver);
++ }
++ }
++
++ /* our beloved beeper */
++ if (AMIGAHW_PRESENT(AMI_AUDIO))
++ amiga_init_sound();
++
++ /*
++ * if it is an A3000, set the magic bit that forces
++ * a hard rekick
++ */
++ if (AMIGAHW_PRESENT(MAGIC_REKICK))
++ *(unsigned char *)ZTWO_VADDR(0xde0002) |= 0x80;
+ }
+
+ static unsigned short jiffy_ticks;
+@@ -490,12 +486,12 @@ static unsigned short jiffy_ticks;
+ static void __init amiga_sched_init(irq_handler_t timer_routine)
+ {
+ static struct resource sched_res = {
+- .name = "timer", .start = 0x00bfd400, .end = 0x00bfd5ff,
++ .name = "timer", .start = 0x00bfd400, .end = 0x00bfd5ff,
+ };
+ jiffy_ticks = (amiga_eclock+HZ/2)/HZ;
+
+ if (request_resource(&mb_resources._ciab, &sched_res))
+- printk("Cannot allocate ciab.ta{lo,hi}\n");
++ printk("Cannot allocate ciab.ta{lo,hi}\n");
+ ciab.cra &= 0xC0; /* turn off timer A, continuous mode, from Eclk */
+ ciab.talo = jiffy_ticks % 256;
+ ciab.tahi = jiffy_ticks / 256;
+@@ -513,7 +509,7 @@ static void __init amiga_sched_init(irq_
+ #define TICK_SIZE 10000
+
+ /* This is always executed with interrupts disabled. */
+-static unsigned long amiga_gettimeoffset (void)
++static unsigned long amiga_gettimeoffset(void)
+ {
+ unsigned short hi, lo, hi2;
+ unsigned long ticks, offset = 0;
+@@ -585,15 +581,15 @@ static int a2000_hwclk(int op, struct rt
+
+ tod_2000.cntrl1 = TOD2000_CNTRL1_HOLD;
+
+- while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--)
+- {
+- tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+- udelay(70);
+- tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
++ while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--) {
++ tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
++ udelay(70);
++ tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
+ }
+
+ if (!cnt)
+- printk(KERN_INFO "hwclk: timed out waiting for RTC (0x%x)\n", tod_2000.cntrl1);
++ printk(KERN_INFO "hwclk: timed out waiting for RTC (0x%x)\n",
++ tod_2000.cntrl1);
+
+ if (!op) { /* read */
+ t->tm_sec = tod_2000.second1 * 10 + tod_2000.second2;
+@@ -606,7 +602,7 @@ static int a2000_hwclk(int op, struct rt
+ if (t->tm_year <= 69)
+ t->tm_year += 100;
+
+- if (!(tod_2000.cntrl3 & TOD2000_CNTRL3_24HMODE)){
++ if (!(tod_2000.cntrl3 & TOD2000_CNTRL3_24HMODE)) {
+ if (!(tod_2000.hour1 & TOD2000_HOUR1_PM) && t->tm_hour == 12)
+ t->tm_hour = 0;
+ else if ((tod_2000.hour1 & TOD2000_HOUR1_PM) && t->tm_hour != 12)
+@@ -642,7 +638,7 @@ static int a2000_hwclk(int op, struct rt
+ return 0;
+ }
+
+-static int amiga_set_clock_mmss (unsigned long nowtime)
++static int amiga_set_clock_mmss(unsigned long nowtime)
+ {
+ short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
+
+@@ -660,8 +656,7 @@ static int amiga_set_clock_mmss (unsigne
+
+ tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
+
+- while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--)
+- {
++ while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--) {
+ tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+ udelay(70);
+ tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
+@@ -681,7 +676,7 @@ static int amiga_set_clock_mmss (unsigne
+ return 0;
+ }
+
+-static unsigned int amiga_get_ss( void )
++static unsigned int amiga_get_ss(void)
+ {
+ unsigned int s;
+
+@@ -695,71 +690,72 @@ static unsigned int amiga_get_ss( void )
+ return s;
+ }
+
+-static NORET_TYPE void amiga_reset( void )
++static NORET_TYPE void amiga_reset(void)
+ ATTRIB_NORET;
+
+-static void amiga_reset (void)
++static void amiga_reset(void)
+ {
+- unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040);
+- unsigned long jmp_addr = virt_to_phys(&&jmp_addr_label);
+-
+- local_irq_disable();
+- if (CPU_IS_040_OR_060)
+- /* Setup transparent translation registers for mapping
+- * of 16 MB kernel segment before disabling translation
+- */
+- __asm__ __volatile__
+- ("movel %0,%/d0\n\t"
+- "andl #0xff000000,%/d0\n\t"
+- "orw #0xe020,%/d0\n\t" /* map 16 MB, enable, cacheable */
+- ".chip 68040\n\t"
+- "movec %%d0,%%itt0\n\t"
+- "movec %%d0,%%dtt0\n\t"
+- ".chip 68k\n\t"
+- "jmp %0@\n\t"
+- : /* no outputs */
+- : "a" (jmp_addr040));
+- else
+- /* for 680[23]0, just disable translation and jump to the physical
+- * address of the label
+- */
+- __asm__ __volatile__
+- ("pmove %/tc,%@\n\t"
+- "bclr #7,%@\n\t"
+- "pmove %@,%/tc\n\t"
+- "jmp %0@\n\t"
+- : /* no outputs */
+- : "a" (jmp_addr));
+- jmp_addr_label040:
+- /* disable translation on '040 now */
+- __asm__ __volatile__
+- ("moveq #0,%/d0\n\t"
+- ".chip 68040\n\t"
+- "movec %%d0,%%tc\n\t" /* disable MMU */
+- ".chip 68k\n\t"
+- : /* no outputs */
+- : /* no inputs */
+- : "d0");
+-
+- jmp_addr_label:
+- /* pickup reset address from AmigaOS ROM, reset devices and jump
+- * to reset address
+- */
+- __asm__ __volatile__
+- ("movew #0x2700,%/sr\n\t"
+- "leal 0x01000000,%/a0\n\t"
+- "subl %/a0@(-0x14),%/a0\n\t"
+- "movel %/a0@(4),%/a0\n\t"
+- "subql #2,%/a0\n\t"
+- "bra 1f\n\t"
+- /* align on a longword boundary */
+- __ALIGN_STR "\n"
+- "1:\n\t"
+- "reset\n\t"
+- "jmp %/a0@" : /* Just that gcc scans it for % escapes */ );
++ unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040);
++ unsigned long jmp_addr = virt_to_phys(&&jmp_addr_label);
+
+- for (;;);
++ local_irq_disable();
++ if (CPU_IS_040_OR_060)
++ /* Setup transparent translation registers for mapping
++ * of 16 MB kernel segment before disabling translation
++ */
++ asm volatile ("\n"
++ " move.l %0,%%d0\n"
++ " and.l #0xff000000,%%d0\n"
++ " or.w #0xe020,%%d0\n" /* map 16 MB, enable, cacheable */
++ " .chip 68040\n"
++ " movec %%d0,%%itt0\n"
++ " movec %%d0,%%dtt0\n"
++ " .chip 68k\n"
++ " jmp %0@\n"
++ : /* no outputs */
++ : "a" (jmp_addr040)
++ : "d0");
++ else
++ /* for 680[23]0, just disable translation and jump to the physical
++ * address of the label
++ */
++ asm volatile ("\n"
++ " pmove %%tc,%@\n"
++ " bclr #7,%@\n"
++ " pmove %@,%%tc\n"
++ " jmp %0@\n"
++ : /* no outputs */
++ : "a" (jmp_addr));
++jmp_addr_label040:
++ /* disable translation on '040 now */
++ asm volatile ("\n"
++ " moveq #0,%%d0\n"
++ " .chip 68040\n"
++ " movec %%d0,%%tc\n" /* disable MMU */
++ " .chip 68k\n"
++ : /* no outputs */
++ : /* no inputs */
++ : "d0");
++
++ jmp_addr_label:
++ /* pickup reset address from AmigaOS ROM, reset devices and jump
++ * to reset address
++ */
++ asm volatile ("\n"
++ " move.w #0x2700,%sr\n"
++ " lea 0x01000000,%a0\n"
++ " sub.l %a0@(-0x14),%a0\n"
++ " move.l %a0@(4),%a0\n"
++ " subq.l #2,%a0\n"
++ " jra 1f\n"
++ /* align on a longword boundary */
++ " " __ALIGN_STR "\n"
++ "1:\n"
++ " reset\n"
++ " jmp %a0@");
+
++ for (;;)
++ ;
+ }
+
+
+@@ -773,11 +769,11 @@ static void amiga_reset (void)
+ #define SAVEKMSG_MAGIC2 0x4B4D5347 /* 'KMSG' */
+
+ struct savekmsg {
+- unsigned long magic1; /* SAVEKMSG_MAGIC1 */
+- unsigned long magic2; /* SAVEKMSG_MAGIC2 */
+- unsigned long magicptr; /* address of magic1 */
+- unsigned long size;
+- char data[0];
++ unsigned long magic1; /* SAVEKMSG_MAGIC1 */
++ unsigned long magic2; /* SAVEKMSG_MAGIC2 */
++ unsigned long magicptr; /* address of magic1 */
++ unsigned long size;
++ char data[0];
+ };
+
+ static struct savekmsg *savekmsg;
+@@ -785,100 +781,100 @@ static struct savekmsg *savekmsg;
+ static void amiga_mem_console_write(struct console *co, const char *s,
+ unsigned int count)
+ {
+- if (savekmsg->size+count <= SAVEKMSG_MAXMEM-sizeof(struct savekmsg)) {
+- memcpy(savekmsg->data+savekmsg->size, s, count);
+- savekmsg->size += count;
+- }
++ if (savekmsg->size + count <= SAVEKMSG_MAXMEM-sizeof(struct savekmsg)) {
++ memcpy(savekmsg->data + savekmsg->size, s, count);
++ savekmsg->size += count;
++ }
+ }
+
+ static void amiga_savekmsg_init(void)
+ {
+- static struct resource debug_res = { .name = "Debug" };
++ static struct resource debug_res = { .name = "Debug" };
+
+- savekmsg = amiga_chip_alloc_res(SAVEKMSG_MAXMEM, &debug_res);
+- savekmsg->magic1 = SAVEKMSG_MAGIC1;
+- savekmsg->magic2 = SAVEKMSG_MAGIC2;
+- savekmsg->magicptr = ZTWO_PADDR(savekmsg);
+- savekmsg->size = 0;
++ savekmsg = amiga_chip_alloc_res(SAVEKMSG_MAXMEM, &debug_res);
++ savekmsg->magic1 = SAVEKMSG_MAGIC1;
++ savekmsg->magic2 = SAVEKMSG_MAGIC2;
++ savekmsg->magicptr = ZTWO_PADDR(savekmsg);
++ savekmsg->size = 0;
+ }
+
+ static void amiga_serial_putc(char c)
+ {
+- amiga_custom.serdat = (unsigned char)c | 0x100;
+- while (!(amiga_custom.serdatr & 0x2000))
+- ;
++ amiga_custom.serdat = (unsigned char)c | 0x100;
++ while (!(amiga_custom.serdatr & 0x2000))
++ ;
+ }
+
+ void amiga_serial_console_write(struct console *co, const char *s,
+- unsigned int count)
++ unsigned int count)
+ {
+- while (count--) {
+- if (*s == '\n')
+- amiga_serial_putc('\r');
+- amiga_serial_putc(*s++);
+- }
++ while (count--) {
++ if (*s == '\n')
++ amiga_serial_putc('\r');
++ amiga_serial_putc(*s++);
++ }
+ }
+
+ #ifdef CONFIG_SERIAL_CONSOLE
+ void amiga_serial_puts(const char *s)
+ {
+- amiga_serial_console_write(NULL, s, strlen(s));
++ amiga_serial_console_write(NULL, s, strlen(s));
+ }
+
+ int amiga_serial_console_wait_key(struct console *co)
+ {
+- int ch;
++ int ch;
+
+- while (!(amiga_custom.intreqr & IF_RBF))
+- barrier();
+- ch = amiga_custom.serdatr & 0xff;
+- /* clear the interrupt, so that another character can be read */
+- amiga_custom.intreq = IF_RBF;
+- return ch;
++ while (!(amiga_custom.intreqr & IF_RBF))
++ barrier();
++ ch = amiga_custom.serdatr & 0xff;
++ /* clear the interrupt, so that another character can be read */
++ amiga_custom.intreq = IF_RBF;
++ return ch;
+ }
+
+ void amiga_serial_gets(struct console *co, char *s, int len)
+ {
+- int ch, cnt = 0;
++ int ch, cnt = 0;
++
++ while (1) {
++ ch = amiga_serial_console_wait_key(co);
+
+- while (1) {
+- ch = amiga_serial_console_wait_key(co);
++ /* Check for backspace. */
++ if (ch == 8 || ch == 127) {
++ if (cnt == 0) {
++ amiga_serial_putc('\007');
++ continue;
++ }
++ cnt--;
++ amiga_serial_puts("\010 \010");
++ continue;
++ }
++
++ /* Check for enter. */
++ if (ch == 10 || ch == 13)
++ break;
++
++ /* See if line is too long. */
++ if (cnt >= len + 1) {
++ amiga_serial_putc(7);
++ cnt--;
++ continue;
++ }
+
+- /* Check for backspace. */
+- if (ch == 8 || ch == 127) {
+- if (cnt == 0) {
+- amiga_serial_putc('\007');
+- continue;
+- }
+- cnt--;
+- amiga_serial_puts("\010 \010");
+- continue;
+- }
+-
+- /* Check for enter. */
+- if (ch == 10 || ch == 13)
+- break;
+-
+- /* See if line is too long. */
+- if (cnt >= len + 1) {
+- amiga_serial_putc(7);
+- cnt--;
+- continue;
+- }
+-
+- /* Store and echo character. */
+- s[cnt++] = ch;
+- amiga_serial_putc(ch);
+- }
+- /* Print enter. */
+- amiga_serial_puts("\r\n");
+- s[cnt] = 0;
++ /* Store and echo character. */
++ s[cnt++] = ch;
++ amiga_serial_putc(ch);
++ }
++ /* Print enter. */
++ amiga_serial_puts("\r\n");
++ s[cnt] = 0;
+ }
+ #endif
+
+ static void __init amiga_debug_init(void)
+ {
+- if (!strcmp( m68k_debug_device, "ser" )) {
++ if (!strcmp(m68k_debug_device, "ser" )) {
+ /* no initialization required (?) */
+ amiga_console_driver.write = amiga_serial_console_write;
+ register_console(&amiga_console_driver);
+@@ -888,10 +884,10 @@ static void __init amiga_debug_init(void
+ #ifdef CONFIG_HEARTBEAT
+ static void amiga_heartbeat(int on)
+ {
+- if (on)
+- ciaa.pra &= ~2;
+- else
+- ciaa.pra |= 2;
++ if (on)
++ ciaa.pra &= ~2;
++ else
++ ciaa.pra |= 2;
+ }
+ #endif
+
+@@ -901,81 +897,81 @@ static void amiga_heartbeat(int on)
+
+ static void amiga_get_model(char *model)
+ {
+- strcpy(model, amiga_model_name);
++ strcpy(model, amiga_model_name);
+ }
+
+
+ static int amiga_get_hardware_list(char *buffer)
+ {
+- int len = 0;
++ int len = 0;
+
+- if (AMIGAHW_PRESENT(CHIP_RAM))
+- len += sprintf(buffer+len, "Chip RAM:\t%ldK\n", amiga_chip_size>>10);
+- len += sprintf(buffer+len, "PS Freq:\t%dHz\nEClock Freq:\t%ldHz\n",
+- amiga_psfreq, amiga_eclock);
+- if (AMIGAHW_PRESENT(AMI_VIDEO)) {
+- char *type;
+- switch(amiga_chipset) {
+- case CS_OCS:
+- type = "OCS";
+- break;
+- case CS_ECS:
+- type = "ECS";
+- break;
+- case CS_AGA:
+- type = "AGA";
+- break;
+- default:
+- type = "Old or Unknown";
+- break;
++ if (AMIGAHW_PRESENT(CHIP_RAM))
++ len += sprintf(buffer+len, "Chip RAM:\t%ldK\n", amiga_chip_size>>10);
++ len += sprintf(buffer+len, "PS Freq:\t%dHz\nEClock Freq:\t%ldHz\n",
++ amiga_psfreq, amiga_eclock);
++ if (AMIGAHW_PRESENT(AMI_VIDEO)) {
++ char *type;
++ switch (amiga_chipset) {
++ case CS_OCS:
++ type = "OCS";
++ break;
++ case CS_ECS:
++ type = "ECS";
++ break;
++ case CS_AGA:
++ type = "AGA";
++ break;
++ default:
++ type = "Old or Unknown";
++ break;
++ }
++ len += sprintf(buffer+len, "Graphics:\t%s\n", type);
+ }
+- len += sprintf(buffer+len, "Graphics:\t%s\n", type);
+- }
+
+ #define AMIGAHW_ANNOUNCE(name, str) \
+- if (AMIGAHW_PRESENT(name)) \
+- len += sprintf (buffer+len, "\t%s\n", str)
++ if (AMIGAHW_PRESENT(name)) \
++ len += sprintf (buffer+len, "\t%s\n", str)
+
+- len += sprintf (buffer + len, "Detected hardware:\n");
++ len += sprintf (buffer + len, "Detected hardware:\n");
+
+- AMIGAHW_ANNOUNCE(AMI_VIDEO, "Amiga Video");
+- AMIGAHW_ANNOUNCE(AMI_BLITTER, "Blitter");
+- AMIGAHW_ANNOUNCE(AMBER_FF, "Amber Flicker Fixer");
+- AMIGAHW_ANNOUNCE(AMI_AUDIO, "Amiga Audio");
+- AMIGAHW_ANNOUNCE(AMI_FLOPPY, "Floppy Controller");
+- AMIGAHW_ANNOUNCE(A3000_SCSI, "SCSI Controller WD33C93 (A3000 style)");
+- AMIGAHW_ANNOUNCE(A4000_SCSI, "SCSI Controller NCR53C710 (A4000T style)");
+- AMIGAHW_ANNOUNCE(A1200_IDE, "IDE Interface (A1200 style)");
+- AMIGAHW_ANNOUNCE(A4000_IDE, "IDE Interface (A4000 style)");
+- AMIGAHW_ANNOUNCE(CD_ROM, "Internal CD ROM drive");
+- AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "Keyboard");
+- AMIGAHW_ANNOUNCE(AMI_MOUSE, "Mouse Port");
+- AMIGAHW_ANNOUNCE(AMI_SERIAL, "Serial Port");
+- AMIGAHW_ANNOUNCE(AMI_PARALLEL, "Parallel Port");
+- AMIGAHW_ANNOUNCE(A2000_CLK, "Hardware Clock (A2000 style)");
+- AMIGAHW_ANNOUNCE(A3000_CLK, "Hardware Clock (A3000 style)");
+- AMIGAHW_ANNOUNCE(CHIP_RAM, "Chip RAM");
+- AMIGAHW_ANNOUNCE(PAULA, "Paula 8364");
+- AMIGAHW_ANNOUNCE(DENISE, "Denise 8362");
+- AMIGAHW_ANNOUNCE(DENISE_HR, "Denise 8373");
+- AMIGAHW_ANNOUNCE(LISA, "Lisa 8375");
+- AMIGAHW_ANNOUNCE(AGNUS_PAL, "Normal/Fat PAL Agnus 8367/8371");
+- AMIGAHW_ANNOUNCE(AGNUS_NTSC, "Normal/Fat NTSC Agnus 8361/8370");
+- AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "Fat Hires PAL Agnus 8372");
+- AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "Fat Hires NTSC Agnus 8372");
+- AMIGAHW_ANNOUNCE(ALICE_PAL, "PAL Alice 8374");
+- AMIGAHW_ANNOUNCE(ALICE_NTSC, "NTSC Alice 8374");
+- AMIGAHW_ANNOUNCE(MAGIC_REKICK, "Magic Hard Rekick");
+- AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA Slot");
++ AMIGAHW_ANNOUNCE(AMI_VIDEO, "Amiga Video");
++ AMIGAHW_ANNOUNCE(AMI_BLITTER, "Blitter");
++ AMIGAHW_ANNOUNCE(AMBER_FF, "Amber Flicker Fixer");
++ AMIGAHW_ANNOUNCE(AMI_AUDIO, "Amiga Audio");
++ AMIGAHW_ANNOUNCE(AMI_FLOPPY, "Floppy Controller");
++ AMIGAHW_ANNOUNCE(A3000_SCSI, "SCSI Controller WD33C93 (A3000 style)");
++ AMIGAHW_ANNOUNCE(A4000_SCSI, "SCSI Controller NCR53C710 (A4000T style)");
++ AMIGAHW_ANNOUNCE(A1200_IDE, "IDE Interface (A1200 style)");
++ AMIGAHW_ANNOUNCE(A4000_IDE, "IDE Interface (A4000 style)");
++ AMIGAHW_ANNOUNCE(CD_ROM, "Internal CD ROM drive");
++ AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "Keyboard");
++ AMIGAHW_ANNOUNCE(AMI_MOUSE, "Mouse Port");
++ AMIGAHW_ANNOUNCE(AMI_SERIAL, "Serial Port");
++ AMIGAHW_ANNOUNCE(AMI_PARALLEL, "Parallel Port");
++ AMIGAHW_ANNOUNCE(A2000_CLK, "Hardware Clock (A2000 style)");
++ AMIGAHW_ANNOUNCE(A3000_CLK, "Hardware Clock (A3000 style)");
++ AMIGAHW_ANNOUNCE(CHIP_RAM, "Chip RAM");
++ AMIGAHW_ANNOUNCE(PAULA, "Paula 8364");
++ AMIGAHW_ANNOUNCE(DENISE, "Denise 8362");
++ AMIGAHW_ANNOUNCE(DENISE_HR, "Denise 8373");
++ AMIGAHW_ANNOUNCE(LISA, "Lisa 8375");
++ AMIGAHW_ANNOUNCE(AGNUS_PAL, "Normal/Fat PAL Agnus 8367/8371");
++ AMIGAHW_ANNOUNCE(AGNUS_NTSC, "Normal/Fat NTSC Agnus 8361/8370");
++ AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "Fat Hires PAL Agnus 8372");
++ AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "Fat Hires NTSC Agnus 8372");
++ AMIGAHW_ANNOUNCE(ALICE_PAL, "PAL Alice 8374");
++ AMIGAHW_ANNOUNCE(ALICE_NTSC, "NTSC Alice 8374");
++ AMIGAHW_ANNOUNCE(MAGIC_REKICK, "Magic Hard Rekick");
++ AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA Slot");
+ #ifdef CONFIG_ZORRO
+- if (AMIGAHW_PRESENT(ZORRO))
+- len += sprintf(buffer+len, "\tZorro II%s AutoConfig: %d Expansion "
+- "Device%s\n",
+- AMIGAHW_PRESENT(ZORRO3) ? "I" : "",
+- zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s");
++ if (AMIGAHW_PRESENT(ZORRO))
++ len += sprintf(buffer+len, "\tZorro II%s AutoConfig: %d Expansion "
++ "Device%s\n",
++ AMIGAHW_PRESENT(ZORRO3) ? "I" : "",
++ zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s");
+ #endif /* CONFIG_ZORRO */
+
+ #undef AMIGAHW_ANNOUNCE
+
+- return(len);
++ return len;
+ }
+--- linux-m68k-2.6.21.orig/arch/m68k/atari/config.c
++++ linux-m68k-2.6.21/arch/m68k/atari/config.c
+@@ -50,19 +50,19 @@ int atari_dont_touch_floppy_select;
+ int atari_rtc_year_offset;
+
+ /* local function prototypes */
+-static void atari_reset( void );
++static void atari_reset(void);
+ static void atari_get_model(char *model);
+ static int atari_get_hardware_list(char *buffer);
+
+ /* atari specific irq functions */
+ extern void atari_init_IRQ (void);
+-extern void atari_mksound( unsigned int count, unsigned int ticks );
++extern void atari_mksound(unsigned int count, unsigned int ticks);
+ #ifdef CONFIG_HEARTBEAT
+-static void atari_heartbeat( int on );
++static void atari_heartbeat(int on);
+ #endif
+
+ /* atari specific timer functions (in time.c) */
+-extern void atari_sched_init(irq_handler_t );
++extern void atari_sched_init(irq_handler_t);
+ extern unsigned long atari_gettimeoffset (void);
+ extern int atari_mste_hwclk (int, struct rtc_time *);
+ extern int atari_tt_hwclk (int, struct rtc_time *);
+@@ -73,48 +73,6 @@ extern int atari_tt_set_clock_mmss (unsi
+ extern void atari_debug_init(void);
+
+
+-/* I've moved hwreg_present() and hwreg_present_bywrite() out into
+- * mm/hwtest.c, to avoid having multiple copies of the same routine
+- * in the kernel [I wanted them in hp300 and they were already used
+- * in the nubus code. NB: I don't have an Atari so this might (just
+- * conceivably) break something.
+- * I've preserved the #if 0 version of hwreg_present_bywrite() here
+- * for posterity.
+- * -- Peter Maydell <pmaydell@chiark.greenend.org.uk>, 05/1998
+- */
+-
+-#if 0
+-static int __init
+-hwreg_present_bywrite(volatile void *regp, unsigned char val)
+-{
+- int ret;
+- long save_sp, save_vbr;
+- static long tmp_vectors[3] = { [2] = (long)&&after_test };
+-
+- __asm__ __volatile__
+- ( "movec %/vbr,%2\n\t" /* save vbr value */
+- "movec %4,%/vbr\n\t" /* set up temporary vectors */
+- "movel %/sp,%1\n\t" /* save sp */
+- "moveq #0,%0\n\t" /* assume not present */
+- "moveb %5,%3@\n\t" /* write the hardware reg */
+- "cmpb %3@,%5\n\t" /* compare it */
+- "seq %0" /* comes here only if reg */
+- /* is present */
+- : "=d&" (ret), "=r&" (save_sp), "=r&" (save_vbr)
+- : "a" (regp), "r" (tmp_vectors), "d" (val)
+- );
+- after_test:
+- __asm__ __volatile__
+- ( "movel %0,%/sp\n\t" /* restore sp */
+- "movec %1,%/vbr" /* restore vbr */
+- : : "r" (save_sp), "r" (save_vbr) : "sp"
+- );
+-
+- return( ret );
+-}
+-#endif
+-
+-
+ /* ++roman: This is a more elaborate test for an SCC chip, since the plain
+ * Medusa board generates DTACK at the SCC's standard addresses, but a SCC
+ * board in the Medusa is possible. Also, the addresses where the ST_ESCC
+@@ -123,26 +81,34 @@ hwreg_present_bywrite(volatile void *reg
+ * should be readable without trouble (from channel A!).
+ */
+
+-static int __init scc_test( volatile char *ctla )
++static int __init scc_test(volatile char *ctla)
+ {
+- if (!hwreg_present( ctla ))
+- return( 0 );
++ if (!hwreg_present(ctla))
++ return 0;
+ MFPDELAY();
+
+- *ctla = 2; MFPDELAY();
+- *ctla = 0x40; MFPDELAY();
++ *ctla = 2;
++ MFPDELAY();
++ *ctla = 0x40;
++ MFPDELAY();
+
+- *ctla = 2; MFPDELAY();
+- if (*ctla != 0x40) return( 0 );
++ *ctla = 2;
++ MFPDELAY();
++ if (*ctla != 0x40)
++ return 0;
+ MFPDELAY();
+
+- *ctla = 2; MFPDELAY();
+- *ctla = 0x60; MFPDELAY();
++ *ctla = 2;
++ MFPDELAY();
++ *ctla = 0x60;
++ MFPDELAY();
+
+- *ctla = 2; MFPDELAY();
+- if (*ctla != 0x60) return( 0 );
++ *ctla = 2;
++ MFPDELAY();
++ if (*ctla != 0x60)
++ return 0;
+
+- return( 1 );
++ return 1;
+ }
+
+
+@@ -152,59 +118,58 @@ static int __init scc_test( volatile cha
+
+ int __init atari_parse_bootinfo(const struct bi_record *record)
+ {
+- int unknown = 0;
+- const u_long *data = record->data;
++ int unknown = 0;
++ const u_long *data = record->data;
+
+- switch (record->tag) {
++ switch (record->tag) {
+ case BI_ATARI_MCH_COOKIE:
+- atari_mch_cookie = *data;
+- break;
++ atari_mch_cookie = *data;
++ break;
+ case BI_ATARI_MCH_TYPE:
+- atari_mch_type = *data;
+- break;
++ atari_mch_type = *data;
++ break;
+ default:
+- unknown = 1;
+- }
+- return(unknown);
++ unknown = 1;
++ break;
++ }
++ return unknown;
+ }
+
+
+ /* Parse the Atari-specific switches= option. */
+-void __init atari_switches_setup( const char *str, unsigned len )
++void __init atari_switches_setup(const char *str, unsigned len)
+ {
+- char switches[len+1];
+- char *p;
+- int ovsc_shift;
+- char *args = switches;
+-
+- /* copy string to local array, strsep works destructively... */
+- strlcpy( switches, str, sizeof(switches) );
+- atari_switches = 0;
+-
+- /* parse the options */
+- while ((p = strsep(&args, ",")) != NULL) {
+- if (!*p) continue;
+- ovsc_shift = 0;
+- if (strncmp( p, "ov_", 3 ) == 0) {
+- p += 3;
+- ovsc_shift = ATARI_SWITCH_OVSC_SHIFT;
+- }
+-
+- if (strcmp( p, "ikbd" ) == 0) {
+- /* RTS line of IKBD ACIA */
+- atari_switches |= ATARI_SWITCH_IKBD << ovsc_shift;
+- }
+- else if (strcmp( p, "midi" ) == 0) {
+- /* RTS line of MIDI ACIA */
+- atari_switches |= ATARI_SWITCH_MIDI << ovsc_shift;
+- }
+- else if (strcmp( p, "snd6" ) == 0) {
+- atari_switches |= ATARI_SWITCH_SND6 << ovsc_shift;
++ char switches[len+1];
++ char *p;
++ int ovsc_shift;
++ char *args = switches;
++
++ /* copy string to local array, strsep works destructively... */
++ strlcpy(switches, str, sizeof(switches));
++ atari_switches = 0;
++
++ /* parse the options */
++ while ((p = strsep(&args, ",")) != NULL) {
++ if (!*p)
++ continue;
++ ovsc_shift = 0;
++ if (strncmp(p, "ov_", 3) == 0) {
++ p += 3;
++ ovsc_shift = ATARI_SWITCH_OVSC_SHIFT;
++ }
++
++ if (strcmp(p, "ikbd") == 0) {
++ /* RTS line of IKBD ACIA */
++ atari_switches |= ATARI_SWITCH_IKBD << ovsc_shift;
++ } else if (strcmp(p, "midi") == 0) {
++ /* RTS line of MIDI ACIA */
++ atari_switches |= ATARI_SWITCH_MIDI << ovsc_shift;
++ } else if (strcmp(p, "snd6") == 0) {
++ atari_switches |= ATARI_SWITCH_SND6 << ovsc_shift;
++ } else if (strcmp(p, "snd7") == 0) {
++ atari_switches |= ATARI_SWITCH_SND7 << ovsc_shift;
++ }
+ }
+- else if (strcmp( p, "snd7" ) == 0) {
+- atari_switches |= ATARI_SWITCH_SND7 << ovsc_shift;
+- }
+- }
+ }
+
+
+@@ -214,284 +179,283 @@ void __init atari_switches_setup( const
+
+ void __init config_atari(void)
+ {
+- unsigned short tos_version;
++ unsigned short tos_version;
+
+- memset(&atari_hw_present, 0, sizeof(atari_hw_present));
++ memset(&atari_hw_present, 0, sizeof(atari_hw_present));
+
+- atari_debug_init();
++ atari_debug_init();
+
+- ioport_resource.end = 0xFFFFFFFF; /* Change size of I/O space from 64KB
+- to 4GB. */
++ /* Change size of I/O space from 64KB to 4GB. */
++ ioport_resource.end = 0xFFFFFFFF;
+
+- mach_sched_init = atari_sched_init;
+- mach_init_IRQ = atari_init_IRQ;
+- mach_get_model = atari_get_model;
+- mach_get_hardware_list = atari_get_hardware_list;
+- mach_gettimeoffset = atari_gettimeoffset;
+- mach_reset = atari_reset;
+- mach_max_dma_address = 0xffffff;
++ mach_sched_init = atari_sched_init;
++ mach_init_IRQ = atari_init_IRQ;
++ mach_get_model = atari_get_model;
++ mach_get_hardware_list = atari_get_hardware_list;
++ mach_gettimeoffset = atari_gettimeoffset;
++ mach_reset = atari_reset;
++ mach_max_dma_address = 0xffffff;
+ #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
+- mach_beep = atari_mksound;
++ mach_beep = atari_mksound;
+ #endif
+ #ifdef CONFIG_HEARTBEAT
+- mach_heartbeat = atari_heartbeat;
++ mach_heartbeat = atari_heartbeat;
+ #endif
+
+- /* Set switches as requested by the user */
+- if (atari_switches & ATARI_SWITCH_IKBD)
+- acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID;
+- if (atari_switches & ATARI_SWITCH_MIDI)
+- acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID;
+- if (atari_switches & (ATARI_SWITCH_SND6|ATARI_SWITCH_SND7)) {
+- sound_ym.rd_data_reg_sel = 14;
+- sound_ym.wd_data = sound_ym.rd_data_reg_sel |
+- ((atari_switches&ATARI_SWITCH_SND6) ? 0x40 : 0) |
+- ((atari_switches&ATARI_SWITCH_SND7) ? 0x80 : 0);
+- }
+-
+- /* ++bjoern:
+- * Determine hardware present
+- */
++ /* Set switches as requested by the user */
++ if (atari_switches & ATARI_SWITCH_IKBD)
++ acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID;
++ if (atari_switches & ATARI_SWITCH_MIDI)
++ acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID;
++ if (atari_switches & (ATARI_SWITCH_SND6|ATARI_SWITCH_SND7)) {
++ sound_ym.rd_data_reg_sel = 14;
++ sound_ym.wd_data = sound_ym.rd_data_reg_sel |
++ ((atari_switches&ATARI_SWITCH_SND6) ? 0x40 : 0) |
++ ((atari_switches&ATARI_SWITCH_SND7) ? 0x80 : 0);
++ }
+
+- printk( "Atari hardware found: " );
+- if (MACH_IS_MEDUSA || MACH_IS_HADES) {
+- /* There's no Atari video hardware on the Medusa, but all the
+- * addresses below generate a DTACK so no bus error occurs! */
+- }
+- else if (hwreg_present( f030_xreg )) {
+- ATARIHW_SET(VIDEL_SHIFTER);
+- printk( "VIDEL " );
+- /* This is a temporary hack: If there is Falcon video
+- * hardware, we assume that the ST-DMA serves SCSI instead of
+- * ACSI. In the future, there should be a better method for
+- * this...
+- */
+- ATARIHW_SET(ST_SCSI);
+- printk( "STDMA-SCSI " );
+- }
+- else if (hwreg_present( tt_palette )) {
+- ATARIHW_SET(TT_SHIFTER);
+- printk( "TT_SHIFTER " );
+- }
+- else if (hwreg_present( &shifter.bas_hi )) {
+- if (hwreg_present( &shifter.bas_lo ) &&
+- (shifter.bas_lo = 0x0aau, shifter.bas_lo == 0x0aau)) {
+- ATARIHW_SET(EXTD_SHIFTER);
+- printk( "EXTD_SHIFTER " );
+- }
+- else {
+- ATARIHW_SET(STND_SHIFTER);
+- printk( "STND_SHIFTER " );
+- }
+- }
+- if (hwreg_present( &mfp.par_dt_reg )) {
+- ATARIHW_SET(ST_MFP);
+- printk( "ST_MFP " );
+- }
+- if (hwreg_present( &tt_mfp.par_dt_reg )) {
+- ATARIHW_SET(TT_MFP);
+- printk( "TT_MFP " );
+- }
+- if (hwreg_present( &tt_scsi_dma.dma_addr_hi )) {
+- ATARIHW_SET(SCSI_DMA);
+- printk( "TT_SCSI_DMA " );
+- }
+- if (!MACH_IS_HADES && hwreg_present( &st_dma.dma_hi )) {
+- ATARIHW_SET(STND_DMA);
+- printk( "STND_DMA " );
+- }
+- if (MACH_IS_MEDUSA || /* The ST-DMA address registers aren't readable
+- * on all Medusas, so the test below may fail */
+- (hwreg_present( &st_dma.dma_vhi ) &&
+- (st_dma.dma_vhi = 0x55) && (st_dma.dma_hi = 0xaa) &&
+- st_dma.dma_vhi == 0x55 && st_dma.dma_hi == 0xaa &&
+- (st_dma.dma_vhi = 0xaa) && (st_dma.dma_hi = 0x55) &&
+- st_dma.dma_vhi == 0xaa && st_dma.dma_hi == 0x55)) {
+- ATARIHW_SET(EXTD_DMA);
+- printk( "EXTD_DMA " );
+- }
+- if (hwreg_present( &tt_scsi.scsi_data )) {
+- ATARIHW_SET(TT_SCSI);
+- printk( "TT_SCSI " );
+- }
+- if (hwreg_present( &sound_ym.rd_data_reg_sel )) {
+- ATARIHW_SET(YM_2149);
+- printk( "YM2149 " );
+- }
+- if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
+- hwreg_present( &tt_dmasnd.ctrl )) {
+- ATARIHW_SET(PCM_8BIT);
+- printk( "PCM " );
+- }
+- if (!MACH_IS_HADES && hwreg_present( &falcon_codec.unused5 )) {
+- ATARIHW_SET(CODEC);
+- printk( "CODEC " );
+- }
+- if (hwreg_present( &dsp56k_host_interface.icr )) {
+- ATARIHW_SET(DSP56K);
+- printk( "DSP56K " );
+- }
+- if (hwreg_present( &tt_scc_dma.dma_ctrl ) &&
++ /* ++bjoern:
++ * Determine hardware present
++ */
++
++ printk("Atari hardware found: ");
++ if (MACH_IS_MEDUSA || MACH_IS_HADES) {
++ /* There's no Atari video hardware on the Medusa, but all the
++ * addresses below generate a DTACK so no bus error occurs! */
++ } else if (hwreg_present(f030_xreg)) {
++ ATARIHW_SET(VIDEL_SHIFTER);
++ printk("VIDEL ");
++ /* This is a temporary hack: If there is Falcon video
++ * hardware, we assume that the ST-DMA serves SCSI instead of
++ * ACSI. In the future, there should be a better method for
++ * this...
++ */
++ ATARIHW_SET(ST_SCSI);
++ printk("STDMA-SCSI ");
++ } else if (hwreg_present(tt_palette)) {
++ ATARIHW_SET(TT_SHIFTER);
++ printk("TT_SHIFTER ");
++ } else if (hwreg_present(&shifter.bas_hi)) {
++ if (hwreg_present(&shifter.bas_lo) &&
++ (shifter.bas_lo = 0x0aau, shifter.bas_lo == 0x0aau)) {
++ ATARIHW_SET(EXTD_SHIFTER);
++ printk("EXTD_SHIFTER ");
++ } else {
++ ATARIHW_SET(STND_SHIFTER);
++ printk("STND_SHIFTER ");
++ }
++ }
++ if (hwreg_present(&mfp.par_dt_reg)) {
++ ATARIHW_SET(ST_MFP);
++ printk("ST_MFP ");
++ }
++ if (hwreg_present(&tt_mfp.par_dt_reg)) {
++ ATARIHW_SET(TT_MFP);
++ printk("TT_MFP ");
++ }
++ if (hwreg_present(&tt_scsi_dma.dma_addr_hi)) {
++ ATARIHW_SET(SCSI_DMA);
++ printk("TT_SCSI_DMA ");
++ }
++ if (!MACH_IS_HADES && hwreg_present(&st_dma.dma_hi)) {
++ ATARIHW_SET(STND_DMA);
++ printk("STND_DMA ");
++ }
++ /*
++ * The ST-DMA address registers aren't readable
++ * on all Medusas, so the test below may fail
++ */
++ if (MACH_IS_MEDUSA ||
++ (hwreg_present(&st_dma.dma_vhi) &&
++ (st_dma.dma_vhi = 0x55) && (st_dma.dma_hi = 0xaa) &&
++ st_dma.dma_vhi == 0x55 && st_dma.dma_hi == 0xaa &&
++ (st_dma.dma_vhi = 0xaa) && (st_dma.dma_hi = 0x55) &&
++ st_dma.dma_vhi == 0xaa && st_dma.dma_hi == 0x55)) {
++ ATARIHW_SET(EXTD_DMA);
++ printk("EXTD_DMA ");
++ }
++ if (hwreg_present(&tt_scsi.scsi_data)) {
++ ATARIHW_SET(TT_SCSI);
++ printk("TT_SCSI ");
++ }
++ if (hwreg_present(&sound_ym.rd_data_reg_sel)) {
++ ATARIHW_SET(YM_2149);
++ printk("YM2149 ");
++ }
++ if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
++ hwreg_present(&tt_dmasnd.ctrl)) {
++ ATARIHW_SET(PCM_8BIT);
++ printk("PCM ");
++ }
++ if (!MACH_IS_HADES && hwreg_present(&falcon_codec.unused5)) {
++ ATARIHW_SET(CODEC);
++ printk("CODEC ");
++ }
++ if (hwreg_present(&dsp56k_host_interface.icr)) {
++ ATARIHW_SET(DSP56K);
++ printk("DSP56K ");
++ }
++ if (hwreg_present(&tt_scc_dma.dma_ctrl) &&
+ #if 0
+- /* This test sucks! Who knows some better? */
+- (tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) &&
+- (tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0)
++ /* This test sucks! Who knows some better? */
++ (tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) &&
++ (tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0)
+ #else
+- !MACH_IS_MEDUSA && !MACH_IS_HADES
++ !MACH_IS_MEDUSA && !MACH_IS_HADES
+ #endif
+- ) {
+- ATARIHW_SET(SCC_DMA);
+- printk( "SCC_DMA " );
+- }
+- if (scc_test( &scc.cha_a_ctrl )) {
+- ATARIHW_SET(SCC);
+- printk( "SCC " );
+- }
+- if (scc_test( &st_escc.cha_b_ctrl )) {
+- ATARIHW_SET( ST_ESCC );
+- printk( "ST_ESCC " );
+- }
+- if (MACH_IS_HADES)
+- {
+- ATARIHW_SET( VME );
+- printk( "VME " );
+- }
+- else if (hwreg_present( &tt_scu.sys_mask )) {
+- ATARIHW_SET(SCU);
+- /* Assume a VME bus if there's a SCU */
+- ATARIHW_SET( VME );
+- printk( "VME SCU " );
+- }
+- if (hwreg_present( (void *)(0xffff9210) )) {
+- ATARIHW_SET(ANALOG_JOY);
+- printk( "ANALOG_JOY " );
+- }
+- if (!MACH_IS_HADES && hwreg_present( blitter.halftone )) {
+- ATARIHW_SET(BLITTER);
+- printk( "BLITTER " );
+- }
+- if (hwreg_present((void *)0xfff00039)) {
+- ATARIHW_SET(IDE);
+- printk( "IDE " );
+- }
++ ) {
++ ATARIHW_SET(SCC_DMA);
++ printk("SCC_DMA ");
++ }
++ if (scc_test(&scc.cha_a_ctrl)) {
++ ATARIHW_SET(SCC);
++ printk("SCC ");
++ }
++ if (scc_test(&st_escc.cha_b_ctrl)) {
++ ATARIHW_SET(ST_ESCC);
++ printk("ST_ESCC ");
++ }
++ if (MACH_IS_HADES) {
++ ATARIHW_SET(VME);
++ printk("VME ");
++ } else if (hwreg_present(&tt_scu.sys_mask)) {
++ ATARIHW_SET(SCU);
++ /* Assume a VME bus if there's a SCU */
++ ATARIHW_SET(VME);
++ printk("VME SCU ");
++ }
++ if (hwreg_present((void *)(0xffff9210))) {
++ ATARIHW_SET(ANALOG_JOY);
++ printk("ANALOG_JOY ");
++ }
++ if (!MACH_IS_HADES && hwreg_present(blitter.halftone)) {
++ ATARIHW_SET(BLITTER);
++ printk("BLITTER ");
++ }
++ if (hwreg_present((void *)0xfff00039)) {
++ ATARIHW_SET(IDE);
++ printk("IDE ");
++ }
+ #if 1 /* This maybe wrong */
+- if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
+- hwreg_present( &tt_microwire.data ) &&
+- hwreg_present( &tt_microwire.mask ) &&
+- (tt_microwire.mask = 0x7ff,
+- udelay(1),
+- tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR,
+- udelay(1),
+- tt_microwire.data != 0)) {
+- ATARIHW_SET(MICROWIRE);
+- while (tt_microwire.mask != 0x7ff) ;
+- printk( "MICROWIRE " );
+- }
++ if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
++ hwreg_present(&tt_microwire.data) &&
++ hwreg_present(&tt_microwire.mask) &&
++ (tt_microwire.mask = 0x7ff,
++ udelay(1),
++ tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR,
++ udelay(1),
++ tt_microwire.data != 0)) {
++ ATARIHW_SET(MICROWIRE);
++ while (tt_microwire.mask != 0x7ff)
++ ;
++ printk("MICROWIRE ");
++ }
+ #endif
+- if (hwreg_present( &tt_rtc.regsel )) {
+- ATARIHW_SET(TT_CLK);
+- printk( "TT_CLK " );
+- mach_hwclk = atari_tt_hwclk;
+- mach_set_clock_mmss = atari_tt_set_clock_mmss;
+- }
+- if (!MACH_IS_HADES && hwreg_present( &mste_rtc.sec_ones)) {
+- ATARIHW_SET(MSTE_CLK);
+- printk( "MSTE_CLK ");
+- mach_hwclk = atari_mste_hwclk;
+- mach_set_clock_mmss = atari_mste_set_clock_mmss;
+- }
+- if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
+- hwreg_present( &dma_wd.fdc_speed ) &&
+- hwreg_write( &dma_wd.fdc_speed, 0 )) {
+- ATARIHW_SET(FDCSPEED);
+- printk( "FDC_SPEED ");
+- }
+- if (!MACH_IS_HADES && !ATARIHW_PRESENT(ST_SCSI)) {
+- ATARIHW_SET(ACSI);
+- printk( "ACSI " );
+- }
+- printk("\n");
+-
+- if (CPU_IS_040_OR_060)
+- /* Now it seems to be safe to turn of the tt0 transparent
+- * translation (the one that must not be turned off in
+- * head.S...)
+- */
+- __asm__ volatile ("moveq #0,%/d0\n\t"
+- ".chip 68040\n\t"
+- "movec %%d0,%%itt0\n\t"
+- "movec %%d0,%%dtt0\n\t"
+- ".chip 68k"
+- : /* no outputs */
+- : /* no inputs */
+- : "d0");
+-
+- /* allocator for memory that must reside in st-ram */
+- atari_stram_init ();
+-
+- /* Set up a mapping for the VMEbus address region:
+- *
+- * VME is either at phys. 0xfexxxxxx (TT) or 0xa00000..0xdfffff
+- * (MegaSTE) In both cases, the whole 16 MB chunk is mapped at
+- * 0xfe000000 virt., because this can be done with a single
+- * transparent translation. On the 68040, lots of often unused
+- * page tables would be needed otherwise. On a MegaSTE or similar,
+- * the highest byte is stripped off by hardware due to the 24 bit
+- * design of the bus.
+- */
++ if (hwreg_present(&tt_rtc.regsel)) {
++ ATARIHW_SET(TT_CLK);
++ printk("TT_CLK ");
++ mach_hwclk = atari_tt_hwclk;
++ mach_set_clock_mmss = atari_tt_set_clock_mmss;
++ }
++ if (!MACH_IS_HADES && hwreg_present(&mste_rtc.sec_ones)) {
++ ATARIHW_SET(MSTE_CLK);
++ printk("MSTE_CLK ");
++ mach_hwclk = atari_mste_hwclk;
++ mach_set_clock_mmss = atari_mste_set_clock_mmss;
++ }
++ if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
++ hwreg_present(&dma_wd.fdc_speed) &&
++ hwreg_write(&dma_wd.fdc_speed, 0)) {
++ ATARIHW_SET(FDCSPEED);
++ printk("FDC_SPEED ");
++ }
++ if (!MACH_IS_HADES && !ATARIHW_PRESENT(ST_SCSI)) {
++ ATARIHW_SET(ACSI);
++ printk("ACSI ");
++ }
++ printk("\n");
+
+- if (CPU_IS_020_OR_030) {
+- unsigned long tt1_val;
+- tt1_val = 0xfe008543; /* Translate 0xfexxxxxx, enable, cache
+- * inhibit, read and write, FDC mask = 3,
+- * FDC val = 4 -> Supervisor only */
+- __asm__ __volatile__ ( ".chip 68030\n\t"
+- "pmove %0@,%/tt1\n\t"
+- ".chip 68k"
+- : : "a" (&tt1_val) );
+- }
+- else {
+- __asm__ __volatile__
+- ( "movel %0,%/d0\n\t"
+- ".chip 68040\n\t"
+- "movec %%d0,%%itt1\n\t"
+- "movec %%d0,%%dtt1\n\t"
+- ".chip 68k"
+- :
+- : "g" (0xfe00a040) /* Translate 0xfexxxxxx, enable,
+- * supervisor only, non-cacheable/
+- * serialized, writable */
+- : "d0" );
+-
+- }
+-
+- /* Fetch tos version at Physical 2 */
+- /* We my not be able to access this address if the kernel is
+- loaded to st ram, since the first page is unmapped. On the
+- Medusa this is always the case and there is nothing we can do
+- about this, so we just assume the smaller offset. For the TT
+- we use the fact that in head.S we have set up a mapping
+- 0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible
+- in the last 16MB of the address space. */
+- tos_version = (MACH_IS_MEDUSA || MACH_IS_HADES) ?
+- 0xfff : *(unsigned short *)0xff000002;
+- atari_rtc_year_offset = (tos_version < 0x306) ? 70 : 68;
++ if (CPU_IS_040_OR_060)
++ /* Now it seems to be safe to turn of the tt0 transparent
++ * translation (the one that must not be turned off in
++ * head.S...)
++ */
++ asm volatile ("\n"
++ " moveq #0,%%d0\n"
++ " .chip 68040\n"
++ " movec %%d0,%%itt0\n"
++ " movec %%d0,%%dtt0\n"
++ " .chip 68k"
++ : /* no outputs */
++ : /* no inputs */
++ : "d0");
++
++ /* allocator for memory that must reside in st-ram */
++ atari_stram_init();
++
++ /* Set up a mapping for the VMEbus address region:
++ *
++ * VME is either at phys. 0xfexxxxxx (TT) or 0xa00000..0xdfffff
++ * (MegaSTE) In both cases, the whole 16 MB chunk is mapped at
++ * 0xfe000000 virt., because this can be done with a single
++ * transparent translation. On the 68040, lots of often unused
++ * page tables would be needed otherwise. On a MegaSTE or similar,
++ * the highest byte is stripped off by hardware due to the 24 bit
++ * design of the bus.
++ */
++
++ if (CPU_IS_020_OR_030) {
++ unsigned long tt1_val;
++ tt1_val = 0xfe008543; /* Translate 0xfexxxxxx, enable, cache
++ * inhibit, read and write, FDC mask = 3,
++ * FDC val = 4 -> Supervisor only */
++ asm volatile ("\n"
++ " .chip 68030\n"
++ " pmove %0@,%/tt1\n"
++ " .chip 68k"
++ : : "a" (&tt1_val));
++ } else {
++ asm volatile ("\n"
++ " .chip 68040\n"
++ " movec %0,%%itt1\n"
++ " movec %0,%%dtt1\n"
++ " .chip 68k"
++ :
++ : "d" (0xfe00a040)); /* Translate 0xfexxxxxx, enable,
++ * supervisor only, non-cacheable/
++ * serialized, writable */
++
++ }
++
++ /* Fetch tos version at Physical 2 */
++ /*
++ * We my not be able to access this address if the kernel is
++ * loaded to st ram, since the first page is unmapped. On the
++ * Medusa this is always the case and there is nothing we can do
++ * about this, so we just assume the smaller offset. For the TT
++ * we use the fact that in head.S we have set up a mapping
++ * 0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible
++ * in the last 16MB of the address space.
++ */
++ tos_version = (MACH_IS_MEDUSA || MACH_IS_HADES) ?
++ 0xfff : *(unsigned short *)0xff000002;
++ atari_rtc_year_offset = (tos_version < 0x306) ? 70 : 68;
+ }
+
+ #ifdef CONFIG_HEARTBEAT
+-static void atari_heartbeat( int on )
++static void atari_heartbeat(int on)
+ {
+- unsigned char tmp;
+- unsigned long flags;
++ unsigned char tmp;
++ unsigned long flags;
+
+- if (atari_dont_touch_floppy_select)
+- return;
++ if (atari_dont_touch_floppy_select)
++ return;
+
+- local_irq_save(flags);
+- sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */
+- tmp = sound_ym.rd_data_reg_sel;
+- sound_ym.wd_data = on ? (tmp & ~0x02) : (tmp | 0x02);
+- local_irq_restore(flags);
++ local_irq_save(flags);
++ sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */
++ tmp = sound_ym.rd_data_reg_sel;
++ sound_ym.wd_data = on ? (tmp & ~0x02) : (tmp | 0x02);
++ local_irq_restore(flags);
+ }
+ #endif
+
+@@ -526,180 +490,171 @@ static void atari_heartbeat( int on )
+
+ /* ++andreas: no need for complicated code, just depend on prefetch */
+
+-static void atari_reset (void)
++static void atari_reset(void)
+ {
+- long tc_val = 0;
+- long reset_addr;
++ long tc_val = 0;
++ long reset_addr;
+
+- /* On the Medusa, phys. 0x4 may contain garbage because it's no
+- ROM. See above for explanation why we cannot use PTOV(4). */
+- reset_addr = MACH_IS_HADES ? 0x7fe00030 :
+- MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 :
+- *(unsigned long *) 0xff000004;
+-
+- /* reset ACIA for switch off OverScan, if it's active */
+- if (atari_switches & ATARI_SWITCH_OVSC_IKBD)
+- acia.key_ctrl = ACIA_RESET;
+- if (atari_switches & ATARI_SWITCH_OVSC_MIDI)
+- acia.mid_ctrl = ACIA_RESET;
+-
+- /* processor independent: turn off interrupts and reset the VBR;
+- * the caches must be left enabled, else prefetching the final jump
+- * instruction doesn't work. */
+- local_irq_disable();
+- __asm__ __volatile__
+- ("moveq #0,%/d0\n\t"
+- "movec %/d0,%/vbr"
+- : : : "d0" );
+-
+- if (CPU_IS_040_OR_060) {
+- unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040);
+- if (CPU_IS_060) {
+- /* 68060: clear PCR to turn off superscalar operation */
+- __asm__ __volatile__
+- ("moveq #0,%/d0\n\t"
+- ".chip 68060\n\t"
+- "movec %%d0,%%pcr\n\t"
+- ".chip 68k"
+- : : : "d0" );
+- }
+-
+- __asm__ __volatile__
+- ("movel %0,%/d0\n\t"
+- "andl #0xff000000,%/d0\n\t"
+- "orw #0xe020,%/d0\n\t" /* map 16 MB, enable, cacheable */
+- ".chip 68040\n\t"
+- "movec %%d0,%%itt0\n\t"
+- "movec %%d0,%%dtt0\n\t"
+- ".chip 68k\n\t"
+- "jmp %0@\n\t"
+- : /* no outputs */
+- : "a" (jmp_addr040)
+- : "d0" );
+- jmp_addr_label040:
+- __asm__ __volatile__
+- ("moveq #0,%/d0\n\t"
+- "nop\n\t"
+- ".chip 68040\n\t"
+- "cinva %%bc\n\t"
+- "nop\n\t"
+- "pflusha\n\t"
+- "nop\n\t"
+- "movec %%d0,%%tc\n\t"
+- "nop\n\t"
+- /* the following setup of transparent translations is needed on the
+- * Afterburner040 to successfully reboot. Other machines shouldn't
+- * care about a different tt regs setup, they also didn't care in
+- * the past that the regs weren't turned off. */
+- "movel #0xffc000,%%d0\n\t" /* whole insn space cacheable */
+- "movec %%d0,%%itt0\n\t"
+- "movec %%d0,%%itt1\n\t"
+- "orw #0x40,%/d0\n\t" /* whole data space non-cacheable/ser. */
+- "movec %%d0,%%dtt0\n\t"
+- "movec %%d0,%%dtt1\n\t"
+- ".chip 68k\n\t"
+- "jmp %0@"
+- : /* no outputs */
+- : "a" (reset_addr)
+- : "d0");
+- }
+- else
+- __asm__ __volatile__
+- ("pmove %0@,%/tc\n\t"
+- "jmp %1@"
+- : /* no outputs */
+- : "a" (&tc_val), "a" (reset_addr));
++ /*
++ * On the Medusa, phys. 0x4 may contain garbage because it's no
++ * ROM. See above for explanation why we cannot use PTOV(4).
++ */
++ reset_addr = MACH_IS_HADES ? 0x7fe00030 :
++ MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 :
++ *(unsigned long *) 0xff000004;
++
++ /* reset ACIA for switch off OverScan, if it's active */
++ if (atari_switches & ATARI_SWITCH_OVSC_IKBD)
++ acia.key_ctrl = ACIA_RESET;
++ if (atari_switches & ATARI_SWITCH_OVSC_MIDI)
++ acia.mid_ctrl = ACIA_RESET;
++
++ /* processor independent: turn off interrupts and reset the VBR;
++ * the caches must be left enabled, else prefetching the final jump
++ * instruction doesn't work.
++ */
++ local_irq_disable();
++ asm volatile ("movec %0,%%vbr"
++ : : "d" (0));
++
++ if (CPU_IS_040_OR_060) {
++ unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040);
++ if (CPU_IS_060) {
++ /* 68060: clear PCR to turn off superscalar operation */
++ asm volatile ("\n"
++ " .chip 68060\n"
++ " movec %0,%%pcr\n"
++ " .chip 68k"
++ : : "d" (0));
++ }
++
++ asm volatile ("\n"
++ " move.l %0,%%d0\n"
++ " and.l #0xff000000,%%d0\n"
++ " or.w #0xe020,%%d0\n" /* map 16 MB, enable, cacheable */
++ " .chip 68040\n"
++ " movec %%d0,%%itt0\n"
++ " movec %%d0,%%dtt0\n"
++ " .chip 68k\n"
++ " jmp %0@"
++ : : "a" (jmp_addr040)
++ : "d0");
++ jmp_addr_label040:
++ asm volatile ("\n"
++ " moveq #0,%%d0\n"
++ " nop\n"
++ " .chip 68040\n"
++ " cinva %%bc\n"
++ " nop\n"
++ " pflusha\n"
++ " nop\n"
++ " movec %%d0,%%tc\n"
++ " nop\n"
++ /* the following setup of transparent translations is needed on the
++ * Afterburner040 to successfully reboot. Other machines shouldn't
++ * care about a different tt regs setup, they also didn't care in
++ * the past that the regs weren't turned off. */
++ " move.l #0xffc000,%%d0\n" /* whole insn space cacheable */
++ " movec %%d0,%%itt0\n"
++ " movec %%d0,%%itt1\n"
++ " or.w #0x40,%/d0\n" /* whole data space non-cacheable/ser. */
++ " movec %%d0,%%dtt0\n"
++ " movec %%d0,%%dtt1\n"
++ " .chip 68k\n"
++ " jmp %0@"
++ : /* no outputs */
++ : "a" (reset_addr)
++ : "d0");
++ } else
++ asm volatile ("\n"
++ " pmove %0@,%%tc\n"
++ " jmp %1@"
++ : /* no outputs */
++ : "a" (&tc_val), "a" (reset_addr));
+ }
+
+
+ static void atari_get_model(char *model)
+ {
+- strcpy(model, "Atari ");
+- switch (atari_mch_cookie >> 16) {
++ strcpy(model, "Atari ");
++ switch (atari_mch_cookie >> 16) {
+ case ATARI_MCH_ST:
+- if (ATARIHW_PRESENT(MSTE_CLK))
+- strcat (model, "Mega ST");
+- else
+- strcat (model, "ST");
+- break;
++ if (ATARIHW_PRESENT(MSTE_CLK))
++ strcat(model, "Mega ST");
++ else
++ strcat(model, "ST");
++ break;
+ case ATARI_MCH_STE:
+- if (MACH_IS_MSTE)
+- strcat (model, "Mega STE");
+- else
+- strcat (model, "STE");
+- break;
++ if (MACH_IS_MSTE)
++ strcat(model, "Mega STE");
++ else
++ strcat(model, "STE");
++ break;
+ case ATARI_MCH_TT:
+- if (MACH_IS_MEDUSA)
+- /* Medusa has TT _MCH cookie */
+- strcat (model, "Medusa");
+- else if (MACH_IS_HADES)
+- strcat(model, "Hades");
+- else
+- strcat (model, "TT");
+- break;
++ if (MACH_IS_MEDUSA)
++ /* Medusa has TT _MCH cookie */
++ strcat(model, "Medusa");
++ else if (MACH_IS_HADES)
++ strcat(model, "Hades");
++ else
++ strcat(model, "TT");
++ break;
+ case ATARI_MCH_FALCON:
+- strcat (model, "Falcon");
+- if (MACH_IS_AB40)
+- strcat (model, " (with Afterburner040)");
+- break;
++ strcat(model, "Falcon");
++ if (MACH_IS_AB40)
++ strcat(model, " (with Afterburner040)");
++ break;
+ default:
+- sprintf (model + strlen (model), "(unknown mach cookie 0x%lx)",
+- atari_mch_cookie);
+- break;
+- }
++ sprintf(model + strlen(model), "(unknown mach cookie 0x%lx)",
++ atari_mch_cookie);
++ break;
++ }
+ }
+
+
+ static int atari_get_hardware_list(char *buffer)
+ {
+- int len = 0, i;
++ int len = 0, i;
+
+- for (i = 0; i < m68k_num_memory; i++)
+- len += sprintf (buffer+len, "\t%3ld MB at 0x%08lx (%s)\n",
+- m68k_memory[i].size >> 20, m68k_memory[i].addr,
+- (m68k_memory[i].addr & 0xff000000 ?
+- "alternate RAM" : "ST-RAM"));
+-
+-#define ATARIHW_ANNOUNCE(name,str) \
+- if (ATARIHW_PRESENT(name)) \
+- len += sprintf (buffer + len, "\t%s\n", str)
+-
+- len += sprintf (buffer + len, "Detected hardware:\n");
+- ATARIHW_ANNOUNCE(STND_SHIFTER, "ST Shifter");
+- ATARIHW_ANNOUNCE(EXTD_SHIFTER, "STe Shifter");
+- ATARIHW_ANNOUNCE(TT_SHIFTER, "TT Shifter");
+- ATARIHW_ANNOUNCE(VIDEL_SHIFTER, "Falcon Shifter");
+- ATARIHW_ANNOUNCE(YM_2149, "Programmable Sound Generator");
+- ATARIHW_ANNOUNCE(PCM_8BIT, "PCM 8 Bit Sound");
+- ATARIHW_ANNOUNCE(CODEC, "CODEC Sound");
+- ATARIHW_ANNOUNCE(TT_SCSI, "SCSI Controller NCR5380 (TT style)");
+- ATARIHW_ANNOUNCE(ST_SCSI, "SCSI Controller NCR5380 (Falcon style)");
+- ATARIHW_ANNOUNCE(ACSI, "ACSI Interface");
+- ATARIHW_ANNOUNCE(IDE, "IDE Interface");
+- ATARIHW_ANNOUNCE(FDCSPEED, "8/16 Mhz Switch for FDC");
+- ATARIHW_ANNOUNCE(ST_MFP, "Multi Function Peripheral MFP 68901");
+- ATARIHW_ANNOUNCE(TT_MFP, "Second Multi Function Peripheral MFP 68901");
+- ATARIHW_ANNOUNCE(SCC, "Serial Communications Controller SCC 8530");
+- ATARIHW_ANNOUNCE(ST_ESCC, "Extended Serial Communications Controller SCC 85230");
+- ATARIHW_ANNOUNCE(ANALOG_JOY, "Paddle Interface");
+- ATARIHW_ANNOUNCE(MICROWIRE, "MICROWIRE(tm) Interface");
+- ATARIHW_ANNOUNCE(STND_DMA, "DMA Controller (24 bit)");
+- ATARIHW_ANNOUNCE(EXTD_DMA, "DMA Controller (32 bit)");
+- ATARIHW_ANNOUNCE(SCSI_DMA, "DMA Controller for NCR5380");
+- ATARIHW_ANNOUNCE(SCC_DMA, "DMA Controller for SCC");
+- ATARIHW_ANNOUNCE(TT_CLK, "Clock Chip MC146818A");
+- ATARIHW_ANNOUNCE(MSTE_CLK, "Clock Chip RP5C15");
+- ATARIHW_ANNOUNCE(SCU, "System Control Unit");
+- ATARIHW_ANNOUNCE(BLITTER, "Blitter");
+- ATARIHW_ANNOUNCE(VME, "VME Bus");
+- ATARIHW_ANNOUNCE(DSP56K, "DSP56001 processor");
++ for (i = 0; i < m68k_num_memory; i++)
++ len += sprintf(buffer+len, "\t%3ld MB at 0x%08lx (%s)\n",
++ m68k_memory[i].size >> 20, m68k_memory[i].addr,
++ (m68k_memory[i].addr & 0xff000000 ?
++ "alternate RAM" : "ST-RAM"));
++
++#define ATARIHW_ANNOUNCE(name, str) \
++ if (ATARIHW_PRESENT(name)) \
++ len += sprintf(buffer + len, "\t%s\n", str)
++
++ len += sprintf(buffer + len, "Detected hardware:\n");
++ ATARIHW_ANNOUNCE(STND_SHIFTER, "ST Shifter");
++ ATARIHW_ANNOUNCE(EXTD_SHIFTER, "STe Shifter");
++ ATARIHW_ANNOUNCE(TT_SHIFTER, "TT Shifter");
++ ATARIHW_ANNOUNCE(VIDEL_SHIFTER, "Falcon Shifter");
++ ATARIHW_ANNOUNCE(YM_2149, "Programmable Sound Generator");
++ ATARIHW_ANNOUNCE(PCM_8BIT, "PCM 8 Bit Sound");
++ ATARIHW_ANNOUNCE(CODEC, "CODEC Sound");
++ ATARIHW_ANNOUNCE(TT_SCSI, "SCSI Controller NCR5380 (TT style)");
++ ATARIHW_ANNOUNCE(ST_SCSI, "SCSI Controller NCR5380 (Falcon style)");
++ ATARIHW_ANNOUNCE(ACSI, "ACSI Interface");
++ ATARIHW_ANNOUNCE(IDE, "IDE Interface");
++ ATARIHW_ANNOUNCE(FDCSPEED, "8/16 Mhz Switch for FDC");
++ ATARIHW_ANNOUNCE(ST_MFP, "Multi Function Peripheral MFP 68901");
++ ATARIHW_ANNOUNCE(TT_MFP, "Second Multi Function Peripheral MFP 68901");
++ ATARIHW_ANNOUNCE(SCC, "Serial Communications Controller SCC 8530");
++ ATARIHW_ANNOUNCE(ST_ESCC, "Extended Serial Communications Controller SCC 85230");
++ ATARIHW_ANNOUNCE(ANALOG_JOY, "Paddle Interface");
++ ATARIHW_ANNOUNCE(MICROWIRE, "MICROWIRE(tm) Interface");
++ ATARIHW_ANNOUNCE(STND_DMA, "DMA Controller (24 bit)");
++ ATARIHW_ANNOUNCE(EXTD_DMA, "DMA Controller (32 bit)");
++ ATARIHW_ANNOUNCE(SCSI_DMA, "DMA Controller for NCR5380");
++ ATARIHW_ANNOUNCE(SCC_DMA, "DMA Controller for SCC");
++ ATARIHW_ANNOUNCE(TT_CLK, "Clock Chip MC146818A");
++ ATARIHW_ANNOUNCE(MSTE_CLK, "Clock Chip RP5C15");
++ ATARIHW_ANNOUNCE(SCU, "System Control Unit");
++ ATARIHW_ANNOUNCE(BLITTER, "Blitter");
++ ATARIHW_ANNOUNCE(VME, "VME Bus");
++ ATARIHW_ANNOUNCE(DSP56K, "DSP56001 processor");
+
+- return(len);
++ return len;
+ }
+-
+-/*
+- * Local variables:
+- * c-indent-level: 4
+- * tab-width: 8
+- * End:
+- */
+--- linux-m68k-2.6.21.orig/arch/m68k/atari/debug.c
++++ linux-m68k-2.6.21/arch/m68k/atari/debug.c
+@@ -30,317 +30,311 @@ int atari_SCC_init_done;
+ int atari_SCC_reset_done;
+
+ static struct console atari_console_driver = {
+- .name = "debug",
+- .flags = CON_PRINTBUFFER,
+- .index = -1,
++ .name = "debug",
++ .flags = CON_PRINTBUFFER,
++ .index = -1,
+ };
+
+
+-static inline void ata_mfp_out (char c)
++static inline void ata_mfp_out(char c)
+ {
+- while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */
+- barrier ();
+- mfp.usart_dta = c;
++ while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */
++ barrier();
++ mfp.usart_dta = c;
+ }
+
+-void atari_mfp_console_write (struct console *co, const char *str,
+- unsigned int count)
++void atari_mfp_console_write(struct console *co, const char *str,
++ unsigned int count)
+ {
+- while (count--) {
+- if (*str == '\n')
+- ata_mfp_out( '\r' );
+- ata_mfp_out( *str++ );
+- }
++ while (count--) {
++ if (*str == '\n')
++ ata_mfp_out('\r');
++ ata_mfp_out(*str++);
++ }
+ }
+
+-static inline void ata_scc_out (char c)
++static inline void ata_scc_out(char c)
+ {
+- do {
++ do {
++ MFPDELAY();
++ } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
+ MFPDELAY();
+- } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
+- MFPDELAY();
+- scc.cha_b_data = c;
++ scc.cha_b_data = c;
+ }
+
+-void atari_scc_console_write (struct console *co, const char *str,
+- unsigned int count)
++void atari_scc_console_write(struct console *co, const char *str,
++ unsigned int count)
+ {
+- while (count--) {
+- if (*str == '\n')
+- ata_scc_out( '\r' );
+- ata_scc_out( *str++ );
+- }
++ while (count--) {
++ if (*str == '\n')
++ ata_scc_out('\r');
++ ata_scc_out(*str++);
++ }
+ }
+
+-static inline void ata_midi_out (char c)
++static inline void ata_midi_out(char c)
+ {
+- while (!(acia.mid_ctrl & ACIA_TDRE)) /* wait for tx buf empty */
+- barrier ();
+- acia.mid_data = c;
++ while (!(acia.mid_ctrl & ACIA_TDRE)) /* wait for tx buf empty */
++ barrier();
++ acia.mid_data = c;
+ }
+
+-void atari_midi_console_write (struct console *co, const char *str,
+- unsigned int count)
++void atari_midi_console_write(struct console *co, const char *str,
++ unsigned int count)
+ {
+- while (count--) {
+- if (*str == '\n')
+- ata_midi_out( '\r' );
+- ata_midi_out( *str++ );
+- }
++ while (count--) {
++ if (*str == '\n')
++ ata_midi_out('\r');
++ ata_midi_out(*str++);
++ }
+ }
+
+-static int ata_par_out (char c)
++static int ata_par_out(char c)
+ {
+- unsigned char tmp;
+- /* This a some-seconds timeout in case no printer is connected */
+- unsigned long i = loops_per_jiffy > 1 ? loops_per_jiffy : 10000000/HZ;
++ unsigned char tmp;
++ /* This a some-seconds timeout in case no printer is connected */
++ unsigned long i = loops_per_jiffy > 1 ? loops_per_jiffy : 10000000/HZ;
+
+- while( (mfp.par_dt_reg & 1) && --i ) /* wait for BUSY == L */
+- ;
+- if (!i) return( 0 );
++ while ((mfp.par_dt_reg & 1) && --i) /* wait for BUSY == L */
++ ;
++ if (!i)
++ return 0;
+
+- sound_ym.rd_data_reg_sel = 15; /* select port B */
+- sound_ym.wd_data = c; /* put char onto port */
+- sound_ym.rd_data_reg_sel = 14; /* select port A */
+- tmp = sound_ym.rd_data_reg_sel;
+- sound_ym.wd_data = tmp & ~0x20; /* set strobe L */
+- MFPDELAY(); /* wait a bit */
+- sound_ym.wd_data = tmp | 0x20; /* set strobe H */
+- return( 1 );
++ sound_ym.rd_data_reg_sel = 15; /* select port B */
++ sound_ym.wd_data = c; /* put char onto port */
++ sound_ym.rd_data_reg_sel = 14; /* select port A */
++ tmp = sound_ym.rd_data_reg_sel;
++ sound_ym.wd_data = tmp & ~0x20; /* set strobe L */
++ MFPDELAY(); /* wait a bit */
++ sound_ym.wd_data = tmp | 0x20; /* set strobe H */
++ return 1;
+ }
+
+-static void atari_par_console_write (struct console *co, const char *str,
+- unsigned int count)
++static void atari_par_console_write(struct console *co, const char *str,
++ unsigned int count)
+ {
+- static int printer_present = 1;
+-
+- if (!printer_present)
+- return;
++ static int printer_present = 1;
+
+- while (count--) {
+- if (*str == '\n')
+- if (!ata_par_out( '\r' )) {
+- printer_present = 0;
++ if (!printer_present)
+ return;
+- }
+- if (!ata_par_out( *str++ )) {
+- printer_present = 0;
+- return;
++
++ while (count--) {
++ if (*str == '\n') {
++ if (!ata_par_out('\r')) {
++ printer_present = 0;
++ return;
++ }
++ }
++ if (!ata_par_out(*str++)) {
++ printer_present = 0;
++ return;
++ }
+ }
+- }
+ }
+
+ #ifdef CONFIG_SERIAL_CONSOLE
+ int atari_mfp_console_wait_key(struct console *co)
+ {
+- while( !(mfp.rcv_stat & 0x80) ) /* wait for rx buf filled */
+- barrier();
+- return( mfp.usart_dta );
++ while (!(mfp.rcv_stat & 0x80)) /* wait for rx buf filled */
++ barrier();
++ return mfp.usart_dta;
+ }
+
+ int atari_scc_console_wait_key(struct console *co)
+ {
+- do {
++ do {
++ MFPDELAY();
++ } while (!(scc.cha_b_ctrl & 0x01)); /* wait for rx buf filled */
+ MFPDELAY();
+- } while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */
+- MFPDELAY();
+- return( scc.cha_b_data );
++ return scc.cha_b_data;
+ }
+
+ int atari_midi_console_wait_key(struct console *co)
+ {
+- while( !(acia.mid_ctrl & ACIA_RDRF) ) /* wait for rx buf filled */
+- barrier();
+- return( acia.mid_data );
++ while (!(acia.mid_ctrl & ACIA_RDRF)) /* wait for rx buf filled */
++ barrier();
++ return acia.mid_data;
+ }
+ #endif
+
+-/* The following two functions do a quick'n'dirty initialization of the MFP or
++/*
++ * The following two functions do a quick'n'dirty initialization of the MFP or
+ * SCC serial ports. They're used by the debugging interface, kgdb, and the
+- * serial console code. */
++ * serial console code.
++ */
+ #ifndef CONFIG_SERIAL_CONSOLE
+-static void __init atari_init_mfp_port( int cflag )
++static void __init atari_init_mfp_port(int cflag)
+ #else
+-void atari_init_mfp_port( int cflag )
++void atari_init_mfp_port(int cflag)
+ #endif
+ {
+- /* timer values for 1200...115200 bps; > 38400 select 110, 134, or 150
+- * bps, resp., and work only correct if there's a RSVE or RSSPEED */
+- static int baud_table[9] = { 16, 11, 8, 4, 2, 1, 175, 143, 128 };
+- int baud = cflag & CBAUD;
+- int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x04 : 0x06) : 0;
+- int csize = ((cflag & CSIZE) == CS7) ? 0x20 : 0x00;
+-
+- if (cflag & CBAUDEX)
+- baud += B38400;
+- if (baud < B1200 || baud > B38400+2)
+- baud = B9600; /* use default 9600bps for non-implemented rates */
+- baud -= B1200; /* baud_table[] starts at 1200bps */
+-
+- mfp.trn_stat &= ~0x01; /* disable TX */
+- mfp.usart_ctr = parity | csize | 0x88; /* 1:16 clk mode, 1 stop bit */
+- mfp.tim_ct_cd &= 0x70; /* stop timer D */
+- mfp.tim_dt_d = baud_table[baud];
+- mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */
+- mfp.trn_stat |= 0x01; /* enable TX */
+-
+- atari_MFP_init_done = 1;
+-}
+-
+-#define SCC_WRITE(reg,val) \
+- do { \
+- scc.cha_b_ctrl = (reg); \
+- MFPDELAY(); \
+- scc.cha_b_ctrl = (val); \
+- MFPDELAY(); \
+- } while(0)
++ /*
++ * timer values for 1200...115200 bps; > 38400 select 110, 134, or 150
++ * bps, resp., and work only correct if there's a RSVE or RSSPEED
++ */
++ static int baud_table[9] = { 16, 11, 8, 4, 2, 1, 175, 143, 128 };
++ int baud = cflag & CBAUD;
++ int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x04 : 0x06) : 0;
++ int csize = ((cflag & CSIZE) == CS7) ? 0x20 : 0x00;
++
++ if (cflag & CBAUDEX)
++ baud += B38400;
++ if (baud < B1200 || baud > B38400+2)
++ baud = B9600; /* use default 9600bps for non-implemented rates */
++ baud -= B1200; /* baud_table[] starts at 1200bps */
++
++ mfp.trn_stat &= ~0x01; /* disable TX */
++ mfp.usart_ctr = parity | csize | 0x88; /* 1:16 clk mode, 1 stop bit */
++ mfp.tim_ct_cd &= 0x70; /* stop timer D */
++ mfp.tim_dt_d = baud_table[baud];
++ mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */
++ mfp.trn_stat |= 0x01; /* enable TX */
++
++ atari_MFP_init_done = 1;
++}
++
++#define SCC_WRITE(reg, val) \
++ do { \
++ scc.cha_b_ctrl = (reg); \
++ MFPDELAY(); \
++ scc.cha_b_ctrl = (val); \
++ MFPDELAY(); \
++ } while (0)
+
+ /* loops_per_jiffy isn't initialized yet, so we can't use udelay(). This does a
+ * delay of ~ 60us. */
+-#define LONG_DELAY() \
+- do { \
+- int i; \
+- for( i = 100; i > 0; --i ) \
+- MFPDELAY(); \
+- } while(0)
++#define LONG_DELAY() \
++ do { \
++ int i; \
++ for (i = 100; i > 0; --i) \
++ MFPDELAY(); \
++ } while (0)
+
+ #ifndef CONFIG_SERIAL_CONSOLE
+-static void __init atari_init_scc_port( int cflag )
++static void __init atari_init_scc_port(int cflag)
+ #else
+-void atari_init_scc_port( int cflag )
++void atari_init_scc_port(int cflag)
+ #endif
+ {
+- extern int atari_SCC_reset_done;
+- static int clksrc_table[9] =
+- /* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */
+- { 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 };
+- static int brgsrc_table[9] =
+- /* reg 14: 0 = RTxC, 2 = PCLK */
+- { 2, 2, 2, 2, 2, 2, 0, 2, 2 };
+- static int clkmode_table[9] =
+- /* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */
+- { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 };
+- static int div_table[9] =
+- /* reg12 (BRG low) */
+- { 208, 138, 103, 50, 24, 11, 1, 0, 0 };
+-
+- int baud = cflag & CBAUD;
+- int clksrc, clkmode, div, reg3, reg5;
+-
+- if (cflag & CBAUDEX)
+- baud += B38400;
+- if (baud < B1200 || baud > B38400+2)
+- baud = B9600; /* use default 9600bps for non-implemented rates */
+- baud -= B1200; /* tables starts at 1200bps */
+-
+- clksrc = clksrc_table[baud];
+- clkmode = clkmode_table[baud];
+- div = div_table[baud];
+- if (ATARIHW_PRESENT(TT_MFP) && baud >= 6) {
+- /* special treatment for TT, where rates >= 38400 are done via TRxC */
+- clksrc = 0x28; /* TRxC */
+- clkmode = baud == 6 ? 0xc0 :
+- baud == 7 ? 0x80 : /* really 76800bps */
+- 0x40; /* really 153600bps */
+- div = 0;
+- }
+-
+- reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40;
+- reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */;
+-
+- (void)scc.cha_b_ctrl; /* reset reg pointer */
+- SCC_WRITE( 9, 0xc0 ); /* reset */
+- LONG_DELAY(); /* extra delay after WR9 access */
+- SCC_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
+- 0x04 /* 1 stopbit */ |
+- clkmode );
+- SCC_WRITE( 3, reg3 );
+- SCC_WRITE( 5, reg5 );
+- SCC_WRITE( 9, 0 ); /* no interrupts */
+- LONG_DELAY(); /* extra delay after WR9 access */
+- SCC_WRITE( 10, 0 ); /* NRZ mode */
+- SCC_WRITE( 11, clksrc ); /* main clock source */
+- SCC_WRITE( 12, div ); /* BRG value */
+- SCC_WRITE( 13, 0 ); /* BRG high byte */
+- SCC_WRITE( 14, brgsrc_table[baud] );
+- SCC_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) );
+- SCC_WRITE( 3, reg3 | 1 );
+- SCC_WRITE( 5, reg5 | 8 );
++ extern int atari_SCC_reset_done;
++ static int clksrc_table[9] =
++ /* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */
++ { 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 };
++ static int brgsrc_table[9] =
++ /* reg 14: 0 = RTxC, 2 = PCLK */
++ { 2, 2, 2, 2, 2, 2, 0, 2, 2 };
++ static int clkmode_table[9] =
++ /* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */
++ { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 };
++ static int div_table[9] =
++ /* reg12 (BRG low) */
++ { 208, 138, 103, 50, 24, 11, 1, 0, 0 };
++
++ int baud = cflag & CBAUD;
++ int clksrc, clkmode, div, reg3, reg5;
++
++ if (cflag & CBAUDEX)
++ baud += B38400;
++ if (baud < B1200 || baud > B38400+2)
++ baud = B9600; /* use default 9600bps for non-implemented rates */
++ baud -= B1200; /* tables starts at 1200bps */
++
++ clksrc = clksrc_table[baud];
++ clkmode = clkmode_table[baud];
++ div = div_table[baud];
++ if (ATARIHW_PRESENT(TT_MFP) && baud >= 6) {
++ /* special treatment for TT, where rates >= 38400 are done via TRxC */
++ clksrc = 0x28; /* TRxC */
++ clkmode = baud == 6 ? 0xc0 :
++ baud == 7 ? 0x80 : /* really 76800bps */
++ 0x40; /* really 153600bps */
++ div = 0;
++ }
++
++ reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40;
++ reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */;
++
++ (void)scc.cha_b_ctrl; /* reset reg pointer */
++ SCC_WRITE(9, 0xc0); /* reset */
++ LONG_DELAY(); /* extra delay after WR9 access */
++ SCC_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03)
++ : 0 | 0x04 /* 1 stopbit */ | clkmode);
++ SCC_WRITE(3, reg3);
++ SCC_WRITE(5, reg5);
++ SCC_WRITE(9, 0); /* no interrupts */
++ LONG_DELAY(); /* extra delay after WR9 access */
++ SCC_WRITE(10, 0); /* NRZ mode */
++ SCC_WRITE(11, clksrc); /* main clock source */
++ SCC_WRITE(12, div); /* BRG value */
++ SCC_WRITE(13, 0); /* BRG high byte */
++ SCC_WRITE(14, brgsrc_table[baud]);
++ SCC_WRITE(14, brgsrc_table[baud] | (div ? 1 : 0));
++ SCC_WRITE(3, reg3 | 1);
++ SCC_WRITE(5, reg5 | 8);
+
+- atari_SCC_reset_done = 1;
+- atari_SCC_init_done = 1;
++ atari_SCC_reset_done = 1;
++ atari_SCC_init_done = 1;
+ }
+
+ #ifndef CONFIG_SERIAL_CONSOLE
+-static void __init atari_init_midi_port( int cflag )
++static void __init atari_init_midi_port(int cflag)
+ #else
+-void atari_init_midi_port( int cflag )
++void atari_init_midi_port(int cflag)
+ #endif
+ {
+- int baud = cflag & CBAUD;
+- int csize = ((cflag & CSIZE) == CS8) ? 0x10 : 0x00;
+- /* warning 7N1 isn't possible! (instead 7O2 is used...) */
+- int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x0c : 0x08) : 0x04;
+- int div;
+-
+- /* 4800 selects 7812.5, 115200 selects 500000, all other (incl. 9600 as
+- * default) the standard MIDI speed 31250. */
+- if (cflag & CBAUDEX)
+- baud += B38400;
+- if (baud == B4800)
+- div = ACIA_DIV64; /* really 7812.5 bps */
+- else if (baud == B38400+2 /* 115200 */)
+- div = ACIA_DIV1; /* really 500 kbps (does that work??) */
+- else
+- div = ACIA_DIV16; /* 31250 bps, standard for MIDI */
++ int baud = cflag & CBAUD;
++ int csize = ((cflag & CSIZE) == CS8) ? 0x10 : 0x00;
++ /* warning 7N1 isn't possible! (instead 7O2 is used...) */
++ int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x0c : 0x08) : 0x04;
++ int div;
++
++ /* 4800 selects 7812.5, 115200 selects 500000, all other (incl. 9600 as
++ * default) the standard MIDI speed 31250. */
++ if (cflag & CBAUDEX)
++ baud += B38400;
++ if (baud == B4800)
++ div = ACIA_DIV64; /* really 7812.5 bps */
++ else if (baud == B38400+2 /* 115200 */)
++ div = ACIA_DIV1; /* really 500 kbps (does that work??) */
++ else
++ div = ACIA_DIV16; /* 31250 bps, standard for MIDI */
+
+- /* RTS low, ints disabled */
+- acia.mid_ctrl = div | csize | parity |
++ /* RTS low, ints disabled */
++ acia.mid_ctrl = div | csize | parity |
+ ((atari_switches & ATARI_SWITCH_MIDI) ?
+ ACIA_RHTID : ACIA_RLTID);
+ }
+
+ void __init atari_debug_init(void)
+ {
+- if (!strcmp( m68k_debug_device, "ser" )) {
+- /* defaults to ser2 for a Falcon and ser1 otherwise */
+- strcpy( m68k_debug_device, MACH_IS_FALCON ? "ser2" : "ser1" );
+-
+- }
+-
+- if (!strcmp( m68k_debug_device, "ser1" )) {
+- /* ST-MFP Modem1 serial port */
+- atari_init_mfp_port( B9600|CS8 );
+- atari_console_driver.write = atari_mfp_console_write;
+- }
+- else if (!strcmp( m68k_debug_device, "ser2" )) {
+- /* SCC Modem2 serial port */
+- atari_init_scc_port( B9600|CS8 );
+- atari_console_driver.write = atari_scc_console_write;
+- }
+- else if (!strcmp( m68k_debug_device, "midi" )) {
+- /* MIDI port */
+- atari_init_midi_port( B9600|CS8 );
+- atari_console_driver.write = atari_midi_console_write;
+- }
+- else if (!strcmp( m68k_debug_device, "par" )) {
+- /* parallel printer */
+- atari_turnoff_irq( IRQ_MFP_BUSY ); /* avoid ints */
+- sound_ym.rd_data_reg_sel = 7; /* select mixer control */
+- sound_ym.wd_data = 0xff; /* sound off, ports are output */
+- sound_ym.rd_data_reg_sel = 15; /* select port B */
+- sound_ym.wd_data = 0; /* no char */
+- sound_ym.rd_data_reg_sel = 14; /* select port A */
+- sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */
+- atari_console_driver.write = atari_par_console_write;
+- }
+- if (atari_console_driver.write)
+- register_console(&atari_console_driver);
+-}
++ if (!strcmp(m68k_debug_device, "ser")) {
++ /* defaults to ser2 for a Falcon and ser1 otherwise */
++ strcpy(m68k_debug_device, MACH_IS_FALCON ? "ser2" : "ser1");
++ }
+
+-/*
+- * Local variables:
+- * c-indent-level: 4
+- * tab-width: 8
+- * End:
+- */
++ if (!strcmp(m68k_debug_device, "ser1")) {
++ /* ST-MFP Modem1 serial port */
++ atari_init_mfp_port(B9600|CS8);
++ atari_console_driver.write = atari_mfp_console_write;
++ } else if (!strcmp(m68k_debug_device, "ser2")) {
++ /* SCC Modem2 serial port */
++ atari_init_scc_port(B9600|CS8);
++ atari_console_driver.write = atari_scc_console_write;
++ } else if (!strcmp(m68k_debug_device, "midi")) {
++ /* MIDI port */
++ atari_init_midi_port(B9600|CS8);
++ atari_console_driver.write = atari_midi_console_write;
++ } else if (!strcmp(m68k_debug_device, "par")) {
++ /* parallel printer */
++ atari_turnoff_irq(IRQ_MFP_BUSY); /* avoid ints */
++ sound_ym.rd_data_reg_sel = 7; /* select mixer control */
++ sound_ym.wd_data = 0xff; /* sound off, ports are output */
++ sound_ym.rd_data_reg_sel = 15; /* select port B */
++ sound_ym.wd_data = 0; /* no char */
++ sound_ym.rd_data_reg_sel = 14; /* select port A */
++ sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */
++ atari_console_driver.write = atari_par_console_write;
++ }
++ if (atari_console_driver.write)
++ register_console(&atari_console_driver);
++}
+--- linux-m68k-2.6.21.orig/arch/m68k/kernel/entry.S
++++ linux-m68k-2.6.21/arch/m68k/kernel/entry.S
+@@ -692,7 +692,7 @@ sys_call_table:
+ .long sys_tgkill /* 265 */
+ .long sys_utimes
+ .long sys_fadvise64_64
+- .long sys_mbind
++ .long sys_mbind
+ .long sys_get_mempolicy
+ .long sys_set_mempolicy /* 270 */
+ .long sys_mq_open
+--- linux-m68k-2.6.21.orig/arch/m68k/kernel/head.S
++++ linux-m68k-2.6.21/arch/m68k/kernel/head.S
+@@ -3195,7 +3195,7 @@ func_start serial_putc,%d0/%d1/%a0/%a1
+ jbra L(serial_putc_done)
+ 3:
+ #endif
+-
++
+ L(serial_putc_done):
+ func_return serial_putc
+
+--- linux-m68k-2.6.21.orig/arch/m68k/kernel/setup.c
++++ linux-m68k-2.6.21/arch/m68k/kernel/setup.c
+@@ -133,78 +133,78 @@ extern void config_hp300(void);
+ extern void config_q40(void);
+ extern void config_sun3x(void);
+
+-extern void mac_debugging_short (int, short);
+-extern void mac_debugging_long (int, long);
+-
+ #define MASK_256K 0xfffc0000
+
+ extern void paging_init(void);
+
+ static void __init m68k_parse_bootinfo(const struct bi_record *record)
+ {
+- while (record->tag != BI_LAST) {
+- int unknown = 0;
+- const unsigned long *data = record->data;
+- switch (record->tag) {
+- case BI_MACHTYPE:
+- case BI_CPUTYPE:
+- case BI_FPUTYPE:
+- case BI_MMUTYPE:
+- /* Already set up by head.S */
+- break;
+-
+- case BI_MEMCHUNK:
+- if (m68k_num_memory < NUM_MEMINFO) {
+- m68k_memory[m68k_num_memory].addr = data[0];
+- m68k_memory[m68k_num_memory].size = data[1];
+- m68k_num_memory++;
+- } else
+- printk("m68k_parse_bootinfo: too many memory chunks\n");
+- break;
+-
+- case BI_RAMDISK:
+- m68k_ramdisk.addr = data[0];
+- m68k_ramdisk.size = data[1];
+- break;
+-
+- case BI_COMMAND_LINE:
+- strlcpy(m68k_command_line, (const char *)data, sizeof(m68k_command_line));
+- break;
+-
+- default:
+- if (MACH_IS_AMIGA)
+- unknown = amiga_parse_bootinfo(record);
+- else if (MACH_IS_ATARI)
+- unknown = atari_parse_bootinfo(record);
+- else if (MACH_IS_MAC)
+- unknown = mac_parse_bootinfo(record);
+- else if (MACH_IS_Q40)
+- unknown = q40_parse_bootinfo(record);
+- else if (MACH_IS_BVME6000)
+- unknown = bvme6000_parse_bootinfo(record);
+- else if (MACH_IS_MVME16x)
+- unknown = mvme16x_parse_bootinfo(record);
+- else if (MACH_IS_MVME147)
+- unknown = mvme147_parse_bootinfo(record);
+- else if (MACH_IS_HP300)
+- unknown = hp300_parse_bootinfo(record);
+- else
+- unknown = 1;
+- }
+- if (unknown)
+- printk("m68k_parse_bootinfo: unknown tag 0x%04x ignored\n",
+- record->tag);
+- record = (struct bi_record *)((unsigned long)record+record->size);
+- }
++ while (record->tag != BI_LAST) {
++ int unknown = 0;
++ const unsigned long *data = record->data;
++
++ switch (record->tag) {
++ case BI_MACHTYPE:
++ case BI_CPUTYPE:
++ case BI_FPUTYPE:
++ case BI_MMUTYPE:
++ /* Already set up by head.S */
++ break;
++
++ case BI_MEMCHUNK:
++ if (m68k_num_memory < NUM_MEMINFO) {
++ m68k_memory[m68k_num_memory].addr = data[0];
++ m68k_memory[m68k_num_memory].size = data[1];
++ m68k_num_memory++;
++ } else
++ printk("m68k_parse_bootinfo: too many memory chunks\n");
++ break;
++
++ case BI_RAMDISK:
++ m68k_ramdisk.addr = data[0];
++ m68k_ramdisk.size = data[1];
++ break;
++
++ case BI_COMMAND_LINE:
++ strlcpy(m68k_command_line, (const char *)data,
++ sizeof(m68k_command_line));
++ break;
++
++ default:
++ if (MACH_IS_AMIGA)
++ unknown = amiga_parse_bootinfo(record);
++ else if (MACH_IS_ATARI)
++ unknown = atari_parse_bootinfo(record);
++ else if (MACH_IS_MAC)
++ unknown = mac_parse_bootinfo(record);
++ else if (MACH_IS_Q40)
++ unknown = q40_parse_bootinfo(record);
++ else if (MACH_IS_BVME6000)
++ unknown = bvme6000_parse_bootinfo(record);
++ else if (MACH_IS_MVME16x)
++ unknown = mvme16x_parse_bootinfo(record);
++ else if (MACH_IS_MVME147)
++ unknown = mvme147_parse_bootinfo(record);
++ else if (MACH_IS_HP300)
++ unknown = hp300_parse_bootinfo(record);
++ else
++ unknown = 1;
++ }
++ if (unknown)
++ printk("m68k_parse_bootinfo: unknown tag 0x%04x ignored\n",
++ record->tag);
++ record = (struct bi_record *)((unsigned long)record +
++ record->size);
++ }
+
+- m68k_realnum_memory = m68k_num_memory;
++ m68k_realnum_memory = m68k_num_memory;
+ #ifdef CONFIG_SINGLE_MEMORY_CHUNK
+- if (m68k_num_memory > 1) {
+- printk("Ignoring last %i chunks of physical memory\n",
+- (m68k_num_memory - 1));
+- m68k_num_memory = 1;
+- }
+- m68k_memoffset = m68k_memory[0].addr-PAGE_OFFSET;
++ if (m68k_num_memory > 1) {
++ printk("Ignoring last %i chunks of physical memory\n",
++ (m68k_num_memory - 1));
++ m68k_num_memory = 1;
++ }
++ m68k_memoffset = m68k_memory[0].addr-PAGE_OFFSET;
+ #endif
+ }
+
+@@ -234,7 +234,7 @@ void __init setup_arch(char **cmdline_p)
+ /* clear the fpu if we have one */
+ if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) {
+ volatile int zero = 0;
+- asm __volatile__ ("frestore %0" : : "m" (zero));
++ asm volatile ("frestore %0" : : "m" (zero));
+ }
+ #endif
+
+@@ -262,32 +262,35 @@ void __init setup_arch(char **cmdline_p)
+ * For the m68k, this is currently only "debug=xxx" to enable printing
+ * certain kernel messages to some machine-specific device.
+ */
+- for( p = *cmdline_p; p && *p; ) {
+- i = 0;
+- if (!strncmp( p, "debug=", 6 )) {
+- strlcpy( m68k_debug_device, p+6, sizeof(m68k_debug_device) );
+- if ((q = strchr( m68k_debug_device, ' ' ))) *q = 0;
+- i = 1;
+- }
++ for (p = *cmdline_p; p && *p;) {
++ i = 0;
++ if (!strncmp(p, "debug=", 6)) {
++ strlcpy(m68k_debug_device, p+6, sizeof(m68k_debug_device));
++ q = strchr(m68k_debug_device, ' ');
++ if (q)
++ *q = 0;
++ i = 1;
++ }
+ #ifdef CONFIG_ATARI
+- /* This option must be parsed very early */
+- if (!strncmp( p, "switches=", 9 )) {
+- extern void atari_switches_setup( const char *, int );
+- atari_switches_setup( p+9, (q = strchr( p+9, ' ' )) ?
+- (q - (p+9)) : strlen(p+9) );
+- i = 1;
+- }
+-#endif
+-
+- if (i) {
+- /* option processed, delete it */
+- if ((q = strchr( p, ' ' )))
+- strcpy( p, q+1 );
+- else
+- *p = 0;
+- } else {
+- if ((p = strchr( p, ' ' ))) ++p;
+- }
++ /* This option must be parsed very early */
++ if (!strncmp(p, "switches=", 9)) {
++ extern void atari_switches_setup(const char *, int);
++ q = strchr(p + 9, ' ');
++ atari_switches_setup(p + 9, q ? (q - (p + 9)) : strlen(p + 9));
++ i = 1;
++ }
++#endif
++
++ if (i) {
++ /* option processed, delete it */
++ if ((q = strchr(p, ' ')))
++ strcpy(p, q + 1);
++ else
++ *p = 0;
++ } else {
++ if ((p = strchr(p, ' ')))
++ ++p;
++ }
+ }
+
+ #ifdef CONFIG_DUMMY_CONSOLE
+@@ -296,62 +299,62 @@ void __init setup_arch(char **cmdline_p)
+
+ switch (m68k_machtype) {
+ #ifdef CONFIG_AMIGA
+- case MACH_AMIGA:
++ case MACH_AMIGA:
+ config_amiga();
+ break;
+ #endif
+ #ifdef CONFIG_ATARI
+- case MACH_ATARI:
++ case MACH_ATARI:
+ config_atari();
+ break;
+ #endif
+ #ifdef CONFIG_MAC
+- case MACH_MAC:
++ case MACH_MAC:
+ config_mac();
+ break;
+ #endif
+ #ifdef CONFIG_SUN3
+- case MACH_SUN3:
++ case MACH_SUN3:
+ config_sun3();
+ break;
+ #endif
+ #ifdef CONFIG_APOLLO
+- case MACH_APOLLO:
++ case MACH_APOLLO:
+ config_apollo();
+ break;
+ #endif
+ #ifdef CONFIG_MVME147
+- case MACH_MVME147:
++ case MACH_MVME147:
+ config_mvme147();
+ break;
+ #endif
+ #ifdef CONFIG_MVME16x
+- case MACH_MVME16x:
++ case MACH_MVME16x:
+ config_mvme16x();
+ break;
+ #endif
+ #ifdef CONFIG_BVME6000
+- case MACH_BVME6000:
++ case MACH_BVME6000:
+ config_bvme6000();
+ break;
+ #endif
+ #ifdef CONFIG_HP300
+- case MACH_HP300:
++ case MACH_HP300:
+ config_hp300();
+ break;
+ #endif
+ #ifdef CONFIG_Q40
+- case MACH_Q40:
+- config_q40();
++ case MACH_Q40:
++ config_q40();
+ break;
+ #endif
+ #ifdef CONFIG_SUN3X
+- case MACH_SUN3X:
++ case MACH_SUN3X:
+ config_sun3x();
+ break;
+ #endif
+- default:
+- panic ("No configuration setup");
++ default:
++ panic("No configuration setup");
+ }
+
+ #ifndef CONFIG_SUN3
+@@ -380,7 +383,7 @@ void __init setup_arch(char **cmdline_p)
+ reserve_bootmem(m68k_ramdisk.addr, m68k_ramdisk.size);
+ initrd_start = (unsigned long)phys_to_virt(m68k_ramdisk.addr);
+ initrd_end = initrd_start + m68k_ramdisk.size;
+- printk ("initrd: %08lx - %08lx\n", initrd_start, initrd_end);
++ printk("initrd: %08lx - %08lx\n", initrd_start, initrd_end);
+ }
+ #endif
+
+@@ -402,18 +405,18 @@ void __init setup_arch(char **cmdline_p)
+ #if defined(CONFIG_ISA) && defined(MULTI_ISA)
+ #if defined(CONFIG_Q40)
+ if (MACH_IS_Q40) {
+- isa_type = Q40_ISA;
+- isa_sex = 0;
++ isa_type = Q40_ISA;
++ isa_sex = 0;
+ }
+ #elif defined(CONFIG_GG2)
+- if (MACH_IS_AMIGA && AMIGAHW_PRESENT(GG2_ISA)){
+- isa_type = GG2_ISA;
+- isa_sex = 0;
++ if (MACH_IS_AMIGA && AMIGAHW_PRESENT(GG2_ISA)) {
++ isa_type = GG2_ISA;
++ isa_sex = 0;
+ }
+ #elif defined(CONFIG_AMIGA_PCMCIA)
+- if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)){
+- isa_type = AG_ISA;
+- isa_sex = 1;
++ if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)) {
++ isa_type = AG_ISA;
++ isa_sex = 1;
+ }
+ #endif
+ #endif
+@@ -421,66 +424,66 @@ void __init setup_arch(char **cmdline_p)
+
+ static int show_cpuinfo(struct seq_file *m, void *v)
+ {
+- const char *cpu, *mmu, *fpu;
+- unsigned long clockfreq, clockfactor;
++ const char *cpu, *mmu, *fpu;
++ unsigned long clockfreq, clockfactor;
+
+ #define LOOP_CYCLES_68020 (8)
+ #define LOOP_CYCLES_68030 (8)
+ #define LOOP_CYCLES_68040 (3)
+ #define LOOP_CYCLES_68060 (1)
+
+- if (CPU_IS_020) {
+- cpu = "68020";
+- clockfactor = LOOP_CYCLES_68020;
+- } else if (CPU_IS_030) {
+- cpu = "68030";
+- clockfactor = LOOP_CYCLES_68030;
+- } else if (CPU_IS_040) {
+- cpu = "68040";
+- clockfactor = LOOP_CYCLES_68040;
+- } else if (CPU_IS_060) {
+- cpu = "68060";
+- clockfactor = LOOP_CYCLES_68060;
+- } else {
+- cpu = "680x0";
+- clockfactor = 0;
+- }
++ if (CPU_IS_020) {
++ cpu = "68020";
++ clockfactor = LOOP_CYCLES_68020;
++ } else if (CPU_IS_030) {
++ cpu = "68030";
++ clockfactor = LOOP_CYCLES_68030;
++ } else if (CPU_IS_040) {
++ cpu = "68040";
++ clockfactor = LOOP_CYCLES_68040;
++ } else if (CPU_IS_060) {
++ cpu = "68060";
++ clockfactor = LOOP_CYCLES_68060;
++ } else {
++ cpu = "680x0";
++ clockfactor = 0;
++ }
+
+ #ifdef CONFIG_M68KFPU_EMU_ONLY
+- fpu="none(soft float)";
++ fpu = "none(soft float)";
+ #else
+- if (m68k_fputype & FPU_68881)
+- fpu = "68881";
+- else if (m68k_fputype & FPU_68882)
+- fpu = "68882";
+- else if (m68k_fputype & FPU_68040)
+- fpu = "68040";
+- else if (m68k_fputype & FPU_68060)
+- fpu = "68060";
+- else if (m68k_fputype & FPU_SUNFPA)
+- fpu = "Sun FPA";
+- else
+- fpu = "none";
+-#endif
+-
+- if (m68k_mmutype & MMU_68851)
+- mmu = "68851";
+- else if (m68k_mmutype & MMU_68030)
+- mmu = "68030";
+- else if (m68k_mmutype & MMU_68040)
+- mmu = "68040";
+- else if (m68k_mmutype & MMU_68060)
+- mmu = "68060";
+- else if (m68k_mmutype & MMU_SUN3)
+- mmu = "Sun-3";
+- else if (m68k_mmutype & MMU_APOLLO)
+- mmu = "Apollo";
+- else
+- mmu = "unknown";
++ if (m68k_fputype & FPU_68881)
++ fpu = "68881";
++ else if (m68k_fputype & FPU_68882)
++ fpu = "68882";
++ else if (m68k_fputype & FPU_68040)
++ fpu = "68040";
++ else if (m68k_fputype & FPU_68060)
++ fpu = "68060";
++ else if (m68k_fputype & FPU_SUNFPA)
++ fpu = "Sun FPA";
++ else
++ fpu = "none";
++#endif
++
++ if (m68k_mmutype & MMU_68851)
++ mmu = "68851";
++ else if (m68k_mmutype & MMU_68030)
++ mmu = "68030";
++ else if (m68k_mmutype & MMU_68040)
++ mmu = "68040";
++ else if (m68k_mmutype & MMU_68060)
++ mmu = "68060";
++ else if (m68k_mmutype & MMU_SUN3)
++ mmu = "Sun-3";
++ else if (m68k_mmutype & MMU_APOLLO)
++ mmu = "Apollo";
++ else
++ mmu = "unknown";
+
+- clockfreq = loops_per_jiffy*HZ*clockfactor;
++ clockfreq = loops_per_jiffy * HZ * clockfactor;
+
+- seq_printf(m, "CPU:\t\t%s\n"
++ seq_printf(m, "CPU:\t\t%s\n"
+ "MMU:\t\t%s\n"
+ "FPU:\t\t%s\n"
+ "Clocking:\t%lu.%1luMHz\n"
+@@ -490,7 +493,7 @@ static int show_cpuinfo(struct seq_file
+ clockfreq/1000000,(clockfreq/100000)%10,
+ loops_per_jiffy/(500000/HZ),(loops_per_jiffy/(5000/HZ))%100,
+ loops_per_jiffy);
+- return 0;
++ return 0;
+ }
+
+ static void *c_start(struct seq_file *m, loff_t *pos)
+@@ -506,44 +509,44 @@ static void c_stop(struct seq_file *m, v
+ {
+ }
+ struct seq_operations cpuinfo_op = {
+- .start = c_start,
+- .next = c_next,
+- .stop = c_stop,
+- .show = show_cpuinfo,
++ .start = c_start,
++ .next = c_next,
++ .stop = c_stop,
++ .show = show_cpuinfo,
+ };
+
+ int get_hardware_list(char *buffer)
+ {
+- int len = 0;
+- char model[80];
+- unsigned long mem;
+- int i;
+-
+- if (mach_get_model)
+- mach_get_model(model);
+- else
+- strcpy(model, "Unknown m68k");
+-
+- len += sprintf(buffer+len, "Model:\t\t%s\n", model);
+- for (mem = 0, i = 0; i < m68k_num_memory; i++)
+- mem += m68k_memory[i].size;
+- len += sprintf(buffer+len, "System Memory:\t%ldK\n", mem>>10);
++ int len = 0;
++ char model[80];
++ unsigned long mem;
++ int i;
++
++ if (mach_get_model)
++ mach_get_model(model);
++ else
++ strcpy(model, "Unknown m68k");
++
++ len += sprintf(buffer + len, "Model:\t\t%s\n", model);
++ for (mem = 0, i = 0; i < m68k_num_memory; i++)
++ mem += m68k_memory[i].size;
++ len += sprintf(buffer + len, "System Memory:\t%ldK\n", mem >> 10);
+
+- if (mach_get_hardware_list)
+- len += mach_get_hardware_list(buffer+len);
++ if (mach_get_hardware_list)
++ len += mach_get_hardware_list(buffer + len);
+
+- return(len);
++ return len;
+ }
+
+ void check_bugs(void)
+ {
+ #ifndef CONFIG_M68KFPU_EMU
+ if (m68k_fputype == 0) {
+- printk( KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, "
+- "WHICH IS REQUIRED BY LINUX/M68K ***\n" );
+- printk( KERN_EMERG "Upgrade your hardware or join the FPU "
+- "emulation project\n" );
+- panic( "no FPU" );
++ printk(KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, "
++ "WHICH IS REQUIRED BY LINUX/M68K ***\n");
++ printk(KERN_EMERG "Upgrade your hardware or join the FPU "
++ "emulation project\n");
++ panic("no FPU");
+ }
+ #endif /* !CONFIG_M68KFPU_EMU */
+ }
+--- linux-m68k-2.6.21.orig/arch/m68k/mac/config.c
++++ linux-m68k-2.6.21/arch/m68k/mac/config.c
+@@ -59,15 +59,15 @@ extern struct mem_info m68k_ramdisk;
+
+ extern char m68k_command_line[CL_SIZE];
+
+-void *mac_env; /* Loaded by the boot asm */
++void *mac_env; /* Loaded by the boot asm */
+
+ /* The phys. video addr. - might be bogus on some machines */
+ unsigned long mac_orig_videoaddr;
+
+ /* Mac specific timer functions */
+-extern unsigned long mac_gettimeoffset (void);
+-extern int mac_hwclk (int, struct rtc_time *);
+-extern int mac_set_clock_mmss (unsigned long);
++extern unsigned long mac_gettimeoffset(void);
++extern int mac_hwclk(int, struct rtc_time *);
++extern int mac_set_clock_mmss(unsigned long);
+ extern int show_mac_interrupts(struct seq_file *, void *);
+ extern void iop_preinit(void);
+ extern void iop_init(void);
+@@ -99,51 +99,52 @@ static void mac_sched_init(irq_handler_t
+
+ int __init mac_parse_bootinfo(const struct bi_record *record)
+ {
+- int unknown = 0;
+- const u_long *data = record->data;
++ int unknown = 0;
++ const u_long *data = record->data;
+
+- switch (record->tag) {
++ switch (record->tag) {
+ case BI_MAC_MODEL:
+- mac_bi_data.id = *data;
+- break;
++ mac_bi_data.id = *data;
++ break;
+ case BI_MAC_VADDR:
+- mac_bi_data.videoaddr = *data;
+- break;
++ mac_bi_data.videoaddr = *data;
++ break;
+ case BI_MAC_VDEPTH:
+- mac_bi_data.videodepth = *data;
+- break;
++ mac_bi_data.videodepth = *data;
++ break;
+ case BI_MAC_VROW:
+- mac_bi_data.videorow = *data;
+- break;
++ mac_bi_data.videorow = *data;
++ break;
+ case BI_MAC_VDIM:
+- mac_bi_data.dimensions = *data;
+- break;
++ mac_bi_data.dimensions = *data;
++ break;
+ case BI_MAC_VLOGICAL:
+- mac_bi_data.videological = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK);
+- mac_orig_videoaddr = *data;
+- break;
++ mac_bi_data.videological = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK);
++ mac_orig_videoaddr = *data;
++ break;
+ case BI_MAC_SCCBASE:
+- mac_bi_data.sccbase = *data;
+- break;
++ mac_bi_data.sccbase = *data;
++ break;
+ case BI_MAC_BTIME:
+- mac_bi_data.boottime = *data;
+- break;
++ mac_bi_data.boottime = *data;
++ break;
+ case BI_MAC_GMTBIAS:
+- mac_bi_data.gmtbias = *data;
+- break;
++ mac_bi_data.gmtbias = *data;
++ break;
+ case BI_MAC_MEMSIZE:
+- mac_bi_data.memsize = *data;
+- break;
++ mac_bi_data.memsize = *data;
++ break;
+ case BI_MAC_CPUID:
+- mac_bi_data.cpuid = *data;
+- break;
+- case BI_MAC_ROMBASE:
+- mac_bi_data.rombase = *data;
+- break;
++ mac_bi_data.cpuid = *data;
++ break;
++ case BI_MAC_ROMBASE:
++ mac_bi_data.rombase = *data;
++ break;
+ default:
+- unknown = 1;
+- }
+- return(unknown);
++ unknown = 1;
++ break;
++ }
++ return unknown;
+ }
+
+ /*
+@@ -155,6 +156,7 @@ int __init mac_parse_bootinfo(const stru
+ static void mac_cache_card_flush(int writeback)
+ {
+ unsigned long flags;
++
+ local_irq_save(flags);
+ via_flush_cache();
+ local_irq_restore(flags);
+@@ -162,28 +164,27 @@ static void mac_cache_card_flush(int wri
+
+ void __init config_mac(void)
+ {
+- if (!MACH_IS_MAC) {
+- printk(KERN_ERR "ERROR: no Mac, but config_mac() called!! \n");
+- }
++ if (!MACH_IS_MAC)
++ printk(KERN_ERR "ERROR: no Mac, but config_mac() called!! \n");
+
+- mach_sched_init = mac_sched_init;
+- mach_init_IRQ = mac_init_IRQ;
+- mach_get_model = mac_get_model;
+- mach_gettimeoffset = mac_gettimeoffset;
++ mach_sched_init = mac_sched_init;
++ mach_init_IRQ = mac_init_IRQ;
++ mach_get_model = mac_get_model;
++ mach_gettimeoffset = mac_gettimeoffset;
+ #warning move to adb/via init
+ #if 0
+- mach_hwclk = mac_hwclk;
++ mach_hwclk = mac_hwclk;
+ #endif
+- mach_set_clock_mmss = mac_set_clock_mmss;
+- mach_reset = mac_reset;
+- mach_halt = mac_poweroff;
+- mach_power_off = mac_poweroff;
++ mach_set_clock_mmss = mac_set_clock_mmss;
++ mach_reset = mac_reset;
++ mach_halt = mac_poweroff;
++ mach_power_off = mac_poweroff;
+ mach_max_dma_address = 0xffffffff;
+ #if 0
+- mach_debug_init = mac_debug_init;
++ mach_debug_init = mac_debug_init;
+ #endif
+ #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
+- mach_beep = mac_mksound;
++ mach_beep = mac_mksound;
+ #endif
+ #ifdef CONFIG_HEARTBEAT
+ #if 0
+@@ -199,21 +200,22 @@ void __init config_mac(void)
+ mac_identify();
+ mac_report_hardware();
+
+- /* AFAIK only the IIci takes a cache card. The IIfx has onboard
+- cache ... someone needs to figure out how to tell if it's on or
+- not. */
++ /*
++ * AFAIK only the IIci takes a cache card. The IIfx has onboard
++ * cache ... someone needs to figure out how to tell if it's on or
++ * not.
++ */
+
+ if (macintosh_config->ident == MAC_MODEL_IICI
+- || macintosh_config->ident == MAC_MODEL_IIFX) {
++ || macintosh_config->ident == MAC_MODEL_IIFX)
+ mach_l2_flush = mac_cache_card_flush;
+- }
+
+ /*
+ * Check for machine specific fixups.
+ */
+
+ #ifdef OLD_NUBUS_CODE
+- nubus_sweep_video();
++ nubus_sweep_video();
+ #endif
+ }
+
+@@ -233,8 +235,7 @@ void __init config_mac(void)
+ struct mac_model *macintosh_config;
+ EXPORT_SYMBOL(macintosh_config);
+
+-static struct mac_model mac_data_table[]=
+-{
++static struct mac_model mac_data_table[] = {
+ /*
+ * We'll pretend to be a Macintosh II, that's pretty safe.
+ */
+@@ -784,12 +785,12 @@ void mac_identify(void)
+ if (!model) {
+ /* no bootinfo model id -> NetBSD booter was used! */
+ /* XXX FIXME: breaks for model > 31 */
+- model=(mac_bi_data.cpuid>>2)&63;
+- printk (KERN_WARNING "No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n");
++ model = (mac_bi_data.cpuid >> 2) & 63;
++ printk(KERN_WARNING "No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n");
+ }
+
+ macintosh_config = mac_data_table;
+- for (m = macintosh_config ; m->ident != -1 ; m++) {
++ for (m = macintosh_config; m->ident != -1; m++) {
+ if (m->ident == model) {
+ macintosh_config = m;
+ break;
+@@ -803,25 +804,25 @@ void mac_identify(void)
+ iop_preinit();
+ mac_debug_init();
+
+- printk (KERN_INFO "Detected Macintosh model: %d \n", model);
++ printk(KERN_INFO "Detected Macintosh model: %d \n", model);
+
+ /*
+ * Report booter data:
+ */
+- printk (KERN_DEBUG " Penguin bootinfo data:\n");
+- printk (KERN_DEBUG " Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n",
++ printk(KERN_DEBUG " Penguin bootinfo data:\n");
++ printk(KERN_DEBUG " Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n",
+ mac_bi_data.videoaddr, mac_bi_data.videorow,
+ mac_bi_data.videodepth, mac_bi_data.dimensions & 0xFFFF,
+ mac_bi_data.dimensions >> 16);
+- printk (KERN_DEBUG " Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n",
++ printk(KERN_DEBUG " Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n",
+ mac_bi_data.videological, mac_orig_videoaddr,
+ mac_bi_data.sccbase);
+- printk (KERN_DEBUG " Boottime: 0x%lx GMTBias: 0x%lx \n",
++ printk(KERN_DEBUG " Boottime: 0x%lx GMTBias: 0x%lx \n",
+ mac_bi_data.boottime, mac_bi_data.gmtbias);
+- printk (KERN_DEBUG " Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n",
++ printk(KERN_DEBUG " Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n",
+ mac_bi_data.id, mac_bi_data.cpuid, mac_bi_data.memsize);
+ #if 0
+- printk ("Ramdisk: addr 0x%lx size 0x%lx\n",
++ printk("Ramdisk: addr 0x%lx size 0x%lx\n",
+ m68k_ramdisk.addr, m68k_ramdisk.size);
+ #endif
+
+@@ -830,22 +831,22 @@ void mac_identify(void)
+ */
+ switch (macintosh_config->scsi_type) {
+ case MAC_SCSI_OLD:
+- MACHW_SET(MAC_SCSI_80);
+- break;
++ MACHW_SET(MAC_SCSI_80);
++ break;
+ case MAC_SCSI_QUADRA:
+ case MAC_SCSI_QUADRA2:
+ case MAC_SCSI_QUADRA3:
+- MACHW_SET(MAC_SCSI_96);
+- if ((macintosh_config->ident == MAC_MODEL_Q900) ||
+- (macintosh_config->ident == MAC_MODEL_Q950))
+- MACHW_SET(MAC_SCSI_96_2);
+- break;
++ MACHW_SET(MAC_SCSI_96);
++ if ((macintosh_config->ident == MAC_MODEL_Q900) ||
++ (macintosh_config->ident == MAC_MODEL_Q950))
++ MACHW_SET(MAC_SCSI_96_2);
++ break;
+ default:
+- printk(KERN_WARNING "config.c: wtf: unknown scsi, using 53c80\n");
+- MACHW_SET(MAC_SCSI_80);
+- break;
+-
++ printk(KERN_WARNING "config.c: wtf: unknown scsi, using 53c80\n");
++ MACHW_SET(MAC_SCSI_80);
++ break;
+ }
++
+ iop_init();
+ via_init();
+ oss_init();
+@@ -860,6 +861,6 @@ void mac_report_hardware(void)
+
+ static void mac_get_model(char *str)
+ {
+- strcpy(str,"Macintosh ");
++ strcpy(str, "Macintosh ");
+ strcat(str, macintosh_config->name);
+ }
+--- linux-m68k-2.6.21.orig/arch/m68k/mac/debug.c
++++ linux-m68k-2.6.21/arch/m68k/mac/debug.c
+@@ -52,7 +52,7 @@ extern void mac_serial_print(const char
+ */
+
+ #ifdef DEBUG_SCREEN
+-static int peng=0, line=0;
++static int peng, line;
+ #endif
+
+ void mac_debugging_short(int pos, short num)
+@@ -74,15 +74,14 @@ void mac_debugging_short(int pos, short
+ }
+
+ /* calculate current offset */
+- pengoffset=(unsigned char *)(mac_videobase+(150+line*2)*mac_rowbytes)
+- +80*peng;
++ pengoffset = (unsigned char *)mac_videobase +
++ (150+line*2) * mac_rowbytes) + 80 * peng;
+
+- pptr=pengoffset;
++ pptr = pengoffset;
+
+- for(i=0;i<8*sizeof(short);i++) /* # of bits */
+- {
++ for (i = 0; i < 8 * sizeof(short); i++) { /* # of bits */
+ /* value mask for bit i, reverse order */
+- *pptr++ = (num & ( 1 << (8*sizeof(short)-i-1) ) ? 0xFF : 0x00);
++ *pptr++ = (num & (1 << (8*sizeof(short)-i-1)) ? 0xFF : 0x00);
+ }
+
+ peng++;
+@@ -115,11 +114,10 @@ void mac_debugging_long(int pos, long ad
+ pengoffset=(unsigned char *)(mac_videobase+(150+line*2)*mac_rowbytes)
+ +80*peng;
+
+- pptr=pengoffset;
++ pptr = pengoffset;
+
+- for(i=0;i<8*sizeof(long);i++) /* # of bits */
+- {
+- *pptr++ = (addr & ( 1 << (8*sizeof(long)-i-1) ) ? 0xFF : 0x00);
++ for (i = 0; i < 8 * sizeof(long); i++) { /* # of bits */
++ *pptr++ = (addr & (1 << (8*sizeof(long)-i-1)) ? 0xFF : 0x00);
+ }
+
+ peng++;
+@@ -136,16 +134,15 @@ void mac_debugging_long(int pos, long ad
+ * TODO: serial debug code
+ */
+
+-struct mac_SCC
+- {
+- u_char cha_b_ctrl;
+- u_char char_dummy1;
+- u_char cha_a_ctrl;
+- u_char char_dummy2;
+- u_char cha_b_data;
+- u_char char_dummy3;
+- u_char cha_a_data;
+- };
++struct mac_SCC {
++ u_char cha_b_ctrl;
++ u_char char_dummy1;
++ u_char cha_a_ctrl;
++ u_char char_dummy2;
++ u_char cha_b_data;
++ u_char char_dummy3;
++ u_char cha_a_data;
++};
+
+ # define scc (*((volatile struct mac_SCC*)mac_bi_data.sccbase))
+
+@@ -158,9 +155,9 @@ int mac_SCC_reset_done;
+ static int scc_port = -1;
+
+ static struct console mac_console_driver = {
+- .name = "debug",
+- .flags = CON_PRINTBUFFER,
+- .index = -1,
++ .name = "debug",
++ .flags = CON_PRINTBUFFER,
++ .index = -1,
+ };
+
+ /*
+@@ -178,8 +175,8 @@ static struct console mac_console_driver
+ * this driver if Mac.
+ */
+
+-void mac_debug_console_write (struct console *co, const char *str,
+- unsigned int count)
++void mac_debug_console_write(struct console *co, const char *str,
++ unsigned int count)
+ {
+ mac_serial_print(str);
+ }
+@@ -190,48 +187,50 @@ void mac_debug_console_write (struct con
+
+ #define uSEC 1
+
+-static inline void mac_sccb_out (char c)
++static inline void mac_sccb_out(char c)
+ {
+- int i;
+- do {
+- for( i = uSEC; i > 0; --i )
++ int i;
++
++ do {
++ for (i = uSEC; i > 0; --i)
++ barrier();
++ } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
++ for (i = uSEC; i > 0; --i)
+ barrier();
+- } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
+- for( i = uSEC; i > 0; --i )
+- barrier();
+- scc.cha_b_data = c;
++ scc.cha_b_data = c;
+ }
+
+-static inline void mac_scca_out (char c)
++static inline void mac_scca_out(char c)
+ {
+- int i;
+- do {
+- for( i = uSEC; i > 0; --i )
++ int i;
++
++ do {
++ for (i = uSEC; i > 0; --i)
++ barrier();
++ } while (!(scc.cha_a_ctrl & 0x04)); /* wait for tx buf empty */
++ for (i = uSEC; i > 0; --i)
+ barrier();
+- } while (!(scc.cha_a_ctrl & 0x04)); /* wait for tx buf empty */
+- for( i = uSEC; i > 0; --i )
+- barrier();
+- scc.cha_a_data = c;
+-}
+-
+-void mac_sccb_console_write (struct console *co, const char *str,
+- unsigned int count)
+-{
+- while (count--) {
+- if (*str == '\n')
+- mac_sccb_out( '\r' );
+- mac_sccb_out( *str++ );
+- }
+-}
+-
+-void mac_scca_console_write (struct console *co, const char *str,
+- unsigned int count)
+-{
+- while (count--) {
+- if (*str == '\n')
+- mac_scca_out( '\r' );
+- mac_scca_out( *str++ );
+- }
++ scc.cha_a_data = c;
++}
++
++void mac_sccb_console_write(struct console *co, const char *str,
++ unsigned int count)
++{
++ while (count--) {
++ if (*str == '\n')
++ mac_sccb_out('\r');
++ mac_sccb_out(*str++);
++ }
++}
++
++void mac_scca_console_write(struct console *co, const char *str,
++ unsigned int count)
++{
++ while (count--) {
++ if (*str == '\n')
++ mac_scca_out('\r');
++ mac_scca_out(*str++);
++ }
+ }
+
+
+@@ -239,41 +238,41 @@ void mac_scca_console_write (struct cons
+ * SCC serial ports. They're used by the debugging interface, kgdb, and the
+ * serial console code. */
+ #define SCCB_WRITE(reg,val) \
+- do { \
+- int i; \
+- scc.cha_b_ctrl = (reg); \
+- for( i = uSEC; i > 0; --i ) \
+- barrier(); \
+- scc.cha_b_ctrl = (val); \
+- for( i = uSEC; i > 0; --i ) \
+- barrier(); \
+- } while(0)
++ do { \
++ int i; \
++ scc.cha_b_ctrl = (reg); \
++ for (i = uSEC; i > 0; --i) \
++ barrier(); \
++ scc.cha_b_ctrl = (val); \
++ for (i = uSEC; i > 0; --i) \
++ barrier(); \
++ } while(0)
+
+ #define SCCA_WRITE(reg,val) \
+- do { \
+- int i; \
+- scc.cha_a_ctrl = (reg); \
+- for( i = uSEC; i > 0; --i ) \
+- barrier(); \
+- scc.cha_a_ctrl = (val); \
+- for( i = uSEC; i > 0; --i ) \
+- barrier(); \
+- } while(0)
++ do { \
++ int i; \
++ scc.cha_a_ctrl = (reg); \
++ for (i = uSEC; i > 0; --i) \
++ barrier(); \
++ scc.cha_a_ctrl = (val); \
++ for (i = uSEC; i > 0; --i) \
++ barrier(); \
++ } while(0)
+
+ /* loops_per_jiffy isn't initialized yet, so we can't use udelay(). This does a
+ * delay of ~ 60us. */
+ /* Mac: loops_per_jiffy min. 19000 ^= .5 us; MFPDELAY was 0.6 us*/
+-#define LONG_DELAY() \
+- do { \
+- int i; \
+- for( i = 60*uSEC; i > 0; --i ) \
+- barrier(); \
+- } while(0)
++#define LONG_DELAY() \
++ do { \
++ int i; \
++ for (i = 60*uSEC; i > 0; --i) \
++ barrier(); \
++ } while(0)
+
+ #ifndef CONFIG_SERIAL_CONSOLE
+-static void __init mac_init_scc_port( int cflag, int port )
++static void __init mac_init_scc_port(int cflag, int port)
+ #else
+-void mac_init_scc_port( int cflag, int port )
++void mac_init_scc_port(int cflag, int port)
+ #endif
+ {
+ extern int mac_SCC_reset_done;
+@@ -292,71 +291,71 @@ void mac_init_scc_port( int cflag, int p
+ /* reg12 (BRG low) */
+ { 94, 62, 46, 22, 10, 4, 1, 0, 0 };
+
+- int baud = cflag & CBAUD;
+- int clksrc, clkmode, div, reg3, reg5;
++ int baud = cflag & CBAUD;
++ int clksrc, clkmode, div, reg3, reg5;
+
+- if (cflag & CBAUDEX)
+- baud += B38400;
+- if (baud < B1200 || baud > B38400+2)
+- baud = B9600; /* use default 9600bps for non-implemented rates */
+- baud -= B1200; /* tables starts at 1200bps */
+-
+- clksrc = clksrc_table[baud];
+- clkmode = clkmode_table[baud];
+- div = div_table[baud];
+-
+- reg3 = (((cflag & CSIZE) == CS8) ? 0xc0 : 0x40);
+- reg5 = (((cflag & CSIZE) == CS8) ? 0x60 : 0x20) | 0x82 /* assert DTR/RTS */;
+-
+- if (port == 1) {
+- (void)scc.cha_b_ctrl; /* reset reg pointer */
+- SCCB_WRITE( 9, 0xc0 ); /* reset */
+- LONG_DELAY(); /* extra delay after WR9 access */
+- SCCB_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
+- 0x04 /* 1 stopbit */ |
+- clkmode );
+- SCCB_WRITE( 3, reg3 );
+- SCCB_WRITE( 5, reg5 );
+- SCCB_WRITE( 9, 0 ); /* no interrupts */
+- LONG_DELAY(); /* extra delay after WR9 access */
+- SCCB_WRITE( 10, 0 ); /* NRZ mode */
+- SCCB_WRITE( 11, clksrc ); /* main clock source */
+- SCCB_WRITE( 12, div ); /* BRG value */
+- SCCB_WRITE( 13, 0 ); /* BRG high byte */
+- SCCB_WRITE( 14, 1 );
+- SCCB_WRITE( 3, reg3 | 1 );
+- SCCB_WRITE( 5, reg5 | 8 );
+- } else if (port == 0) {
+- (void)scc.cha_a_ctrl; /* reset reg pointer */
+- SCCA_WRITE( 9, 0xc0 ); /* reset */
+- LONG_DELAY(); /* extra delay after WR9 access */
+- SCCA_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
++ if (cflag & CBAUDEX)
++ baud += B38400;
++ if (baud < B1200 || baud > B38400+2)
++ baud = B9600; /* use default 9600bps for non-implemented rates */
++ baud -= B1200; /* tables starts at 1200bps */
++
++ clksrc = clksrc_table[baud];
++ clkmode = clkmode_table[baud];
++ div = div_table[baud];
++
++ reg3 = (((cflag & CSIZE) == CS8) ? 0xc0 : 0x40);
++ reg5 = (((cflag & CSIZE) == CS8) ? 0x60 : 0x20) | 0x82 /* assert DTR/RTS */;
++
++ if (port == 1) {
++ (void)scc.cha_b_ctrl; /* reset reg pointer */
++ SCCB_WRITE(9, 0xc0); /* reset */
++ LONG_DELAY(); /* extra delay after WR9 access */
++ SCCB_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
++ 0x04 /* 1 stopbit */ |
++ clkmode);
++ SCCB_WRITE(3, reg3);
++ SCCB_WRITE(5, reg5);
++ SCCB_WRITE(9, 0); /* no interrupts */
++ LONG_DELAY(); /* extra delay after WR9 access */
++ SCCB_WRITE(10, 0); /* NRZ mode */
++ SCCB_WRITE(11, clksrc); /* main clock source */
++ SCCB_WRITE(12, div); /* BRG value */
++ SCCB_WRITE(13, 0); /* BRG high byte */
++ SCCB_WRITE(14, 1);
++ SCCB_WRITE(3, reg3 | 1);
++ SCCB_WRITE(5, reg5 | 8);
++ } else if (port == 0) {
++ (void)scc.cha_a_ctrl; /* reset reg pointer */
++ SCCA_WRITE(9, 0xc0); /* reset */
++ LONG_DELAY(); /* extra delay after WR9 access */
++ SCCA_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
+ 0x04 /* 1 stopbit */ |
+- clkmode );
+- SCCA_WRITE( 3, reg3 );
+- SCCA_WRITE( 5, reg5 );
+- SCCA_WRITE( 9, 0 ); /* no interrupts */
+- LONG_DELAY(); /* extra delay after WR9 access */
+- SCCA_WRITE( 10, 0 ); /* NRZ mode */
+- SCCA_WRITE( 11, clksrc ); /* main clock source */
+- SCCA_WRITE( 12, div ); /* BRG value */
+- SCCA_WRITE( 13, 0 ); /* BRG high byte */
+- SCCA_WRITE( 14, 1 );
+- SCCA_WRITE( 3, reg3 | 1 );
+- SCCA_WRITE( 5, reg5 | 8 );
+- }
++ clkmode);
++ SCCA_WRITE(3, reg3);
++ SCCA_WRITE(5, reg5);
++ SCCA_WRITE(9, 0); /* no interrupts */
++ LONG_DELAY(); /* extra delay after WR9 access */
++ SCCA_WRITE(10, 0); /* NRZ mode */
++ SCCA_WRITE(11, clksrc); /* main clock source */
++ SCCA_WRITE(12, div); /* BRG value */
++ SCCA_WRITE(13, 0); /* BRG high byte */
++ SCCA_WRITE(14, 1);
++ SCCA_WRITE(3, reg3 | 1);
++ SCCA_WRITE(5, reg5 | 8);
++ }
+
+- mac_SCC_reset_done = 1;
+- mac_SCC_init_done = 1;
++ mac_SCC_reset_done = 1;
++ mac_SCC_init_done = 1;
+ }
+ #endif /* DEBUG_SERIAL */
+
+-void mac_init_scca_port( int cflag )
++void mac_init_scca_port(int cflag)
+ {
+ mac_init_scc_port(cflag, 0);
+ }
+
+-void mac_init_sccb_port( int cflag )
++void mac_init_sccb_port(int cflag)
+ {
+ mac_init_scc_port(cflag, 1);
+ }
+@@ -364,34 +363,26 @@ void mac_init_sccb_port( int cflag )
+ void __init mac_debug_init(void)
+ {
+ #ifdef DEBUG_SERIAL
+- if ( !strcmp( m68k_debug_device, "ser" )
+- || !strcmp( m68k_debug_device, "ser1" )) {
+- /* Mac modem port */
+- mac_init_scc_port( B9600|CS8, 0 );
+- mac_console_driver.write = mac_scca_console_write;
+- scc_port = 0;
+- }
+- else if (!strcmp( m68k_debug_device, "ser2" )) {
+- /* Mac printer port */
+- mac_init_scc_port( B9600|CS8, 1 );
+- mac_console_driver.write = mac_sccb_console_write;
+- scc_port = 1;
+- }
++ if (!strcmp(m68k_debug_device, "ser") ||
++ !strcmp(m68k_debug_device, "ser1")) {
++ /* Mac modem port */
++ mac_init_scc_port(B9600|CS8, 0);
++ mac_console_driver.write = mac_scca_console_write;
++ scc_port = 0;
++ } else if (!strcmp(m68k_debug_device, "ser2")) {
++ /* Mac printer port */
++ mac_init_scc_port(B9600|CS8, 1);
++ mac_console_driver.write = mac_sccb_console_write;
++ scc_port = 1;
++ }
+ #endif
+ #ifdef DEBUG_HEADS
+- if ( !strcmp( m68k_debug_device, "scn" )
+- || !strcmp( m68k_debug_device, "con" )) {
+- /* display, using head.S console routines */
+- mac_console_driver.write = mac_debug_console_write;
+- }
++ if (!strcmp(m68k_debug_device, "scn") ||
++ !strcmp(m68k_debug_device, "con")) {
++ /* display, using head.S console routines */
++ mac_console_driver.write = mac_debug_console_write;
++ }
+ #endif
+- if (mac_console_driver.write)
+- register_console(&mac_console_driver);
++ if (mac_console_driver.write)
++ register_console(&mac_console_driver);
+ }
+-
+-/*
+- * Local variables:
+- * c-indent-level: 4
+- * tab-width: 8
+- * End:
+- */
+--- linux-m68k-2.6.21.orig/arch/m68k/q40/config.c
++++ linux-m68k-2.6.21/arch/m68k/q40/config.c
+@@ -35,35 +35,35 @@
+ #include <asm/machdep.h>
+ #include <asm/q40_master.h>
+
+-extern irqreturn_t q40_process_int (int level, struct pt_regs *regs);
+-extern void q40_init_IRQ (void);
++extern irqreturn_t q40_process_int(int level, struct pt_regs *regs);
++extern void q40_init_IRQ(void);
+ static void q40_get_model(char *model);
+ static int q40_get_hardware_list(char *buffer);
+ extern void q40_sched_init(irq_handler_t handler);
+
+-extern unsigned long q40_gettimeoffset (void);
+-extern int q40_hwclk (int, struct rtc_time *);
+-extern unsigned int q40_get_ss (void);
+-extern int q40_set_clock_mmss (unsigned long);
++extern unsigned long q40_gettimeoffset(void);
++extern int q40_hwclk(int, struct rtc_time *);
++extern unsigned int q40_get_ss(void);
++extern int q40_set_clock_mmss(unsigned long);
+ static int q40_get_rtc_pll(struct rtc_pll_info *pll);
+ static int q40_set_rtc_pll(struct rtc_pll_info *pll);
+-extern void q40_reset (void);
++extern void q40_reset(void);
+ void q40_halt(void);
+ extern void q40_waitbut(void);
+-void q40_set_vectors (void);
++void q40_set_vectors(void);
+
+-extern void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/ );
++extern void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/);
+
+ extern char m68k_debug_device[];
+ static void q40_mem_console_write(struct console *co, const char *b,
+- unsigned int count);
++ unsigned int count);
+
+ extern int ql_ticks;
+
+ static struct console q40_console_driver = {
+- .name = "debug",
+- .flags = CON_PRINTBUFFER,
+- .index = -1,
++ .name = "debug",
++ .flags = CON_PRINTBUFFER,
++ .index = -1,
+ };
+
+
+@@ -74,150 +74,157 @@ static int _cpleft;
+ static void q40_mem_console_write(struct console *co, const char *s,
+ unsigned int count)
+ {
+- char *p=(char *)s;
++ const char *p = s;
+
+- if (count<_cpleft)
+- while (count-- >0){
+- *q40_mem_cptr=*p++;
+- q40_mem_cptr+=4;
+- _cpleft--;
+- }
++ if (count < _cpleft) {
++ while (count-- > 0) {
++ *q40_mem_cptr = *p++;
++ q40_mem_cptr += 4;
++ _cpleft--;
++ }
++ }
+ }
++
+ #if 0
+ void printq40(char *str)
+ {
+- int l=strlen(str);
+- char *p=q40_mem_cptr;
++ int l = strlen(str);
++ char *p = q40_mem_cptr;
+
+- while (l-- >0 && _cpleft-- >0)
+- {
+- *p=*str++;
+- p+=4;
+- }
+- q40_mem_cptr=p;
++ while (l-- > 0 && _cpleft-- > 0) {
++ *p = *str++;
++ p += 4;
++ }
++ q40_mem_cptr = p;
+ }
+ #endif
+
+-static int halted=0;
++static int halted;
+
+ #ifdef CONFIG_HEARTBEAT
+ static void q40_heartbeat(int on)
+ {
+- if (halted) return;
++ if (halted)
++ return;
+
+- if (on)
+- Q40_LED_ON();
+- else
+- Q40_LED_OFF();
++ if (on)
++ Q40_LED_ON();
++ else
++ Q40_LED_OFF();
+ }
+ #endif
+
+ void q40_reset(void)
+ {
+- halted=1;
+- printk ("\n\n*******************************************\n"
++ halted = 1;
++ printk("\n\n*******************************************\n"
+ "Called q40_reset : press the RESET button!! \n"
+ "*******************************************\n");
+ Q40_LED_ON();
+- while(1) ;
++ while (1)
++ ;
+ }
+ void q40_halt(void)
+ {
+- halted=1;
+- printk ("\n\n*******************\n"
+- " Called q40_halt\n"
+- "*******************\n");
++ halted = 1;
++ printk("\n\n*******************\n"
++ " Called q40_halt\n"
++ "*******************\n");
+ Q40_LED_ON();
+- while(1) ;
++ while (1)
++ ;
+ }
+
+ static void q40_get_model(char *model)
+ {
+- sprintf(model, "Q40");
++ sprintf(model, "Q40");
+ }
+
+ /* No hardware options on Q40? */
+
+ static int q40_get_hardware_list(char *buffer)
+ {
+- *buffer = '\0';
+- return 0;
++ *buffer = '\0';
++ return 0;
+ }
+
+-static unsigned int serports[]={0x3f8,0x2f8,0x3e8,0x2e8,0};
++static unsigned int serports[] =
++{
++ 0x3f8,0x2f8,0x3e8,0x2e8,0
++};
+ void q40_disable_irqs(void)
+ {
+- unsigned i,j;
++ unsigned i, j;
+
+- j=0;
+- while((i=serports[j++])) outb(0,i+UART_IER);
+- master_outb(0,EXT_ENABLE_REG);
+- master_outb(0,KEY_IRQ_ENABLE_REG);
++ j = 0;
++ while ((i = serports[j++]))
++ outb(0, i + UART_IER);
++ master_outb(0, EXT_ENABLE_REG);
++ master_outb(0, KEY_IRQ_ENABLE_REG);
+ }
+
+ void __init config_q40(void)
+ {
+- mach_sched_init = q40_sched_init;
++ mach_sched_init = q40_sched_init;
+
+- mach_init_IRQ = q40_init_IRQ;
+- mach_gettimeoffset = q40_gettimeoffset;
+- mach_hwclk = q40_hwclk;
+- mach_get_ss = q40_get_ss;
+- mach_get_rtc_pll = q40_get_rtc_pll;
+- mach_set_rtc_pll = q40_set_rtc_pll;
+- mach_set_clock_mmss = q40_set_clock_mmss;
+-
+- mach_reset = q40_reset;
+- mach_get_model = q40_get_model;
+- mach_get_hardware_list = q40_get_hardware_list;
++ mach_init_IRQ = q40_init_IRQ;
++ mach_gettimeoffset = q40_gettimeoffset;
++ mach_hwclk = q40_hwclk;
++ mach_get_ss = q40_get_ss;
++ mach_get_rtc_pll = q40_get_rtc_pll;
++ mach_set_rtc_pll = q40_set_rtc_pll;
++ mach_set_clock_mmss = q40_set_clock_mmss;
++
++ mach_reset = q40_reset;
++ mach_get_model = q40_get_model;
++ mach_get_hardware_list = q40_get_hardware_list;
+
+ #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
+- mach_beep = q40_mksound;
++ mach_beep = q40_mksound;
+ #endif
+ #ifdef CONFIG_HEARTBEAT
+- mach_heartbeat = q40_heartbeat;
++ mach_heartbeat = q40_heartbeat;
+ #endif
+- mach_halt = q40_halt;
++ mach_halt = q40_halt;
+
+- /* disable a few things that SMSQ might have left enabled */
+- q40_disable_irqs();
++ /* disable a few things that SMSQ might have left enabled */
++ q40_disable_irqs();
+
+- /* no DMA at all, but ide-scsi requires it.. make sure
+- * all physical RAM fits into the boundary - otherwise
+- * allocator may play costly and useless tricks */
+- mach_max_dma_address = 1024*1024*1024;
+-
+- /* useful for early debugging stages - writes kernel messages into SRAM */
+- if (!strncmp( m68k_debug_device,"mem",3 ))
+- {
+- /*printk("using NVRAM debug, q40_mem_cptr=%p\n",q40_mem_cptr);*/
+- _cpleft=2000-((long)q40_mem_cptr-0xff020000)/4;
+- q40_console_driver.write = q40_mem_console_write;
+- register_console(&q40_console_driver);
+- }
++ /* no DMA at all, but ide-scsi requires it.. make sure
++ * all physical RAM fits into the boundary - otherwise
++ * allocator may play costly and useless tricks */
++ mach_max_dma_address = 1024*1024*1024;
++
++ /* useful for early debugging stages - writes kernel messages into SRAM */
++ if (!strncmp( m68k_debug_device,"mem", 3)) {
++ /*printk("using NVRAM debug, q40_mem_cptr=%p\n",q40_mem_cptr);*/
++ _cpleft = 2000 - ((long)q40_mem_cptr-0xff020000) / 4;
++ q40_console_driver.write = q40_mem_console_write;
++ register_console(&q40_console_driver);
++ }
+ }
+
+
+ int q40_parse_bootinfo(const struct bi_record *rec)
+ {
+- return 1;
++ return 1;
+ }
+
+
+-static inline unsigned char bcd2bin (unsigned char b)
++static inline unsigned char bcd2bin(unsigned char b)
+ {
+- return ((b>>4)*10 + (b&15));
++ return (b >> 4) * 10 + (b & 15);
+ }
+
+-static inline unsigned char bin2bcd (unsigned char b)
++static inline unsigned char bin2bcd(unsigned char b)
+ {
+- return (((b/10)*16) + (b%10));
++ return (b / 10) * 16 + (b % 10);
+ }
+
+
+-unsigned long q40_gettimeoffset (void)
++unsigned long q40_gettimeoffset(void)
+ {
+- return 5000*(ql_ticks!=0);
++ return 5000 * (ql_ticks != 0);
+ }
+
+
+@@ -238,9 +245,9 @@ unsigned long q40_gettimeoffset (void)
+
+ int q40_hwclk(int op, struct rtc_time *t)
+ {
+- if (op)
+- { /* Write.... */
+- Q40_RTC_CTRL |= Q40_RTC_WRITE;
++ if (op) {
++ /* Write.... */
++ Q40_RTC_CTRL |= Q40_RTC_WRITE;
+
+ Q40_RTC_SECS = bin2bcd(t->tm_sec);
+ Q40_RTC_MINS = bin2bcd(t->tm_min);
+@@ -251,25 +258,23 @@ int q40_hwclk(int op, struct rtc_time *t
+ if (t->tm_wday >= 0)
+ Q40_RTC_DOW = bin2bcd(t->tm_wday+1);
+
+- Q40_RTC_CTRL &= ~(Q40_RTC_WRITE);
+- }
+- else
+- { /* Read.... */
+- Q40_RTC_CTRL |= Q40_RTC_READ;
+-
+- t->tm_year = bcd2bin (Q40_RTC_YEAR);
+- t->tm_mon = bcd2bin (Q40_RTC_MNTH)-1;
+- t->tm_mday = bcd2bin (Q40_RTC_DATE);
+- t->tm_hour = bcd2bin (Q40_RTC_HOUR);
+- t->tm_min = bcd2bin (Q40_RTC_MINS);
+- t->tm_sec = bcd2bin (Q40_RTC_SECS);
+-
+- Q40_RTC_CTRL &= ~(Q40_RTC_READ);
+-
+- if (t->tm_year < 70)
+- t->tm_year += 100;
+- t->tm_wday = bcd2bin(Q40_RTC_DOW)-1;
+-
++ Q40_RTC_CTRL &= ~(Q40_RTC_WRITE);
++ } else {
++ /* Read.... */
++ Q40_RTC_CTRL |= Q40_RTC_READ;
++
++ t->tm_year = bcd2bin (Q40_RTC_YEAR);
++ t->tm_mon = bcd2bin (Q40_RTC_MNTH)-1;
++ t->tm_mday = bcd2bin (Q40_RTC_DATE);
++ t->tm_hour = bcd2bin (Q40_RTC_HOUR);
++ t->tm_min = bcd2bin (Q40_RTC_MINS);
++ t->tm_sec = bcd2bin (Q40_RTC_SECS);
++
++ Q40_RTC_CTRL &= ~(Q40_RTC_READ);
++
++ if (t->tm_year < 70)
++ t->tm_year += 100;
++ t->tm_wday = bcd2bin(Q40_RTC_DOW)-1;
+ }
+
+ return 0;
+@@ -285,29 +290,25 @@ unsigned int q40_get_ss(void)
+ * clock is out by > 30 minutes. Logic lifted from atari code.
+ */
+
+-int q40_set_clock_mmss (unsigned long nowtime)
++int q40_set_clock_mmss(unsigned long nowtime)
+ {
+ int retval = 0;
+ short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
+
+ int rtc_minutes;
+
++ rtc_minutes = bcd2bin(Q40_RTC_MINS);
+
+- rtc_minutes = bcd2bin (Q40_RTC_MINS);
+-
+- if ((rtc_minutes < real_minutes
+- ? real_minutes - rtc_minutes
+- : rtc_minutes - real_minutes) < 30)
+- {
+- Q40_RTC_CTRL |= Q40_RTC_WRITE;
++ if ((rtc_minutes < real_minutes ?
++ real_minutes - rtc_minutes :
++ rtc_minutes - real_minutes) < 30) {
++ Q40_RTC_CTRL |= Q40_RTC_WRITE;
+ Q40_RTC_MINS = bin2bcd(real_minutes);
+ Q40_RTC_SECS = bin2bcd(real_seconds);
+ Q40_RTC_CTRL &= ~(Q40_RTC_WRITE);
+- }
+- else
++ } else
+ retval = -1;
+
+-
+ return retval;
+ }
+
+@@ -318,21 +319,23 @@ int q40_set_clock_mmss (unsigned long no
+
+ static int q40_get_rtc_pll(struct rtc_pll_info *pll)
+ {
+- int tmp=Q40_RTC_CTRL;
++ int tmp = Q40_RTC_CTRL;
++
+ pll->pll_value = tmp & Q40_RTC_PLL_MASK;
+ if (tmp & Q40_RTC_PLL_SIGN)
+ pll->pll_value = -pll->pll_value;
+- pll->pll_max=31;
+- pll->pll_min=-31;
+- pll->pll_posmult=512;
+- pll->pll_negmult=256;
+- pll->pll_clock=125829120;
++ pll->pll_max = 31;
++ pll->pll_min = -31;
++ pll->pll_posmult = 512;
++ pll->pll_negmult = 256;
++ pll->pll_clock = 125829120;
++
+ return 0;
+ }
+
+ static int q40_set_rtc_pll(struct rtc_pll_info *pll)
+ {
+- if (!pll->pll_ctrl){
++ if (!pll->pll_ctrl) {
+ /* the docs are a bit unclear so I am doublesetting */
+ /* RTC_WRITE here ... */
+ int tmp = (pll->pll_value & 31) | (pll->pll_value<0 ? 32 : 0) |
+--- linux-m68k-2.6.21.orig/arch/m68k/sun3x/prom.c
++++ linux-m68k-2.6.21/arch/m68k/sun3x/prom.c
+@@ -34,43 +34,43 @@ e_vector *sun3x_prom_vbr;
+ /* Handle returning to the prom */
+ void sun3x_halt(void)
+ {
+- unsigned long flags;
++ unsigned long flags;
+
+- /* Disable interrupts while we mess with things */
+- local_irq_save(flags);
++ /* Disable interrupts while we mess with things */
++ local_irq_save(flags);
+
+- /* Restore prom vbr */
+- __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr));
++ /* Restore prom vbr */
++ asm volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr));
+
+- /* Restore prom NMI clock */
+-// sun3x_disable_intreg(5);
+- sun3_enable_irq(7);
++ /* Restore prom NMI clock */
++// sun3x_disable_intreg(5);
++ sun3_enable_irq(7);
+
+- /* Let 'er rip */
+- __asm__ volatile ("trap #14" : : );
++ /* Let 'er rip */
++ asm volatile ("trap #14");
+
+- /* Restore everything */
+- sun3_disable_irq(7);
+- sun3_enable_irq(5);
++ /* Restore everything */
++ sun3_disable_irq(7);
++ sun3_enable_irq(5);
+
+- __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors));
+- local_irq_restore(flags);
++ asm volatile ("movec %0,%%vbr" : : "r" ((void*)vectors));
++ local_irq_restore(flags);
+ }
+
+ void sun3x_reboot(void)
+ {
+- /* This never returns, don't bother saving things */
+- local_irq_disable();
++ /* This never returns, don't bother saving things */
++ local_irq_disable();
+
+- /* Restore prom vbr */
+- __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr));
++ /* Restore prom vbr */
++ asm volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr));
+
+- /* Restore prom NMI clock */
+- sun3_disable_irq(5);
+- sun3_enable_irq(7);
++ /* Restore prom NMI clock */
++ sun3_disable_irq(5);
++ sun3_enable_irq(7);
+
+- /* Let 'er rip */
+- (*romvec->pv_reboot)("vmlinux");
++ /* Let 'er rip */
++ (*romvec->pv_reboot)("vmlinux");
+ }
+
+ extern char m68k_debug_device[];
+@@ -78,54 +78,52 @@ extern char m68k_debug_device[];
+ static void sun3x_prom_write(struct console *co, const char *s,
+ unsigned int count)
+ {
+- while (count--) {
+- if (*s == '\n')
+- sun3x_putchar('\r');
+- sun3x_putchar(*s++);
+- }
++ while (count--) {
++ if (*s == '\n')
++ sun3x_putchar('\r');
++ sun3x_putchar(*s++);
++ }
+ }
+
+ /* debug console - write-only */
+
+ static struct console sun3x_debug = {
+- .name = "debug",
+- .write = sun3x_prom_write,
+- .flags = CON_PRINTBUFFER,
+- .index = -1,
++ .name = "debug",
++ .write = sun3x_prom_write,
++ .flags = CON_PRINTBUFFER,
++ .index = -1,
+ };
+
+ void sun3x_prom_init(void)
+ {
+- /* Read the vector table */
++ /* Read the vector table */
+
+- sun3x_putchar = *(void (**)(int)) (SUN3X_P_PUTCHAR);
+- sun3x_getchar = *(int (**)(void)) (SUN3X_P_GETCHAR);
+- sun3x_mayget = *(int (**)(void)) (SUN3X_P_MAYGET);
+- sun3x_mayput = *(int (**)(int)) (SUN3X_P_MAYPUT);
+- sun3x_prom_reboot = *(void (**)(void)) (SUN3X_P_REBOOT);
+- sun3x_prom_abort = *(e_vector *) (SUN3X_P_ABORT);
+- romvec = (struct linux_romvec *)SUN3X_PROM_BASE;
+-
+- idprom_init();
+-
+- if(!((idprom->id_machtype & SM_ARCH_MASK) == SM_SUN3X)) {
+- printk("Warning: machine reports strange type %02x\n",
+- idprom->id_machtype);
+- printk("Pretending it's a 3/80, but very afraid...\n");
+- idprom->id_machtype = SM_SUN3X | SM_3_80;
+- }
+-
+- /* point trap #14 at abort.
+- * XXX this is futile since we restore the vbr first - oops
+- */
+- vectors[VEC_TRAP14] = sun3x_prom_abort;
+-
+- /* If debug=prom was specified, start the debug console */
+-
+- if (!strcmp(m68k_debug_device, "prom"))
+- register_console(&sun3x_debug);
++ sun3x_putchar = *(void (**)(int)) (SUN3X_P_PUTCHAR);
++ sun3x_getchar = *(int (**)(void)) (SUN3X_P_GETCHAR);
++ sun3x_mayget = *(int (**)(void)) (SUN3X_P_MAYGET);
++ sun3x_mayput = *(int (**)(int)) (SUN3X_P_MAYPUT);
++ sun3x_prom_reboot = *(void (**)(void)) (SUN3X_P_REBOOT);
++ sun3x_prom_abort = *(e_vector *) (SUN3X_P_ABORT);
++ romvec = (struct linux_romvec *)SUN3X_PROM_BASE;
++
++ idprom_init();
++
++ if (!((idprom->id_machtype & SM_ARCH_MASK) == SM_SUN3X)) {
++ printk("Warning: machine reports strange type %02x\n",
++ idprom->id_machtype);
++ printk("Pretending it's a 3/80, but very afraid...\n");
++ idprom->id_machtype = SM_SUN3X | SM_3_80;
++ }
++
++ /* point trap #14 at abort.
++ * XXX this is futile since we restore the vbr first - oops
++ */
++ vectors[VEC_TRAP14] = sun3x_prom_abort;
+
++ /* If debug=prom was specified, start the debug console */
+
++ if (!strcmp(m68k_debug_device, "prom"))
++ register_console(&sun3x_debug);
+ }
+
+ /* some prom functions to export */
+@@ -141,7 +139,6 @@ int prom_getbool (int node, char *prop)
+
+ void prom_printf(char *fmt, ...)
+ {
+-
+ }
+
+ void prom_halt (void)
+@@ -159,7 +156,7 @@ prom_get_idprom(char *idbuf, int num_byt
+ int i;
+
+ /* make a copy of the idprom structure */
+- for(i = 0; i < num_bytes; i++)
++ for (i = 0; i < num_bytes; i++)
+ idbuf[i] = ((char *)SUN3X_IDPROM)[i];
+
+ return idbuf[0];
diff --git a/debian/patches/bugfix/m68k/mac68k-cuda-adb-fixes.diff b/debian/patches/bugfix/m68k/mac68k-cuda-adb-fixes.diff
new file mode 100644
index 000000000000..84932c27c190
--- /dev/null
+++ b/debian/patches/bugfix/m68k/mac68k-cuda-adb-fixes.diff
@@ -0,0 +1,176 @@
+Subject: [PATCH 10/13] CUDA ADB fixes
+Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>,
+ linuxppc-dev@ozlabs.org
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+Fix the flakiness in the CUDA ADB driver on m68k macs (keypresses getting
+wedged down or ADB just going AWOL altogether).
+
+The only IRQ used by this driver is the VIA shift register IRQ. The PowerMac
+conditional code disables the other VIA IRQ sources, so don't mess with the
+other IRQ flags in the common code -- m68k macs need them.
+
+When polling, don't disable local interrupts when we only need to disable the
+CUDA interrupt.
+
+Unless polling, don't clear the shift register IRQ flag. On m68k macs this
+creates a race that often breaks CUDA ADB.
+
+Tested on Quadra 840av and LC630 (both m68k); also Beige G3 (powerpc).
+
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ drivers/macintosh/via-cuda.c | 58 +++++++++++++++++++++++--------------------
+ 1 file changed, 32 insertions(+), 26 deletions(-)
+
+--- linux-m68k-2.6.21.orig/drivers/macintosh/via-cuda.c
++++ linux-m68k-2.6.21/drivers/macintosh/via-cuda.c
+@@ -82,6 +82,7 @@ static unsigned char cuda_rbuf[16];
+ static unsigned char *reply_ptr;
+ static int reading_reply;
+ static int data_index;
++static int cuda_irq;
+ #ifdef CONFIG_PPC
+ static struct device_node *vias;
+ #endif
+@@ -160,10 +161,8 @@ int __init find_via_cuda(void)
+ /* Clear and enable interrupts, but only on PPC. On 68K it's done */
+ /* for us by the main VIA driver in arch/m68k/mac/via.c */
+
+-#ifndef CONFIG_MAC
+ out_8(&via[IFR], 0x7f); /* clear interrupts by writing 1s */
+ out_8(&via[IER], IER_SET|SR_INT); /* enable interrupt from SR */
+-#endif
+
+ /* enable autopoll */
+ cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1);
+@@ -181,24 +180,22 @@ int __init find_via_cuda(void)
+
+ static int __init via_cuda_start(void)
+ {
+- unsigned int irq;
+-
+ if (via == NULL)
+ return -ENODEV;
+
+ #ifdef CONFIG_MAC
+- irq = IRQ_MAC_ADB;
++ cuda_irq = IRQ_MAC_ADB;
+ #else /* CONFIG_MAC */
+- irq = irq_of_parse_and_map(vias, 0);
+- if (irq == NO_IRQ) {
++ cuda_irq = irq_of_parse_and_map(vias, 0);
++ if (cuda_irq == NO_IRQ) {
+ printk(KERN_ERR "via-cuda: can't map interrupts for %s\n",
+ vias->full_name);
+ return -ENODEV;
+ }
+-#endif /* CONFIG_MAP */
++#endif /* CONFIG_MAC */
+
+- if (request_irq(irq, cuda_interrupt, 0, "ADB", cuda_interrupt)) {
+- printk(KERN_ERR "via-cuda: can't request irq %d\n", irq);
++ if (request_irq(cuda_irq, cuda_interrupt, 0, "ADB", cuda_interrupt)) {
++ printk(KERN_ERR "via-cuda: can't request irq %d\n", cuda_irq);
+ return -EAGAIN;
+ }
+
+@@ -238,6 +235,7 @@ cuda_init(void)
+ printk(KERN_ERR "cuda_init_via() failed\n");
+ return -ENODEV;
+ }
++ out_8(&via[IER], IER_SET|SR_INT); /* enable interrupt from SR */
+
+ return via_cuda_start();
+ #endif
+@@ -263,15 +261,17 @@ cuda_init_via(void)
+ out_8(&via[B], in_8(&via[B]) | TACK | TIP); /* negate them */
+ out_8(&via[ACR] ,(in_8(&via[ACR]) & ~SR_CTRL) | SR_EXT); /* SR data in */
+ (void)in_8(&via[SR]); /* clear any left-over data */
+-#ifndef CONFIG_MAC
++#ifdef CONFIG_PPC
+ out_8(&via[IER], 0x7f); /* disable interrupts from VIA */
+ (void)in_8(&via[IER]);
++#else
++ out_8(&via[IER], SR_INT); /* disable SR interrupt from VIA */
+ #endif
+
+ /* delay 4ms and then clear any pending interrupt */
+ mdelay(4);
+ (void)in_8(&via[SR]);
+- out_8(&via[IFR], in_8(&via[IFR]) & 0x7f);
++ out_8(&via[IFR], SR_INT);
+
+ /* sync with the CUDA - assert TACK without TIP */
+ out_8(&via[B], in_8(&via[B]) & ~TACK);
+@@ -282,7 +282,7 @@ cuda_init_via(void)
+ /* wait for the interrupt and then clear it */
+ WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (2)");
+ (void)in_8(&via[SR]);
+- out_8(&via[IFR], in_8(&via[IFR]) & 0x7f);
++ out_8(&via[IFR], SR_INT);
+
+ /* finish the sync by negating TACK */
+ out_8(&via[B], in_8(&via[B]) | TACK);
+@@ -291,7 +291,7 @@ cuda_init_via(void)
+ WAIT_FOR(in_8(&via[B]) & TREQ, "CUDA response to sync (3)");
+ WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (4)");
+ (void)in_8(&via[SR]);
+- out_8(&via[IFR], in_8(&via[IFR]) & 0x7f);
++ out_8(&via[IFR], SR_INT);
+ out_8(&via[B], in_8(&via[B]) | TIP); /* should be unnecessary */
+
+ return 0;
+@@ -428,16 +428,12 @@ cuda_start(void)
+ void
+ cuda_poll(void)
+ {
+- unsigned long flags;
+-
+ /* cuda_interrupt only takes a normal lock, we disable
+ * interrupts here to avoid re-entering and thus deadlocking.
+- * An option would be to disable only the IRQ source with
+- * disable_irq(), would that work on m68k ? --BenH
+ */
+- local_irq_save(flags);
++ disable_irq(cuda_irq);
+ cuda_interrupt(0, NULL);
+- local_irq_restore(flags);
++ enable_irq(cuda_irq);
+ }
+
+ static irqreturn_t
+@@ -448,15 +444,25 @@ cuda_interrupt(int irq, void *arg)
+ unsigned char ibuf[16];
+ int ibuf_len = 0;
+ int complete = 0;
+- unsigned char virq;
+
+ spin_lock(&cuda_lock);
+
+- virq = in_8(&via[IFR]) & 0x7f;
+- out_8(&via[IFR], virq);
+- if ((virq & SR_INT) == 0) {
+- spin_unlock(&cuda_lock);
+- return IRQ_NONE;
++ /* On powermacs, this handler is registered for the VIA IRQ. But it uses
++ * just the shift register IRQ -- other VIA interrupt sources are disabled.
++ * On m68k macs, the VIA IRQ sources are dispatched individually. Unless
++ * we are polling, the shift register IRQ flag has already been cleared.
++ */
++
++#ifdef CONFIG_MAC
++ if (!arg)
++#endif
++ {
++ if ((in_8(&via[IFR]) & SR_INT) == 0) {
++ spin_unlock(&cuda_lock);
++ return IRQ_NONE;
++ } else {
++ out_8(&via[IFR], SR_INT);
++ }
+ }
+
+ status = (~in_8(&via[B]) & (TIP|TREQ)) | (in_8(&via[ACR]) & SR_OUT);
diff --git a/debian/patches/bugfix/m68k/mac68k-finish_irq_cleanup.diff b/debian/patches/bugfix/m68k/mac68k-finish_irq_cleanup.diff
new file mode 100644
index 000000000000..a7f5a343f5a1
--- /dev/null
+++ b/debian/patches/bugfix/m68k/mac68k-finish_irq_cleanup.diff
@@ -0,0 +1,162 @@
+Subject: [PATCH 8/13] m68k: Mac IRQ cleanup
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+There are no slow IRQs on Macs since Roman Zippel's IRQ reorganisation that
+went into 2.6.16 and removed mac_irq_list[] and the do_mac_irq_list()
+dispatcher. (They were implemented in do_mac_irq_list() by lowering the IPL.)
+Hence there's no more use for mutual exclusion in the Mac interrupt
+dispatchers. Remove it.
+
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ arch/m68k/mac/baboon.c | 20 +++++++-------------
+ arch/m68k/mac/oss.c | 4 ----
+ arch/m68k/mac/psc.c | 2 --
+ arch/m68k/mac/via.c | 10 ----------
+ 4 files changed, 7 insertions(+), 29 deletions(-)
+
+--- linux-m68k-2.6.21.orig/arch/m68k/mac/baboon.c
++++ linux-m68k-2.6.21/arch/m68k/mac/baboon.c
+@@ -22,7 +22,7 @@
+ /* #define DEBUG_BABOON */
+ /* #define DEBUG_IRQS */
+
+-int baboon_present,baboon_active;
++int baboon_present;
+ volatile struct baboon *baboon;
+
+ irqreturn_t baboon_irq(int, void *);
+@@ -45,7 +45,6 @@ void __init baboon_init(void)
+
+ baboon = (struct baboon *) BABOON_BASE;
+ baboon_present = 1;
+- baboon_active = 0;
+
+ printk("Baboon detected at %p\n", baboon);
+ }
+@@ -70,9 +69,9 @@ irqreturn_t baboon_irq(int irq, void *de
+ unsigned char events;
+
+ #ifdef DEBUG_IRQS
+- printk("baboon_irq: mb_control %02X mb_ifr %02X mb_status %02X active %02X\n",
++ printk("baboon_irq: mb_control %02X mb_ifr %02X mb_status %02X\n",
+ (uint) baboon->mb_control, (uint) baboon->mb_ifr,
+- (uint) baboon->mb_status, baboon_active);
++ (uint) baboon->mb_status);
+ #endif
+
+ if (!(events = baboon->mb_ifr & 0x07))
+@@ -81,11 +80,9 @@ irqreturn_t baboon_irq(int irq, void *de
+ irq_num = IRQ_BABOON_0;
+ irq_bit = 1;
+ do {
+- if (events & irq_bit/* & baboon_active*/) {
+- baboon_active &= ~irq_bit;
++ if (events & irq_bit) {
+ baboon->mb_ifr &= ~irq_bit;
+ m68k_handle_int(irq_num);
+- baboon_active |= irq_bit;
+ }
+ irq_bit <<= 1;
+ irq_num++;
+@@ -99,21 +96,18 @@ irqreturn_t baboon_irq(int irq, void *de
+ }
+
+ void baboon_irq_enable(int irq) {
+- int irq_idx = IRQ_IDX(irq);
+-
+ #ifdef DEBUG_IRQUSE
+ printk("baboon_irq_enable(%d)\n", irq);
+ #endif
+- baboon_active |= (1 << irq_idx);
++ /* FIXME: figure out how to mask and unmask baboon interrupt sources */
++ enable_irq(IRQ_NUBUS_C);
+ }
+
+ void baboon_irq_disable(int irq) {
+- int irq_idx = IRQ_IDX(irq);
+-
+ #ifdef DEBUG_IRQUSE
+ printk("baboon_irq_disable(%d)\n", irq);
+ #endif
+- baboon_active &= ~(1 << irq_idx);
++ disable_irq(IRQ_NUBUS_C);
+ }
+
+ void baboon_irq_clear(int irq) {
+--- linux-m68k-2.6.21.orig/arch/m68k/mac/oss.c
++++ linux-m68k-2.6.21/arch/m68k/mac/oss.c
+@@ -112,10 +112,8 @@ irqreturn_t oss_irq(int irq, void *dev_i
+ oss->irq_pending &= ~OSS_IP_SOUND;
+ /* FIXME: call sound handler */
+ } else if (events & OSS_IP_SCSI) {
+- oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED;
+ oss->irq_pending &= ~OSS_IP_SCSI;
+ m68k_handle_int(IRQ_MAC_SCSI);
+- oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI;
+ } else {
+ /* FIXME: error check here? */
+ }
+@@ -149,10 +147,8 @@ irqreturn_t oss_nubus_irq(int irq, void
+ --i;
+ irq_bit >>= 1;
+ if (events & irq_bit) {
+- oss->irq_level[i] = OSS_IRQLEV_DISABLED;
+ oss->irq_pending &= ~irq_bit;
+ m68k_handle_int(NUBUS_SOURCE_BASE + i);
+- oss->irq_level[i] = OSS_IRQLEV_NUBUS;
+ }
+ } while(events & (irq_bit - 1));
+ return IRQ_HANDLED;
+--- linux-m68k-2.6.21.orig/arch/m68k/mac/psc.c
++++ linux-m68k-2.6.21/arch/m68k/mac/psc.c
+@@ -147,10 +147,8 @@ irqreturn_t psc_irq(int irq, void *dev_i
+ irq_bit = 1;
+ do {
+ if (events & irq_bit) {
+- psc_write_byte(pIER, irq_bit);
+ psc_write_byte(pIFR, irq_bit);
+ m68k_handle_int(irq_num);
+- psc_write_byte(pIER, irq_bit | 0x80);
+ }
+ irq_num++;
+ irq_bit <<= 1;
+--- linux-m68k-2.6.21.orig/arch/m68k/mac/via.c
++++ linux-m68k-2.6.21/arch/m68k/mac/via.c
+@@ -443,11 +443,6 @@ void __init via_nubus_init(void)
+ /*
+ * The generic VIA interrupt routines (shamelessly stolen from Alan Cox's
+ * via6522.c :-), disable/pending masks added.
+- *
+- * The new interrupt architecture in macints.c takes care of a lot of the
+- * gruntwork for us, including tallying the interrupts and calling the
+- * handlers on the linked list. All we need to do here is basically generate
+- * the machspec interrupt number after clearing the interrupt.
+ */
+
+ irqreturn_t via1_irq(int irq, void *dev_id)
+@@ -463,10 +458,8 @@ irqreturn_t via1_irq(int irq, void *dev_
+ irq_bit = 1;
+ do {
+ if (events & irq_bit) {
+- via1[vIER] = irq_bit;
+ via1[vIFR] = irq_bit;
+ m68k_handle_int(irq_num);
+- via1[vIER] = irq_bit | 0x80;
+ }
+ ++irq_num;
+ irq_bit <<= 1;
+@@ -502,11 +495,8 @@ irqreturn_t via2_irq(int irq, void *dev_
+ irq_bit = 1;
+ do {
+ if (events & irq_bit) {
+- via2[gIER] = irq_bit;
+ via2[gIFR] = irq_bit | rbv_clear;
+ m68k_handle_int(irq_num);
+- if (irq_num != IRQ_MAC_NUBUS || nubus_disabled == 0)
+- via2[gIER] = irq_bit | 0x80;
+ }
+ ++irq_num;
+ irq_bit <<= 1;
diff --git a/debian/patches/bugfix/m68k/mac68k-irq-plan-e.diff b/debian/patches/bugfix/m68k/mac68k-irq-plan-e.diff
new file mode 100644
index 000000000000..fb367101d197
--- /dev/null
+++ b/debian/patches/bugfix/m68k/mac68k-irq-plan-e.diff
@@ -0,0 +1,270 @@
+Subject: [PATCH 7/13] m68k: Mac nubus IRQ fixes (plan E)
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+Some Macs lack a slot interrupt enable register. So the existing code makes
+disabled and unregistered slot IRQ lines outputs set high. This seems to work
+on quadras, but does not work on genuine VIAs (perhaps the card still succeeds
+in pulling the line low, or perhaps because this increases the settle time on
+the port A input, meaning that the CA1 IRQ could fire before the slot line
+reads active).
+
+Because of this, the nubus_active flags were used to mask IRQs, which is
+actually worse than the problem it tries to solve. Any interrupt masked by
+nubus_active will remain asserted and prevent further transitions on CA1. And
+so the nubus gets wedged regardless of hardware (emulated VIA ASIC, real VIA
+chip or RBV).
+
+The best solution to this hardware limitation of genuine VIAs is to disable the
+umbrella SLOTS IRQ when disabling a slot on those machines. Unfortunately, this
+means all slot IRQs get disabled when any slot IRQ is disabled. But it is only
+a problem when there's more than 1 device using nubus interrupts.
+
+Another potential problem for genuine VIAs is an unregistered nubus IRQ.
+Eventually it will be possible to enable the CA1 interrupt by installing its
+handler only _after_ all nubus drivers have loaded but _before_ the kernel
+needs them, at which time this last problem can be fixed. For now it can be
+worked around:
+
+ - disable MacOS extensions
+ - don't boot MacOS (use the Emile bootloader instead)
+ - get the bootloaders to disable ROM drivers (Penguin does this for video
+ cards already, don't know about Emile)
+ - physically remove unsupported cards
+
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ arch/m68k/mac/via.c | 141 +++++++++++++++++++++++++++++-----------------------
+ 1 file changed, 80 insertions(+), 61 deletions(-)
+
+--- linux-m68k-2.6.21.orig/arch/m68k/mac/via.c
++++ linux-m68k-2.6.21/arch/m68k/mac/via.c
+@@ -64,7 +64,19 @@ static int gIER,gIFR,gBufA,gBufB;
+ #define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF)
+ #define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8)
+
+-static int nubus_active;
++/* To disable a NuBus slot on Quadras we make the slot IRQ lines outputs, set
++ * high. On RBV we just use the slot interrupt enable register. On Macs with
++ * genuine VIA chips we must use nubus_disabled to keep track of disabled slot
++ * interrupts. When any slot IRQ is disabled we mask the (edge triggered) CA1
++ * or "SLOTS" interrupt. When no slot is disabled, we unmask the CA1 interrupt.
++ * So, on genuine VIAs, having more than one NuBus IRQ can mean trouble,
++ * because closing one of those drivers can mask all of the NuBus interrupts.
++ * Also, since we can't mask the unregistered slot IRQs on genuine VIAs, it's
++ * possible to get interrupts from cards that MacOS or the ROM has configured
++ * but we have not. FWIW, "Designing Cards and Drivers for Macintosh II and
++ * Macintosh SE", page 9-8, says, a slot IRQ with no driver would crash MacOS.
++ */
++static u8 nubus_disabled;
+
+ void via_debug_dump(void);
+ irqreturn_t via1_irq(int, void *);
+@@ -383,9 +395,6 @@ int via_get_cache_disable(void)
+
+ void __init via_nubus_init(void)
+ {
+- /* don't set nubus_active = 0 here, it kills the Baboon */
+- /* interrupt that we've already registered. */
+-
+ /* unlock nubus transactions */
+
+ if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
+@@ -399,28 +408,35 @@ void __init via_nubus_init(void)
+ via2[gBufB] |= 0x02;
+ }
+
+- /* disable nubus slot interrupts. */
+- if (rbv_present) {
++ /* Disable all the slot interrupts (where possible). */
++
++ switch (macintosh_config->via_type) {
++ case MAC_VIA_II:
++ /* Just make the port A lines inputs. */
++ switch(macintosh_config->ident) {
++ case MAC_MODEL_II:
++ case MAC_MODEL_IIX:
++ case MAC_MODEL_IICX:
++ case MAC_MODEL_SE30:
++ /* The top two bits are RAM size outputs. */
++ via2[vDirA] &= 0xC0;
++ break;
++ default:
++ via2[vDirA] &= 0x80;
++ }
++ break;
++ case MAC_VIA_IIci:
++ /* RBV. Disable all the slot interrupts. SIER works like IER. */
+ via2[rSIER] = 0x7F;
+- via2[rSIER] = nubus_active | 0x80;
+- } else {
+- /* These are ADB bits on PMU */
++ break;
++ case MAC_VIA_QUADRA:
++ /* Disable the inactive slot interrupts by making those lines outputs. */
+ if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
+- (macintosh_config->adb_type != MAC_ADB_PB2)) {
+- switch(macintosh_config->ident)
+- {
+- case MAC_MODEL_II:
+- case MAC_MODEL_IIX:
+- case MAC_MODEL_IICX:
+- case MAC_MODEL_SE30:
+- via2[vBufA] |= 0x3F;
+- via2[vDirA] = ~nubus_active | 0xc0;
+- break;
+- default:
+- via2[vBufA] = 0xFF;
+- via2[vDirA] = ~nubus_active;
+- }
++ (macintosh_config->adb_type != MAC_ADB_PB2)) {
++ via2[vBufA] |= 0x7F;
++ via2[vDirA] |= 0x7F;
+ }
++ break;
+ }
+ }
+
+@@ -489,7 +505,8 @@ irqreturn_t via2_irq(int irq, void *dev_
+ via2[gIER] = irq_bit;
+ via2[gIFR] = irq_bit | rbv_clear;
+ m68k_handle_int(irq_num);
+- via2[gIER] = irq_bit | 0x80;
++ if (irq_num != IRQ_MAC_NUBUS || nubus_disabled == 0)
++ via2[gIER] = irq_bit | 0x80;
+ }
+ ++irq_num;
+ irq_bit <<= 1;
+@@ -511,7 +528,7 @@ irqreturn_t via_nubus_irq(int irq, void
+ if (rbv_present)
+ events &= via2[rSIER];
+ else
+- events &= nubus_active;
++ events &= ~via2[vDirA];
+ if (!events)
+ return IRQ_NONE;
+
+@@ -533,7 +550,7 @@ irqreturn_t via_nubus_irq(int irq, void
+ if (rbv_present)
+ events &= via2[rSIER];
+ else
+- events &= nubus_active;
++ events &= ~via2[vDirA];
+ } while (events);
+ return IRQ_HANDLED;
+ }
+@@ -541,38 +558,38 @@ irqreturn_t via_nubus_irq(int irq, void
+ void via_irq_enable(int irq) {
+ int irq_src = IRQ_SRC(irq);
+ int irq_idx = IRQ_IDX(irq);
+- int irq_bit = 1 << irq_idx;
+
+ #ifdef DEBUG_IRQUSE
+ printk(KERN_DEBUG "via_irq_enable(%d)\n", irq);
+ #endif
+
+ if (irq_src == 1) {
+- via1[vIER] = irq_bit | 0x80;
++ via1[vIER] = IER_SET_BIT(irq_idx);
+ } else if (irq_src == 2) {
+- via2[gIER] = irq_bit | 0x80;
++ if (irq != IRQ_MAC_NUBUS || nubus_disabled == 0)
++ via2[gIER] = IER_SET_BIT(irq_idx);
+ } else if (irq_src == 7) {
+- nubus_active |= irq_bit;
+- if (rbv_present) {
+- /* enable the slot interrupt. SIER works like IER. */
++ switch (macintosh_config->via_type) {
++ case MAC_VIA_II:
++ nubus_disabled &= ~(1 << irq_idx);
++ /* Enable the CA1 interrupt when no slot is disabled. */
++ if (!nubus_disabled)
++ via2[gIER] = IER_SET_BIT(1);
++ break;
++ case MAC_VIA_IIci:
++ /* On RBV, enable the slot interrupt.
++ * SIER works like IER.
++ */
+ via2[rSIER] = IER_SET_BIT(irq_idx);
+- } else {
+- /* Make sure the bit is an input, to enable the irq */
+- /* But not on PowerBooks, that's ADB... */
++ break;
++ case MAC_VIA_QUADRA:
++ /* Make the port A line an input to enable the slot irq.
++ * But not on PowerBooks, that's ADB.
++ */
+ if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
+- (macintosh_config->adb_type != MAC_ADB_PB2)) {
+- switch(macintosh_config->ident)
+- {
+- case MAC_MODEL_II:
+- case MAC_MODEL_IIX:
+- case MAC_MODEL_IICX:
+- case MAC_MODEL_SE30:
+- via2[vDirA] &= (~irq_bit | 0xc0);
+- break;
+- default:
+- via2[vDirA] &= ~irq_bit;
+- }
+- }
++ (macintosh_config->adb_type != MAC_ADB_PB2))
++ via2[vDirA] &= ~(1 << irq_idx);
++ break;
+ }
+ }
+ }
+@@ -580,29 +597,31 @@ void via_irq_enable(int irq) {
+ void via_irq_disable(int irq) {
+ int irq_src = IRQ_SRC(irq);
+ int irq_idx = IRQ_IDX(irq);
+- int irq_bit = 1 << irq_idx;
+
+ #ifdef DEBUG_IRQUSE
+ printk(KERN_DEBUG "via_irq_disable(%d)\n", irq);
+ #endif
+
+ if (irq_src == 1) {
+- via1[vIER] = irq_bit & 0x7F;
++ via1[vIER] = IER_CLR_BIT(irq_idx);
+ } else if (irq_src == 2) {
+- via2[gIER] = irq_bit & 0x7F;
++ via2[gIER] = IER_CLR_BIT(irq_idx);
+ } else if (irq_src == 7) {
+- if (rbv_present) {
+- /* disable the slot interrupt. SIER works like IER. */
++ switch (macintosh_config->via_type) {
++ case MAC_VIA_II:
++ nubus_disabled |= 1 << irq_idx;
++ if (nubus_disabled)
++ via2[gIER] = IER_CLR_BIT(1);
++ break;
++ case MAC_VIA_IIci:
+ via2[rSIER] = IER_CLR_BIT(irq_idx);
+- } else {
+- /* disable the nubus irq by changing dir to output */
+- /* except on PMU */
++ break;
++ case MAC_VIA_QUADRA:
+ if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
+- (macintosh_config->adb_type != MAC_ADB_PB2)) {
+- via2[vDirA] |= irq_bit;
+- }
++ (macintosh_config->adb_type != MAC_ADB_PB2))
++ via2[vDirA] |= 1 << irq_idx;
++ break;
+ }
+- nubus_active &= ~irq_bit;
+ }
+ }
+
+@@ -638,7 +657,7 @@ int via_irq_pending(int irq)
+ } else if (irq_src == 2) {
+ return via2[gIFR] & irq_bit;
+ } else if (irq_src == 7) {
+- /* FIXME: this can't work while a slot irq is disabled! */
++ /* Always 0 for MAC_VIA_QUADRA if the slot irq is disabled. */
+ return ~via2[gBufA] & irq_bit;
+ }
+ return 0;
diff --git a/debian/patches/bugfix/m68k/mac68k-irq-prep.diff b/debian/patches/bugfix/m68k/mac68k-irq-prep.diff
new file mode 100644
index 000000000000..e43e329e9adc
--- /dev/null
+++ b/debian/patches/bugfix/m68k/mac68k-irq-prep.diff
@@ -0,0 +1,375 @@
+Subject: [PATCH 6/13] m68k: Mac IRQ prep
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+Make sure that there are no slot IRQs asserted before leaving the nubus
+handler. If there are and we don't then the nubus gets wedged because this
+prevents a CA1 transition, which means no more nubus IRQs.
+
+Make the interrupt dispatch loops terminate sooner.
+
+Explicitly initialise the VIA latches to make the code more easily understood.
+
+Also some cleanups.
+
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ arch/m68k/mac/baboon.c | 12 ++--
+ arch/m68k/mac/oss.c | 8 ++
+ arch/m68k/mac/psc.c | 19 +++---
+ arch/m68k/mac/via.c | 139 ++++++++++++++++++++++++++++++-------------------
+ 4 files changed, 110 insertions(+), 68 deletions(-)
+
+--- linux-m68k-2.6.21.orig/arch/m68k/mac/baboon.c
++++ linux-m68k-2.6.21/arch/m68k/mac/baboon.c
+@@ -66,7 +66,7 @@ void __init baboon_register_interrupts(v
+
+ irqreturn_t baboon_irq(int irq, void *dev_id)
+ {
+- int irq_bit,i;
++ int irq_bit, irq_num;
+ unsigned char events;
+
+ #ifdef DEBUG_IRQS
+@@ -78,14 +78,18 @@ irqreturn_t baboon_irq(int irq, void *de
+ if (!(events = baboon->mb_ifr & 0x07))
+ return IRQ_NONE;
+
+- for (i = 0, irq_bit = 1 ; i < 3 ; i++, irq_bit <<= 1) {
++ irq_num = IRQ_BABOON_0;
++ irq_bit = 1;
++ do {
+ if (events & irq_bit/* & baboon_active*/) {
+ baboon_active &= ~irq_bit;
+ baboon->mb_ifr &= ~irq_bit;
+- m68k_handle_int(IRQ_BABOON_0 + i);
++ m68k_handle_int(irq_num);
+ baboon_active |= irq_bit;
+ }
+- }
++ irq_bit <<= 1;
++ irq_num++;
++ } while(events >= irq_bit);
+ #if 0
+ if (baboon->mb_ifr & 0x02) macide_ack_intr(NULL);
+ /* for now we need to smash all interrupts */
+--- linux-m68k-2.6.21.orig/arch/m68k/mac/oss.c
++++ linux-m68k-2.6.21/arch/m68k/mac/oss.c
+@@ -143,14 +143,18 @@ irqreturn_t oss_nubus_irq(int irq, void
+ #endif
+ /* There are only six slots on the OSS, not seven */
+
+- for (i = 0, irq_bit = 1 ; i < 6 ; i++, irq_bit <<= 1) {
++ i = 6;
++ irq_bit = 0x40;
++ do {
++ --i;
++ irq_bit >>= 1;
+ if (events & irq_bit) {
+ oss->irq_level[i] = OSS_IRQLEV_DISABLED;
+ oss->irq_pending &= ~irq_bit;
+ m68k_handle_int(NUBUS_SOURCE_BASE + i);
+ oss->irq_level[i] = OSS_IRQLEV_NUBUS;
+ }
+- }
++ } while(events & (irq_bit - 1));
+ return IRQ_HANDLED;
+ }
+
+--- linux-m68k-2.6.21.orig/arch/m68k/mac/psc.c
++++ linux-m68k-2.6.21/arch/m68k/mac/psc.c
+@@ -131,11 +131,8 @@ irqreturn_t psc_irq(int irq, void *dev_i
+ {
+ int pIFR = pIFRbase + ((int) dev_id);
+ int pIER = pIERbase + ((int) dev_id);
+- int base_irq;
+- int irq_bit,i;
+- unsigned char events;
+-
+- base_irq = irq << 3;
++ int irq_num;
++ unsigned char irq_bit, events;
+
+ #ifdef DEBUG_IRQS
+ printk("psc_irq: irq %d pIFR = 0x%02X pIER = 0x%02X\n",
+@@ -146,14 +143,18 @@ irqreturn_t psc_irq(int irq, void *dev_i
+ if (!events)
+ return IRQ_NONE;
+
+- for (i = 0, irq_bit = 1 ; i < 4 ; i++, irq_bit <<= 1) {
+- if (events & irq_bit) {
++ irq_num = irq << 3;
++ irq_bit = 1;
++ do {
++ if (events & irq_bit) {
+ psc_write_byte(pIER, irq_bit);
+ psc_write_byte(pIFR, irq_bit);
+- m68k_handle_int(base_irq + i);
++ m68k_handle_int(irq_num);
+ psc_write_byte(pIER, irq_bit | 0x80);
+ }
+- }
++ irq_num++;
++ irq_bit <<= 1;
++ } while (events >= irq_bit);
+ return IRQ_HANDLED;
+ }
+
+--- linux-m68k-2.6.21.orig/arch/m68k/mac/via.c
++++ linux-m68k-2.6.21/arch/m68k/mac/via.c
+@@ -13,6 +13,10 @@
+ * for info. A full-text web search on 6522 AND VIA will probably also
+ * net some usefulness. <cananian@alumni.princeton.edu> 20apr1999
+ *
++ * Additional data is here (the SY6522 was used in the Mac II etc):
++ * http://www.6502.org/documents/datasheets/synertek/synertek_sy6522.pdf
++ * http://www.6502.org/documents/datasheets/synertek/synertek_sy6522_programming_reference.pdf
++ *
+ * PRAM/RTC access algorithms are from the NetBSD RTC toolkit version 1.08b
+ * by Erik Vogan and adapted to Linux by Joshua M. Thompson (funaho@jurai.org)
+ *
+@@ -37,7 +41,7 @@ volatile __u8 *via1, *via2;
+ /* See note in mac_via.h about how this is possibly not useful */
+ volatile long *via_memory_bogon=(long *)&via_memory_bogon;
+ #endif
+-int rbv_present,via_alt_mapping;
++int rbv_present, via_alt_mapping;
+ __u8 rbv_clear;
+
+ /*
+@@ -138,11 +142,11 @@ void __init via_init(void)
+
+ printk(KERN_INFO "VIA2 at %p is ", via2);
+ if (rbv_present) {
+- printk(KERN_INFO "an RBV\n");
++ printk("an RBV\n");
+ } else if (oss_present) {
+- printk(KERN_INFO "an OSS\n");
++ printk("an OSS\n");
+ } else {
+- printk(KERN_INFO "a 6522 or clone\n");
++ printk("a 6522 or clone\n");
+ }
+
+ #ifdef DEBUG_VIA
+@@ -163,6 +167,7 @@ void __init via_init(void)
+ via1[vT2CL] = 0;
+ via1[vT2CH] = 0;
+ via1[vACR] &= 0x3F;
++ via1[vACR] &= ~0x03; /* disable port A & B latches */
+
+ /*
+ * SE/30: disable video IRQ
+@@ -234,6 +239,22 @@ void __init via_init(void)
+ via2[vT2CL] = 0;
+ via2[vT2CH] = 0;
+ via2[vACR] &= 0x3F;
++ via2[vACR] &= ~0x03; /* disable port A & B latches */
++ }
++
++ /*
++ * Set vPCR for SCSI interrupts (but not on RBV)
++ */
++ if (!rbv_present) {
++ if (macintosh_config->scsi_type == MAC_SCSI_OLD) {
++ /* CB2 (IRQ) indep. input, positive edge */
++ /* CA2 (DRQ) indep. input, positive edge */
++ via2[vPCR] = 0x66;
++ } else {
++ /* CB2 (IRQ) indep. input, negative edge */
++ /* CA2 (DRQ) indep. input, negative edge */
++ via2[vPCR] = 0x22;
++ }
+ }
+ }
+
+@@ -367,19 +388,14 @@ void __init via_nubus_init(void)
+
+ /* unlock nubus transactions */
+
+- if (!rbv_present) {
++ if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
++ (macintosh_config->adb_type != MAC_ADB_PB2)) {
+ /* set the line to be an output on non-RBV machines */
+- if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
+- (macintosh_config->adb_type != MAC_ADB_PB2)) {
++ if (!rbv_present)
+ via2[vDirB] |= 0x02;
+- }
+- }
+-
+- /* this seems to be an ADB bit on PMU machines */
+- /* according to MkLinux. -- jmt */
+
+- if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
+- (macintosh_config->adb_type != MAC_ADB_PB2)) {
++ /* this seems to be an ADB bit on PMU machines */
++ /* according to MkLinux. -- jmt */
+ via2[gBufB] |= 0x02;
+ }
+
+@@ -420,20 +436,25 @@ void __init via_nubus_init(void)
+
+ irqreturn_t via1_irq(int irq, void *dev_id)
+ {
+- int irq_bit, i;
+- unsigned char events, mask;
++ int irq_num;
++ unsigned char irq_bit, events;
+
+- mask = via1[vIER] & 0x7F;
+- if (!(events = via1[vIFR] & mask))
++ events = via1[vIFR] & via1[vIER] & 0x7F;
++ if (!events)
+ return IRQ_NONE;
+
+- for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1)
++ irq_num = VIA1_SOURCE_BASE;
++ irq_bit = 1;
++ do {
+ if (events & irq_bit) {
+ via1[vIER] = irq_bit;
+ via1[vIFR] = irq_bit;
+- m68k_handle_int(VIA1_SOURCE_BASE + i);
++ m68k_handle_int(irq_num);
+ via1[vIER] = irq_bit | 0x80;
+ }
++ ++irq_num;
++ irq_bit <<= 1;
++ } while (events >= irq_bit);
+
+ #if 0 /* freakin' pmu is doing weird stuff */
+ if (!oss_present) {
+@@ -454,20 +475,25 @@ irqreturn_t via1_irq(int irq, void *dev_
+
+ irqreturn_t via2_irq(int irq, void *dev_id)
+ {
+- int irq_bit, i;
+- unsigned char events, mask;
++ int irq_num;
++ unsigned char irq_bit, events;
+
+- mask = via2[gIER] & 0x7F;
+- if (!(events = via2[gIFR] & mask))
++ events = via2[gIFR] & via2[gIER] & 0x7F;
++ if (!events)
+ return IRQ_NONE;
+
+- for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1)
++ irq_num = VIA2_SOURCE_BASE;
++ irq_bit = 1;
++ do {
+ if (events & irq_bit) {
+ via2[gIER] = irq_bit;
+ via2[gIFR] = irq_bit | rbv_clear;
+- m68k_handle_int(VIA2_SOURCE_BASE + i);
++ m68k_handle_int(irq_num);
+ via2[gIER] = irq_bit | 0x80;
+ }
++ ++irq_num;
++ irq_bit <<= 1;
++ } while (events >= irq_bit);
+ return IRQ_HANDLED;
+ }
+
+@@ -478,19 +504,37 @@ irqreturn_t via2_irq(int irq, void *dev_
+
+ irqreturn_t via_nubus_irq(int irq, void *dev_id)
+ {
+- int irq_bit, i;
+- unsigned char events;
++ int slot_irq;
++ unsigned char slot_bit, events;
+
+- if (!(events = ~via2[gBufA] & nubus_active))
++ events = ~via2[gBufA] & 0x7F;
++ if (rbv_present)
++ events &= via2[rSIER];
++ else
++ events &= nubus_active;
++ if (!events)
+ return IRQ_NONE;
+
+- for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) {
+- if (events & irq_bit) {
+- via_irq_disable(NUBUS_SOURCE_BASE + i);
+- m68k_handle_int(NUBUS_SOURCE_BASE + i);
+- via_irq_enable(NUBUS_SOURCE_BASE + i);
+- }
+- }
++ do {
++ slot_irq = IRQ_NUBUS_F;
++ slot_bit = 0x40;
++ do {
++ if (events & slot_bit) {
++ events &= ~slot_bit;
++ m68k_handle_int(slot_irq);
++ }
++ --slot_irq;
++ slot_bit >>= 1;
++ } while (events);
++
++ /* clear the CA1 interrupt and make certain there's no more. */
++ via2[gIFR] = 0x02 | rbv_clear;
++ events = ~via2[gBufA] & 0x7F;
++ if (rbv_present)
++ events &= via2[rSIER];
++ else
++ events &= nubus_active;
++ } while (events);
+ return IRQ_HANDLED;
+ }
+
+@@ -506,20 +550,6 @@ void via_irq_enable(int irq) {
+ if (irq_src == 1) {
+ via1[vIER] = irq_bit | 0x80;
+ } else if (irq_src == 2) {
+- /*
+- * Set vPCR for SCSI interrupts (but not on RBV)
+- */
+- if ((irq_idx == 0) && !rbv_present) {
+- if (macintosh_config->scsi_type == MAC_SCSI_OLD) {
+- /* CB2 (IRQ) indep. input, positive edge */
+- /* CA2 (DRQ) indep. input, positive edge */
+- via2[vPCR] = 0x66;
+- } else {
+- /* CB2 (IRQ) indep. input, negative edge */
+- /* CA2 (DRQ) indep. input, negative edge */
+- via2[vPCR] = 0x22;
+- }
+- }
+ via2[gIER] = irq_bit | 0x80;
+ } else if (irq_src == 7) {
+ nubus_active |= irq_bit;
+@@ -557,9 +587,9 @@ void via_irq_disable(int irq) {
+ #endif
+
+ if (irq_src == 1) {
+- via1[vIER] = irq_bit;
++ via1[vIER] = irq_bit & 0x7F;
+ } else if (irq_src == 2) {
+- via2[gIER] = irq_bit;
++ via2[gIER] = irq_bit & 0x7F;
+ } else if (irq_src == 7) {
+ if (rbv_present) {
+ /* disable the slot interrupt. SIER works like IER. */
+@@ -586,7 +616,9 @@ void via_irq_clear(int irq) {
+ } else if (irq_src == 2) {
+ via2[gIFR] = irq_bit | rbv_clear;
+ } else if (irq_src == 7) {
+- /* FIXME: hmm.. */
++ /* FIXME: There is no way to clear an individual nubus slot
++ * IRQ flag, other than getting the device to do it.
++ */
+ }
+ }
+
+@@ -606,6 +638,7 @@ int via_irq_pending(int irq)
+ } else if (irq_src == 2) {
+ return via2[gIFR] & irq_bit;
+ } else if (irq_src == 7) {
++ /* FIXME: this can't work while a slot irq is disabled! */
+ return ~via2[gBufA] & irq_bit;
+ }
+ return 0;
diff --git a/debian/patches/bugfix/m68k/mac68k-macii-adb-fixes.diff b/debian/patches/bugfix/m68k/mac68k-macii-adb-fixes.diff
new file mode 100644
index 000000000000..b1018ce46e3a
--- /dev/null
+++ b/debian/patches/bugfix/m68k/mac68k-macii-adb-fixes.diff
@@ -0,0 +1,873 @@
+Subject: [PATCH 9/13] m68k: Mac II ADB fixes
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+Fix a crash caused by requests placed in the queue with the completed flag
+already set. This lead to some ADB_SYNC requests returning early and their
+request structs being popped off the stack while still queued. Stack corruption
+ensued or an invalid request callback pointer was invoked or both. Eliminate
+macii_retransmit() and its buggy implementation of macii_write(). Have
+macii_queue_poll() fully initialise the request queues.
+
+Fix a bug in macii_queue_poll() where the last_req pointer was not being set.
+This caused some requests to leave the queue before being completed (and would
+also corrupt the stack under certain conditions).
+
+Fix a race in macii_start that could set the state machine to "reading" while
+current_req was null.
+
+No longer send poll commands with the ADBREQ_REPLY flag -- doing that caused
+the replies to be stored in the request buffer where they were forgotten
+about.
+
+Don't autopoll by continuously sending new Talk commands. Get the controller to
+do that for us. This reduces the ADB interrupt rate on an idle bus to about 5
+per second. Only autopoll the devices that were probed.
+
+Explicitly clear the interrupt flag when polling.
+
+Use disable_irq rather than local_irq_save when polling.
+
+Remove excess local_irq_save/restore pairs.
+
+Improve bus timeout and service request detection.
+
+Remove unused code (last_reply, adb_dir etc) and unneeded code (prefix_len,
+first_byte etc).
+
+Change TIP and TACK to their correct names on this ADB controller (ST_EVEN and
+ST_ODD).
+
+Add some commentry.
+
+Add a generous quantity of sanity checks (BUG_ONs).
+
+Let m68k macs use the adb_sync boot param too.
+
+Tested on Mac II, Mac IIci, Quadra 650, Quadra 700 etc.
+
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ arch/m68k/kernel/setup.c | 10
+ drivers/macintosh/via-macii.c | 582 +++++++++++++++++-------------------------
+ 2 files changed, 251 insertions(+), 341 deletions(-)
+
+--- linux-m68k-2.6.21.orig/arch/m68k/kernel/setup.c
++++ linux-m68k-2.6.21/arch/m68k/kernel/setup.c
+@@ -513,3 +513,13 @@ void check_bugs(void)
+ }
+ #endif /* !CONFIG_M68KFPU_EMU */
+ }
++
++#ifdef CONFIG_ADB
++static int __init adb_probe_sync_enable (char *str) {
++ extern int __adb_probe_sync;
++ __adb_probe_sync = 1;
++ return 1;
++}
++
++__setup("adb_sync", adb_probe_sync_enable);
++#endif /* CONFIG_ADB */
+--- linux-m68k-2.6.21.orig/drivers/macintosh/via-macii.c
++++ linux-m68k-2.6.21/drivers/macintosh/via-macii.c
+@@ -12,6 +12,15 @@
+ * 1999-08-02 (jmt) - Initial rewrite for Unified ADB.
+ * 2000-03-29 Tony Mantler <tonym@mac.linux-m68k.org>
+ * - Big overhaul, should actually work now.
++ * 2006-12-31 Finn Thain <fthain@telegraphics.com.au> - Another overhaul.
++ *
++ * Suggested reading:
++ * Inside Macintosh, ch. 5 ADB Manager
++ * Guide to the Macinstosh Family Hardware, ch. 8 Apple Desktop Bus
++ * Rockwell R6522 VIA datasheet
++ *
++ * Apple's "ADB Analyzer" bus sniffer is invaluable:
++ * ftp://ftp.apple.com/developer/Tool_Chest/Devices_-_Hardware/Apple_Desktop_Bus/
+ */
+
+ #include <stdarg.h>
+@@ -26,7 +35,6 @@
+ #include <asm/macints.h>
+ #include <asm/machw.h>
+ #include <asm/mac_via.h>
+-#include <asm/io.h>
+ #include <asm/system.h>
+
+ static volatile unsigned char *via;
+@@ -51,9 +59,7 @@ static volatile unsigned char *via;
+ #define ANH (15*RS) /* A-side data, no handshake */
+
+ /* Bits in B data register: all active low */
+-#define TREQ 0x08 /* Transfer request (input) */
+-#define TACK 0x10 /* Transfer acknowledge (output) */
+-#define TIP 0x20 /* Transfer in progress (output) */
++#define CTLR_IRQ 0x08 /* Controller rcv status (input) */
+ #define ST_MASK 0x30 /* mask for selecting ADB state bits */
+
+ /* Bits in ACR */
+@@ -65,8 +71,6 @@ static volatile unsigned char *via;
+ #define IER_SET 0x80 /* set bits in IER */
+ #define IER_CLR 0 /* clear bits in IER */
+ #define SR_INT 0x04 /* Shift register full/empty */
+-#define SR_DATA 0x08 /* Shift register data */
+-#define SR_CLOCK 0x10 /* Shift register clock */
+
+ /* ADB transaction states according to GMHW */
+ #define ST_CMD 0x00 /* ADB state: command byte */
+@@ -77,7 +81,6 @@ static volatile unsigned char *via;
+ static int macii_init_via(void);
+ static void macii_start(void);
+ static irqreturn_t macii_interrupt(int irq, void *arg);
+-static void macii_retransmit(int);
+ static void macii_queue_poll(void);
+
+ static int macii_probe(void);
+@@ -103,29 +106,37 @@ static enum macii_state {
+ sending,
+ reading,
+ read_done,
+- awaiting_reply
+ } macii_state;
+
+-static int need_poll;
+-static int command_byte;
+-static int last_reply;
+-static int last_active;
+-
+-static struct adb_request *current_req;
+-static struct adb_request *last_req;
+-static struct adb_request *retry_req;
+-static unsigned char reply_buf[16];
+-static unsigned char *reply_ptr;
+-static int reply_len;
+-static int reading_reply;
+-static int data_index;
+-static int first_byte;
+-static int prefix_len;
+-static int status = ST_IDLE|TREQ;
+-static int last_status;
+-static int driver_running;
+-
+-/* debug level 10 required for ADB logging (should be && debug_adb, ideally) */
++static struct adb_request *current_req; /* first request struct in the queue */
++static struct adb_request *last_req; /* last request struct in the queue */
++static unsigned char reply_buf[16]; /* storage for autopolled replies */
++static unsigned char *reply_ptr; /* next byte in req->data or reply_buf */
++static int reading_reply; /* store reply in reply_buf else req->reply */
++static int data_index; /* index of the next byte to send from req->data */
++static int reply_len; /* number of bytes received in reply_buf or req->reply */
++static int status; /* VIA's ADB status bits captured upon interrupt */
++static int last_status; /* status bits as at previous interrupt */
++static int srq_asserted; /* have to poll for the device that asserted it */
++static int command_byte; /* the most recent command byte transmitted */
++static int autopoll_devs; /* bits set are device addresses to be polled */
++
++/* Sanity check for request queue. Doesn't check for cycles. */
++static int request_is_queued(struct adb_request *req) {
++ struct adb_request *cur;
++ unsigned long flags;
++ local_irq_save(flags);
++ cur = current_req;
++ while (cur) {
++ if (cur == req) {
++ local_irq_restore(flags);
++ return 1;
++ }
++ cur = cur->next;
++ }
++ local_irq_restore(flags);
++ return 0;
++}
+
+ /* Check for MacII style ADB */
+ static int macii_probe(void)
+@@ -147,15 +158,16 @@ int macii_init(void)
+ local_irq_save(flags);
+
+ err = macii_init_via();
+- if (err) return err;
++ if (err) goto out;
+
+ err = request_irq(IRQ_MAC_ADB, macii_interrupt, IRQ_FLG_LOCK, "ADB",
+ macii_interrupt);
+- if (err) return err;
++ if (err) goto out;
+
+ macii_state = idle;
++out:
+ local_irq_restore(flags);
+- return 0;
++ return err;
+ }
+
+ /* initialize the hardware */
+@@ -163,12 +175,12 @@ static int macii_init_via(void)
+ {
+ unsigned char x;
+
+- /* Set the lines up. We want TREQ as input TACK|TIP as output */
+- via[DIRB] = (via[DIRB] | TACK | TIP) & ~TREQ;
++ /* We want CTLR_IRQ as input and ST_EVEN | ST_ODD as output lines. */
++ via[DIRB] = (via[DIRB] | ST_EVEN | ST_ODD) & ~CTLR_IRQ;
+
+ /* Set up state: idle */
+ via[B] |= ST_IDLE;
+- last_status = via[B] & (ST_MASK|TREQ);
++ last_status = via[B] & (ST_MASK|CTLR_IRQ);
+
+ /* Shift register on input */
+ via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT;
+@@ -179,81 +191,72 @@ static int macii_init_via(void)
+ return 0;
+ }
+
+-/* Send an ADB poll (Talk Register 0 command, tagged on the front of the request queue) */
++/* Send an ADB poll (Talk Register 0 command prepended to the request queue) */
+ static void macii_queue_poll(void)
+ {
+- static int device = 0;
+- static int in_poll=0;
++ /* No point polling the active device as it will never assert SRQ, so
++ * poll the next device in the autopoll list. This could leave us
++ * stuck in a polling loop if an unprobed device is asserting SRQ.
++ * In theory, that could only happen if a device was plugged in after
++ * probing started. Unplugging it again will break the cycle.
++ * (Simply polling the next higher device often ends up polling almost
++ * every device (after wrapping around), which takes too long.)
++ */
++ int device_mask;
++ int next_device;
+ static struct adb_request req;
+- unsigned long flags;
+-
+- if (in_poll) printk("macii_queue_poll: double poll!\n");
+
+- in_poll++;
+- if (++device > 15) device = 1;
+-
+- adb_request(&req, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1,
+- ADB_READREG(device, 0));
+-
+- local_irq_save(flags);
++ if (!autopoll_devs) return;
+
++ device_mask = (1 << (((command_byte & 0xF0) >> 4) + 1)) - 1;
++ if (autopoll_devs & ~device_mask)
++ next_device = ffs(autopoll_devs & ~device_mask) - 1;
++ else
++ next_device = ffs(autopoll_devs) - 1;
++
++ BUG_ON(request_is_queued(&req));
++
++ adb_request(&req, NULL, ADBREQ_NOSEND, 1,
++ ADB_READREG(next_device, 0));
++
++ req.sent = 0;
++ req.complete = 0;
++ req.reply_len = 0;
+ req.next = current_req;
+- current_req = &req;
+-
+- local_irq_restore(flags);
+- macii_start();
+- in_poll--;
+-}
+-
+-/* Send an ADB retransmit (Talk, appended to the request queue) */
+-static void macii_retransmit(int device)
+-{
+- static int in_retransmit = 0;
+- static struct adb_request rt;
+- unsigned long flags;
+-
+- if (in_retransmit) printk("macii_retransmit: double retransmit!\n");
+-
+- in_retransmit++;
+-
+- adb_request(&rt, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1,
+- ADB_READREG(device, 0));
+-
+- local_irq_save(flags);
+
+ if (current_req != NULL) {
+- last_req->next = &rt;
+- last_req = &rt;
++ current_req = &req;
+ } else {
+- current_req = &rt;
+- last_req = &rt;
++ current_req = &req;
++ last_req = &req;
+ }
+-
+- if (macii_state == idle) macii_start();
+-
+- local_irq_restore(flags);
+- in_retransmit--;
+ }
+
+ /* Send an ADB request; if sync, poll out the reply 'till it's done */
+ static int macii_send_request(struct adb_request *req, int sync)
+ {
+- int i;
++ int err;
++ unsigned long flags;
+
+- i = macii_write(req);
+- if (i) return i;
++ BUG_ON(request_is_queued(req));
+
+- if (sync) {
+- while (!req->complete) macii_poll();
++ local_irq_save(flags);
++ err = macii_write(req);
++ local_irq_restore(flags);
++
++ if (!err && sync) {
++ while (!req->complete) {
++ macii_poll();
++ }
++ BUG_ON(request_is_queued(req));
+ }
+- return 0;
++
++ return err;
+ }
+
+-/* Send an ADB request */
++/* Send an ADB request (append to request queue) */
+ static int macii_write(struct adb_request *req)
+ {
+- unsigned long flags;
+-
+ if (req->nbytes < 2 || req->data[0] != ADB_PACKET || req->nbytes > 15) {
+ req->complete = 1;
+ return -EINVAL;
+@@ -264,8 +267,6 @@ static int macii_write(struct adb_reques
+ req->complete = 0;
+ req->reply_len = 0;
+
+- local_irq_save(flags);
+-
+ if (current_req != NULL) {
+ last_req->next = req;
+ last_req = req;
+@@ -274,28 +275,52 @@ static int macii_write(struct adb_reques
+ last_req = req;
+ if (macii_state == idle) macii_start();
+ }
+-
+- local_irq_restore(flags);
+ return 0;
+ }
+
+ /* Start auto-polling */
+ static int macii_autopoll(int devs)
+ {
+- /* Just ping a random default address */
+- if (!(current_req || retry_req))
+- macii_retransmit( (last_active < 16 && last_active > 0) ? last_active : 3);
+- return 0;
++ static struct adb_request req;
++ unsigned long flags;
++ int err = 0;
++
++ /* bit 1 == device 1, and so on. */
++ autopoll_devs = devs & 0xFFFE;
++
++ if (!autopoll_devs) return 0;
++
++ local_irq_save(flags);
++
++ if (current_req == NULL) {
++ /* Send a Talk Reg 0. The controller will repeatedly transmit
++ * this as long as it is idle.
++ */
++ adb_request(&req, NULL, ADBREQ_NOSEND, 1,
++ ADB_READREG(ffs(autopoll_devs) - 1, 0));
++ err = macii_write(&req);
++ }
++
++ local_irq_restore(flags);
++ return err;
++}
++
++static inline int need_autopoll(void) {
++ /* Was the last command Talk Reg 0
++ * and is the target on the autopoll list?
++ */
++ if ((command_byte & 0x0F) == 0x0C &&
++ ((1 << ((command_byte & 0xF0) >> 4)) & autopoll_devs))
++ return 0;
++ return 1;
+ }
+
+ /* Prod the chip without interrupts */
+ static void macii_poll(void)
+ {
+- unsigned long flags;
+-
+- local_irq_save(flags);
+- if (via[IFR] & SR_INT) macii_interrupt(0, NULL);
+- local_irq_restore(flags);
++ disable_irq(IRQ_MAC_ADB);
++ macii_interrupt(0, NULL);
++ enable_irq(IRQ_MAC_ADB);
+ }
+
+ /* Reset the bus */
+@@ -303,73 +328,34 @@ static int macii_reset_bus(void)
+ {
+ static struct adb_request req;
+
++ if (request_is_queued(&req))
++ return 0;
++
+ /* Command = 0, Address = ignored */
+ adb_request(&req, NULL, 0, 1, ADB_BUSRESET);
+
++ /* Don't want any more requests during the Global Reset low time. */
++ udelay(3000);
++
+ return 0;
+ }
+
+ /* Start sending ADB packet */
+ static void macii_start(void)
+ {
+- unsigned long flags;
+ struct adb_request *req;
+
+ req = current_req;
+- if (!req) return;
+-
+- /* assert macii_state == idle */
+- if (macii_state != idle) {
+- printk("macii_start: called while driver busy (%p %x %x)!\n",
+- req, macii_state, (uint) via1[B] & (ST_MASK|TREQ));
+- return;
+- }
+
+- local_irq_save(flags);
+-
+- /*
+- * IRQ signaled ?? (means ADB controller wants to send, or might
+- * be end of packet if we were reading)
+- */
+-#if 0 /* FIXME: This is broke broke broke, for some reason */
+- if ((via[B] & TREQ) == 0) {
+- printk("macii_start: weird poll stuff. huh?\n");
+- /*
+- * FIXME - we need to restart this on a timer
+- * or a collision at boot hangs us.
+- * Never set macii_state to idle here, or macii_start
+- * won't be called again from send_request!
+- * (need to re-check other cases ...)
+- */
+- /*
+- * if the interrupt handler set the need_poll
+- * flag, it's hopefully a SRQ poll or re-Talk
+- * so we try to send here anyway
+- */
+- if (!need_poll) {
+- if (console_loglevel == 10)
+- printk("macii_start: device busy - retry %p state %d status %x!\n",
+- req, macii_state,
+- (uint) via[B] & (ST_MASK|TREQ));
+- retry_req = req;
+- /* set ADB status here ? */
+- local_irq_restore(flags);
+- return;
+- } else {
+- need_poll = 0;
+- }
+- }
+-#endif
+- /*
+- * Another retry pending? (sanity check)
++ BUG_ON(req == NULL);
++
++ BUG_ON(macii_state != idle);
++
++ /* Now send it. Be careful though, that first byte of the request
++ * is actually ADB_PACKET; the real data begins at index 1!
++ * And req->nbytes is the number of bytes of real data plus one.
+ */
+- if (retry_req) {
+- retry_req = NULL;
+- }
+
+- /* Now send it. Be careful though, that first byte of the request */
+- /* is actually ADB_PACKET; the real data begins at index 1! */
+-
+ /* store command byte */
+ command_byte = req->data[1];
+ /* Output mode */
+@@ -381,115 +367,97 @@ static void macii_start(void)
+
+ macii_state = sending;
+ data_index = 2;
+-
+- local_irq_restore(flags);
+ }
+
+ /*
+- * The notorious ADB interrupt handler - does all of the protocol handling,
+- * except for starting new send operations. Relies heavily on the ADB
+- * controller sending and receiving data, thereby generating SR interrupts
+- * for us. This means there has to be always activity on the ADB bus, otherwise
+- * the whole process dies and has to be re-kicked by sending TALK requests ...
+- * CUDA-based Macs seem to solve this with the autopoll option, for MacII-type
+- * ADB the problem isn't solved yet (retransmit of the latest active TALK seems
+- * a good choice; either on timeout or on a timer interrupt).
++ * The notorious ADB interrupt handler - does all of the protocol handling.
++ * Relies on the ADB controller sending and receiving data, thereby
++ * generating shift register interrupts (SR_INT) for us. This means there has
++ * to be activity on the ADB bus. The chip will poll to achieve this.
+ *
+ * The basic ADB state machine was left unchanged from the original MacII code
+ * by Alan Cox, which was based on the CUDA driver for PowerMac.
+- * The syntax of the ADB status lines seems to be totally different on MacII,
+- * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle for
+- * sending, and Idle -> Even -> Odd -> Even ->...-> Idle for receiving. Start
+- * and end of a receive packet are signaled by asserting /IRQ on the interrupt
+- * line. Timeouts are signaled by a sequence of 4 0xFF, with /IRQ asserted on
+- * every other byte. SRQ is probably signaled by 3 or more 0xFF tacked on the
+- * end of a packet. (Thanks to Guido Koerber for eavesdropping on the ADB
+- * protocol with a logic analyzer!!)
+- *
+- * Note: As of 21/10/97, the MacII ADB part works including timeout detection
+- * and retransmit (Talk to the last active device).
++ * The syntax of the ADB status lines is totally different on MacII,
++ * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle
++ * for sending and Idle -> Even -> Odd -> Even ->...-> Idle for receiving.
++ * Start and end of a receive packet are signalled by asserting /IRQ on the
++ * interrupt line (/IRQ means the CTLR_IRQ bit in port B; not to be confused
++ * with the VIA shift register interrupt. /IRQ never actually interrupts the
++ * processor, it's just an ordinary input.)
+ */
+ static irqreturn_t macii_interrupt(int irq, void *arg)
+ {
+- int x, adbdir;
+- unsigned long flags;
++ int x;
++ static int entered;
+ struct adb_request *req;
+
+- last_status = status;
+-
+- /* prevent races due to SCSI enabling ints */
+- local_irq_save(flags);
+-
+- if (driver_running) {
+- local_irq_restore(flags);
+- return IRQ_NONE;
++ if (!arg) {
++ /* Clear the SR IRQ flag when polling. */
++ if (via[IFR] & SR_INT)
++ via[IFR] = SR_INT;
++ else
++ return IRQ_NONE;
+ }
+
+- driver_running = 1;
+-
+- status = via[B] & (ST_MASK|TREQ);
+- adbdir = via[ACR] & SR_OUT;
++ BUG_ON(entered++);
++
++ last_status = status;
++ status = via[B] & (ST_MASK|CTLR_IRQ);
+
+ switch (macii_state) {
+ case idle:
++ if (reading_reply) {
++ reply_ptr = current_req->reply;
++ } else {
++ BUG_ON(current_req != NULL);
++ reply_ptr = reply_buf;
++ }
++
+ x = via[SR];
+- first_byte = x;
+- /* set ADB state = even for first data byte */
+- via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
+
+- reply_buf[0] = first_byte; /* was command_byte?? */
+- reply_ptr = reply_buf + 1;
+- reply_len = 1;
+- prefix_len = 1;
+- reading_reply = 0;
+-
+- macii_state = reading;
+- break;
++ if ((status & CTLR_IRQ) && (x == 0xFF)) {
++ /* Bus timeout without SRQ sequence:
++ * data is "FF" while CTLR_IRQ is "H"
++ */
++ reply_len = 0;
++ srq_asserted = 0;
++ macii_state = read_done;
++ } else {
++ macii_state = reading;
++ *reply_ptr = x;
++ reply_len = 1;
++ }
+
+- case awaiting_reply:
+- /* handshake etc. for II ?? */
+- x = via[SR];
+- first_byte = x;
+ /* set ADB state = even for first data byte */
+ via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
+-
+- current_req->reply[0] = first_byte;
+- reply_ptr = current_req->reply + 1;
+- reply_len = 1;
+- prefix_len = 1;
+- reading_reply = 1;
+-
+- macii_state = reading;
+ break;
+
+ case sending:
+ req = current_req;
+ if (data_index >= req->nbytes) {
+- /* print an error message if a listen command has no data */
+- if (((command_byte & 0x0C) == 0x08)
+- /* && (console_loglevel == 10) */
+- && (data_index == 2))
+- printk("MacII ADB: listen command with no data: %x!\n",
+- command_byte);
+- /* reset to shift in */
+- via[ACR] &= ~SR_OUT;
+- x = via[SR];
+- /* set ADB state idle - might get SRQ */
+- via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
+-
+ req->sent = 1;
++ macii_state = idle;
+
+ if (req->reply_expected) {
+- macii_state = awaiting_reply;
++ reading_reply = 1;
+ } else {
+ req->complete = 1;
+ current_req = req->next;
+ if (req->done) (*req->done)(req);
+- macii_state = idle;
+- if (current_req || retry_req)
++
++ if (current_req)
+ macii_start();
+ else
+- macii_retransmit((command_byte & 0xF0) >> 4);
++ if (need_autopoll())
++ macii_autopoll(autopoll_devs);
++ }
++
++ if (macii_state == idle) {
++ /* reset to shift in */
++ via[ACR] &= ~SR_OUT;
++ x = via[SR];
++ /* set ADB state idle - might get SRQ */
++ via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
+ }
+ } else {
+ via[SR] = req->data[data_index++];
+@@ -505,147 +473,79 @@ static irqreturn_t macii_interrupt(int i
+ break;
+
+ case reading:
++ x = via[SR];
++ BUG_ON((status & ST_MASK) == ST_CMD ||
++ (status & ST_MASK) == ST_IDLE);
+
+- /* timeout / SRQ handling for II hw */
+- if( (first_byte == 0xFF && (reply_len-prefix_len)==2
+- && memcmp(reply_ptr-2,"\xFF\xFF",2)==0) ||
+- ((reply_len-prefix_len)==3
+- && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0))
+- {
+- /*
+- * possible timeout (in fact, most probably a
+- * timeout, since SRQ can't be signaled without
+- * transfer on the bus).
+- * The last three bytes seen were FF, together
+- * with the starting byte (in case we started
+- * on 'idle' or 'awaiting_reply') this probably
+- * makes four. So this is mostl likely #5!
+- * The timeout signal is a pattern 1 0 1 0 0..
+- * on /INT, meaning we missed it :-(
+- */
+- x = via[SR];
+- if (x != 0xFF) printk("MacII ADB: mistaken timeout/SRQ!\n");
++ /* Bus timeout with SRQ sequence:
++ * data is "XX FF" while CTLR_IRQ is "L L"
++ * End of packet without SRQ sequence:
++ * data is "XX...YY 00" while CTLR_IRQ is "L...H L"
++ * End of packet SRQ sequence:
++ * data is "XX...YY 00" while CTLR_IRQ is "L...L L"
++ * (where XX is the first response byte and
++ * YY is the last byte of valid response data.)
++ */
+
+- if ((status & TREQ) == (last_status & TREQ)) {
+- /* Not a timeout. Unsolicited SRQ? weird. */
+- /* Terminate the SRQ packet and poll */
+- need_poll = 1;
++ srq_asserted = 0;
++ if (!(status & CTLR_IRQ)) {
++ if (x == 0xFF) {
++ if (!(last_status & CTLR_IRQ)) {
++ macii_state = read_done;
++ reply_len = 0;
++ srq_asserted = 1;
++ }
++ } else if (x == 0x00) {
++ macii_state = read_done;
++ if (!(last_status & CTLR_IRQ))
++ srq_asserted = 1;
+ }
+- /* There's no packet to get, so reply is blank */
+- via[B] ^= ST_MASK;
+- reply_ptr -= (reply_len-prefix_len);
+- reply_len = prefix_len;
+- macii_state = read_done;
+- break;
+- } /* end timeout / SRQ handling for II hw. */
++ }
+
+- if((reply_len-prefix_len)>3
+- && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0)
+- {
+- /* SRQ tacked on data packet */
+- /* Terminate the packet (SRQ never ends) */
+- x = via[SR];
+- macii_state = read_done;
+- reply_len -= 3;
+- reply_ptr -= 3;
+- need_poll = 1;
+- /* need to continue; next byte not seen else */
+- } else {
+- /* Sanity check */
+- if (reply_len > 15) reply_len = 0;
+- /* read byte */
+- x = via[SR];
+- *reply_ptr = x;
++ if (macii_state == reading) {
++ BUG_ON(reply_len > 15);
+ reply_ptr++;
++ *reply_ptr = x;
+ reply_len++;
+ }
+- /* The usual handshake ... */
+
+- /*
+- * NetBSD hints that the next to last byte
+- * is sent with IRQ !!
+- * Guido found out it's the last one (0x0),
+- * but IRQ should be asserted already.
+- * Problem with timeout detection: First
+- * transition to /IRQ might be second
+- * byte of timeout packet!
+- * Timeouts are signaled by 4x FF.
+- */
+- if (((status & TREQ) == 0) && (x == 0x00)) { /* != 0xFF */
+- /* invert state bits, toggle ODD/EVEN */
+- via[B] ^= ST_MASK;
+-
+- /* adjust packet length */
+- reply_len--;
+- reply_ptr--;
+- macii_state = read_done;
+- } else {
+- /* not caught: ST_CMD */
+- /* required for re-entry 'reading'! */
+- if ((status & ST_MASK) == ST_IDLE) {
+- /* (in)sanity check - set even */
+- via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
+- } else {
+- /* invert state bits */
+- via[B] ^= ST_MASK;
+- }
+- }
++ /* invert state bits, toggle ODD/EVEN */
++ via[B] ^= ST_MASK;
+ break;
+
+ case read_done:
+ x = via[SR];
++
+ if (reading_reply) {
++ reading_reply = 0;
+ req = current_req;
+- req->reply_len = reply_ptr - req->reply;
++ req->reply_len = reply_len;
+ req->complete = 1;
+ current_req = req->next;
+ if (req->done) (*req->done)(req);
+- } else {
+- adb_input(reply_buf, reply_ptr - reply_buf, 0);
+- }
++ } else if (reply_len && autopoll_devs)
++ adb_input(reply_buf, reply_len, 0);
+
+- /*
+- * remember this device ID; it's the latest we got a
+- * reply from!
+- */
+- last_reply = command_byte;
+- last_active = (command_byte & 0xF0) >> 4;
++ macii_state = idle;
+
+ /* SRQ seen before, initiate poll now */
+- if (need_poll) {
+- macii_state = idle;
++ if (srq_asserted)
+ macii_queue_poll();
+- need_poll = 0;
+- break;
+- }
+-
+- /* set ADB state to idle */
+- via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
+-
+- /* /IRQ seen, so the ADB controller has data for us */
+- if ((via[B] & TREQ) != 0) {
+- macii_state = reading;
+
+- reply_buf[0] = command_byte;
+- reply_ptr = reply_buf + 1;
+- reply_len = 1;
+- prefix_len = 1;
+- reading_reply = 0;
+- } else {
+- /* no IRQ, send next packet or wait */
+- macii_state = idle;
+- if (current_req)
+- macii_start();
+- else
+- macii_retransmit(last_active);
+- }
++ if (current_req)
++ macii_start();
++ else
++ if (need_autopoll())
++ macii_autopoll(autopoll_devs);
++
++ if (macii_state == idle)
++ via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
+ break;
+
+ default:
+ break;
+ }
+- /* reset mutex and interrupts */
+- driver_running = 0;
+- local_irq_restore(flags);
++
++ entered--;
+ return IRQ_HANDLED;
+ }
diff --git a/debian/patches/bugfix/m68k/mac68k-macmace-fixes.diff b/debian/patches/bugfix/m68k/mac68k-macmace-fixes.diff
new file mode 100644
index 000000000000..a97885b26615
--- /dev/null
+++ b/debian/patches/bugfix/m68k/mac68k-macmace-fixes.diff
@@ -0,0 +1,951 @@
+Subject: [PATCH 11/13] m68k: macmace fixes
+Cc: Jeff Garzik <jgarzik@pobox.com>, netdev@vger.kernel.org
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+Fix a race condition in the transmit code, where the dma interrupt could update
+the free tx buffer count concurrently and wedge the tx queue.
+
+Fix the misuse of the rx frame status and rx frame length registers: no more
+"fifo overrun" errors caused by the OFLOW bit being tested in the frame length
+register (instead of the status register), and no more missed packets due to
+incorrect length taken from status register (instead of the frame length
+register).
+
+Fix a panic (skb_over_panic BUG) caused by allocating and then copying an
+incoming packet while the packet length register was changing.
+
+Cut-and-paste the reset code from the powermac mace driver (mace.c), so the NIC
+functions when MacOS does not initialise it (important for anyone wanting to
+use the Emile boot loader).
+
+Cut-and-paste the error counting and timeout recovery code from mace.c.
+
+Fix over allocation of rx buffer memory (it's page order, not page count).
+
+Converted to driver model.
+
+Converted to DMA API.
+
+Since I've run out of ways to make it fail, and since it performs well now,
+promote the driver from EXPERIMENTAL status. Tested on both quadra 840av and
+660av.
+
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ drivers/net/Kconfig | 4
+ drivers/net/Space.c | 4
+ drivers/net/macmace.c | 591 ++++++++++++++++++++++++++++++--------------------
+ 3 files changed, 364 insertions(+), 235 deletions(-)
+
+--- linux-m68k-2.6.21.orig/drivers/net/Kconfig
++++ linux-m68k-2.6.21/drivers/net/Kconfig
+@@ -337,8 +337,8 @@ config MACSONIC
+ be called macsonic.
+
+ config MACMACE
+- bool "Macintosh (AV) onboard MACE ethernet (EXPERIMENTAL)"
+- depends on NET_ETHERNET && MAC && EXPERIMENTAL
++ bool "Macintosh (AV) onboard MACE ethernet"
++ depends on NET_ETHERNET && MAC
+ select CRC32
+ help
+ Support for the onboard AMD 79C940 MACE Ethernet controller used in
+--- linux-m68k-2.6.21.orig/drivers/net/Space.c
++++ linux-m68k-2.6.21/drivers/net/Space.c
+@@ -83,7 +83,6 @@ extern struct net_device *bagetlance_pro
+ extern struct net_device *mvme147lance_probe(int unit);
+ extern struct net_device *tc515_probe(int unit);
+ extern struct net_device *lance_probe(int unit);
+-extern struct net_device *mace_probe(int unit);
+ extern struct net_device *mac8390_probe(int unit);
+ extern struct net_device *mac89x0_probe(int unit);
+ extern struct net_device *mc32_probe(int unit);
+@@ -274,9 +273,6 @@ static struct devprobe2 m68k_probes[] __
+ #ifdef CONFIG_MVME147_NET /* MVME147 internal Ethernet */
+ {mvme147lance_probe, 0},
+ #endif
+-#ifdef CONFIG_MACMACE /* Mac 68k Quadra AV builtin Ethernet */
+- {mace_probe, 0},
+-#endif
+ #ifdef CONFIG_MAC8390 /* NuBus NS8390-based cards */
+ {mac8390_probe, 0},
+ #endif
+--- linux-m68k-2.6.21.orig/drivers/net/macmace.c
++++ linux-m68k-2.6.21/drivers/net/macmace.c
+@@ -12,6 +12,11 @@
+ * Copyright (C) 1998 Alan Cox <alan@redhat.com>
+ *
+ * Modified heavily by Joshua M. Thompson based on Dave Huang's NetBSD driver
++ *
++ * Copyright (C) 2007 Finn Thain
++ *
++ * Converted to DMA API, converted to unified driver model,
++ * sync'd some routines with mace.c and fixed various bugs.
+ */
+
+
+@@ -23,8 +28,9 @@
+ #include <linux/string.h>
+ #include <linux/crc32.h>
+ #include <linux/bitrev.h>
++#include <linux/dma-mapping.h>
++#include <linux/platform_device.h>
+ #include <asm/io.h>
+-#include <asm/pgtable.h>
+ #include <asm/irq.h>
+ #include <asm/macintosh.h>
+ #include <asm/macints.h>
+@@ -32,13 +38,20 @@
+ #include <asm/page.h>
+ #include "mace.h"
+
+-#define N_TX_RING 1
+-#define N_RX_RING 8
+-#define N_RX_PAGES ((N_RX_RING * 0x0800 + PAGE_SIZE - 1) / PAGE_SIZE)
++static char mac_mace_string[] = "macmace";
++static struct platform_device *mac_mace_device;
++
++#define N_TX_BUFF_ORDER 0
++#define N_TX_RING (1 << N_TX_BUFF_ORDER)
++#define N_RX_BUFF_ORDER 3
++#define N_RX_RING (1 << N_RX_BUFF_ORDER)
++
+ #define TX_TIMEOUT HZ
+
+-/* Bits in transmit DMA status */
+-#define TX_DMA_ERR 0x80
++#define MACE_BUFF_SIZE 0x800
++
++/* Chip rev needs workaround on HW & multicast addr change */
++#define BROKEN_ADDRCHG_REV 0x0941
+
+ /* The MACE is simply wired down on a Mac68K box */
+
+@@ -47,40 +60,46 @@
+
+ struct mace_data {
+ volatile struct mace *mace;
+- volatile unsigned char *tx_ring;
+- volatile unsigned char *tx_ring_phys;
+- volatile unsigned char *rx_ring;
+- volatile unsigned char *rx_ring_phys;
++ unsigned char *tx_ring;
++ dma_addr_t tx_ring_phys;
++ unsigned char *rx_ring;
++ dma_addr_t rx_ring_phys;
+ int dma_intr;
+ struct net_device_stats stats;
+ int rx_slot, rx_tail;
+ int tx_slot, tx_sloti, tx_count;
++ int chipid;
++ struct device *device;
+ };
+
+ struct mace_frame {
+- u16 len;
+- u16 status;
+- u16 rntpc;
+- u16 rcvcc;
+- u32 pad1;
+- u32 pad2;
++ u8 rcvcnt;
++ u8 pad1;
++ u8 rcvsts;
++ u8 pad2;
++ u8 rntpc;
++ u8 pad3;
++ u8 rcvcc;
++ u8 pad4;
++ u32 pad5;
++ u32 pad6;
+ u8 data[1];
+ /* And frame continues.. */
+ };
+
+ #define PRIV_BYTES sizeof(struct mace_data)
+
+-extern void psc_debug_dump(void);
+-
+ static int mace_open(struct net_device *dev);
+ static int mace_close(struct net_device *dev);
+ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev);
+ static struct net_device_stats *mace_stats(struct net_device *dev);
+ static void mace_set_multicast(struct net_device *dev);
+ static int mace_set_address(struct net_device *dev, void *addr);
++static void mace_reset(struct net_device *dev);
+ static irqreturn_t mace_interrupt(int irq, void *dev_id);
+ static irqreturn_t mace_dma_intr(int irq, void *dev_id);
+ static void mace_tx_timeout(struct net_device *dev);
++static void __mace_set_address(struct net_device *dev, void *addr);
+
+ /*
+ * Load a receive DMA channel with a base address and ring length
+@@ -88,7 +107,7 @@ static void mace_tx_timeout(struct net_d
+
+ static void mace_load_rxdma_base(struct net_device *dev, int set)
+ {
+- struct mace_data *mp = (struct mace_data *) dev->priv;
++ struct mace_data *mp = netdev_priv(dev);
+
+ psc_write_word(PSC_ENETRD_CMD + set, 0x0100);
+ psc_write_long(PSC_ENETRD_ADDR + set, (u32) mp->rx_ring_phys);
+@@ -103,7 +122,7 @@ static void mace_load_rxdma_base(struct
+
+ static void mace_rxdma_reset(struct net_device *dev)
+ {
+- struct mace_data *mp = (struct mace_data *) dev->priv;
++ struct mace_data *mp = netdev_priv(dev);
+ volatile struct mace *mace = mp->mace;
+ u8 maccc = mace->maccc;
+
+@@ -130,7 +149,7 @@ static void mace_rxdma_reset(struct net_
+
+ static void mace_txdma_reset(struct net_device *dev)
+ {
+- struct mace_data *mp = (struct mace_data *) dev->priv;
++ struct mace_data *mp = netdev_priv(dev);
+ volatile struct mace *mace = mp->mace;
+ u8 maccc;
+
+@@ -168,7 +187,7 @@ static void mace_dma_off(struct net_devi
+ * model of Macintrash has a MACE (AV macintoshes)
+ */
+
+-struct net_device *mace_probe(int unit)
++static int __devinit mace_probe(struct platform_device *pdev)
+ {
+ int j;
+ struct mace_data *mp;
+@@ -179,24 +198,28 @@ struct net_device *mace_probe(int unit)
+ int err;
+
+ if (found || macintosh_config->ether_type != MAC_ETHER_MACE)
+- return ERR_PTR(-ENODEV);
++ return -ENODEV;
+
+ found = 1; /* prevent 'finding' one on every device probe */
+
+ dev = alloc_etherdev(PRIV_BYTES);
+ if (!dev)
+- return ERR_PTR(-ENOMEM);
++ return -ENOMEM;
+
+- if (unit >= 0)
+- sprintf(dev->name, "eth%d", unit);
++ mp = netdev_priv(dev);
++
++ mp->device = &pdev->dev;
++ SET_NETDEV_DEV(dev, &pdev->dev);
++ SET_MODULE_OWNER(dev);
+
+- mp = (struct mace_data *) dev->priv;
+ dev->base_addr = (u32)MACE_BASE;
+ mp->mace = (volatile struct mace *) MACE_BASE;
+
+ dev->irq = IRQ_MAC_MACE;
+ mp->dma_intr = IRQ_MAC_MACE_DMA;
+
++ mp->chipid = mp->mace->chipid_hi << 8 | mp->mace->chipid_lo;
++
+ /*
+ * The PROM contains 8 bytes which total 0xFF when XOR'd
+ * together. Due to the usual peculiar apple brain damage
+@@ -217,7 +240,7 @@ struct net_device *mace_probe(int unit)
+
+ if (checksum != 0xFF) {
+ free_netdev(dev);
+- return ERR_PTR(-ENODEV);
++ return -ENODEV;
+ }
+
+ memset(&mp->stats, 0, sizeof(mp->stats));
+@@ -237,22 +260,98 @@ struct net_device *mace_probe(int unit)
+
+ err = register_netdev(dev);
+ if (!err)
+- return dev;
++ return 0;
+
+ free_netdev(dev);
+- return ERR_PTR(err);
++ return err;
++}
++
++/*
++ * Reset the chip.
++ */
++
++static void mace_reset(struct net_device *dev)
++{
++ struct mace_data *mp = netdev_priv(dev);
++ volatile struct mace *mb = mp->mace;
++ int i;
++
++ /* soft-reset the chip */
++ i = 200;
++ while (--i) {
++ mb->biucc = SWRST;
++ if (mb->biucc & SWRST) {
++ udelay(10);
++ continue;
++ }
++ break;
++ }
++ if (!i) {
++ printk(KERN_ERR "macmace: cannot reset chip!\n");
++ return;
++ }
++
++ mb->maccc = 0; /* turn off tx, rx */
++ mb->imr = 0xFF; /* disable all intrs for now */
++ i = mb->ir;
++
++ mb->biucc = XMTSP_64;
++ mb->utr = RTRD;
++ mb->fifocc = XMTFW_8 | RCVFW_64 | XMTFWU | RCVFWU;
++
++ mb->xmtfc = AUTO_PAD_XMIT; /* auto-pad short frames */
++ mb->rcvfc = 0;
++
++ /* load up the hardware address */
++ __mace_set_address(dev, dev->dev_addr);
++
++ /* clear the multicast filter */
++ if (mp->chipid == BROKEN_ADDRCHG_REV)
++ mb->iac = LOGADDR;
++ else {
++ mb->iac = ADDRCHG | LOGADDR;
++ while ((mb->iac & ADDRCHG) != 0)
++ ;
++ }
++ for (i = 0; i < 8; ++i)
++ mb->ladrf = 0;
++
++ /* done changing address */
++ if (mp->chipid != BROKEN_ADDRCHG_REV)
++ mb->iac = 0;
++
++ mb->plscc = PORTSEL_AUI;
+ }
+
+ /*
+ * Load the address on a mace controller.
+ */
+
+-static int mace_set_address(struct net_device *dev, void *addr)
++static void __mace_set_address(struct net_device *dev, void *addr)
+ {
+- unsigned char *p = addr;
+- struct mace_data *mp = (struct mace_data *) dev->priv;
++ struct mace_data *mp = netdev_priv(dev);
+ volatile struct mace *mb = mp->mace;
++ unsigned char *p = addr;
+ int i;
++
++ /* load up the hardware address */
++ if (mp->chipid == BROKEN_ADDRCHG_REV)
++ mb->iac = PHYADDR;
++ else {
++ mb->iac = ADDRCHG | PHYADDR;
++ while ((mb->iac & ADDRCHG) != 0)
++ ;
++ }
++ for (i = 0; i < 6; ++i)
++ mb->padr = dev->dev_addr[i] = p[i];
++ if (mp->chipid != BROKEN_ADDRCHG_REV)
++ mb->iac = 0;
++}
++
++static int mace_set_address(struct net_device *dev, void *addr)
++{
++ struct mace_data *mp = netdev_priv(dev);
++ volatile struct mace *mb = mp->mace;
+ unsigned long flags;
+ u8 maccc;
+
+@@ -260,15 +359,10 @@ static int mace_set_address(struct net_d
+
+ maccc = mb->maccc;
+
+- /* load up the hardware address */
+- mb->iac = ADDRCHG | PHYADDR;
+- while ((mb->iac & ADDRCHG) != 0);
+-
+- for (i = 0; i < 6; ++i) {
+- mb->padr = dev->dev_addr[i] = p[i];
+- }
++ __mace_set_address(dev, addr);
+
+ mb->maccc = maccc;
++
+ local_irq_restore(flags);
+
+ return 0;
+@@ -281,31 +375,11 @@ static int mace_set_address(struct net_d
+
+ static int mace_open(struct net_device *dev)
+ {
+- struct mace_data *mp = (struct mace_data *) dev->priv;
++ struct mace_data *mp = netdev_priv(dev);
+ volatile struct mace *mb = mp->mace;
+-#if 0
+- int i;
+
+- i = 200;
+- while (--i) {
+- mb->biucc = SWRST;
+- if (mb->biucc & SWRST) {
+- udelay(10);
+- continue;
+- }
+- break;
+- }
+- if (!i) {
+- printk(KERN_ERR "%s: software reset failed!!\n", dev->name);
+- return -EAGAIN;
+- }
+-#endif
+-
+- mb->biucc = XMTSP_64;
+- mb->fifocc = XMTFW_16 | RCVFW_64 | XMTFWU | RCVFWU | XMTBRST | RCVBRST;
+- mb->xmtfc = AUTO_PAD_XMIT;
+- mb->plscc = PORTSEL_AUI;
+- /* mb->utr = RTRD; */
++ /* reset the chip */
++ mace_reset(dev);
+
+ if (request_irq(dev->irq, mace_interrupt, 0, dev->name, dev)) {
+ printk(KERN_ERR "%s: can't get irq %d\n", dev->name, dev->irq);
+@@ -319,25 +393,21 @@ static int mace_open(struct net_device *
+
+ /* Allocate the DMA ring buffers */
+
+- mp->rx_ring = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, N_RX_PAGES);
+- mp->tx_ring = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, 0);
+-
+- if (mp->tx_ring==NULL || mp->rx_ring==NULL) {
+- if (mp->rx_ring) free_pages((u32) mp->rx_ring, N_RX_PAGES);
+- if (mp->tx_ring) free_pages((u32) mp->tx_ring, 0);
+- free_irq(dev->irq, dev);
+- free_irq(mp->dma_intr, dev);
+- printk(KERN_ERR "%s: unable to allocate DMA buffers\n", dev->name);
+- return -ENOMEM;
++ mp->tx_ring = dma_alloc_coherent(mp->device,
++ N_TX_RING * MACE_BUFF_SIZE,
++ &mp->tx_ring_phys, GFP_KERNEL);
++ if (mp->tx_ring == NULL) {
++ printk(KERN_ERR "%s: unable to allocate DMA tx buffers\n", dev->name);
++ goto out1;
+ }
+
+- mp->rx_ring_phys = (unsigned char *) virt_to_bus((void *)mp->rx_ring);
+- mp->tx_ring_phys = (unsigned char *) virt_to_bus((void *)mp->tx_ring);
+-
+- /* We want the Rx buffer to be uncached and the Tx buffer to be writethrough */
+-
+- kernel_set_cachemode((void *)mp->rx_ring, N_RX_PAGES * PAGE_SIZE, IOMAP_NOCACHE_NONSER);
+- kernel_set_cachemode((void *)mp->tx_ring, PAGE_SIZE, IOMAP_WRITETHROUGH);
++ mp->rx_ring = dma_alloc_coherent(mp->device,
++ N_RX_RING * MACE_BUFF_SIZE,
++ &mp->rx_ring_phys, GFP_KERNEL);
++ if (mp->rx_ring == NULL) {
++ printk(KERN_ERR "%s: unable to allocate DMA rx buffers\n", dev->name);
++ goto out2;
++ }
+
+ mace_dma_off(dev);
+
+@@ -348,34 +418,22 @@ static int mace_open(struct net_device *
+ psc_write_word(PSC_ENETWR_CTL, 0x0400);
+ psc_write_word(PSC_ENETRD_CTL, 0x0400);
+
+-#if 0
+- /* load up the hardware address */
+-
+- mb->iac = ADDRCHG | PHYADDR;
+-
+- while ((mb->iac & ADDRCHG) != 0);
+-
+- for (i = 0; i < 6; ++i)
+- mb->padr = dev->dev_addr[i];
+-
+- /* clear the multicast filter */
+- mb->iac = ADDRCHG | LOGADDR;
+-
+- while ((mb->iac & ADDRCHG) != 0);
+-
+- for (i = 0; i < 8; ++i)
+- mb->ladrf = 0;
+-
+- mb->plscc = PORTSEL_GPSI + ENPLSIO;
+-
+- mb->maccc = ENXMT | ENRCV;
+- mb->imr = RCVINT;
+-#endif
+-
+ mace_rxdma_reset(dev);
+ mace_txdma_reset(dev);
+
++ /* turn it on! */
++ mb->maccc = ENXMT | ENRCV;
++ /* enable all interrupts except receive interrupts */
++ mb->imr = RCVINT;
+ return 0;
++
++out2:
++ dma_free_coherent(mp->device, N_TX_RING * MACE_BUFF_SIZE,
++ mp->tx_ring, mp->tx_ring_phys);
++out1:
++ free_irq(dev->irq, dev);
++ free_irq(mp->dma_intr, dev);
++ return -ENOMEM;
+ }
+
+ /*
+@@ -384,19 +442,13 @@ static int mace_open(struct net_device *
+
+ static int mace_close(struct net_device *dev)
+ {
+- struct mace_data *mp = (struct mace_data *) dev->priv;
++ struct mace_data *mp = netdev_priv(dev);
+ volatile struct mace *mb = mp->mace;
+
+ mb->maccc = 0; /* disable rx and tx */
+ mb->imr = 0xFF; /* disable all irqs */
+ mace_dma_off(dev); /* disable rx and tx dma */
+
+- free_irq(dev->irq, dev);
+- free_irq(IRQ_MAC_MACE_DMA, dev);
+-
+- free_pages((u32) mp->rx_ring, N_RX_PAGES);
+- free_pages((u32) mp->tx_ring, 0);
+-
+ return 0;
+ }
+
+@@ -406,15 +458,20 @@ static int mace_close(struct net_device
+
+ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
+ {
+- struct mace_data *mp = (struct mace_data *) dev->priv;
++ struct mace_data *mp = netdev_priv(dev);
++ unsigned long flags;
+
+- /* Stop the queue if the buffer is full */
++ /* Stop the queue since there's only the one buffer */
+
++ local_irq_save(flags);
++ netif_stop_queue(dev);
+ if (!mp->tx_count) {
+- netif_stop_queue(dev);
+- return 1;
++ printk(KERN_ERR "macmace: tx queue running but no free buffers.\n");
++ local_irq_restore(flags);
++ return NETDEV_TX_BUSY;
+ }
+ mp->tx_count--;
++ local_irq_restore(flags);
+
+ mp->stats.tx_packets++;
+ mp->stats.tx_bytes += skb->len;
+@@ -433,23 +490,26 @@ static int mace_xmit_start(struct sk_buf
+
+ dev_kfree_skb(skb);
+
+- return 0;
++ dev->trans_start = jiffies;
++ return NETDEV_TX_OK;
+ }
+
+ static struct net_device_stats *mace_stats(struct net_device *dev)
+ {
+- struct mace_data *p = (struct mace_data *) dev->priv;
+- return &p->stats;
++ struct mace_data *mp = netdev_priv(dev);
++ return &mp->stats;
+ }
+
+ static void mace_set_multicast(struct net_device *dev)
+ {
+- struct mace_data *mp = (struct mace_data *) dev->priv;
++ struct mace_data *mp = netdev_priv(dev);
+ volatile struct mace *mb = mp->mace;
+ int i, j;
+ u32 crc;
+ u8 maccc;
++ unsigned long flags;
+
++ local_irq_save(flags);
+ maccc = mb->maccc;
+ mb->maccc &= ~PROM;
+
+@@ -474,116 +534,122 @@ static void mace_set_multicast(struct ne
+ }
+ }
+
+- mb->iac = ADDRCHG | LOGADDR;
+- while (mb->iac & ADDRCHG);
+-
+- for (i = 0; i < 8; ++i) {
+- mb->ladrf = multicast_filter[i];
++ if (mp->chipid == BROKEN_ADDRCHG_REV)
++ mb->iac = LOGADDR;
++ else {
++ mb->iac = ADDRCHG | LOGADDR;
++ while ((mb->iac & ADDRCHG) != 0)
++ ;
+ }
++ for (i = 0; i < 8; ++i)
++ mb->ladrf = multicast_filter[i];
++ if (mp->chipid != BROKEN_ADDRCHG_REV)
++ mb->iac = 0;
+ }
+
+ mb->maccc = maccc;
++ local_irq_restore(flags);
+ }
+
+-/*
+- * Miscellaneous interrupts are handled here. We may end up
+- * having to bash the chip on the head for bad errors
+- */
+-
+ static void mace_handle_misc_intrs(struct mace_data *mp, int intr)
+ {
+ volatile struct mace *mb = mp->mace;
+ static int mace_babbles, mace_jabbers;
+
+- if (intr & MPCO) {
++ if (intr & MPCO)
+ mp->stats.rx_missed_errors += 256;
+- }
+- mp->stats.rx_missed_errors += mb->mpc; /* reading clears it */
+-
+- if (intr & RNTPCO) {
++ mp->stats.rx_missed_errors += mb->mpc; /* reading clears it */
++ if (intr & RNTPCO)
+ mp->stats.rx_length_errors += 256;
+- }
+- mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */
+-
+- if (intr & CERR) {
++ mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */
++ if (intr & CERR)
+ ++mp->stats.tx_heartbeat_errors;
+- }
+- if (intr & BABBLE) {
+- if (mace_babbles++ < 4) {
+- printk(KERN_DEBUG "mace: babbling transmitter\n");
+- }
+- }
+- if (intr & JABBER) {
+- if (mace_jabbers++ < 4) {
+- printk(KERN_DEBUG "mace: jabbering transceiver\n");
+- }
+- }
++ if (intr & BABBLE)
++ if (mace_babbles++ < 4)
++ printk(KERN_DEBUG "macmace: babbling transmitter\n");
++ if (intr & JABBER)
++ if (mace_jabbers++ < 4)
++ printk(KERN_DEBUG "macmace: jabbering transceiver\n");
+ }
+
+-/*
+- * A transmit error has occurred. (We kick the transmit side from
+- * the DMA completion)
+- */
+-
+-static void mace_xmit_error(struct net_device *dev)
++static irqreturn_t mace_interrupt(int irq, void *dev_id)
+ {
+- struct mace_data *mp = (struct mace_data *) dev->priv;
++ struct net_device *dev = (struct net_device *) dev_id;
++ struct mace_data *mp = netdev_priv(dev);
+ volatile struct mace *mb = mp->mace;
+- u8 xmtfs, xmtrc;
++ int intr, fs;
++ unsigned int flags;
++
++ /* don't want the dma interrupt handler to fire */
++ local_irq_save(flags);
+
+- xmtfs = mb->xmtfs;
+- xmtrc = mb->xmtrc;
++ intr = mb->ir; /* read interrupt register */
++ mace_handle_misc_intrs(mp, intr);
+
+- if (xmtfs & XMTSV) {
+- if (xmtfs & UFLO) {
+- printk("%s: DMA underrun.\n", dev->name);
+- mp->stats.tx_errors++;
+- mp->stats.tx_fifo_errors++;
+- mace_txdma_reset(dev);
++ if (intr & XMTINT) {
++ fs = mb->xmtfs;
++ if ((fs & XMTSV) == 0) {
++ printk(KERN_ERR "macmace: xmtfs not valid! (fs=%x)\n", fs);
++ mace_reset(dev);
++ /*
++ * XXX mace likes to hang the machine after a xmtfs error.
++ * This is hard to reproduce, reseting *may* help
++ */
+ }
+- if (xmtfs & RTRY) {
+- mp->stats.collisions++;
++ /* dma should have finished */
++ if (!mp->tx_count) {
++ printk(KERN_DEBUG "macmace: tx ring ran out? (fs=%x)\n", fs);
++ }
++ /* Update stats */
++ if (fs & (UFLO|LCOL|LCAR|RTRY)) {
++ ++mp->stats.tx_errors;
++ if (fs & LCAR)
++ ++mp->stats.tx_carrier_errors;
++ else if (fs & (UFLO|LCOL|RTRY)) {
++ ++mp->stats.tx_aborted_errors;
++ if (mb->xmtfs & UFLO) {
++ printk(KERN_ERR "%s: DMA underrun.\n", dev->name);
++ mp->stats.tx_fifo_errors++;
++ mace_txdma_reset(dev);
++ }
++ }
+ }
+ }
+-}
+
+-/*
+- * A receive interrupt occurred.
+- */
++ if (mp->tx_count)
++ netif_wake_queue(dev);
+
+-static void mace_recv_interrupt(struct net_device *dev)
+-{
+-/* struct mace_data *mp = (struct mace_data *) dev->priv; */
+-// volatile struct mace *mb = mp->mace;
+-}
++ local_irq_restore(flags);
+
+-/*
+- * Process the chip interrupt
+- */
++ return IRQ_HANDLED;
++}
+
+-static irqreturn_t mace_interrupt(int irq, void *dev_id)
++static void mace_tx_timeout(struct net_device *dev)
+ {
+- struct net_device *dev = (struct net_device *) dev_id;
+- struct mace_data *mp = (struct mace_data *) dev->priv;
++ struct mace_data *mp = netdev_priv(dev);
+ volatile struct mace *mb = mp->mace;
+- u8 ir;
++ unsigned long flags;
+
+- ir = mb->ir;
+- mace_handle_misc_intrs(mp, ir);
++ local_irq_save(flags);
+
+- if (ir & XMTINT) {
+- mace_xmit_error(dev);
+- }
+- if (ir & RCVINT) {
+- mace_recv_interrupt(dev);
+- }
+- return IRQ_HANDLED;
+-}
++ /* turn off both tx and rx and reset the chip */
++ mb->maccc = 0;
++ printk(KERN_ERR "macmace: transmit timeout - resetting\n");
++ mace_txdma_reset(dev);
++ mace_reset(dev);
+
+-static void mace_tx_timeout(struct net_device *dev)
+-{
+-/* struct mace_data *mp = (struct mace_data *) dev->priv; */
+-// volatile struct mace *mb = mp->mace;
++ /* restart rx dma */
++ mace_rxdma_reset(dev);
++
++ mp->tx_count = N_TX_RING;
++ netif_wake_queue(dev);
++
++ /* turn it on! */
++ mb->maccc = ENXMT | ENRCV;
++ /* enable all interrupts except receive interrupts */
++ mb->imr = RCVINT;
++
++ local_irq_restore(flags);
+ }
+
+ /*
+@@ -592,41 +658,40 @@ static void mace_tx_timeout(struct net_d
+
+ static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf)
+ {
+- struct mace_data *mp = (struct mace_data *) dev->priv;
++ struct mace_data *mp = netdev_priv(dev);
+ struct sk_buff *skb;
++ unsigned int frame_status = mf->rcvsts;
+
+- if (mf->status & RS_OFLO) {
+- printk("%s: fifo overflow.\n", dev->name);
+- mp->stats.rx_errors++;
+- mp->stats.rx_fifo_errors++;
+- }
+- if (mf->status&(RS_CLSN|RS_FRAMERR|RS_FCSERR))
++ if (frame_status & (RS_OFLO | RS_CLSN | RS_FRAMERR | RS_FCSERR)) {
+ mp->stats.rx_errors++;
++ if (frame_status & RS_OFLO) {
++ printk(KERN_DEBUG "%s: fifo overflow.\n", dev->name);
++ mp->stats.rx_fifo_errors++;
++ }
++ if (frame_status & RS_CLSN)
++ mp->stats.collisions++;
++ if (frame_status & RS_FRAMERR)
++ mp->stats.rx_frame_errors++;
++ if (frame_status & RS_FCSERR)
++ mp->stats.rx_crc_errors++;
++ } else {
++ unsigned int frame_length = mf->rcvcnt + ((frame_status & 0x0F) << 8 );
+
+- if (mf->status&RS_CLSN) {
+- mp->stats.collisions++;
+- }
+- if (mf->status&RS_FRAMERR) {
+- mp->stats.rx_frame_errors++;
+- }
+- if (mf->status&RS_FCSERR) {
+- mp->stats.rx_crc_errors++;
+- }
++ skb = dev_alloc_skb(frame_length + 2);
++ if (!skb) {
++ mp->stats.rx_dropped++;
++ return;
++ }
++ skb_reserve(skb, 2);
++ memcpy(skb_put(skb, frame_length), mf->data, frame_length);
+
+- skb = dev_alloc_skb(mf->len+2);
+- if (!skb) {
+- mp->stats.rx_dropped++;
+- return;
++ skb->dev = dev;
++ skb->protocol = eth_type_trans(skb, dev);
++ netif_rx(skb);
++ dev->last_rx = jiffies;
++ mp->stats.rx_packets++;
++ mp->stats.rx_bytes += frame_length;
+ }
+- skb_reserve(skb,2);
+- memcpy(skb_put(skb, mf->len), mf->data, mf->len);
+-
+- skb->dev = dev;
+- skb->protocol = eth_type_trans(skb, dev);
+- netif_rx(skb);
+- dev->last_rx = jiffies;
+- mp->stats.rx_packets++;
+- mp->stats.rx_bytes += mf->len;
+ }
+
+ /*
+@@ -636,7 +701,7 @@ static void mace_dma_rx_frame(struct net
+ static irqreturn_t mace_dma_intr(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *) dev_id;
+- struct mace_data *mp = (struct mace_data *) dev->priv;
++ struct mace_data *mp = netdev_priv(dev);
+ int left, head;
+ u16 status;
+ u32 baka;
+@@ -663,7 +728,8 @@ static irqreturn_t mace_dma_intr(int irq
+ /* Loop through the ring buffer and process new packages */
+
+ while (mp->rx_tail < head) {
+- mace_dma_rx_frame(dev, (struct mace_frame *) (mp->rx_ring + (mp->rx_tail * 0x0800)));
++ mace_dma_rx_frame(dev, (struct mace_frame*) (mp->rx_ring
++ + (mp->rx_tail * MACE_BUFF_SIZE)));
+ mp->rx_tail++;
+ }
+
+@@ -690,9 +756,76 @@ static irqreturn_t mace_dma_intr(int irq
+ psc_write_word(PSC_ENETWR_CMD + mp->tx_sloti, 0x0100);
+ mp->tx_sloti ^= 0x10;
+ mp->tx_count++;
+- netif_wake_queue(dev);
+ }
+ return IRQ_HANDLED;
+ }
+
+ MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Macintosh MACE ethernet driver");
++
++static int __devexit mac_mace_device_remove (struct platform_device *pdev)
++{
++ struct net_device *dev = platform_get_drvdata(pdev);
++ struct mace_data *mp = netdev_priv(dev);
++
++ unregister_netdev(dev);
++
++ free_irq(dev->irq, dev);
++ free_irq(IRQ_MAC_MACE_DMA, dev);
++
++ dma_free_coherent(mp->device, N_RX_RING * MACE_BUFF_SIZE,
++ mp->rx_ring, mp->rx_ring_phys);
++ dma_free_coherent(mp->device, N_TX_RING * MACE_BUFF_SIZE,
++ mp->tx_ring, mp->tx_ring_phys);
++
++ free_netdev(dev);
++
++ return 0;
++}
++
++static struct platform_driver mac_mace_driver = {
++ .probe = mace_probe,
++ .remove = __devexit_p(mac_mace_device_remove),
++ .driver = {
++ .name = mac_mace_string,
++ },
++};
++
++static int __init mac_mace_init_module(void)
++{
++ int err;
++
++ if ((err = platform_driver_register(&mac_mace_driver))) {
++ printk(KERN_ERR "Driver registration failed\n");
++ return err;
++ }
++
++ mac_mace_device = platform_device_alloc(mac_mace_string, 0);
++ if (!mac_mace_device)
++ goto out_unregister;
++
++ if (platform_device_add(mac_mace_device)) {
++ platform_device_put(mac_mace_device);
++ mac_mace_device = NULL;
++ }
++
++ return 0;
++
++out_unregister:
++ platform_driver_unregister(&mac_mace_driver);
++
++ return -ENOMEM;
++}
++
++static void __exit mac_mace_cleanup_module(void)
++{
++ platform_driver_unregister(&mac_mace_driver);
++
++ if (mac_mace_device) {
++ platform_device_unregister(mac_mace_device);
++ mac_mace_device = NULL;
++ }
++}
++
++module_init(mac_mace_init_module);
++module_exit(mac_mace_cleanup_module);
diff --git a/debian/patches/bugfix/m68k/mac68k-macsonic-via-alt-mapping.diff b/debian/patches/bugfix/m68k/mac68k-macsonic-via-alt-mapping.diff
new file mode 100644
index 000000000000..0998c9cab31a
--- /dev/null
+++ b/debian/patches/bugfix/m68k/mac68k-macsonic-via-alt-mapping.diff
@@ -0,0 +1,194 @@
+Subject: [PATCH 13/13] SONIC interrupt handling
+Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>,
+ Jeff Garzik <jgarzik@pobox.com>, netdev@vger.kernel.org,
+ linux-mips@linux-mips.org
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+Install the built-in macsonic interrupt handler on both IRQs when using
+via_alt_mapping. Otherwise the rare interrupt that still comes from the
+nubus slot will wedge the nubus.
+
+$ cat /proc/interrupts
+auto 2: 89176 via2
+auto 3: 744367 sonic
+auto 4: 0 scc
+auto 6: 318363 via1
+auto 7: 0 NMI
+mac 9: 119413 framebuffer vbl
+mac 10: 1971 ADB
+mac 14: 198517 timer
+mac 17: 89104 nubus
+mac 19: 72 Mac ESP SCSI
+mac 56: 629 sonic
+mac 62: 1142593 ide0
+
+Version 1 of this patch had a bug where a nubus sonic card would register
+two interrupt handlers. Only a built-in sonic needs both.
+
+Versions 2 and 3 needed some cleanups, as Raylynn Knight and Christoph
+Hellwig pointed out (thanks).
+
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+---
+ drivers/net/jazzsonic.c | 23 +++++++++++++++++++----
+ drivers/net/macsonic.c | 46 ++++++++++++++++++++++++++++++++++++++++++----
+ drivers/net/sonic.c | 25 -------------------------
+ 3 files changed, 61 insertions(+), 33 deletions(-)
+
+--- linux-m68k-2.6.22-rc1.orig/drivers/net/jazzsonic.c
++++ linux-m68k-2.6.22-rc1/drivers/net/jazzsonic.c
+@@ -88,6 +88,23 @@ static unsigned short known_revisions[]
+ 0xffff /* end of list */
+ };
+
++static int jazzsonic_open(struct net_device* dev)
++{
++ if (request_irq(dev->irq, &sonic_interrupt, IRQF_DISABLED, "sonic", dev)) {
++ printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
++ return -EAGAIN;
++ }
++ return sonic_open(dev);
++}
++
++static int jazzsonic_close(struct net_device* dev)
++{
++ int err;
++ err = sonic_close(dev);
++ free_irq(dev->irq, dev);
++ return err;
++}
++
+ static int __init sonic_probe1(struct net_device *dev)
+ {
+ static unsigned version_printed;
+@@ -169,8 +186,8 @@ static int __init sonic_probe1(struct ne
+ lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
+ * SONIC_BUS_SCALE(lp->dma_bitmode));
+
+- dev->open = sonic_open;
+- dev->stop = sonic_close;
++ dev->open = jazzsonic_open;
++ dev->stop = jazzsonic_close;
+ dev->hard_start_xmit = sonic_send_packet;
+ dev->get_stats = sonic_get_stats;
+ dev->set_multicast_list = &sonic_multicast_list;
+@@ -260,8 +277,6 @@ MODULE_DESCRIPTION("Jazz SONIC ethernet
+ module_param(sonic_debug, int, 0);
+ MODULE_PARM_DESC(sonic_debug, "jazzsonic debug level (1-4)");
+
+-#define SONIC_IRQ_FLAG IRQF_DISABLED
+-
+ #include "sonic.c"
+
+ static int __devexit jazz_sonic_device_remove (struct platform_device *pdev)
+--- linux-m68k-2.6.22-rc1.orig/drivers/net/macsonic.c
++++ linux-m68k-2.6.22-rc1/drivers/net/macsonic.c
+@@ -130,6 +130,46 @@ static inline void bit_reverse_addr(unsi
+ addr[i] = bitrev8(addr[i]);
+ }
+
++static irqreturn_t macsonic_interrupt(int irq, void *dev_id)
++{
++ irqreturn_t result;
++ unsigned long flags;
++
++ local_irq_save(flags);
++ result = sonic_interrupt(irq, dev_id);
++ local_irq_restore(flags);
++ return result;
++}
++
++static int macsonic_open(struct net_device* dev)
++{
++ if (request_irq(dev->irq, &sonic_interrupt, IRQ_FLG_FAST, "sonic", dev)) {
++ printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
++ return -EAGAIN;
++ }
++ /* Under the A/UX interrupt scheme, the onboard SONIC interrupt comes
++ * in at priority level 3. However, we sometimes get the level 2 inter-
++ * rupt as well, which must prevent re-entrance of the sonic handler.
++ */
++ if (dev->irq == IRQ_AUTO_3)
++ if (request_irq(IRQ_NUBUS_9, &macsonic_interrupt, IRQ_FLG_FAST, "sonic", dev)) {
++ printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, IRQ_NUBUS_9);
++ free_irq(dev->irq, dev);
++ return -EAGAIN;
++ }
++ return sonic_open(dev);
++}
++
++static int macsonic_close(struct net_device* dev)
++{
++ int err;
++ err = sonic_close(dev);
++ free_irq(dev->irq, dev);
++ if (dev->irq == IRQ_AUTO_3)
++ free_irq(IRQ_NUBUS_9, dev);
++ return err;
++}
++
+ int __init macsonic_init(struct net_device* dev)
+ {
+ struct sonic_local* lp = netdev_priv(dev);
+@@ -160,8 +200,8 @@ int __init macsonic_init(struct net_devi
+ lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
+ * SONIC_BUS_SCALE(lp->dma_bitmode));
+
+- dev->open = sonic_open;
+- dev->stop = sonic_close;
++ dev->open = macsonic_open;
++ dev->stop = macsonic_close;
+ dev->hard_start_xmit = sonic_send_packet;
+ dev->get_stats = sonic_get_stats;
+ dev->set_multicast_list = &sonic_multicast_list;
+@@ -572,8 +612,6 @@ MODULE_DESCRIPTION("Macintosh SONIC ethe
+ module_param(sonic_debug, int, 0);
+ MODULE_PARM_DESC(sonic_debug, "macsonic debug level (1-4)");
+
+-#define SONIC_IRQ_FLAG IRQ_FLG_FAST
+-
+ #include "sonic.c"
+
+ static int __devexit mac_sonic_device_remove (struct platform_device *pdev)
+--- linux-m68k-2.6.22-rc1.orig/drivers/net/sonic.c
++++ linux-m68k-2.6.22-rc1/drivers/net/sonic.c
+@@ -50,29 +50,6 @@ static int sonic_open(struct net_device
+ if (sonic_debug > 2)
+ printk("sonic_open: initializing sonic driver.\n");
+
+- /*
+- * We don't need to deal with auto-irq stuff since we
+- * hardwire the sonic interrupt.
+- */
+-/*
+- * XXX Horrible work around: We install sonic_interrupt as fast interrupt.
+- * This means that during execution of the handler interrupt are disabled
+- * covering another bug otherwise corrupting data. This doesn't mean
+- * this glue works ok under all situations.
+- *
+- * Note (dhd): this also appears to prevent lockups on the Macintrash
+- * when more than one Ethernet card is installed (knock on wood)
+- *
+- * Note (fthain): whether the above is still true is anyones guess. Certainly
+- * the buffer handling algorithms will not tolerate re-entrance without some
+- * mutual exclusion added. Anyway, the memcpy has now been eliminated from the
+- * rx code to make this a faster "fast interrupt".
+- */
+- if (request_irq(dev->irq, &sonic_interrupt, SONIC_IRQ_FLAG, "sonic", dev)) {
+- printk(KERN_ERR "\n%s: unable to get IRQ %d .\n", dev->name, dev->irq);
+- return -EAGAIN;
+- }
+-
+ for (i = 0; i < SONIC_NUM_RRS; i++) {
+ struct sk_buff *skb = dev_alloc_skb(SONIC_RBSIZE + 2);
+ if (skb == NULL) {
+@@ -169,8 +146,6 @@ static int sonic_close(struct net_device
+ }
+ }
+
+- free_irq(dev->irq, dev); /* release the IRQ */
+-
+ return 0;
+ }
+
diff --git a/debian/patches/bugfix/m68k/mac68k-patch_A-mac68k_cvs_nubus_defines.diff b/debian/patches/bugfix/m68k/mac68k-patch_A-mac68k_cvs_nubus_defines.diff
new file mode 100644
index 000000000000..7572b96cc5e6
--- /dev/null
+++ b/debian/patches/bugfix/m68k/mac68k-patch_A-mac68k_cvs_nubus_defines.diff
@@ -0,0 +1,222 @@
+Subject: [PATCH 3/13] NuBus header update
+Cc: nubus-pmac-users@lists.sourceforge.net
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+Sync the nubus defines with the latest code in the mac68k repo. Some of these
+are needed for DP8390 driver update in the next patch.
+
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ drivers/net/macsonic.c | 2
+ include/linux/nubus.h | 126 +++++++++++++++++++++++++++++--------------------
+ 2 files changed, 76 insertions(+), 52 deletions(-)
+
+--- linux-m68k-2.6.21.orig/drivers/net/macsonic.c
++++ linux-m68k-2.6.21/drivers/net/macsonic.c
+@@ -402,7 +402,7 @@ int __init macsonic_ident(struct nubus_d
+ ndev->dr_sw == NUBUS_DRSW_DAYNA)
+ return MACSONIC_DAYNA;
+
+- if (ndev->dr_hw == NUBUS_DRHW_SONIC_LC &&
++ if (ndev->dr_hw == NUBUS_DRHW_APPLE_SONIC_LC &&
+ ndev->dr_sw == 0) { /* huh? */
+ return MACSONIC_APPLE16;
+ }
+--- linux-m68k-2.6.21.orig/include/linux/nubus.h
++++ linux-m68k-2.6.21/include/linux/nubus.h
+@@ -28,18 +28,18 @@ enum nubus_category {
+ };
+
+ enum nubus_type_network {
+- NUBUS_TYPE_ETHERNET = 0x0001,
+- NUBUS_TYPE_RS232 = 0x0002
++ NUBUS_TYPE_ETHERNET = 0x0001,
++ NUBUS_TYPE_RS232 = 0x0002
+ };
+
+ enum nubus_type_display {
+- NUBUS_TYPE_VIDEO = 0x0001
++ NUBUS_TYPE_VIDEO = 0x0001
+ };
+
+ enum nubus_type_cpu {
+- NUBUS_TYPE_68020 = 0x0003,
+- NUBUS_TYPE_68030 = 0x0004,
+- NUBUS_TYPE_68040 = 0x0005
++ NUBUS_TYPE_68020 = 0x0003,
++ NUBUS_TYPE_68030 = 0x0004,
++ NUBUS_TYPE_68040 = 0x0005
+ };
+
+ /* Known <Cat,Type,SW,HW> tuples: (according to TattleTech and Slots)
+@@ -56,6 +56,7 @@ enum nubus_type_cpu {
+ *
+ * SONIC comm-slot/on-board and DuoDock Ethernet: <4,1,1,272>
+ * SONIC LC-PDS Ethernet (Dayna, but like Apple 16-bit, sort of): <4,1,1,271>
++ * Apple SONIC LC-PDS Ethernet ("Apple Ethernet LC Twisted-Pair Card"): <4,1,0,281>
+ * Sonic Systems Ethernet A-Series Card: <4,1,268,256>
+ * Asante MacCon NuBus-A: <4,1,260,256> (alpha-1.0,1.1 revision)
+ * ROM on the above card: <2,1,0,0>
+@@ -80,24 +81,26 @@ enum nubus_type_cpu {
+ /* Add known DrSW values here */
+ enum nubus_drsw {
+ /* NUBUS_CAT_DISPLAY */
+- NUBUS_DRSW_APPLE = 0x0001,
+- NUBUS_DRSW_APPLE_HIRES = 0x0013, /* MacII HiRes card driver */
++ NUBUS_DRSW_APPLE = 0x0001,
++ NUBUS_DRSW_APPLE_HIRES = 0x0013, /* MacII HiRes card driver */
+
+ /* NUBUS_CAT_NETWORK */
+- NUBUS_DRSW_CABLETRON = 0x0001,
+- NUBUS_DRSW_SONIC_LC = 0x0001,
+- NUBUS_DRSW_KINETICS = 0x0103,
+- NUBUS_DRSW_ASANTE = 0x0104,
+- NUBUS_DRSW_DAYNA = 0x010b,
+- NUBUS_DRSW_FARALLON = 0x010c,
+- NUBUS_DRSW_APPLE_SN = 0x010f,
+- NUBUS_DRSW_DAYNA2 = 0x0115,
++ NUBUS_DRSW_3COM = 0x0000,
++ NUBUS_DRSW_CABLETRON = 0x0001,
++ NUBUS_DRSW_SONIC_LC = 0x0001,
++ NUBUS_DRSW_KINETICS = 0x0103,
++ NUBUS_DRSW_ASANTE = 0x0104,
++ NUBUS_DRSW_TECHWORKS = 0x0109,
++ NUBUS_DRSW_DAYNA = 0x010b,
++ NUBUS_DRSW_FARALLON = 0x010c,
++ NUBUS_DRSW_APPLE_SN = 0x010f,
++ NUBUS_DRSW_DAYNA2 = 0x0115,
+ NUBUS_DRSW_FOCUS = 0x011a,
+ NUBUS_DRSW_ASANTE_CS = 0x011d, /* use asante SMC9194 driver */
+- NUBUS_DRSW_DAYNA_LC = 0x011e,
++ NUBUS_DRSW_DAYNA_LC = 0x011e,
+
+ /* NUBUS_CAT_CPU */
+- NUBUS_DRSW_NONE = 0x0000,
++ NUBUS_DRSW_NONE = 0x0000,
+ };
+
+ /* DrHW: Uniquely identifies the hardware interface to a board (or at
+@@ -107,27 +110,48 @@ enum nubus_drsw {
+ /* Add known DrHW values here */
+ enum nubus_drhw {
+ /* NUBUS_CAT_DISPLAY */
+- NUBUS_DRHW_APPLE_TFB = 0x0001, /* Toby frame buffer card */
+- NUBUS_DRHW_APPLE_HRVC = 0x0013, /* Mac II High Res Video card */
+- NUBUS_DRHW_APPLE_RBV1 = 0x0018, /* IIci RBV video */
+- NUBUS_DRHW_APPLE_MDC = 0x0019, /* Macintosh Display Card */
+- NUBUS_DRHW_APPLE_SONORA = 0x0022, /* Sonora built-in video */
+- NUBUS_DRHW_APPLE_JET = 0x0029, /* Jet framebuffer (DuoDock) */
++ NUBUS_DRHW_APPLE_TFB = 0x0001, /* Toby frame buffer card */
++ NUBUS_DRHW_APPLE_WVC = 0x0006, /* Apple Workstation Video Card */
++ NUBUS_DRHW_SIGMA_CLRMAX = 0x0007, /* Sigma Design ColorMax */
++ NUBUS_DRHW_APPLE_SE30 = 0x0009, /* Apple SE/30 video */
++ NUBUS_DRHW_APPLE_HRVC = 0x0013, /* Mac II High-Res Video Card */
++ NUBUS_DRHW_APPLE_PVC = 0x0017, /* Mac II Portrait Video Card */
++ NUBUS_DRHW_APPLE_RBV1 = 0x0018, /* IIci RBV video */
++ NUBUS_DRHW_APPLE_MDC = 0x0019, /* Macintosh Display Card */
++ NUBUS_DRHW_APPLE_SONORA = 0x0022, /* Sonora built-in video */
++ NUBUS_DRHW_APPLE_24AC = 0x002b, /* Mac 24AC Video Card */
+ NUBUS_DRHW_APPLE_VALKYRIE = 0x002e,
+- NUBUS_DRHW_THUNDER24 = 0x02cb, /* SuperMac Thunder/24 */
++ NUBUS_DRHW_APPLE_JET = 0x0029, /* Jet framebuffer (DuoDock) */
++ NUBUS_DRHW_SMAC_GFX = 0x0105, /* SuperMac GFX */
++ NUBUS_DRHW_RASTER_CB264 = 0x013B, /* RasterOps ColorBoard 264 */
++ NUBUS_DRHW_MICRON_XCEED = 0x0146, /* Micron Exceed color */
++ NUBUS_DRHW_RDIUS_GSC = 0x0153, /* Radius GS/C */
++ NUBUS_DRHW_SMAC_SPEC8 = 0x017B, /* SuperMac Spectrum/8 */
++ NUBUS_DRHW_SMAC_SPEC24 = 0x017C, /* SuperMac Spectrum/24 */
++ NUBUS_DRHW_RASTER_CB364 = 0x026F, /* RasterOps ColorBoard 364 */
++ NUBUS_DRHW_RDIUS_DCGX = 0x027C, /* Radius DirectColor/GX */
++ NUBUS_DRHW_RDIUS_PC8 = 0x0291, /* Radius PrecisionColor 8 */
++ NUBUS_DRHW_LAPIS_PCS8 = 0x0292, /* Lapis ProColorServer 8 */
++ NUBUS_DRHW_RASTER_24LXI = 0x02A0, /* RasterOps 8/24 XLi */
++ NUBUS_DRHW_RASTER_PBPGT = 0x02A5, /* RasterOps PaintBoard Prism GT */
++ NUBUS_DRHW_EMACH_FSX = 0x02AE, /* E-Machines Futura SX */
++ NUBUS_DRHW_SMAC_THUND24 = 0x02CB, /* SuperMac Thunder/24 */
++ NUBUS_DRHW_RDIUS_PC24XP = 0x0406, /* Radius PrecisionColor 24Xp */
++ NUBUS_DRHW_RDIUS_PC24X = 0x040A, /* Radius PrecisionColor 24X */
++ NUBUS_DRHW_RDIUS_PC8XJ = 0x040B, /* Radius PrecisionColor 8XJ */
+
+ /* NUBUS_CAT_NETWORK */
+- NUBUS_DRHW_INTERLAN = 0x0100,
+- NUBUS_DRHW_SMC9194 = 0x0101,
+- NUBUS_DRHW_KINETICS = 0x0106,
+- NUBUS_DRHW_CABLETRON = 0x0109,
+- NUBUS_DRHW_ASANTE_LC = 0x010f,
+- NUBUS_DRHW_SONIC = 0x0110,
+- NUBUS_DRHW_SONIC_NB = 0x0118,
+- NUBUS_DRHW_SONIC_LC = 0x0119,
+-
+- /* NUBUS_CAT_COMMUNICATIONS */
+- NUBUS_DRHW_DOVEFAX = 0x0100,
++ NUBUS_DRHW_INTERLAN = 0x0100,
++ NUBUS_DRHW_SMC9194 = 0x0101,
++ NUBUS_DRHW_KINETICS = 0x0106,
++ NUBUS_DRHW_CABLETRON = 0x0109,
++ NUBUS_DRHW_ASANTE_LC = 0x010f,
++ NUBUS_DRHW_SONIC = 0x0110,
++ NUBUS_DRHW_TECHWORKS = 0x0112,
++ NUBUS_DRHW_APPLE_SONIC_NB = 0x0118,
++ NUBUS_DRHW_APPLE_SONIC_LC = 0x0119,
++ NUBUS_DRHW_FOCUS = 0x011c,
++ NUBUS_DRHW_SONNET = 0x011d,
+ };
+
+ /* Resource IDs: These are the identifiers for the various weird and
+@@ -153,17 +177,17 @@ enum nubus_res_id {
+
+ /* Category-specific resources. */
+ enum nubus_board_res_id {
+- NUBUS_RESID_BOARDID = 0x0020,
++ NUBUS_RESID_BOARDID = 0x0020,
+ NUBUS_RESID_PRAMINITDATA = 0x0021,
+- NUBUS_RESID_PRIMARYINIT = 0x0022,
++ NUBUS_RESID_PRIMARYINIT = 0x0022,
+ NUBUS_RESID_TIMEOUTCONST = 0x0023,
+- NUBUS_RESID_VENDORINFO = 0x0024,
+- NUBUS_RESID_BOARDFLAGS = 0x0025,
+- NUBUS_RESID_SECONDINIT = 0x0026,
++ NUBUS_RESID_VENDORINFO = 0x0024,
++ NUBUS_RESID_BOARDFLAGS = 0x0025,
++ NUBUS_RESID_SECONDINIT = 0x0026,
+
+ /* Not sure why Apple put these next two in here */
+- NUBUS_RESID_VIDNAMES = 0x0041,
+- NUBUS_RESID_VIDMODES = 0x007e
++ NUBUS_RESID_VIDNAMES = 0x0041,
++ NUBUS_RESID_VIDMODES = 0x007e
+ };
+
+ /* Fields within the vendor info directory */
+@@ -185,13 +209,13 @@ enum nubus_cpu_res_id {
+ };
+
+ enum nubus_display_res_id {
+- NUBUS_RESID_GAMMADIR = 0x0040,
+- NUBUS_RESID_FIRSTMODE = 0x0080,
+- NUBUS_RESID_SECONDMODE = 0x0081,
+- NUBUS_RESID_THIRDMODE = 0x0082,
+- NUBUS_RESID_FOURTHMODE = 0x0083,
+- NUBUS_RESID_FIFTHMODE = 0x0084,
+- NUBUS_RESID_SIXTHMODE = 0x0085
++ NUBUS_RESID_GAMMADIR = 0x0040,
++ NUBUS_RESID_FIRSTMODE = 0x0080,
++ NUBUS_RESID_SECONDMODE = 0x0081,
++ NUBUS_RESID_THIRDMODE = 0x0082,
++ NUBUS_RESID_FOURTHMODE = 0x0083,
++ NUBUS_RESID_FIFTHMODE = 0x0084,
++ NUBUS_RESID_SIXTHMODE = 0x0085
+ };
+
+ struct nubus_dir
+@@ -214,7 +238,7 @@ struct nubus_board {
+ struct nubus_board* next;
+ struct nubus_dev* first_dev;
+
+- /* Only 9-E actually exist, though 0-8 are also theoretically
++ /* Only 9-E actually exist, though 0-8 are also theoretically
+ possible, and 0 is a special case which represents the
+ motherboard and onboard peripherals (Ethernet, video) */
+ int slot;
diff --git a/debian/patches/bugfix/m68k/mac68k-patch_B-mac68k_cvs_DP8390_update.diff b/debian/patches/bugfix/m68k/mac68k-patch_B-mac68k_cvs_DP8390_update.diff
new file mode 100644
index 000000000000..3ee8e2bd4e56
--- /dev/null
+++ b/debian/patches/bugfix/m68k/mac68k-patch_B-mac68k_cvs_DP8390_update.diff
@@ -0,0 +1,398 @@
+Subject: [PATCH 4/13] m68k: Mac DP8390 update
+Cc: Jeff Garzik <jgarzik@pobox.com>, netdev@vger.kernel.org
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+Fix the support for C/NET nubus ethernet cards etc. Sync up the DP8390 driver
+with the latest code in the mac68k repo.
+
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ drivers/net/mac8390.c | 245 +++++++++++++++++++++++++++++++++++---------------
+ 1 file changed, 175 insertions(+), 70 deletions(-)
+
+--- linux-m68k-2.6.21.orig/drivers/net/mac8390.c
++++ linux-m68k-2.6.21/drivers/net/mac8390.c
+@@ -14,6 +14,8 @@
+ /* 2001-05-15: support for Cabletron ported from old daynaport driver
+ * and fixed access to Sonic Sys card which masquerades as a Farallon
+ * by rayk@knightsmanor.org */
++/* 2002-12-30: Try to support more cards, some clues from NetBSD driver */
++/* 2003-12-26: Make sure Asante cards always work. */
+
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+@@ -61,25 +63,21 @@ static char version[] =
+ #define DAYNA_8390_BASE 0x80000
+ #define DAYNA_8390_MEM 0x00000
+
+-#define KINETICS_8390_BASE 0x80000
+-#define KINETICS_8390_MEM 0x00000
+-
+ #define CABLETRON_8390_BASE 0x90000
+ #define CABLETRON_8390_MEM 0x00000
+
++#define INTERLAN_8390_BASE 0xE0000
++#define INTERLAN_8390_MEM 0xD0000
++
+ enum mac8390_type {
+ MAC8390_NONE = -1,
+ MAC8390_APPLE,
+ MAC8390_ASANTE,
+- MAC8390_FARALLON, /* Apple, Asante, and Farallon are all compatible */
++ MAC8390_FARALLON,
+ MAC8390_CABLETRON,
+ MAC8390_DAYNA,
+ MAC8390_INTERLAN,
+ MAC8390_KINETICS,
+- MAC8390_FOCUS,
+- MAC8390_SONICSYS,
+- MAC8390_DAYNA2,
+- MAC8390_DAYNA3,
+ };
+
+ static const char * cardname[] = {
+@@ -90,10 +88,6 @@ static const char * cardname[] = {
+ "dayna",
+ "interlan",
+ "kinetics",
+- "focus",
+- "sonic systems",
+- "dayna2",
+- "dayna_lc",
+ };
+
+ static int word16[] = {
+@@ -104,10 +98,6 @@ static int word16[] = {
+ 0, /* dayna */
+ 1, /* interlan */
+ 0, /* kinetics */
+- 1, /* focus (??) */
+- 1, /* sonic systems */
+- 1, /* dayna2 */
+- 1, /* dayna-lc */
+ };
+
+ /* on which cards do we use NuBus resources? */
+@@ -119,10 +109,12 @@ static int useresources[] = {
+ 0, /* dayna */
+ 0, /* interlan */
+ 0, /* kinetics */
+- 0, /* focus (??) */
+- 1, /* sonic systems */
+- 1, /* dayna2 */
+- 1, /* dayna-lc */
++};
++
++enum mac8390_access {
++ ACCESS_UNKNOWN = 0,
++ ACCESS_32,
++ ACCESS_16,
+ };
+
+ extern enum mac8390_type mac8390_ident(struct nubus_dev * dev);
+@@ -134,8 +126,9 @@ static int mac8390_initdev(struct net_de
+ static int mac8390_open(struct net_device * dev);
+ static int mac8390_close(struct net_device * dev);
+ static void mac8390_no_reset(struct net_device *dev);
++static void interlan_reset(struct net_device *dev);
+
+-/* Sane (32-bit chunk memory read/write) - Apple/Asante/Farallon do this*/
++/* Sane (32-bit chunk memory read/write) - Some Farallon and Apple do this*/
+ static void sane_get_8390_hdr(struct net_device *dev,
+ struct e8390_pkt_hdr *hdr, int ring_page);
+ static void sane_block_input(struct net_device * dev, int count,
+@@ -172,23 +165,93 @@ static void word_memcpy_fromcard(void *t
+
+ enum mac8390_type __init mac8390_ident(struct nubus_dev * dev)
+ {
+- if (dev->dr_sw == NUBUS_DRSW_ASANTE)
+- return MAC8390_ASANTE;
+- if (dev->dr_sw == NUBUS_DRSW_FARALLON)
+- return MAC8390_FARALLON;
+- if (dev->dr_sw == NUBUS_DRSW_KINETICS)
+- return MAC8390_KINETICS;
+- if (dev->dr_sw == NUBUS_DRSW_DAYNA)
+- return MAC8390_DAYNA;
+- if (dev->dr_sw == NUBUS_DRSW_DAYNA2)
+- return MAC8390_DAYNA2;
+- if (dev->dr_sw == NUBUS_DRSW_DAYNA_LC)
+- return MAC8390_DAYNA3;
+- if (dev->dr_hw == NUBUS_DRHW_CABLETRON)
+- return MAC8390_CABLETRON;
++ switch (dev->dr_sw) {
++ case NUBUS_DRSW_3COM:
++ switch (dev->dr_hw) {
++ case NUBUS_DRHW_APPLE_SONIC_NB:
++ case NUBUS_DRHW_APPLE_SONIC_LC:
++ case NUBUS_DRHW_SONNET:
++ return MAC8390_NONE;
++ break;
++ default:
++ return MAC8390_APPLE;
++ break;
++ }
++ break;
++
++ case NUBUS_DRSW_APPLE:
++ switch (dev->dr_hw) {
++ case NUBUS_DRHW_ASANTE_LC:
++ return MAC8390_NONE;
++ break;
++ case NUBUS_DRHW_CABLETRON:
++ return MAC8390_CABLETRON;
++ break;
++ default:
++ return MAC8390_APPLE;
++ break;
++ }
++ break;
++
++ case NUBUS_DRSW_ASANTE:
++ return MAC8390_ASANTE;
++ break;
++
++ case NUBUS_DRSW_TECHWORKS:
++ case NUBUS_DRSW_DAYNA2:
++ case NUBUS_DRSW_DAYNA_LC:
++ if (dev->dr_hw == NUBUS_DRHW_CABLETRON)
++ return MAC8390_CABLETRON;
++ else
++ return MAC8390_APPLE;
++ break;
++
++ case NUBUS_DRSW_FARALLON:
++ return MAC8390_FARALLON;
++ break;
++
++ case NUBUS_DRSW_KINETICS:
++ switch (dev->dr_hw) {
++ case NUBUS_DRHW_INTERLAN:
++ return MAC8390_INTERLAN;
++ break;
++ default:
++ return MAC8390_KINETICS;
++ break;
++ }
++ break;
++
++ case NUBUS_DRSW_DAYNA:
++ // These correspond to Dayna Sonic cards
++ // which use the macsonic driver
++ if (dev->dr_hw == NUBUS_DRHW_SMC9194 ||
++ dev->dr_hw == NUBUS_DRHW_INTERLAN )
++ return MAC8390_NONE;
++ else
++ return MAC8390_DAYNA;
++ break;
++ }
+ return MAC8390_NONE;
+ }
+
++enum mac8390_access __init mac8390_testio(volatile unsigned long membase)
++{
++ unsigned long outdata = 0xA5A0B5B0;
++ unsigned long indata = 0x00000000;
++ /* Try writing 32 bits */
++ memcpy((char *)membase, (char *)&outdata, 4);
++ /* Now compare them */
++ if (memcmp((char *)&outdata, (char *)membase, 4) == 0)
++ return ACCESS_32;
++ /* Write 16 bit output */
++ word_memcpy_tocard((char *)membase, (char *)&outdata, 4);
++ /* Now read it back */
++ word_memcpy_fromcard((char *)&indata, (char *)membase, 4);
++ if (outdata == indata)
++ return ACCESS_16;
++ return ACCESS_UNKNOWN;
++}
++
+ int __init mac8390_memsize(unsigned long membase)
+ {
+ unsigned long flags;
+@@ -287,14 +350,6 @@ struct net_device * __init mac8390_probe
+ continue;
+ } else {
+ nubus_get_rsrc_mem(dev->dev_addr, &ent, 6);
+- /* Some Sonic Sys cards masquerade as Farallon */
+- if (cardtype == MAC8390_FARALLON &&
+- dev->dev_addr[0] == 0x0 &&
+- dev->dev_addr[1] == 0x40 &&
+- dev->dev_addr[2] == 0x10) {
+- /* This is really Sonic Sys card */
+- cardtype = MAC8390_SONICSYS;
+- }
+ }
+
+ if (useresources[cardtype] == 1) {
+@@ -334,6 +389,17 @@ struct net_device * __init mac8390_probe
+ dev->mem_start +
+ mac8390_memsize(dev->mem_start);
+ break;
++ case MAC8390_INTERLAN:
++ dev->base_addr =
++ (int)(ndev->board->slot_addr +
++ INTERLAN_8390_BASE);
++ dev->mem_start =
++ (int)(ndev->board->slot_addr +
++ INTERLAN_8390_MEM);
++ dev->mem_end =
++ dev->mem_start +
++ mac8390_memsize(dev->mem_start);
++ break;
+ case MAC8390_CABLETRON:
+ dev->base_addr =
+ (int)(ndev->board->slot_addr +
+@@ -356,8 +422,8 @@ struct net_device * __init mac8390_probe
+
+ default:
+ printk(KERN_ERR "Card type %s is"
+- " unsupported, sorry\n",
+- cardname[cardtype]);
++ " unsupported, sorry\n",
++ ndev->board->name);
+ continue;
+ }
+ }
+@@ -438,7 +504,7 @@ static int __init mac8390_initdev(struct
+ 24, 26, 28, 30
+ };
+
+- int access_bitmode;
++ int access_bitmode = 0;
+
+ /* Now fill in our stuff */
+ dev->open = &mac8390_open;
+@@ -468,29 +534,47 @@ static int __init mac8390_initdev(struct
+
+ /* Fill in model-specific information and functions */
+ switch(type) {
+- case MAC8390_SONICSYS:
+- /* 16 bit card, register map is reversed */
+- ei_status.reset_8390 = &mac8390_no_reset;
+- ei_status.block_input = &slow_sane_block_input;
+- ei_status.block_output = &slow_sane_block_output;
+- ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+- ei_status.reg_offset = back4_offsets;
+- access_bitmode = 0;
+- break;
+ case MAC8390_FARALLON:
+ case MAC8390_APPLE:
++ switch(mac8390_testio(dev->mem_start)) {
++ case ACCESS_UNKNOWN:
++ printk("Don't know how to access card memory!\n");
++ return -ENODEV;
++ break;
++
++ case ACCESS_16:
++ /* 16 bit card, register map is reversed */
++ ei_status.reset_8390 = &mac8390_no_reset;
++ ei_status.block_input = &slow_sane_block_input;
++ ei_status.block_output = &slow_sane_block_output;
++ ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
++ ei_status.reg_offset = back4_offsets;
++ break;
++
++ case ACCESS_32:
++ /* 32 bit card, register map is reversed */
++ ei_status.reset_8390 = &mac8390_no_reset;
++ ei_status.block_input = &sane_block_input;
++ ei_status.block_output = &sane_block_output;
++ ei_status.get_8390_hdr = &sane_get_8390_hdr;
++ ei_status.reg_offset = back4_offsets;
++ access_bitmode = 1;
++ break;
++ }
++ break;
++
+ case MAC8390_ASANTE:
+- case MAC8390_DAYNA2:
+- case MAC8390_DAYNA3:
+- /* 32 bit card, register map is reversed */
+- /* sane */
++ /* Some Asante cards pass the 32 bit test
++ * but overwrite system memory when run at 32 bit.
++ * so we run them all at 16 bit.
++ */
+ ei_status.reset_8390 = &mac8390_no_reset;
+- ei_status.block_input = &sane_block_input;
+- ei_status.block_output = &sane_block_output;
+- ei_status.get_8390_hdr = &sane_get_8390_hdr;
++ ei_status.block_input = &slow_sane_block_input;
++ ei_status.block_output = &slow_sane_block_output;
++ ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+ ei_status.reg_offset = back4_offsets;
+- access_bitmode = 1;
+ break;
++
+ case MAC8390_CABLETRON:
+ /* 16 bit card, register map is short forward */
+ ei_status.reset_8390 = &mac8390_no_reset;
+@@ -498,21 +582,30 @@ static int __init mac8390_initdev(struct
+ ei_status.block_output = &slow_sane_block_output;
+ ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+ ei_status.reg_offset = fwrd2_offsets;
+- access_bitmode = 0;
+ break;
++
+ case MAC8390_DAYNA:
+ case MAC8390_KINETICS:
+- /* 16 bit memory */
++ /* 16 bit memory, register map is forward */
+ /* dayna and similar */
+ ei_status.reset_8390 = &mac8390_no_reset;
+ ei_status.block_input = &dayna_block_input;
+ ei_status.block_output = &dayna_block_output;
+ ei_status.get_8390_hdr = &dayna_get_8390_hdr;
+ ei_status.reg_offset = fwrd4_offsets;
+- access_bitmode = 0;
+ break;
++
++ case MAC8390_INTERLAN:
++ /* 16 bit memory, register map is forward */
++ ei_status.reset_8390 = &interlan_reset;
++ ei_status.block_input = &slow_sane_block_input;
++ ei_status.block_output = &slow_sane_block_output;
++ ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
++ ei_status.reg_offset = fwrd4_offsets;
++ break;
++
+ default:
+- printk(KERN_ERR "Card type %s is unsupported, sorry\n", cardname[type]);
++ printk(KERN_ERR "Card type %s is unsupported, sorry\n", ndev->board->name);
+ return -ENODEV;
+ }
+
+@@ -530,9 +623,9 @@ static int __init mac8390_initdev(struct
+ printk(":");
+ }
+ }
+- printk(" IRQ %d, shared memory at %#lx-%#lx, %d-bit access.\n",
+- dev->irq, dev->mem_start, dev->mem_end-1,
+- access_bitmode?32:16);
++ printk(" IRQ %d, %d KB shared memory at %#lx, %d-bit access.\n",
++ dev->irq, (int)((dev->mem_end - dev->mem_start)/0x1000) * 4,
++ dev->mem_start, access_bitmode?32:16);
+ return 0;
+ }
+
+@@ -561,6 +654,18 @@ static void mac8390_no_reset(struct net_
+ return;
+ }
+
++static void interlan_reset(struct net_device *dev)
++{
++ unsigned char *target=nubus_slot_addr(IRQ2SLOT(dev->irq));
++ if (ei_debug > 1)
++ printk("Need to reset the NS8390 t=%lu...", jiffies);
++ ei_status.txing = 0;
++ target[0xC0000] = 0;
++ if (ei_debug > 1)
++ printk("reset complete\n");
++ return;
++}
++
+ /* dayna_memcpy_fromio/dayna_memcpy_toio */
+ /* directly from daynaport.c by Alan Cox */
+ static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from, int count)
diff --git a/debian/patches/bugfix/m68k/mac68k-patch_d-via-alt-mapping.diff b/debian/patches/bugfix/m68k/mac68k-patch_d-via-alt-mapping.diff
new file mode 100644
index 000000000000..78a098803a19
--- /dev/null
+++ b/debian/patches/bugfix/m68k/mac68k-patch_d-via-alt-mapping.diff
@@ -0,0 +1,30 @@
+Subject: [PATCH 2/13] m68k: Mac interrupt priorities
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+Add some more machines that support A/UX interrupt priorities. There are
+probably others as well, but I've only tested these ones so far.
+
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ arch/m68k/mac/via.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- linux-m68k-2.6.21.orig/arch/m68k/mac/via.c
++++ linux-m68k-2.6.21/arch/m68k/mac/via.c
+@@ -193,8 +193,14 @@ void __init via_init(void)
+ /* that the IIfx emulates this alternate mapping using the OSS. */
+
+ switch(macintosh_config->ident) {
++ case MAC_MODEL_P475:
++ case MAC_MODEL_P475F:
++ case MAC_MODEL_P575:
++ case MAC_MODEL_Q605:
++ case MAC_MODEL_Q605_ACC:
+ case MAC_MODEL_C610:
+ case MAC_MODEL_Q610:
++ case MAC_MODEL_Q630:
+ case MAC_MODEL_C650:
+ case MAC_MODEL_Q650:
+ case MAC_MODEL_Q700:
diff --git a/debian/patches/bugfix/m68k/mac68k-remove-unused-adb-header.diff b/debian/patches/bugfix/m68k/mac68k-remove-unused-adb-header.diff
new file mode 100644
index 000000000000..b6cc37c12c08
--- /dev/null
+++ b/debian/patches/bugfix/m68k/mac68k-remove-unused-adb-header.diff
@@ -0,0 +1,92 @@
+Subject: [PATCH 1/13] m68k: remove unused adb.h
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+The asm-m68k/adb.h header is unused. Some definitions are wrong and the rest
+are duplicated in linux/adb.h. Remove it.
+
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+
+---
+ include/asm-m68k/adb.h | 75 -------------------------------------------------
+ 1 file changed, 75 deletions(-)
+
+--- linux-m68k-2.6.21.orig/include/asm-m68k/adb.h
++++ /dev/null
+@@ -1,75 +0,0 @@
+-/*
+- * Definitions for talking to ADB and CUDA. The CUDA is a microcontroller
+- * which controls the ADB, system power, RTC, and various other things on
+- * later Macintoshes
+- *
+- * Copyright (C) 1996 Paul Mackerras.
+- */
+-
+-/* First byte sent to or received from CUDA */
+-#define ADB_PACKET 0
+-#define CUDA_PACKET 1
+-#define ERROR_PACKET 2
+-#define TIMER_PACKET 3
+-#define POWER_PACKET 4
+-#define MACIIC_PACKET 5
+-
+-/* ADB commands (2nd byte) */
+-#define ADB_BUSRESET 0
+-#define ADB_FLUSH(id) (1 + ((id) << 4))
+-#define ADB_WRITEREG(id, reg) (8 + (reg) + ((id) << 4))
+-#define ADB_READREG(id, reg) (0xc + (reg) + ((id) << 4))
+-
+-/* ADB default device IDs (upper 4 bits of 2nd byte) */
+-#define ADB_DONGLE 1 /* "software execution control" devices */
+-#define ADB_KEYBOARD 2
+-#define ADB_MOUSE 3
+-#define ADB_TABLET 4
+-#define ADB_MODEM 5
+-#define ADB_MISC 7 /* maybe a monitor */
+-
+-/* CUDA commands (2nd byte) */
+-#define CUDA_WARM_START 0
+-#define CUDA_AUTOPOLL 1
+-#define CUDA_GET_6805_ADDR 2
+-#define CUDA_GET_TIME 3
+-#define CUDA_GET_PRAM 7
+-#define CUDA_SET_6805_ADDR 8
+-#define CUDA_SET_TIME 9
+-#define CUDA_POWERDOWN 0xa
+-#define CUDA_POWERUP_TIME 0xb
+-#define CUDA_SET_PRAM 0xc
+-#define CUDA_MS_RESET 0xd
+-#define CUDA_SEND_DFAC 0xe
+-#define CUDA_RESET_SYSTEM 0x11
+-#define CUDA_SET_IPL 0x12
+-#define CUDA_SET_AUTO_RATE 0x14
+-#define CUDA_GET_AUTO_RATE 0x16
+-#define CUDA_SET_DEVICE_LIST 0x19
+-#define CUDA_GET_DEVICE_LIST 0x1a
+-#define CUDA_GET_SET_IIC 0x22
+-
+-#ifdef __KERNEL__
+-
+-struct adb_request {
+- unsigned char data[16];
+- int nbytes;
+- unsigned char reply[16];
+- int reply_len;
+- unsigned char reply_expected;
+- unsigned char sent;
+- unsigned char got_reply;
+- void (*done)(struct adb_request *);
+- void *arg;
+- struct adb_request *next;
+-};
+-
+-void via_adb_init(void);
+-int adb_request(struct adb_request *req,
+- void (*done)(struct adb_request *), int nbytes, ...);
+-int adb_send_request(struct adb_request *req);
+-void adb_poll(void);
+-int adb_register(int default_id,
+- void (*handler)(unsigned char *, int, struct pt_regs *));
+-
+-#endif /* __KERNEL */
diff --git a/debian/patches/bugfix/m68k/mac68k-revert-remaining-irq-damage.diff b/debian/patches/bugfix/m68k/mac68k-revert-remaining-irq-damage.diff
new file mode 100644
index 000000000000..bfc12bad9044
--- /dev/null
+++ b/debian/patches/bugfix/m68k/mac68k-revert-remaining-irq-damage.diff
@@ -0,0 +1,80 @@
+Subject: [PATCH 5/13] m68k: reverse Mac IRQ damage
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+Reverse the last of a monumental brown-paper-bag commit that went into the 2.3
+kernel.
+
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ arch/m68k/mac/baboon.c | 2 +-
+ arch/m68k/mac/oss.c | 6 +++---
+ arch/m68k/mac/psc.c | 2 +-
+ arch/m68k/mac/via.c | 2 +-
+ 4 files changed, 6 insertions(+), 6 deletions(-)
+
+--- linux-m68k-2.6.21.orig/arch/m68k/mac/baboon.c
++++ linux-m68k-2.6.21/arch/m68k/mac/baboon.c
+@@ -81,9 +81,9 @@ irqreturn_t baboon_irq(int irq, void *de
+ for (i = 0, irq_bit = 1 ; i < 3 ; i++, irq_bit <<= 1) {
+ if (events & irq_bit/* & baboon_active*/) {
+ baboon_active &= ~irq_bit;
++ baboon->mb_ifr &= ~irq_bit;
+ m68k_handle_int(IRQ_BABOON_0 + i);
+ baboon_active |= irq_bit;
+- baboon->mb_ifr &= ~irq_bit;
+ }
+ }
+ #if 0
+--- linux-m68k-2.6.21.orig/arch/m68k/mac/oss.c
++++ linux-m68k-2.6.21/arch/m68k/mac/oss.c
+@@ -109,12 +109,12 @@ irqreturn_t oss_irq(int irq, void *dev_i
+ /* FIXME: how do you clear a pending IRQ? */
+
+ if (events & OSS_IP_SOUND) {
+- /* FIXME: call sound handler */
+ oss->irq_pending &= ~OSS_IP_SOUND;
++ /* FIXME: call sound handler */
+ } else if (events & OSS_IP_SCSI) {
+ oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED;
+- m68k_handle_int(IRQ_MAC_SCSI);
+ oss->irq_pending &= ~OSS_IP_SCSI;
++ m68k_handle_int(IRQ_MAC_SCSI);
+ oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI;
+ } else {
+ /* FIXME: error check here? */
+@@ -146,8 +146,8 @@ irqreturn_t oss_nubus_irq(int irq, void
+ for (i = 0, irq_bit = 1 ; i < 6 ; i++, irq_bit <<= 1) {
+ if (events & irq_bit) {
+ oss->irq_level[i] = OSS_IRQLEV_DISABLED;
+- m68k_handle_int(NUBUS_SOURCE_BASE + i);
+ oss->irq_pending &= ~irq_bit;
++ m68k_handle_int(NUBUS_SOURCE_BASE + i);
+ oss->irq_level[i] = OSS_IRQLEV_NUBUS;
+ }
+ }
+--- linux-m68k-2.6.21.orig/arch/m68k/mac/psc.c
++++ linux-m68k-2.6.21/arch/m68k/mac/psc.c
+@@ -149,8 +149,8 @@ irqreturn_t psc_irq(int irq, void *dev_i
+ for (i = 0, irq_bit = 1 ; i < 4 ; i++, irq_bit <<= 1) {
+ if (events & irq_bit) {
+ psc_write_byte(pIER, irq_bit);
+- m68k_handle_int(base_irq + i);
+ psc_write_byte(pIFR, irq_bit);
++ m68k_handle_int(base_irq + i);
+ psc_write_byte(pIER, irq_bit | 0x80);
+ }
+ }
+--- linux-m68k-2.6.21.orig/arch/m68k/mac/via.c
++++ linux-m68k-2.6.21/arch/m68k/mac/via.c
+@@ -430,8 +430,8 @@ irqreturn_t via1_irq(int irq, void *dev_
+ for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1)
+ if (events & irq_bit) {
+ via1[vIER] = irq_bit;
+- m68k_handle_int(VIA1_SOURCE_BASE + i);
+ via1[vIFR] = irq_bit;
++ m68k_handle_int(VIA1_SOURCE_BASE + i);
+ via1[vIER] = irq_bit | 0x80;
+ }
+
diff --git a/debian/patches/bugfix/m68k/mac68k-sonic-fixes.diff b/debian/patches/bugfix/m68k/mac68k-sonic-fixes.diff
new file mode 100644
index 000000000000..580678611ac6
--- /dev/null
+++ b/debian/patches/bugfix/m68k/mac68k-sonic-fixes.diff
@@ -0,0 +1,106 @@
+Subject: [PATCH 12/13] SONIC: small fix and cleanup
+Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>,
+ Jeff Garzik <jgarzik@pobox.com>, netdev@vger.kernel.org,
+ linux-mips@linux-mips.org
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+Fix a potential problem in the timeout handling: don't free the DMA buffers
+before resetting the chip.
+
+Also a trivial cleanup. Bring macsonic and jazzsonic into sync.
+
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ drivers/net/jazzsonic.c | 4 ++--
+ drivers/net/macsonic.c | 17 ++++++++---------
+ drivers/net/sonic.c | 7 ++++++-
+ 3 files changed, 16 insertions(+), 12 deletions(-)
+
+--- linux-m68k-2.6.21.orig/drivers/net/jazzsonic.c
++++ linux-m68k-2.6.21/drivers/net/jazzsonic.c
+@@ -269,11 +269,11 @@ static int __devexit jazz_sonic_device_r
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct sonic_local* lp = netdev_priv(dev);
+
+- unregister_netdev (dev);
++ unregister_netdev(dev);
+ dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
+ lp->descriptors, lp->descriptors_laddr);
+ release_region (dev->base_addr, SONIC_MEM_SIZE);
+- free_netdev (dev);
++ free_netdev(dev);
+
+ return 0;
+ }
+--- linux-m68k-2.6.21.orig/drivers/net/macsonic.c
++++ linux-m68k-2.6.21/drivers/net/macsonic.c
+@@ -522,7 +522,7 @@ int __init mac_nubus_sonic_probe(struct
+ return macsonic_init(dev);
+ }
+
+-static int __init mac_sonic_probe(struct platform_device *device)
++static int __init mac_sonic_probe(struct platform_device *pdev)
+ {
+ struct net_device *dev;
+ struct sonic_local *lp;
+@@ -534,8 +534,8 @@ static int __init mac_sonic_probe(struct
+ return -ENOMEM;
+
+ lp = netdev_priv(dev);
+- lp->device = &device->dev;
+- SET_NETDEV_DEV(dev, &device->dev);
++ lp->device = &pdev->dev;
++ SET_NETDEV_DEV(dev, &pdev->dev);
+ SET_MODULE_OWNER(dev);
+
+ /* This will catch fatal stuff like -ENOMEM as well as success */
+@@ -576,15 +576,15 @@ MODULE_PARM_DESC(sonic_debug, "macsonic
+
+ #include "sonic.c"
+
+-static int __devexit mac_sonic_device_remove (struct platform_device *device)
++static int __devexit mac_sonic_device_remove (struct platform_device *pdev)
+ {
+- struct net_device *dev = platform_get_drvdata(device);
++ struct net_device *dev = platform_get_drvdata(pdev);
+ struct sonic_local* lp = netdev_priv(dev);
+
+- unregister_netdev (dev);
++ unregister_netdev(dev);
+ dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
+ lp->descriptors, lp->descriptors_laddr);
+- free_netdev (dev);
++ free_netdev(dev);
+
+ return 0;
+ }
+@@ -607,9 +607,8 @@ static int __init mac_sonic_init_module(
+ }
+
+ mac_sonic_device = platform_device_alloc(mac_sonic_string, 0);
+- if (!mac_sonic_device) {
++ if (!mac_sonic_device)
+ goto out_unregister;
+- }
+
+ if (platform_device_add(mac_sonic_device)) {
+ platform_device_put(mac_sonic_device);
+--- linux-m68k-2.6.21.orig/drivers/net/sonic.c
++++ linux-m68k-2.6.21/drivers/net/sonic.c
+@@ -179,8 +179,13 @@ static void sonic_tx_timeout(struct net_
+ {
+ struct sonic_local *lp = netdev_priv(dev);
+ int i;
+- /* Stop the interrupts for this */
++ /*
++ * put the Sonic into software-reset mode and
++ * disable all interrupts before releasing DMA buffers
++ */
+ SONIC_WRITE(SONIC_IMR, 0);
++ SONIC_WRITE(SONIC_ISR, 0x7fff);
++ SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
+ /* We could resend the original skbs. Easier to re-initialise. */
+ for (i = 0; i < SONIC_NUM_TDS; i++) {
+ if(lp->tx_laddr[i]) {
diff --git a/debian/patches/bugfix/m68k/nfeth-virt_to_phys.diff b/debian/patches/bugfix/m68k/nfeth-virt_to_phys.diff
new file mode 100644
index 000000000000..c89e6df799a5
--- /dev/null
+++ b/debian/patches/bugfix/m68k/nfeth-virt_to_phys.diff
@@ -0,0 +1,19 @@
+Subject: [PATCH] m68k: ARAnyM virtual Ethernet missing include
+
+Add missing #include <asm/virtconvert.h> (needed for virt_to_phys())
+
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ arch/m68k/emu/nfeth.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- linux-m68k-2.6.21.orig/arch/m68k/emu/nfeth.c
++++ linux-m68k-2.6.21/arch/m68k/emu/nfeth.c
+@@ -14,6 +14,7 @@
+ #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 */
diff --git a/debian/patches/bugfix/m68k/pmu_queue_request-conflict.diff b/debian/patches/bugfix/m68k/pmu_queue_request-conflict.diff
new file mode 100644
index 000000000000..6a3ee51f680e
--- /dev/null
+++ b/debian/patches/bugfix/m68k/pmu_queue_request-conflict.diff
@@ -0,0 +1,32 @@
+Subject: m68k: pmu_queue_request() declaration conflict
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+Fixes a "static qualifier follows non-static qualifier" error from gcc 4.
+
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ drivers/macintosh/via-pmu68k.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- linux-m68k-2.6.21.orig/drivers/macintosh/via-pmu68k.c
++++ linux-m68k-2.6.21/drivers/macintosh/via-pmu68k.c
+@@ -111,7 +111,6 @@ static int pmu_send_request(struct adb_r
+ static int pmu_autopoll(int devs);
+ void pmu_poll(void);
+ static int pmu_reset_bus(void);
+-static int pmu_queue_request(struct adb_request *req);
+
+ static void pmu_start(void);
+ static void send_byte(int x);
+@@ -475,7 +474,7 @@ pmu_request(struct adb_request *req, voi
+ return pmu_queue_request(req);
+ }
+
+-static int
++int
+ pmu_queue_request(struct adb_request *req)
+ {
+ unsigned long flags;
diff --git a/debian/patches/bugfix/m68k/sun3-3x-cg3-bw2.diff b/debian/patches/bugfix/m68k/sun3-3x-cg3-bw2.diff
new file mode 100644
index 000000000000..a9bff3ae83cf
--- /dev/null
+++ b/debian/patches/bugfix/m68k/sun3-3x-cg3-bw2.diff
@@ -0,0 +1,887 @@
+From: David Miller <davem@davemloft.net>
+To: sammy@sammy.net
+Cc: linux-m68k@vger.kernel.org
+Subject: Re: [PATCH] cg3/bw2: add Sun3/Sun3x support
+
+From: Sam Creasey <sammy@sammy.net>
+Date: Tue, 3 Apr 2007 10:32:35 -0400
+
+> This patch (re) introduces support for the CG3 driver on Sun3, and for
+> BW2 on Sun3x. It applies cleanly to both the m68k CVS tree and the
+> vanilla tree.
+>
+> Signed-off-by: Sam Creasey <sammy@sammy.net>
+
+If you guys want to share driver code with the Sparc port, please do
+it properly.
+
+I am not applying a pile of ifdef's that basically duplicate half of
+the existing driver.
+
+What you can do instead is to build a fake openprom device tree and
+register those devices with the generic device subsystem, and then the
+driver will mostly just work out of the box. It should be easy to
+duplicate the arch/sparc64/kernel/prom.c and of_device.c code you
+use as well as the driver interfaces in include/asm-sparc64/prom.h
+and of_device.h
+
+This way you don't need to shit all over the drivers adding hardcoded
+register addresses and ad-hoc probing code. For special behaviors,
+you can add openprom node properties that the driver can test for at
+run time to guide behavior, again instead of ifdefs.
+
+---------------------------------------------------------------------------
+
+From sammy@sammy.net Tue Apr 3 16:47:32 2007
+Date: Tue, 3 Apr 2007 10:32:35 -0400
+From: Sam Creasey <sammy@sammy.net>
+To: linux-m68k@vger.kernel.org, David S. Miller <davem@davemloft.net>
+Subject: [PATCH] cg3/bw2: add Sun3/Sun3x support
+
+This patch (re) introduces support for the CG3 driver on Sun3, and for
+BW2 on Sun3x. It applies cleanly to both the m68k CVS tree and the
+vanilla tree.
+
+Signed-off-by: Sam Creasey <sammy@sammy.net>
+
+---
+ drivers/video/Kconfig | 14 ++
+ drivers/video/Makefile | 1
+ drivers/video/bw2.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++--
+ drivers/video/cg3.c | 212 ++++++++++++++++++++++++++++++++++++++++++-
+ drivers/video/p4lib.c | 107 ++++++++++++++++++++++
+ drivers/video/p4lib.h | 56 +++++++++++
+ drivers/video/sbuslib.c | 13 ++
+ 7 files changed, 616 insertions(+), 19 deletions(-)
+
+--- linux-m68k-2.6.21.orig/drivers/video/Kconfig
++++ linux-m68k-2.6.21/drivers/video/Kconfig
+@@ -600,6 +600,16 @@ config FB_GBE_MEM
+ This is the amount of memory reserved for the framebuffer,
+ which can be any value between 1MB and 8MB.
+
++config FB_SUN3
++ bool "Sun3 framebuffer support"
++ depends on (FB = y) && (SUN3 || SUN3X)
++ help
++ Support framebuffer devices on Sun3/3x. Note that if you say yes
++ here, any framebuffer drivers you select MUST be installed in the
++ target system, or be disabled on the command line. (e.g. if you
++ don't have a bw2, include video=bw2fb:off. If you don't have
++ a cg3, include video=cg3fb:off.)
++
+ config FB_SBUS
+ bool "SBUS and UPA framebuffers"
+ depends on (FB = y) && SPARC
+@@ -608,7 +618,7 @@ config FB_SBUS
+
+ config FB_BW2
+ bool "BWtwo support"
+- depends on (FB = y) && (SPARC && FB_SBUS)
++ depends on (FB = y) && ((SPARC && FB_SBUS) || (SUN3X && FB_SUN3))
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+@@ -617,7 +627,7 @@ config FB_BW2
+
+ config FB_CG3
+ bool "CGthree support"
+- depends on (FB = y) && (SPARC && FB_SBUS)
++ depends on (FB = y) && ((SPARC && FB_SBUS) || (SUN3 && FB_SUN3))
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+--- linux-m68k-2.6.21.orig/drivers/video/Makefile
++++ linux-m68k-2.6.21/drivers/video/Makefile
+@@ -106,6 +106,7 @@ obj-$(CONFIG_FB_VESA) += ves
+ obj-$(CONFIG_FB_IMAC) += imacfb.o
+ obj-$(CONFIG_FB_VGA16) += vga16fb.o vgastate.o
+ obj-$(CONFIG_FB_OF) += offb.o
++obj-$(CONFIG_FB_SUN3) += p4lib.o
+
+ # the test framebuffer is last
+ obj-$(CONFIG_FB_VIRTUAL) += vfb.o
+--- linux-m68k-2.6.21.orig/drivers/video/bw2.c
++++ linux-m68k-2.6.21/drivers/video/bw2.c
+@@ -20,18 +20,29 @@
+
+ #include <asm/io.h>
+ #include <asm/oplib.h>
++#ifndef CONFIG_FB_SUN3
+ #include <asm/prom.h>
+ #include <asm/of_device.h>
++#endif
+ #include <asm/fbio.h>
+
+ #include "sbuslib.h"
+
++#ifdef CONFIG_FB_SUN3
++#ifdef CONFIG_SUN3
++#include <asm/sun3mmu.h>
++#endif
++#include <asm/machines.h>
++#include <asm/idprom.h>
++#include <asm/sbus.h>
++#include "p4lib.h"
++#endif
+ /*
+ * Local functions.
+ */
+-
++#ifndef CONFIG_FB_SUN3
+ static int bw2_blank(int, struct fb_info *);
+-
++#endif
+ static int bw2_mmap(struct fb_info *, struct vm_area_struct *);
+ static int bw2_ioctl(struct fb_info *, unsigned int, unsigned long);
+
+@@ -41,7 +52,11 @@ static int bw2_ioctl(struct fb_info *, u
+
+ static struct fb_ops bw2_ops = {
+ .owner = THIS_MODULE,
++#ifdef CONFIG_FB_SUN3
++ .fb_blank = NULL,
++#else
+ .fb_blank = bw2_blank,
++#endif
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+@@ -53,7 +68,18 @@ static struct fb_ops bw2_ops = {
+ };
+
+ /* OBio addresses for the bwtwo registers */
++#ifdef CONFIG_FB_SUN3
++/* sun3 series */
++#define BWTWO_OBMEM_ADDR 0x1f000000
++#define BWTWO_OBMEM_ADDR_50 0x00100000
++#define BWTWO_OBMEM_ADDR_P4 0x1f300000
++#define BWTWO_OBMEM_ADDR_3X 0x50300000
++/* is this true for 3/50? */
++#define BWTWO_FB_OFFSET 0x100000
++#define BWTWO_OBMEM_HIGHRES_60 0x1f1c0000
++#else
+ #define BWTWO_REGISTER_OFFSET 0x400000
++#endif
+
+ struct bt_regs {
+ u32 addr;
+@@ -108,8 +134,11 @@ struct bw2_regs {
+
+ struct bw2_par {
+ spinlock_t lock;
++#ifdef CONFIG_FB_SUN3
++ volatile u32 *regs;
++#else
+ struct bw2_regs __iomem *regs;
+-
++#endif
+ u32 flags;
+ #define BW2_FLAG_BLANKED 0x00000001
+
+@@ -118,6 +147,7 @@ struct bw2_par {
+ unsigned long fbsize;
+ };
+
++#ifndef CONFIG_FB_SUN3
+ /**
+ * bw2_blank - Optional function. Blanks the display.
+ * @blank_mode: the blank mode we want.
+@@ -156,6 +186,7 @@ bw2_blank(int blank, struct fb_info *inf
+
+ return 0;
+ }
++#endif
+
+ static struct sbus_mmap_map bw2_mmap_map[] = {
+ {
+@@ -198,6 +229,17 @@ static void __devinit bw2_init_fix(struc
+ info->fix.accel = FB_ACCEL_SUN_BWTWO;
+ }
+
++struct all_info {
++ struct fb_info info;
++ struct bw2_par par;
++};
++/* CONFIG_FB_SUN3 has a different implementation for the remaining
++ functions, since:
++ 1) No OpenProm
++ 2) Fixed frequency
++ 3) No support for multiple BWtwo's */
++#ifndef CONFIG_FB_SUN3
++
+ static u8 bw2regs_1600[] __devinitdata = {
+ 0x14, 0x8b, 0x15, 0x28, 0x16, 0x03, 0x17, 0x13,
+ 0x18, 0x7b, 0x19, 0x05, 0x1a, 0x34, 0x1b, 0x2e,
+@@ -279,11 +321,6 @@ static void __devinit bw2_do_default_mod
+ }
+ }
+
+-struct all_info {
+- struct fb_info info;
+- struct bw2_par par;
+-};
+-
+ static int __devinit bw2_init_one(struct of_device *op)
+ {
+ struct device_node *dp = op->node;
+@@ -397,6 +434,185 @@ static void __exit bw2_exit(void)
+ return of_unregister_driver(&bw2_driver);
+ }
+
++#else /* !CONFIG_FB_SUN3 */
++
++static struct all_info *bw2_all = NULL;
++
++static void bw2_do_default_mode(struct bw2_par *par, struct fb_info *info,
++ int *linebytes)
++{
++ int highres = 0;
++
++ if(idprom->id_machtype == (SM_SUN3|SM_3_260))
++ /* the 3/260 is allegedly always highres */
++ highres = 1;
++ if(idprom->id_machtype == (SM_SUN3|SM_3_60)) {
++#ifdef CONFIG_SUN3
++ /* we won't hit this unless running on a sun3 anyway */
++ volatile u32 *reg;
++ u32 il
++
++ reg = sun3_ioremap(BW2_OBMEM_HIGHRES_60, sizeof(u32),
++ SUN3_PAGE_TYPE_MEMORY);
++ i = *reg;
++ iounmap(reg);
++ if((i != -1) && (i& 0x80) == 0)
++ highres = 1;
++#endif
++ }
++
++ if(highres) {
++ info->var.xres = info->var.xres_virtual = 1600;
++ info->var.yres = info->var.yres_virtual = 1280;
++ *linebytes = 1600 / 8;
++ }
++}
++
++
++static int __devinit bw2_init_one(unsigned long phys_addr)
++{
++ struct all_info *all;
++ int linebytes, err, id;
++ all = kzalloc(sizeof(*all), GFP_KERNEL);
++ if (!all)
++ return -ENOMEM;
++
++ spin_lock_init(&all->par.lock);
++
++ all->par.physbase = phys_addr;
++
++#ifdef CONFIG_SUN3
++ all->par.regs = sun3_ioremap(phys_addr, sizeof(u32),
++ SUN3_PAGE_TYPE_MEMORY);
++#else
++ all->par.regs = ioremap_nocache(phys_addr, sizeof(u32));
++#endif
++ /* look for the p4 register, or assume we're OBIO if it's not found */
++ id = p4fb_get_id(all->par.regs);
++ printk("bwtwo: p4id %08x\n", id);
++
++ /* mutable memory address, probably save to say we've got an onboard fb */
++ if(id == -1) {
++ iounmap((void *)all->par.regs);
++ /* only currently supported on sun3. Perhaps someday sun4. */
++ if((idprom->id_machtype & SM_ARCH_MASK) != SM_SUN3) {
++ kfree(all);
++ return -ENODEV;
++ }
++
++ p4fb_fill_var(&all->info.var, NULL, 1);
++ bw2_do_default_mode(&all->par, &all->info, &linebytes);
++ } else {
++ if(id != P4_ID_BW2) {
++ kfree(all);
++ iounmap((void *)all->par.regs);
++ return -ENODEV;
++ }
++
++ p4fb_fill_var(&all->info.var, (volatile u32 *)all->par.regs, 1);
++ }
++
++ linebytes = all->info.var.xres / 8;
++
++ all->info.var.red.length = all->info.var.green.length =
++ all->info.var.blue.length = all->info.var.bits_per_pixel;
++ all->info.var.red.offset = all->info.var.green.offset =
++ all->info.var.blue.offset = 0;
++
++ all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
++
++ all->info.flags = FBINFO_DEFAULT;
++ all->info.fbops = &bw2_ops;
++
++ if(id == -1) {
++#ifdef CONFIG_SUN3
++ all->info.screen_base = sun3_ioremap(phys_addr,
++ all->par.fbsize,
++ SUN3_PAGE_TYPE_MEMORY);
++#else
++ all->info.screen_base = ioremap(phys_addr,
++ all->par.fbsize);
++#endif
++ } else {
++#ifdef CONFIG_SUN3
++ all->info.screen_base = sun3_ioremap(phys_addr + BWTWO_FB_OFFSET,
++ all->par.fbsize,
++ SUN3_PAGE_TYPE_MEMORY);
++#else
++ all->info.screen_base = ioremap(phys_addr + BWTWO_FB_OFFSET,
++ all->par.fbsize);
++#endif
++ }
++
++ p4fb_video_enable(all->par.regs);
++
++ all->info.par = &all->par;
++
++ bw2_init_fix(&all->info, linebytes);
++
++ err= register_framebuffer(&all->info);
++ if (err < 0) {
++ iounmap((void *)all->par.regs);
++ iounmap((void *)all->info.screen_base);
++ kfree(all);
++ return err;
++ }
++
++ bw2_all = all;
++
++ printk("%s: bwtwo at %lx\n",
++ all->info.fix.id, all->par.physbase);
++
++ return 0;
++}
++
++static int __init bw2_init(void)
++{
++ if(fb_get_options("bw2fb", NULL))
++ return -ENODEV;
++
++ if(bw2_all != NULL)
++ return -ENODEV;
++
++ /* currently only sun3/80 P4 is supported/tested */
++ switch(idprom->id_machtype) {
++ case SM_SUN3X|SM_3_80:
++ case SM_SUN3X|SM_3_460:
++ return bw2_init_one(BWTWO_OBMEM_ADDR_3X);
++
++ case SM_SUN3|SM_3_50:
++ return bw2_init_one(BWTWO_OBMEM_ADDR_50);
++
++ case SM_SUN3|SM_3_160:
++ case SM_SUN3|SM_3_260:
++ case SM_SUN3|SM_3_110:
++ case SM_SUN3|SM_3_60:
++ return bw2_init_one(BWTWO_OBMEM_ADDR);
++ default:
++ break;
++ }
++
++ return -ENODEV;
++}
++
++static void __exit bw2_exit(void)
++{
++ struct all_info *all = bw2_all;
++ if(bw2_all == NULL)
++ return;
++
++ unregister_framebuffer(&all->info);
++
++ iounmap((void *)all->par.regs);
++ iounmap((void *)all->info.screen_base);
++
++ kfree(all);
++
++ bw2_all = NULL;
++
++ return;
++}
++#endif /* CONFIG_FB_SUN3 */
+
+ module_init(bw2_init);
+ module_exit(bw2_exit);
+--- linux-m68k-2.6.21.orig/drivers/video/cg3.c
++++ linux-m68k-2.6.21/drivers/video/cg3.c
+@@ -20,12 +20,24 @@
+
+ #include <asm/io.h>
+ #include <asm/oplib.h>
++#ifndef CONFIG_FB_SUN3
+ #include <asm/prom.h>
+ #include <asm/of_device.h>
++#endif
+ #include <asm/fbio.h>
+
+ #include "sbuslib.h"
+
++#ifdef CONFIG_FB_SUN3
++#ifdef CONFIG_SUN3
++#include <asm/sun3mmu.h>
++#endif
++#include <asm/machines.h>
++#include <asm/idprom.h>
++#include <asm/sbus.h>
++#include "p4lib.h"
++#endif
++
+ /*
+ * Local functions.
+ */
+@@ -108,8 +120,16 @@ struct cg3_regs {
+ };
+
+ /* Offset of interesting structures in the OBIO space */
+-#define CG3_REGS_OFFSET 0x400000UL
+-#define CG3_RAM_OFFSET 0x800000UL
++#ifdef CONFIG_SUN3
++#define CGFOUR_OBMEM_ADDR_60 0x1f000000
++#define CGFOUR_OBMEM_ADDR_110 0x1f300000
++#define CG3_REGS_OFFSET (-0x100000)
++#define CG3_RAM_OFFSET 0x500000UL
++#else
++#define CG3_REGS_OFFSET 0x400000UL
++#define CG3_RAM_OFFSET 0x800000UL
++#endif
++
+
+ struct cg3_par {
+ spinlock_t lock;
+@@ -250,6 +270,18 @@ static int cg3_ioctl(struct fb_info *inf
+ * Initialisation
+ */
+
++struct all_info {
++ struct fb_info info;
++ struct cg3_par par;
++};
++
++
++/* CONFIG_FB_SUN3 has a different implementation for the remaining
++ functions, since:
++ 1) No OpenProm
++ 2) Fixed frequency
++ 3) No support for multiple CGthree's */
++#ifndef CONFIG_FB_SUN3
+ static void __devinit cg3_init_fix(struct fb_info *info, int linebytes,
+ struct device_node *dp)
+ {
+@@ -351,12 +383,8 @@ static void __devinit cg3_do_default_mod
+ regp = (u8 __iomem *)&par->regs->cmap.control;
+ sbus_writeb(p[1], regp);
+ }
+-}
+
+-struct all_info {
+- struct fb_info info;
+- struct cg3_par par;
+-};
++}
+
+ static int __devinit cg3_init_one(struct of_device *op)
+ {
+@@ -426,8 +454,8 @@ static int __devinit cg3_init_one(struct
+
+ dev_set_drvdata(&op->dev, all);
+
+- printk("%s: cg3 at %lx:%lx\n",
+- dp->full_name, all->par.which_io, all->par.physbase);
++ printk("%s: cg3 at %lx\n",
++ dp->full_name, all->par.physbase);
+
+ return 0;
+ }
+@@ -488,6 +516,172 @@ static void __exit cg3_exit(void)
+ of_unregister_driver(&cg3_driver);
+ }
+
++#else /* !CONFIG_FB_SUN3 */
++static void
++cg3_init_fix(struct fb_info *info, int linebytes)
++{
++
++ strcpy(info->fix.id, "SUN3 CG3");
++
++ info->fix.type = FB_TYPE_PACKED_PIXELS;
++ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
++
++ info->fix.line_length = linebytes;
++
++ info->fix.accel = FB_ACCEL_SUN_CGTHREE;
++}
++static void cg3_do_default_mode(struct cg3_par *par)
++{
++ /* kick up the sun3 -- 66hz prom mode only */
++ /* this also turns off the overlay in case it's really a cg4 */
++
++ par->regs->cmap.addr = 4;
++ par->regs->cmap.control = 0xff;
++ par->regs->cmap.addr = 5;
++ par->regs->cmap.control = 0;
++ par->regs->cmap.addr = 6;
++ par->regs->cmap.control = 0x40;
++ par->regs->cmap.addr = 7;
++ par->regs->cmap.control = 0;
++
++}
++
++/* The Sun3 version of this driver only supports one cgthree.
++ This really isn't an issue, because it also only supports
++ the 3/60 OBIO cg3, and not vme cards (of which there could be more
++ than one) */
++static struct all_info *cg3_all = NULL;
++
++static int __devinit cg3_init_one(unsigned long phys_addr)
++{
++ struct all_info *all;
++ int linebytes, err;
++ volatile u32 *p4reg = NULL;
++
++ all = kzalloc(sizeof(*all), GFP_KERNEL);
++ if (!all)
++ return -ENOMEM;
++
++ spin_lock_init(&all->par.lock);
++
++ all->par.physbase = phys_addr;
++
++#if 0
++ /* it would be nice to use p4 registers here, but it appears
++ * some P4 framebuffers don't actually have useful data.
++ * So we just plod along regardless */
++ p4reg = sun3_ioremap(all->par.physbase, sizeof(u32),
++ SUN3_PAGE_TYPE_MEMORY);
++ id = p4fb_get_id(p4reg);
++ printk("cg3: p4id %08x\n", *p4reg);
++
++ if(id != P4_ID_CG4) {
++ iounmap((void *)p4reg);
++ kfree(all);
++ return -ENODEV;
++ }
++
++#endif
++ p4fb_fill_var(&all->info.var, p4reg, 8);
++ if(p4reg != NULL)
++ iounmap((void *)p4reg);
++
++ all->info.var.red.length = 8;
++ all->info.var.green.length = 8;
++ all->info.var.blue.length = 8;
++ linebytes = all->info.var.xres;
++
++ all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
++
++ all->par.regs = (struct cg3_regs *)
++ sun3_ioremap(all->par.physbase + CG3_REGS_OFFSET,
++ sizeof(struct cg3_regs), SUN3_PAGE_TYPE_MEMORY);
++
++
++ all->info.flags = FBINFO_DEFAULT;
++ all->info.fbops = &cg3_ops;
++ all->info.screen_base = (char *)
++ sun3_ioremap(all->par.physbase + CG3_RAM_OFFSET,
++ all->par.fbsize, SUN3_PAGE_TYPE_MEMORY);
++ all->info.par = &all->par;
++
++ cg3_blank(0, &all->info);
++
++ cg3_do_default_mode(&all->par);
++
++ if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
++ kfree(all);
++ return -ENOMEM;
++ }
++
++ fb_set_cmap(&all->info.cmap, &all->info);
++
++ cg3_init_fix(&all->info, linebytes);
++
++ err = register_framebuffer(&all->info);
++ if (err < 0) {
++ fb_dealloc_cmap(&all->info.cmap);
++ iounmap(all->par.regs);
++ iounmap(all->info.screen_base);
++ kfree(all);
++ return err;
++ }
++
++ cg3_all = all;
++
++ printk("%s: cg3 at %lx\n",
++ all->info.fix.id, all->par.physbase);
++
++ return 0;
++}
++
++static int __init cg3_init(void)
++{
++ if (fb_get_options("cg3fb", NULL))
++ return -ENODEV;
++
++ if(cg3_all != NULL)
++ return -ENODEV;
++
++ /* currently only sun3/60 P4 is supported/tested */
++ switch(idprom->id_machtype) {
++ case SM_SUN3|SM_3_60:
++ return cg3_init_one(CGFOUR_OBMEM_ADDR_60);
++
++ case SM_SUN3|SM_3_110:
++ /* 3/110 is a guess, no 3/110 to test on */
++ return cg3_init_one(CGFOUR_OBMEM_ADDR_110);
++
++ default:
++ break;
++ }
++
++ return -ENODEV;
++}
++
++static void __exit cg3_exit(void)
++{
++ struct all_info *all = cg3_all;
++
++ if(cg3_all == NULL)
++ return;
++
++ unregister_framebuffer(&all->info);
++ fb_dealloc_cmap(&all->info.cmap);
++
++ iounmap(all->par.regs);
++ iounmap(all->info.screen_base);
++
++ kfree(all);
++
++ cg3_all = NULL;
++
++ return;
++
++}
++
++#endif /* CONFIG_FB_SUN3 */
++
+ module_init(cg3_init);
+ module_exit(cg3_exit);
+
+--- /dev/null
++++ linux-m68k-2.6.21/drivers/video/p4lib.c
+@@ -0,0 +1,107 @@
++/* p4lib.c: Helper library for Sun P4 framebuffer drivers
++ *
++ * Copyright (C) 2007 Sam Creasey (sammy@sammy.net)
++ */
++
++#include <linux/compat.h>
++#include <linux/kernel.h>
++#include <linux/types.h>
++
++#include <linux/fb.h>
++
++#include "p4lib.h"
++
++int p4fb_get_id(volatile u32 *p4reg)
++{
++
++#ifdef CONFIG_SUN3
++ /* this code makes the 3x cry, and it can't have onboard fb anyway */
++ u32 x, old;
++
++ /* attempt to read the id bit back from the p4 register, if
++ * we're able to modify the value, conclude there's no p4
++ * device there. This should enable us to determine if we're
++ * dealing with, for example, a builtin bw2 or a p4 bw2. */
++
++ old = *p4reg;
++ x = old & ~P4_CTRL_RESET;
++
++ *p4reg = x ^ P4_ID_MASK;
++ if((*p4reg ^ x) & P4_ID_MASK) {
++ /* we managed to change the type bits, not a p4 port */
++ *p4reg = old;
++ return -1;
++ }
++#endif
++ return ((*p4reg) & P4_ID_MASK) >> P4_ID_SHIFT;
++}
++
++int p4fb_get_res(volatile u32 *p4reg)
++{
++ return ((*p4reg) & P4_RES_MASK) >> P4_RES_SHIFT;
++}
++
++void p4fb_video_enable(volatile u32 *p4reg)
++{
++ u32 x;
++
++ x = *p4reg;
++ x &= ~(P4_CTRL_VIDEO_EN | P4_CTRL_INT);
++ x |= P4_CTRL_VIDEO_EN;
++ *p4reg = x;
++
++}
++
++/* This function basically assumes that p4fb_get_id returns a sane
++ * value for this card/instance. If this was not true, calling with
++ * NULL for p4reg will return the defaults */
++void p4fb_fill_var(struct fb_var_screeninfo *var, volatile u32 *p4reg, int bpp)
++{
++ memset(var, 0, sizeof(*var));
++
++ if(p4reg == NULL) {
++ var->xres = 1152;
++ var->yres = 900;
++ } else {
++ switch(p4fb_get_res(p4reg)) {
++ case P4_RES_1600X1280:
++ var->xres = 1600;
++ var->yres = 1280;
++ break;
++ case P4_RES_1152X900:
++ var->xres = 1152;
++ var->yres = 900;
++ break;
++ case P4_RES_1024X1024:
++ var->xres = 1024;
++ var->yres = 1024;
++ break;
++ case P4_RES_1280X1024:
++ var->xres = 1280;
++ var->yres = 1024;
++ break;
++ case P4_RES_1440X1440:
++ var->xres = 1440;
++ var->yres = 1400;
++ break;
++ case P4_RES_640X480:
++ var->xres = 640;
++ var->yres = 480;
++ break;
++ default:
++ /* this may or may not be the right thing to
++ * do here, but plod on anyway */
++ var->xres = 1152;
++ var->yres = 900;
++ break;
++ }
++ }
++
++ var->xres_virtual = var->xres;
++ var->yres_virtual = var->yres;
++ var->bits_per_pixel = bpp;
++}
++
++EXPORT_SYMBOL(p4fb_get_id);
++EXPORT_SYMBOL(p4fb_get_res);
++EXPORT_SYMBOL(p4fb_fill_var);
+--- /dev/null
++++ linux-m68k-2.6.21/drivers/video/p4lib.h
+@@ -0,0 +1,56 @@
++/* p4lib.h: helper functions for p4 framebuffers */
++
++#ifndef _P4LIB_H
++#define _P4LIB_H
++
++/* register defintions applicable to p4 framebuffers found on some
++ Sun3/3x machines (and some Sun4 machines, though these are not
++ currently supported or tested). These machines have a single 32bit
++ register at the start of the p4 address space.
++
++ The format of this register is as follows:
++
++ bit 31 : unused
++ bits 30-28: type
++ bits 27-24: resolution
++ bits 23-8: unused
++ bits 7-0: status/control
++
++ The CG8 may break this format, if that turns out to be true, I'll
++ fix once I have a CG8 to test against...
++*/
++
++/* control register, lower 8bits */
++#define P4_CTRL_DIAG 0x80 /* ??? */
++#define P4_CTRL_RBCLR 0x40 /* ??? */
++#define P4_CTRL_VIDEO_EN 0x20 /* enable video */
++#define P4_CTRL_SYNC 0x10 /* ??? */
++#define P4_CTRL_VTRACE 0x08 /* ??? */
++#define P4_CTRL_INT 0x04 /* read: int pending, write: clear int */
++#define P4_CTRL_INT_EN 0x02 /* enable interrupts */
++#define P4_CTRL_RESET 0x01 /* reset */
++
++/* framebuffer identification -- bits 31-28 */
++#define P4_ID_MASK 0x70000000
++#define P4_ID_SHIFT 24
++#define P4_ID_BW2 0x00
++#define P4_ID_CG4 0x40 /* supported in linux as a cg3 */
++#define P4_ID_CG6 0x60
++
++/* framebuffer resolution - bits 27-24 */
++#define P4_RES_MASK 0x0f000000
++#define P4_RES_SHIFT 24
++#define P4_RES_1600X1280 0x00
++#define P4_RES_1152X900 0x01 /* only tested resolution */
++#define P4_RES_1024X1024 0x02
++#define P4_RES_1280X1024 0x03
++#define P4_RES_1440X1440 0x04
++#define P4_RES_640X480 0x05
++
++/* actual helper functions */
++extern int p4fb_get_id(volatile u32 *p4reg);
++extern int p4fb_get_res(volatile u32 *p4reg);
++extern void p4fb_video_enable(volatile u32 *p4reg);
++extern void p4fb_fill_var(struct fb_var_screeninfo *var, volatile u32 *p4reg, int bpp);
++
++#endif /* P4LIB_H */
+--- linux-m68k-2.6.21.orig/drivers/video/sbuslib.c
++++ linux-m68k-2.6.21/drivers/video/sbuslib.c
+@@ -13,6 +13,10 @@
+ #include <asm/oplib.h>
+ #include <asm/fbio.h>
+
++#if defined(CONFIG_SUN3) || defined(CONFIG_SUN3X)
++#include <asm/uaccess.h>
++#endif
++
+ #include "sbuslib.h"
+
+ void sbusfb_fill_var(struct fb_var_screeninfo *var, int prom_node, int bpp)
+@@ -21,6 +25,7 @@ void sbusfb_fill_var(struct fb_var_scree
+
+ var->xres = prom_getintdefault(prom_node, "width", 1152);
+ var->yres = prom_getintdefault(prom_node, "height", 900);
++
+ var->xres_virtual = var->xres;
+ var->yres_virtual = var->yres;
+ var->bits_per_pixel = bpp;
+@@ -80,12 +85,20 @@ int sbusfb_mmap_helper(struct sbus_mmap_
+ }
+ if (page + map_size > size)
+ map_size = size - page;
++#if !defined(CONFIG_FB_SUN3)
+ r = io_remap_pfn_range(vma,
+ vma->vm_start + page,
+ MK_IOSPACE_PFN(iospace,
+ map_offset >> PAGE_SHIFT),
+ map_size,
+ vma->vm_page_prot);
++#else
++ r = io_remap_pfn_range(vma,
++ vma->vm_start + page,
++ map_offset, map_size,
++ vma->vm_page_prot);
++#endif
++
+ if (r)
+ return -EAGAIN;
+ page += map_size;
diff --git a/debian/patches/bugfix/m68k/sun3-3x-serial.diff b/debian/patches/bugfix/m68k/sun3-3x-serial.diff
new file mode 100644
index 000000000000..d49c94941d19
--- /dev/null
+++ b/debian/patches/bugfix/m68k/sun3-3x-serial.diff
@@ -0,0 +1,486 @@
+From: David Miller <davem@davemloft.net>
+To: sammy@sammy.net
+Cc: linux-m68k@vger.kernel.org
+Subject: Re: [PATCH] Sun3/3x Serial driver support
+
+From: Sam Creasey <sammy@sammy.net>
+Date: Tue, 3 Apr 2007 10:43:42 -0400
+
+> Adds serial support for sun3/3x machines. This patch has basically
+> been around for years, but my own laziness has kept me from committing
+> upstream.
+>
+> Signed-off-by: Sam Creasey <sammy@sammy.net>
+
+Same thing here, please build a proper openprom device tree in
+the sun3 port and then you'll need to make few, if any,
+changes to the sparc drivers.
+
+I've made these drivers as portable as possible, frankly, and
+if you cook up proper in-kernel device objects, you'll need
+to do no porting at all.
+
+---------------------------------------------------------------------------
+
+From sammy@sammy.net Tue Apr 3 16:47:31 2007
+Date: Tue, 3 Apr 2007 10:43:42 -0400
+From: Sam Creasey <sammy@sammy.net>
+To: linux-m68k@vger.kernel.org, David S. Miller <davem@davemloft.net>
+Subject: [PATCH] Sun3/3x Serial driver support
+
+Adds serial support for sun3/3x machines. This patch has basically
+been around for years, but my own laziness has kept me from committing
+upstream.
+
+Signed-off-by: Sam Creasey <sammy@sammy.net>
+
+---
+ drivers/serial/Kconfig | 4
+ drivers/serial/suncore.c | 4
+ drivers/serial/sunzilog.c | 200 +++++++++++++++++++++++++++++++++++++++++++---
+ 3 files changed, 195 insertions(+), 13 deletions(-)
+
+--- linux-m68k-2.6.21.orig/drivers/serial/Kconfig
++++ linux-m68k-2.6.21/drivers/serial/Kconfig
+@@ -543,14 +543,14 @@ config SERIAL_UARTLITE_CONSOLE
+
+ config SERIAL_SUNCORE
+ bool
+- depends on SPARC
++ depends on SPARC || SUN3 || SUN3X
+ select SERIAL_CORE
+ select SERIAL_CORE_CONSOLE
+ default y
+
+ config SERIAL_SUNZILOG
+ tristate "Sun Zilog8530 serial support"
+- depends on SPARC
++ depends on SPARC || SUN3 || SUN3X
+ help
+ This driver supports the Zilog8530 serial ports found on many Sparc
+ systems. Say Y or M if you want to be able to these serial ports.
+--- linux-m68k-2.6.21.orig/drivers/serial/suncore.c
++++ linux-m68k-2.6.21/drivers/serial/suncore.c
+@@ -29,6 +29,7 @@ EXPORT_SYMBOL(sunserial_current_minor);
+ void
+ sunserial_console_termios(struct console *con)
+ {
++#if !defined(CONFIG_SUN3) && !defined (CONFIG_SUN3X)
+ char mode[16], buf[16], *s;
+ char *mode_prop = "ttyX-mode";
+ char *cd_prop = "ttyX-ignore-cd";
+@@ -162,6 +163,9 @@ no_options:
+ }
+
+ con->cflag = cflag;
++#else /* CONFIG_SUN3(X) */
++ con->cflag = CREAD | HUPCL | CLOCAL | B9600 | CS8;
++#endif
+ }
+
+ EXPORT_SYMBOL(sunserial_console_termios);
+--- linux-m68k-2.6.21.orig/drivers/serial/sunzilog.c
++++ linux-m68k-2.6.21/drivers/serial/sunzilog.c
+@@ -35,13 +35,30 @@
+
+ #include <asm/io.h>
+ #include <asm/irq.h>
+-#include <asm/prom.h>
+-#include <asm/of_device.h>
+
+ #if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+ #define SUPPORT_SYSRQ
+ #endif
+
++#if defined(CONFIG_SUN3) || defined(CONFIG_SUN3X)
++#include <asm/oplib.h>
++#include <asm/sbus.h>
++#define readb sbus_readb
++#define writeb sbus_writeb
++
++#else
++#include <asm/prom.h>
++#include <asm/of_device.h>
++#endif
++
++#ifdef CONFIG_SUN3
++#include <asm/sun3mmu.h>
++#endif
++
++#ifdef CONFIG_SUN3X
++#include <asm/sun3xprom.h>
++#endif
++
+ #include <linux/serial_core.h>
+
+ #include "suncore.h"
+@@ -415,7 +432,15 @@ static void sunzilog_status_handle(struc
+ if (!(status & BRK_ABRT))
+ break;
+ }
+- sun_do_break();
++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X)
++ sun_do_break();
++#else
++#ifdef CONFIG_SUN3
++ prom_reboot("");
++#else
++ sun3x_reboot();
++#endif
++#endif
+ return;
+ }
+ }
+@@ -523,6 +548,13 @@ static irqreturn_t sunzilog_interrupt(in
+ struct tty_struct *tty;
+ unsigned char r3;
+
++#if defined(CONFIG_SUN3) || defined(CONFIG_SUN3X)
++ if(!channel) {
++ up = up->next;
++ continue;
++ }
++#endif
++
+ spin_lock(&up->port.lock);
+ r3 = read_zsreg(channel, R3);
+
+@@ -1193,6 +1225,7 @@ static struct console sunzilog_console_o
+
+ static inline struct console *SUNZILOG_CONSOLE(void)
+ {
++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X)
+ int i;
+
+ if (con_is_present())
+@@ -1209,6 +1242,10 @@ static inline struct console *SUNZILOG_C
+
+ sunzilog_console_ops.index = i;
+ sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS;
++#else
++ sunzilog_console_ops.index = 0;
++ sunzilog_port_table[0].flags |= SUNZILOG_FLAG_IS_CONS;
++#endif
+
+ return &sunzilog_console_ops;
+ }
+@@ -1266,6 +1303,8 @@ static void __init sunzilog_register_ser
+ }
+ #endif
+
++static int zilog_irq = -1;
++
+ static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
+ {
+ struct zilog_channel __iomem *channel;
+@@ -1276,9 +1315,16 @@ static void __devinit sunzilog_init_hw(s
+
+ spin_lock_irqsave(&up->port.lock, flags);
+ if (ZS_IS_CHANNEL_A(up)) {
++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X)
+ write_zsreg(channel, R9, FHWRES);
+ ZSDELAY_LONG();
++#endif
+ (void) read_zsreg(channel, R0);
++#ifdef CONFIG_SUN3
++ /* should sun3x run here? */
++ /* program the int vector */
++ write_zsreg(channel, R2, 0x18+zilog_irq);
++#endif
+ }
+
+ if (up->flags & (SUNZILOG_FLAG_CONS_KEYB |
+@@ -1293,7 +1339,11 @@ static void __devinit sunzilog_init_hw(s
+ up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
+ up->curregs[R3] = RxENAB | Rx8;
+ up->curregs[R5] = TxENAB | Tx8;
++#ifdef CONFIG_SUN3
++ up->curregs[R9] = MIE;
++#else
+ up->curregs[R9] = NV | MIE;
++#endif
+ up->curregs[R10] = NRZ;
+ up->curregs[R11] = TCBR | RCBR;
+ baud = 9600;
+@@ -1314,9 +1364,75 @@ static void __devinit sunzilog_init_hw(s
+ #endif
+ }
+
+-static int zilog_irq = -1;
++#if defined(CONFIG_SUN3) || defined(CONFIG_SUN3X)
++static struct zilog_layout * __init get_zs(int chip)
++{
++ unsigned int vaddr = 0;
+
++ if (chip < 0 || chip >= NUM_SUNZILOG) {
++ prom_printf("SunZilog: Illegal chip number %d in get_zs.\n", chip);
++ prom_halt();
++ }
++
++#ifndef CONFIG_SUN3X
++ /* sun3 OBIO version */
++ /* Grrr, these have to be hardcoded aieee */
++ switch(chip) {
++ case 0:
++ for(vaddr = 0xfe00000; vaddr < (0xfe00000 +
++ SUN3_PMEG_SIZE); vaddr += SUN3_PTE_SIZE) {
++ unsigned long iopte;
++
++ iopte = sun3_get_pte(vaddr);
++ if(!(iopte & SUN3_PAGE_TYPE_IO)) /* this an io page? */
++ continue;
++
++ if(((iopte & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT) ==
++ 0x20000) {
++ break;
++ }
++ }
++ break;
++ case 1:
++ for(vaddr = 0xfe00000; vaddr < (0xfe00000 +
++ SUN3_PMEG_SIZE); vaddr += SUN3_PTE_SIZE) {
++
++ unsigned long iopte;
++
++ iopte = sun3_get_pte(vaddr);
++ if(!(iopte & SUN3_PAGE_TYPE_IO)) /* this an io page? */
++ continue;
++
++ if(((iopte & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT) ==
++ 0) {
++ break;
++ }
++ }
++ break;
++ };
++#else
++ /* sun3x is a wee bit cleaner. :) */
++ switch(chip) {
++ case 0:
++ vaddr = SUN3X_ZS2;
++ break;
++
++ case 1:
++ vaddr = SUN3X_ZS1;
++ break;
++ }
++#endif
++
++ if(!vaddr)
++ panic("get_zs whee no serial chip mappable");
++
++ return (struct zilog_layout *)(unsigned long) vaddr;
++}
++
++static int __devinit zs_probe(void)
++#else
+ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *match)
++#endif
+ {
+ static int inst;
+ struct uart_sunzilog_port *up;
+@@ -1325,51 +1441,70 @@ static int __devinit zs_probe(struct of_
+ int err;
+
+ keyboard_mouse = 0;
++#if defined(CONFIG_SUN3) || defined(CONFIG_SUN3X)
++ sunzilog_chip_regs[inst] = get_zs(inst);
++ if(inst)
++ keyboard_mouse = 1;
++#else
+ if (of_find_property(op->node, "keyboard", NULL))
+ keyboard_mouse = 1;
+
+ sunzilog_chip_regs[inst] = of_ioremap(&op->resource[0], 0,
+ sizeof(struct zilog_layout),
+ "zs");
++#endif /* CONFIG_SUN3 || CONFIG_SUN3X */
++
+ if (!sunzilog_chip_regs[inst])
+ return -ENOMEM;
+
+ rp = sunzilog_chip_regs[inst];
+
++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X)
+ if (zilog_irq == -1)
+ zilog_irq = op->irqs[0];
++#endif
+
+ up = &sunzilog_port_table[inst * 2];
+
+ /* Channel A */
+- up[0].port.mapbase = op->resource[0].start + 0x00;
+ up[0].port.membase = (void __iomem *) &rp->channelA;
+- up[0].port.iotype = UPIO_MEM;
++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X)
++ up[0].port.mapbase = op->resource[0].start + 0x00;
+ up[0].port.irq = op->irqs[0];
++ up[0].port.dev = &op->dev;
++#else
++ up[0].port.mapbase = (unsigned long)up[0].port.membase;
++ up[0].port.irq = zilog_irq;
++#endif
++ up[0].port.iotype = UPIO_MEM;
+ up[0].port.uartclk = ZS_CLOCK;
+ up[0].port.fifosize = 1;
+ up[0].port.ops = &sunzilog_pops;
+ up[0].port.type = PORT_SUNZILOG;
+ up[0].port.flags = 0;
+ up[0].port.line = (inst * 2) + 0;
+- up[0].port.dev = &op->dev;
+ up[0].flags |= SUNZILOG_FLAG_IS_CHANNEL_A;
+ if (keyboard_mouse)
+ up[0].flags |= SUNZILOG_FLAG_CONS_KEYB;
+ sunzilog_init_hw(&up[0]);
+
+ /* Channel B */
+- up[1].port.mapbase = op->resource[0].start + 0x04;
+ up[1].port.membase = (void __iomem *) &rp->channelB;
+- up[1].port.iotype = UPIO_MEM;
++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X)
++ up[1].port.mapbase = op->resource[0].start + 0x04;
+ up[1].port.irq = op->irqs[0];
++ up[1].port.dev = &op->dev;
++#else
++ up[1].port.mapbase = (unsigned long)up[1].port.membase;
++ up[1].port.irq = zilog_irq;
++#endif
++ up[1].port.iotype = UPIO_MEM;
+ up[1].port.uartclk = ZS_CLOCK;
+ up[1].port.fifosize = 1;
+ up[1].port.ops = &sunzilog_pops;
+ up[1].port.type = PORT_SUNZILOG;
+ up[1].port.flags = 0;
+ up[1].port.line = (inst * 2) + 1;
+- up[1].port.dev = &op->dev;
+ up[1].flags |= 0;
+ if (keyboard_mouse)
+ up[1].flags |= SUNZILOG_FLAG_CONS_MOUSE;
+@@ -1378,33 +1513,50 @@ static int __devinit zs_probe(struct of_
+ if (!keyboard_mouse) {
+ err = uart_add_one_port(&sunzilog_reg, &up[0].port);
+ if (err) {
++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X)
+ of_iounmap(&op->resource[0],
+ rp, sizeof(struct zilog_layout));
++#endif
+ return err;
+ }
+ err = uart_add_one_port(&sunzilog_reg, &up[1].port);
+ if (err) {
+ uart_remove_one_port(&sunzilog_reg, &up[0].port);
++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X)
+ of_iounmap(&op->resource[0],
+ rp, sizeof(struct zilog_layout));
++#endif
+ return err;
+ }
+ } else {
++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X)
+ printk(KERN_INFO "%s: Keyboard at MMIO %lx (irq = %d) "
+ "is a zs\n",
+ op->dev.bus_id, up[0].port.mapbase, op->irqs[0]);
+ printk(KERN_INFO "%s: Mouse at MMIO %lx (irq = %d) "
+ "is a zs\n",
+ op->dev.bus_id, up[1].port.mapbase, op->irqs[0]);
++#else
++ printk(KERN_INFO "zs%d: Keyboard at MMIO %lx (irq = %d) "
++ "is a zs\n",
++ inst, up[0].port.mapbase, zilog_irq);
++ printk(KERN_INFO "zs%d: Mouse at MMIO %lx (irq = %d) "
++ "is a zs\n",
++ inst, up[1].port.mapbase, zilog_irq);
++#endif
+ }
+
++
++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X)
+ dev_set_drvdata(&op->dev, &up[0]);
++#endif
+
+ inst++;
+
+ return 0;
+ }
+
++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X)
+ static void __devexit zs_remove_one(struct uart_sunzilog_port *up)
+ {
+ if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) {
+@@ -1445,13 +1597,17 @@ static struct of_platform_driver zs_driv
+ .probe = zs_probe,
+ .remove = __devexit_p(zs_remove),
+ };
++#endif /* !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) */
+
+ static int __init sunzilog_init(void)
+ {
++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X)
+ struct device_node *dp;
++#endif
+ int err, uart_count;
+ int num_keybms;
+
++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X)
+ NUM_SUNZILOG = 0;
+ num_keybms = 0;
+ for_each_node_by_name(dp, "zs") {
+@@ -1459,6 +1615,10 @@ static int __init sunzilog_init(void)
+ if (of_find_property(dp, "keyboard", NULL))
+ num_keybms++;
+ }
++#else
++ NUM_SUNZILOG = 2;
++ num_keybms = 1;
++#endif
+
+ uart_count = 0;
+ if (NUM_SUNZILOG) {
+@@ -1481,6 +1641,7 @@ static int __init sunzilog_init(void)
+
+ sunserial_current_minor += uart_count;
+ }
++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X)
+
+ err = of_register_driver(&zs_driver, &of_bus_type);
+ if (err)
+@@ -1492,12 +1653,28 @@ static int __init sunzilog_init(void)
+ if (err)
+ goto out_unregister_driver;
+ }
++#else
++
++ zilog_irq = 6;
++ err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_DISABLED,
++ "zs", sunzilog_irq_chain);
++ if (err)
++ goto out_unregister_uart;
++
++ /* probe for two zs instances on sun3/3x */
++ zs_probe();
++ zs_probe();
++
++
++#endif
+
+ out:
+ return err;
+
++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X)
+ out_unregister_driver:
+ of_unregister_driver(&zs_driver);
++#endif
+
+ out_unregister_uart:
+ if (NUM_SUNZILOG) {
+@@ -1512,8 +1689,9 @@ out_free_tables:
+
+ static void __exit sunzilog_exit(void)
+ {
++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X)
+ of_unregister_driver(&zs_driver);
+-
++#endif
+ if (zilog_irq != -1) {
+ free_irq(zilog_irq, sunzilog_irq_chain);
+ zilog_irq = -1;
diff --git a/debian/patches/bugfix/m68k/sun3-numints.diff b/debian/patches/bugfix/m68k/sun3-numints.diff
new file mode 100644
index 000000000000..1eea7a7fdb7d
--- /dev/null
+++ b/debian/patches/bugfix/m68k/sun3-numints.diff
@@ -0,0 +1,23 @@
+Subject: [PATCH] m68k: Correct number of interrupts for Sun3
+
+From: Sam Creasey <sammy@sammy.net>
+
+Only attempt to initialize the amount of interrupts a sun3 actually has...
+
+Signed-off-by: Sam Creasey <sammy@sammy.net>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ arch/m68k/sun3/sun3ints.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- linux-m68k-2.6.21.orig/arch/m68k/sun3/sun3ints.c
++++ linux-m68k-2.6.21/arch/m68k/sun3/sun3ints.c
+@@ -103,7 +103,7 @@ void sun3_init_IRQ(void)
+
+ m68k_setup_auto_interrupt(sun3_inthandle);
+ m68k_setup_irq_controller(&sun3_irq_controller, IRQ_AUTO_1, 7);
+- m68k_setup_user_interrupt(VEC_USER, 192, NULL);
++ m68k_setup_user_interrupt(VEC_USER, 128, NULL);
+
+ request_irq(IRQ_AUTO_5, sun3_int5, 0, "int5", NULL);
+ request_irq(IRQ_AUTO_7, sun3_int7, 0, "int7", NULL);
diff --git a/debian/patches/bugfix/m68k/unnecessary-m68k_memoffset.diff b/debian/patches/bugfix/m68k/unnecessary-m68k_memoffset.diff
new file mode 100644
index 000000000000..b646820100d1
--- /dev/null
+++ b/debian/patches/bugfix/m68k/unnecessary-m68k_memoffset.diff
@@ -0,0 +1,30 @@
+Subject: [PATCH] m68k: Remove unnecessary m68k_memoffset export and init
+
+From: Roman Zippel <zippel@linux-m68k.org>
+
+Remove an unnecessary m68k_memoffset export and initialization
+
+Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ arch/m68k/kernel/setup.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- linux-m68k-2.6.21.orig/arch/m68k/kernel/setup.c
++++ linux-m68k-2.6.21/arch/m68k/kernel/setup.c
+@@ -61,7 +61,6 @@ int m68k_num_memory;
+ int m68k_realnum_memory;
+ EXPORT_SYMBOL(m68k_realnum_memory);
+ unsigned long m68k_memoffset;
+-EXPORT_SYMBOL(m68k_memoffset);
+ struct mem_info m68k_memory[NUM_MEMINFO];
+ EXPORT_SYMBOL(m68k_memory);
+
+@@ -199,7 +198,6 @@ static void __init m68k_parse_bootinfo(c
+ (m68k_num_memory - 1));
+ m68k_num_memory = 1;
+ }
+- m68k_memoffset = m68k_memory[0].addr-PAGE_OFFSET;
+ #endif
+ }
+
diff --git a/debian/patches/bugfix/m68k/via-pmu68k-dead-code.diff b/debian/patches/bugfix/m68k/via-pmu68k-dead-code.diff
new file mode 100644
index 000000000000..3d57ea2d1e71
--- /dev/null
+++ b/debian/patches/bugfix/m68k/via-pmu68k-dead-code.diff
@@ -0,0 +1,263 @@
+Subject: [PATCH] remove dead code in via-pmu68k
+Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
+
+From: Johannes Berg <johannes@sipsolutions.net>
+
+When suspend is ever implemented for pmu68k it really should follow the
+generic pm_ops concept and not mirror the platform-specific /dev/pmu
+device with ioctls on it. Hence, this patch removes the unused code there;
+should the implementers need it they can look at via-pmu.c and/or the
+history of the file.
+
+Signed-off-by: Johannes Berg <johannes@sipsolutions.net
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ drivers/macintosh/via-pmu68k.c | 240 -----------------------------------------
+ 1 file changed, 240 deletions(-)
+
+--- linux-m68k-2.6.21.orig/drivers/macintosh/via-pmu68k.c
++++ linux-m68k-2.6.21/drivers/macintosh/via-pmu68k.c
+@@ -818,243 +818,3 @@ pmu_present(void)
+ {
+ return (pmu_kind != PMU_UNKNOWN);
+ }
+-
+-#if 0 /* needs some work for 68K */
+-
+-/*
+- * This struct is used to store config register values for
+- * PCI devices which may get powered off when we sleep.
+- */
+-static struct pci_save {
+- u16 command;
+- u16 cache_lat;
+- u16 intr;
+-} *pbook_pci_saves;
+-static int n_pbook_pci_saves;
+-
+-static inline void
+-pbook_pci_save(void)
+-{
+- int npci;
+- struct pci_dev *pd = NULL;
+- struct pci_save *ps;
+-
+- npci = 0;
+- while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL)
+- ++npci;
+- n_pbook_pci_saves = npci;
+- if (npci == 0)
+- return;
+- ps = kmalloc(npci * sizeof(*ps), GFP_KERNEL);
+- pbook_pci_saves = ps;
+- if (ps == NULL)
+- return;
+-
+- pd = NULL;
+- while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
+- pci_read_config_word(pd, PCI_COMMAND, &ps->command);
+- pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat);
+- pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr);
+- ++ps;
+- --npci;
+- }
+-}
+-
+-static inline void
+-pbook_pci_restore(void)
+-{
+- u16 cmd;
+- struct pci_save *ps = pbook_pci_saves;
+- struct pci_dev *pd = NULL;
+- int j;
+-
+- while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
+- if (ps->command == 0)
+- continue;
+- pci_read_config_word(pd, PCI_COMMAND, &cmd);
+- if ((ps->command & ~cmd) == 0)
+- continue;
+- switch (pd->hdr_type) {
+- case PCI_HEADER_TYPE_NORMAL:
+- for (j = 0; j < 6; ++j)
+- pci_write_config_dword(pd,
+- PCI_BASE_ADDRESS_0 + j*4,
+- pd->resource[j].start);
+- pci_write_config_dword(pd, PCI_ROM_ADDRESS,
+- pd->resource[PCI_ROM_RESOURCE].start);
+- pci_write_config_word(pd, PCI_CACHE_LINE_SIZE,
+- ps->cache_lat);
+- pci_write_config_word(pd, PCI_INTERRUPT_LINE,
+- ps->intr);
+- pci_write_config_word(pd, PCI_COMMAND, ps->command);
+- break;
+- /* other header types not restored at present */
+- }
+- }
+-}
+-
+-/*
+- * Put the powerbook to sleep.
+- */
+-#define IRQ_ENABLE ((unsigned int *)0xf3000024)
+-#define MEM_CTRL ((unsigned int *)0xf8000070)
+-
+-int powerbook_sleep(void)
+-{
+- int ret, i, x;
+- static int save_backlight;
+- static unsigned int save_irqen;
+- unsigned long msr;
+- unsigned int hid0;
+- unsigned long p, wait;
+- struct adb_request sleep_req;
+-
+- /* Notify device drivers */
+- ret = blocking_notifier_call_chain(&sleep_notifier_list,
+- PBOOK_SLEEP, NULL);
+- if (ret & NOTIFY_STOP_MASK)
+- return -EBUSY;
+-
+- /* Sync the disks. */
+- /* XXX It would be nice to have some way to ensure that
+- * nobody is dirtying any new buffers while we wait. */
+- sys_sync();
+-
+- /* Turn off the display backlight */
+- save_backlight = backlight_enabled;
+- if (save_backlight)
+- pmu_enable_backlight(0);
+-
+- /* Give the disks a little time to actually finish writing */
+- for (wait = jiffies + (HZ/4); time_before(jiffies, wait); )
+- mb();
+-
+- /* Disable all interrupts except pmu */
+- save_irqen = in_le32(IRQ_ENABLE);
+- for (i = 0; i < 32; ++i)
+- if (i != vias->intrs[0].line && (save_irqen & (1 << i)))
+- disable_irq(i);
+- asm volatile("mtdec %0" : : "r" (0x7fffffff));
+-
+- /* Save the state of PCI config space for some slots */
+- pbook_pci_save();
+-
+- /* Set the memory controller to keep the memory refreshed
+- while we're asleep */
+- for (i = 0x403f; i >= 0x4000; --i) {
+- out_be32(MEM_CTRL, i);
+- do {
+- x = (in_be32(MEM_CTRL) >> 16) & 0x3ff;
+- } while (x == 0);
+- if (x >= 0x100)
+- break;
+- }
+-
+- /* Ask the PMU to put us to sleep */
+- pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
+- while (!sleep_req.complete)
+- mb();
+- /* displacement-flush the L2 cache - necessary? */
+- for (p = KERNELBASE; p < KERNELBASE + 0x100000; p += 0x1000)
+- i = *(volatile int *)p;
+- asleep = 1;
+-
+- /* Put the CPU into sleep mode */
+- asm volatile("mfspr %0,1008" : "=r" (hid0) :);
+- hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP;
+- asm volatile("mtspr 1008,%0" : : "r" (hid0));
+- local_save_flags(msr);
+- msr |= MSR_POW | MSR_EE;
+- local_irq_restore(msr);
+- udelay(10);
+-
+- /* OK, we're awake again, start restoring things */
+- out_be32(MEM_CTRL, 0x3f);
+- pbook_pci_restore();
+-
+- /* wait for the PMU interrupt sequence to complete */
+- while (asleep)
+- mb();
+-
+- /* reenable interrupts */
+- for (i = 0; i < 32; ++i)
+- if (i != vias->intrs[0].line && (save_irqen & (1 << i)))
+- enable_irq(i);
+-
+- /* Notify drivers */
+- blocking_notifier_call_chain(&sleep_notifier_list, PBOOK_WAKE, NULL);
+-
+- /* reenable ADB autopoll */
+- pmu_adb_autopoll(adb_dev_map);
+-
+- /* Turn on the screen backlight, if it was on before */
+- if (save_backlight)
+- pmu_enable_backlight(1);
+-
+- /* Wait for the hard disk to spin up */
+-
+- return 0;
+-}
+-
+-/*
+- * Support for /dev/pmu device
+- */
+-static int pmu_open(struct inode *inode, struct file *file)
+-{
+- return 0;
+-}
+-
+-static ssize_t pmu_read(struct file *file, char *buf,
+- size_t count, loff_t *ppos)
+-{
+- return 0;
+-}
+-
+-static ssize_t pmu_write(struct file *file, const char *buf,
+- size_t count, loff_t *ppos)
+-{
+- return 0;
+-}
+-
+-static int pmu_ioctl(struct inode * inode, struct file *filp,
+- u_int cmd, u_long arg)
+-{
+- int error;
+- __u32 value;
+-
+- switch (cmd) {
+- case PMU_IOC_SLEEP:
+- return -ENOSYS;
+- case PMU_IOC_GET_BACKLIGHT:
+- return put_user(backlight_level, (__u32 *)arg);
+- case PMU_IOC_SET_BACKLIGHT:
+- error = get_user(value, (__u32 *)arg);
+- if (!error)
+- pmu_set_brightness(value);
+- return error;
+- case PMU_IOC_GET_MODEL:
+- return put_user(pmu_kind, (__u32 *)arg);
+- }
+- return -EINVAL;
+-}
+-
+-static const struct file_operations pmu_device_fops = {
+- .read = pmu_read,
+- .write = pmu_write,
+- .ioctl = pmu_ioctl,
+- .open = pmu_open,
+-};
+-
+-static struct miscdevice pmu_device = {
+- PMU_MINOR, "pmu", &pmu_device_fops
+-};
+-
+-void pmu_device_init(void)
+-{
+- if (!via)
+- return;
+- if (misc_register(&pmu_device) < 0)
+- printk(KERN_ERR "via-pmu68k: cannot register misc device.\n");
+-}
+-#endif /* CONFIG_PMAC_PBOOK */
+-
diff --git a/debian/patches/bugfix/m68k/zorro-resource_size_t-warnings.diff b/debian/patches/bugfix/m68k/zorro-resource_size_t-warnings.diff
new file mode 100644
index 000000000000..0bdc7d7987a7
--- /dev/null
+++ b/debian/patches/bugfix/m68k/zorro-resource_size_t-warnings.diff
@@ -0,0 +1,50 @@
+Subject: [PATCH] Amiga Zorro bus: kill resource_size_t warnings
+
+Kill resource_size_t warnings by casting resource_size_t to unsigned long when
+formatting Zorro bus resources, as they are always 32-bit.
+
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+---
+ drivers/zorro/proc.c | 5 +++--
+ drivers/zorro/zorro-sysfs.c | 3 ++-
+ drivers/zorro/zorro.c | 3 ++-
+ 3 files changed, 7 insertions(+), 4 deletions(-)
+
+--- linux-m68k-2.6.21.orig/drivers/zorro/proc.c
++++ linux-m68k-2.6.21/drivers/zorro/proc.c
+@@ -90,8 +90,9 @@ get_zorro_dev_info(char *buf, char **sta
+ for (slot = cnt = 0; slot < zorro_num_autocon && count > cnt; slot++) {
+ struct zorro_dev *z = &zorro_autocon[slot];
+ len = sprintf(buf, "%02x\t%08x\t%08lx\t%08lx\t%02x\n", slot,
+- z->id, zorro_resource_start(z),
+- zorro_resource_len(z), z->rom.er_Type);
++ z->id, (unsigned long)zorro_resource_start(z),
++ (unsigned long)zorro_resource_len(z),
++ z->rom.er_Type);
+ at += len;
+ if (at >= pos) {
+ if (!*start) {
+--- linux-m68k-2.6.21.orig/drivers/zorro/zorro-sysfs.c
++++ linux-m68k-2.6.21/drivers/zorro/zorro-sysfs.c
+@@ -42,7 +42,8 @@ static ssize_t zorro_show_resource(struc
+ struct zorro_dev *z = to_zorro_dev(dev);
+
+ return sprintf(buf, "0x%08lx 0x%08lx 0x%08lx\n",
+- zorro_resource_start(z), zorro_resource_end(z),
++ (unsigned long)zorro_resource_start(z),
++ (unsigned long)zorro_resource_end(z),
+ zorro_resource_flags(z));
+ }
+
+--- linux-m68k-2.6.21.orig/drivers/zorro/zorro.c
++++ linux-m68k-2.6.21/drivers/zorro/zorro.c
+@@ -164,7 +164,8 @@ static int __init zorro_init(void)
+ if (request_resource(zorro_find_parent_resource(z), &z->resource))
+ printk(KERN_ERR "Zorro: Address space collision on device %s "
+ "[%lx:%lx]\n",
+- z->name, zorro_resource_start(z), zorro_resource_end(z));
++ z->name, (unsigned long)zorro_resource_start(z),
++ (unsigned long)zorro_resource_end(z));
+ sprintf(z->dev.bus_id, "%02x", i);
+ z->dev.parent = &zorro_bus.dev;
+ z->dev.bus = &zorro_bus_type;