diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/CREDITS.m68k linux-1.2.13pl3/CREDITS.m68k
--- linux-1.2.13pl2/CREDITS.m68k	Wed Dec 31 19:00:00 1969
+++ linux-1.2.13pl3/CREDITS.m68k	Mon Oct 23 20:18:40 1995
@@ -0,0 +1,230 @@
+N: Martin Apel
+E: apel@physik.uni-kl.de
+D: 68040 MMU stuff and caches
+
+N: Bjoern Brauel
+E: BjoernBrauel@wi2.maus.de
+D: initiated Atari port, adaption of head.S
+D: Falcon IDE driver
+D: Atari floppy driver
+D: Falcon fixes for Atari SCSI
+D: much basic things all around the kernel
+D: initial Medusa port
+
+N: Lars Brinkhoff
+E: f93labr@dd.chalmers.se
+D: first SCC driver version
+S: Gibraltarg 94/261; 412 79 Goteborg
+S: SWEDEN
+
+N: David Carter
+E: d.p.carter@ic.ac.uk
+D: amiga console and high level console
+D: low level Amiga console code
+S: 32a Champion Hill, Camberwell, London
+S: UK
+
+N: J\"org Dorchain
+E: dorchain@mpi-sb.mpg.de
+D: lp driver changes
+D: New Amiga floppy code supporting MS-DOS disks
+D: iso9660-fs fix for Amiga CDs
+D: AFFS extension
+D: enhanced root-dir protection bits
+D: support for hard and soft links.
+
+N: Torsten Ebeling
+E: tebelin@informatik.uni-kl.de
+D: 4000 (not A1200) IDE hard disk controller
+
+N: Janos Farkas
+E: CHEXUM@sparta.banki.hu
+D: TCP header bitfield fix
+
+N: Thorsten Floeck
+E: flock@wctc6.chemie.uni-wuppertal.de
+D: Medusa testing, logistic support
+
+N: Arno Griffioen.
+E: arno@marlene.usn.nl
+D: High level terminal emulation
+D: VTxxx Terminal Emulation
+
+N: Roman Hodek
+E: rnhodek@cip.informatik.uni-erlangen.de
+D: coordinator for v0.9 releases, Atari coordinator
+D: Atari port
+D: Atari console & keyboard
+D: interrupt-driven Atari floppy driver
+D: Atari SCSI driver
+D: Atari ACSI driver
+D: interrupt sharing between SCSI, IDE, ACSI and floppy
+D: port of MS-DOS filesystem
+D: splitting serial driver into mid-level and low-level
+D: LL serial drivers for Atari MFP and SCC
+D: co-development of framebuffer conecpt
+D: Atari LL-framebuffer device abstraction (TT, Falcon, ST(e), external)
+D: Medusa port
+D: Atari DMA sound driver fixes
+D: many minor stuff all around the kernel
+
+N: Topi Kanerva
+E: topi@susanna.oulu.fi
+D: Includes a driver for the Hydra Amiganet board.
+
+N: Guenther Kelleter
+E: guenther@pool.informatik.rwth-aachen.de
+E: GuentherKelleter@ac3.maus.de (NO mails >16KByte please)
+D: Falcon framebuffer driver
+D: Falcon video mode detection
+D: fix Falcon SCSI locking
+D: patch net code
+D: misc patch all over the kernel (ACSI, SCSI, net code, ...)
+
+N: Arjan Knorr
+E: arjan@usn.nl
+D: some work for the initial Atari port
+D: first Atari coordinator
+
+N: Torsten Lang
+D: A fix for ACSI scatter-gather
+
+N: Karl-Heinz Lohner
+E: Karl-HeinzLohner@m.maus.de
+D: Fixed a nasty bug in TT-SCSI
+
+N: Benjamin Lorenz
+E: benni@phil.uni-sb.de
+D: fix mouse support
+
+
+N: Hamish Macdonald
+E: hamish@border.ocunix.on.ca
+D: Amiga port
+D: coordinator for v1.2 releases
+
+N: Michael Marte
+E: marte@informatik.uni-muenchen.de
+D: Atari DMA sound driver
+
+N: Joerg Mayer
+E: jmayer@informatik.uni-kl.de
+D: maintains FAQ
+
+N: Helmut Neukirchen
+D: published first WWW pages
+
+N: Frank Neumann
+E: Frank.Neumann@arbi.informatik.uni-oldenburg.de
+D: ISO9660 file system code
+D: "Linux/m68k installation guide"
+
+
+N: Michael Rausch
+D: 4000 (not A1200) IDE hard disk controller
+D: Amiga Mouse driver
+D: Amiga Parallel Port printer driver
+
+N: Thomas Roesch
+E: ThomasRoesch@m2.maus.de
+D: Atari SCSI fix for IBM disks
+
+N: Martin Rogge
+E: MartinRogge@ki.maus.de
+D: Better ACSI support for changeable media
+S: Moellenholt 24, D-24107 Kiel
+S: GERMANY
+
+N: William Rucklidge
+E: rucklidge@parc.xerox.com
+D: 68040 cache changes
+D: Early AGA modes in console driver
+
+N: Martin Schaller
+E: MartinSchaller@r.maus.de
+D: Framebuffer concept
+D: ML framebuffer implementation
+D: LL framebuffer driver for Atari TT
+D: port of X11 to Linux/68k
+D: OverScan support
+D: Atari MIDI driver
+D: fixed several nasty bugs in Atari SCSI (uninited vars...)
+D: net codes fixes
+
+N: Torsten Scherer
+E: itschere@TechFak.Uni-Bielefeld.DE
+D: Fixed rotate-9-bytes bug in Atari SCSI
+D: fix Atari mouse movement buffers
+D: fix ttyioctl.c
+
+N: Michael Schl\"uter
+E: MichaelSchlueter@sl.maus.de
+D: Fixed DMA sound
+D: fix in interrupt driven part of lp driver
+
+N: Andreas Schwab
+E: schwab@issan.informatik.uni-dortmund.de
+D: Atari TT port
+D: first bootable Atari Linux
+D: generalized non-autovector interrupt support
+D: generalized multiple consoles
+D: checksum functions for network code
+D: patch for kernel in ELF format
+D: fixed FPU (68881/2) handling
+D: Minix V2 filesystem
+D: numerous bug fixes
+D: general kernel hacker
+D: general ELF/m68k support
+D: integrate 0.9.x changes into 1.2.x
+
+N: Bernard Sebastien
+D: Atari console driver
+
+N: Jes Degn Soerensen
+E: jds@kom.auc.dk
+D: FPU support fixes
+D: ECS support for the original monochrome Amiga framebuffer/amicon.
+D: '040 fixes for the A3000/A2091/GVP SCSI-drivers.
+D: very soon a driver for the GVP IO-Extender's serial ports
+
+N: Michael Thurm
+E: MichaelThurm@do2.maus.de
+D: Falcon IDE now also explicitly enables its interrupt on entry,
+
+N: Geert Uytterhoeven
+E: Geert.Uytterhoeven@cs.kuleuven.ac.be
+D: 4000 (not A1200) IDE hard disk controller
+D: Amiga Fast File System code
+D: Fix to console cut&paste
+D: FPU support fixes
+D: New frame buffer implementation for Amiga
+D: Source for Amiga bootstrap updated to 1.12a.
+D: The 0.9.10 kernel couldn't be compiled without Atari support
+D: due to a misplaced #endif in drivers/char/serial.c
+D: Additional AGA modes from
+D: Ariadne Ethernet driver
+D: A2065 Ethernet driver
+D: Amiga-lilo
+D: /proc/zorro
+D: /proc/hardware
+D: Some '040 fixes in 1.2.x
+S: C. Huysmansstraat 12
+S: B-3128 Baal
+S: BELGIUM
+
+N: Robert H. de Vries
+E: rhdv@fss.fokker.nl
+D: second Atari coordinator, initial Atari port
+S: Simulation and Robotics, Fokker Space & Systems
+
+N: Ingo Wilken
+D: "Linux/m68k installation guide"
+
+E: dg8y@rs11.hrz.th-darmstadt.de
+D: Fix scatter-gather
+
+E: jshiffle@netcom.com
+D: Scatter-gather for the Amiga
+
+E: michael@duck.syd.de
+D: Atari DMA sound driver
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/Makefile linux-1.2.13pl3/Makefile
--- linux-1.2.13pl2/Makefile	Tue Sep 19 23:47:45 1995
+++ linux-1.2.13pl3/Makefile	Fri Oct 13 19:06:17 1995
@@ -1,6 +1,7 @@
 VERSION = 1
 PATCHLEVEL = 2
 SUBLEVEL = 13
+SUBLEVEL1 = $(SUBLEVEL)pl3
 
 ARCH = m68k
 
@@ -155,7 +156,7 @@
 	fi
 
 include/linux/version.h: $(CONFIGURATION) Makefile newversion
-	@echo \#define UTS_RELEASE \"$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)pl2\" > include/linux/version.h
+	@echo \#define UTS_RELEASE \"$(VERSION).$(PATCHLEVEL).$(SUBLEVEL1)\" > include/linux/version.h
 	@if [ -f .name ]; then \
 	   echo \#define UTS_VERSION \"\#`cat .version`-`cat .name` `date`\"; \
 	 else \
@@ -187,7 +188,7 @@
 	
 modules_install:
 	@( \
-	MODLIB=/lib/modules/$(VERSION).$(PATCHLEVEL).$(SUBLEVEL); \
+	MODLIB=/lib/modules/$(VERSION).$(PATCHLEVEL).$(SUBLEVEL1); \
 	cd modules; \
 	MODULES=""; \
 	inst_mod() { These=`cat $$1`; MODULES="$$MODULES $$These"; \
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/arch/m68k/Makefile linux-1.2.13pl3/arch/m68k/Makefile
--- linux-1.2.13pl2/arch/m68k/Makefile	Tue Sep 12 21:13:53 1995
+++ linux-1.2.13pl3/arch/m68k/Makefile	Mon Oct 23 20:37:07 1995
@@ -80,6 +80,7 @@
 
 archclean:
 	@$(MAKEBOOT) clean
+	rm -f bootstrap
 
 archdep:
 	$(MAKEBOOT) dep
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/arch/m68k/amiga/Makefile linux-1.2.13pl3/arch/m68k/amiga/Makefile
--- linux-1.2.13pl2/arch/m68k/amiga/Makefile	Sun Jun 18 21:56:04 1995
+++ linux-1.2.13pl3/arch/m68k/amiga/Makefile	Fri Oct 13 18:11:38 1995
@@ -17,6 +17,10 @@
 OBJS	= config.o amikeyb.o amiints.o amicon.o font.o amipart.o \
 	  chipram.o amisound.o amifb.o
 
+ifdef CONFIG_ZORRO
+OBJS    := $(OBJS) zorro.o
+endif
+
 amiga.o: $(OBJS)
 	$(LD) -r -o amiga.o $(OBJS)
 
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/arch/m68k/amiga/amikeyb.c linux-1.2.13pl3/arch/m68k/amiga/amikeyb.c
--- linux-1.2.13pl2/arch/m68k/amiga/amikeyb.c	Mon Jun 19 21:55:19 1995
+++ linux-1.2.13pl3/arch/m68k/amiga/amikeyb.c	Fri Oct 13 18:51:55 1995
@@ -258,7 +258,7 @@
     /*
      * Initialize serial data direction.
      */
-    ciaa.cra &= ~0x41;	     /* serial data in, turn off TA */
+    ciaa.cra &= ~0x40;	     /* serial data in, turn off TA */
 
     /*
      * arrange for processing of keyboard interrupt
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/arch/m68k/amiga/config.c linux-1.2.13pl3/arch/m68k/amiga/config.c
--- linux-1.2.13pl2/arch/m68k/amiga/config.c	Tue Sep 12 21:13:54 1995
+++ linux-1.2.13pl3/arch/m68k/amiga/config.c	Fri Oct 13 18:52:31 1995
@@ -47,6 +47,7 @@
 extern void amiga_hd_setup (char *str, int *ints);
 extern void amiga_waitbut(void);
 extern struct consw ami_con;
+extern void amiga_zorro_ident(void);
 
 void config_amiga(void)
 {
@@ -90,6 +91,13 @@
      */
     if (boot_info.bi_amiga.model == AMI_3000)
 	    *(u_char *)ZTWO_VADDR(0xde0002) |= 0x80;
+
+#ifdef CONFIG_ZORRO
+    /*
+     * Identify all known AutoConfig Expansion Devices
+     */
+    amiga_zorro_ident();
+#endif /* CONFIG_ZORRO */
 }
 
 extern long time_finetune;	/* from kernel/sched.c */
@@ -108,14 +116,14 @@
     /* CIA interrupts when counter underflows, so adjust ticks by 1 */
     ticks -= 1;
 
-    ciab.cra &= 0xC0;	 /* turn off timer A, continous mode, from Eclk */
-    ciab.talo = ticks % 256;
-    ciab.tahi = ticks / 256;
+    ciaa.cra &= 0xC0;	 /* turn off timer A, continous mode, from Eclk */
+    ciaa.talo = ticks % 256;
+    ciaa.tahi = ticks / 256;
 
-    /* install interrupt service routine for CIAB Timer A */
-    add_isr (IRQ_AMIGA_CIAB_TA, timer_routine, 0, NULL);
+    /* install interrupt service routine for CIAA Timer A */
+    add_isr (IRQ_AMIGA_CIAA_TA, timer_routine, 0, NULL);
     /* start timer */
-    ciab.cra |= 0x01;
+    ciaa.cra |= 0x01;
 }
 
 #define TICK_SIZE 10000
@@ -127,12 +135,12 @@
     unsigned long ticks, offset = 0;
 
     /* read CIA B timer A current value */
-    hi	= ciab.tahi;
-    lo	= ciab.talo;
-    hi2 = ciab.tahi;
+    hi	= ciaa.tahi;
+    lo	= ciaa.talo;
+    hi2 = ciaa.tahi;
 
     if (hi != hi2) {
-	lo = ciab.talo;
+	lo = ciaa.talo;
 	hi = hi2;
     }
 
@@ -143,7 +151,7 @@
 /* reading the ICR clears all interrupts.  bad idea! */
 	if (ticks > NTSC_JIFFY_TICKS - NTSC_JIFFY_TICKS / 100)
 	  /* check for pending interrupt */
-	  if (ciab.icr & CIA_ICR_TA)
+	  if (ciaa.icr & CIA_ICR_TA)
 	    offset = 10000;
 #endif
 	ticks = (NTSC_JIFFY_TICKS-1) - ticks;
@@ -153,7 +161,7 @@
 /* reading the ICR clears all interrupts.  bad idea! */
 	if (ticks > PAL_JIFFY_TICKS - PAL_JIFFY_TICKS / 100)
 	  /* check for pending interrupt */
-	  if (ciab.icr & CIA_ICR_TA)
+	  if (ciaa.icr & CIA_ICR_TA)
 	    offset = 10000;
 #endif
 	ticks = (PAL_JIFFY_TICKS-1) - ticks;
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/arch/m68k/amiga/zorro.c linux-1.2.13pl3/arch/m68k/amiga/zorro.c
--- linux-1.2.13pl2/arch/m68k/amiga/zorro.c	Wed Dec 31 19:00:00 1969
+++ linux-1.2.13pl3/arch/m68k/amiga/zorro.c	Fri Oct 13 18:11:39 1995
@@ -0,0 +1,344 @@
+/*
+ *		linux/arch/m68k/amiga/zorro.c
+ *
+ *		Copyright (C) 1995 Geert Uytterhoeven
+ *
+ *		This file is subject to the terms and conditions of the GNU General Public
+ *		License.  See the file README.legal in the main directory of this archive
+ *		for more details.
+ */
+
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <asm/bootinfo.h>
+#include <asm/amigatypes.h>
+
+
+	/*
+	 *		Zorro Expansion Device Manufacturers and Products
+	 */
+
+struct Manufacturer {
+	char *Name;
+	u_short ID;
+	u_short NumProd;
+	struct Product *Products;
+};
+
+struct Product {
+	char *Name;
+	u_char ID;
+};
+
+#define DEF_PROD(name, id) \
+	{ name, PROD_##id }
+#define DEF_MANUF(name, id) \
+	{ name, MANUF_##id, sizeof(Prod_##id)/sizeof(struct Product), Prod_##id }
+
+
+	/*
+	 *		Known Zorro Expansion Devices
+	 *
+	 *		Warning: Make sure the Manufacturer and Product names are not too
+	 *					long (max. 80 characters per board indentification line)
+	 */
+
+static struct Product Prod_COMMODORE[] = {
+	DEF_PROD("A2090/A2090A HD Controller", A2090A),
+	DEF_PROD("A2091 HD Controller", A2091),
+	DEF_PROD("A590 HD Controller", A590),
+	DEF_PROD("A2090B 2090 Autoboot Card", A2090B),
+	DEF_PROD("Arcnet Card", ARCNET),
+	DEF_PROD("A2052/58.RAM | 590/2091.RAM", CBMRAM),
+	DEF_PROD("A560 Memory Module", A560RAM),
+	DEF_PROD("A2232 Serial Prototype", A2232PROTO),
+	DEF_PROD("A2232 Serial Production", A2232),
+	DEF_PROD("A2620 68020/RAM Card", A2620),
+	DEF_PROD("A2630 68030/RAM Card", A2630),
+	DEF_PROD("A4091 SCSI HD Controller", A4091),
+	DEF_PROD("Romulator Card", ROMULATOR),
+	DEF_PROD("A3000 Test Fixture", A3000TESTFIX),
+	DEF_PROD("A2065 Ethernet Card", A2065)
+};
+
+static struct Product Prod_COMMODORE2[] = {
+	DEF_PROD("Bridgeboard", BRIDGEBOARD),
+	DEF_PROD("A2386-SX Bridgeboard", A2386SX),
+};
+
+static struct Product Prod_U_LOWELL[] = {
+	DEF_PROD("A2410 Hires Graphics Card", A2410)
+};
+
+static struct Product Prod_AMERISTAR[] = {
+	DEF_PROD("A2065 Ethernet Card", AMERISTAR2065)
+};
+
+static struct Product Prod_GVP[] = {
+	DEF_PROD("Series II SCSI Controller", GVPIISCSI),
+	DEF_PROD("Series II SCSI Controller", GVPIISCSI_2),
+	DEF_PROD("GVP Series II RAM", GVPIIRAM),
+	DEF_PROD("GVP IV-24 Graphics Board", GVPIV_24),
+	DEF_PROD("GVP I/O Extender", GVPIO_EXT)
+};
+
+static struct Product Prod_GVP2[] = {
+	DEF_PROD("GVP Spectrum Graphics Board (RAM)", SPECTRUM_RAM),
+	DEF_PROD("GVP Spectrum Graphics Board (REG)", SPECTRUM_REG)
+};
+
+static struct Product Prod_VILLAGE_TRONIC[] = {
+	DEF_PROD("Ariadne Ethernet Card", ARIADNE),
+	DEF_PROD("Picasso II Graphics Board (RAM)", PICASSO_II_RAM),
+	DEF_PROD("Picasso II Graphics Board (REG)", PICASSO_II_REG)
+};
+
+static struct Product Prod_HELFRICH1[] = {
+	DEF_PROD("Rainbow3 Graphics Board", RAINBOW3)
+};
+
+static struct Product Prod_HELFRICH2[] = {
+	DEF_PROD("Piccolo Graphics Board (RAM)", PICCOLO_RAM),
+	DEF_PROD("Piccolo Graphics Board (REG)", PICCOLO_REG),
+	DEF_PROD("PeggyPlus MPEG Decoder Board", PEGGY_PLUS),
+	DEF_PROD("SD64 Graphics Board (RAM)", SD64_RAM),
+	DEF_PROD("SD64 Graphics Board (REG)", SD64_REG)
+};
+
+static struct Product Prod_HYDRA_SYSTEMS[] = {
+	DEF_PROD("Amiganet Board", AMIGANET)
+};
+
+static struct Product Prod_MEMPHIS[] = {
+	DEF_PROD("Stormbringer", STORMBRINGER)
+};
+
+static struct Product Prod_SUPRA[] = {
+	DEF_PROD("Supra 2400 Modem", SUPRA_2400MODEM)
+};
+
+static struct Product Prod_BSC[] = {
+	DEF_PROD("BSC ALF 3 SCSI Controller", ALF_3_SCSI)
+};
+
+static struct Product Prod_BSC2[] = {
+	DEF_PROD("BSC Oktagon 2008 SCSI Controller", OKTAGON_2008),
+	DEF_PROD("BSC Tandem", TANDEM),
+	DEF_PROD("BSC Par/Ser Card", PAR_SER_CARD),
+	DEF_PROD("BSC MultiFace III", MULTIFACE_III),
+	DEF_PROD("BSC ISDN Master", ISDN_MASTER)
+};
+
+static struct Product Prod_JOCHHEIM[] = {
+	DEF_PROD("Jochheim RAM", JOCHHEIM_RAM)
+};
+
+static struct Product Prod_CHECKPOINT[] = {
+	DEF_PROD("Serial Solution", SERIAL_SOLUTION)
+};
+
+static struct Product Prod_GOLEM[] = {
+	DEF_PROD("Golem SCSI-II Controller", GOLEM_SCSI_II)
+};
+
+static struct Product Prod_ADV_SYS_SOFT[] = {
+	DEF_PROD("Nexus SCSI Controller", NEXUS_SCSI),
+	DEF_PROD("Nexus RAM", NEXUS_RAM)
+};
+
+static struct Product Prod_XPERT_PRODEV[] = {
+	DEF_PROD("Merlin Graphics Board (RAM)", MERLIN_RAM),
+	DEF_PROD("Merlin Graphics Board (REG)", MERLIN_REG)
+};
+
+static struct Product Prod_UTILITIES_ULTD[] = {
+	DEF_PROD("Emplant Deluxe", EMPLANT_DELUXE),
+	DEF_PROD("Emplant Deluxe", EMPLANT_DELUXE2)
+};
+
+static struct Product Prod_HARMS_PROF[] = {
+	DEF_PROD("3500 Turbo board", 3500_TURBO)
+};
+
+static struct Product Prod_VORTEX[] = {
+	DEF_PROD("Golden Gate 80386 Board", GOLDEN_GATE_386),
+	DEF_PROD("Golden Gate RAM", GOLDEN_GATE_RAM),
+	DEF_PROD("Golden Gate 80486 Board", GOLDEN_GATE_486)
+};
+
+static struct Product Prod_PHASE5[] = {
+	DEF_PROD("FastLane RAM", FASTLANE_RAM),
+	DEF_PROD("FastLane SCSI", FASTLANE_SCSI),
+	DEF_PROD("CyberVision64 Graphics Board", CYBERVISION)
+};
+
+static struct Product Prod_APOLLO[] = {
+	DEF_PROD("AT-Apollo", AT_APOLLO)
+};
+
+static struct Product Prod_UWE_GERLACH[] = {
+	DEF_PROD("RAM/ROM", UG_RAM_ROM)
+};
+
+static struct Product Prod_MACROSYSTEMS[] = {
+	DEF_PROD("Warp Engine", WARP_ENGINE)
+};
+
+static struct Product Prod_MACROSYSTEMS2[] = {
+	DEF_PROD("Maestro", MAESTRO),
+	DEF_PROD("VLab", VLAB),
+	DEF_PROD("Maestro Pro", MAESTRO_PRO),
+	DEF_PROD("Retina Z2 Graphics Board", RETINA_Z2),
+	DEF_PROD("MultiEvolution", MULTI_EVOLUTION)
+};
+
+static struct Product Prod_MICROBOTICS[] = {
+	DEF_PROD("VXL-30 Turbo Board", VXL_30)
+};
+
+static struct Manufacturer Manufacturers[] = {
+	DEF_MANUF("Commodore", COMMODORE),
+	DEF_MANUF("Commodore", COMMODORE2),
+	DEF_MANUF("University of Lowell", U_LOWELL),
+	DEF_MANUF("Ameristar", AMERISTAR),
+	DEF_MANUF("Helfrich", HELFRICH1),
+	DEF_MANUF("Helfrich", HELFRICH2),
+	DEF_MANUF("Great Valley Products", GVP),
+	DEF_MANUF("Great Valley Products", GVP2),
+	DEF_MANUF("Village Tronic", VILLAGE_TRONIC),
+	DEF_MANUF("Hydra Systems", HYDRA_SYSTEMS),
+	DEF_MANUF("Memphis", MEMPHIS),
+	DEF_MANUF("Supra", SUPRA),
+	DEF_MANUF("BSC", BSC),
+	DEF_MANUF("BSC", BSC2),
+	DEF_MANUF("Jochheim", JOCHHEIM),
+	DEF_MANUF("Checkpoint Technologies", CHECKPOINT),
+	DEF_MANUF("Golem", GOLEM),
+	DEF_MANUF("Advanced Systems & Software", ADV_SYS_SOFT),
+	DEF_MANUF("XPert/ProDev", XPERT_PRODEV),
+	DEF_MANUF("Utilities Unlimited", UTILITIES_ULTD),
+	DEF_MANUF("Harms Professional", HARMS_PROF),
+	DEF_MANUF("Vortex", VORTEX),
+	DEF_MANUF("Phase5", PHASE5),
+	DEF_MANUF("Apollo", APOLLO),
+	DEF_MANUF("Uwe Gerlach", UWE_GERLACH),
+	DEF_MANUF("MacroSystems", MACROSYSTEMS),
+	DEF_MANUF("MacroSystems", MACROSYSTEMS2),
+	DEF_MANUF("MicroBotics", MICROBOTICS)
+};
+
+#define NUM_MANUF (sizeof(Manufacturers)/sizeof(struct Manufacturer))
+
+
+	/*
+	 *		Identify an AutoConfig Expansion Device
+	 *
+	 *		If the board was configured by a Linux/68k driver, an asterisk will
+	 *		be printed before the board address (except for unknown and `Hacker
+	 *		Test' boards).
+	 */
+
+static int identify(int devnum, char *buf)
+{
+	struct ConfigDev *cd;
+	int manuf, prod;
+	u_long addr, size;
+	char *manufname, *prodname;
+	char zorro, mag, configured;
+	int identified = 0;
+	int i, j, len = 0;
+
+	cd = &boot_info.bi_amiga.autocon[devnum];
+	manuf = cd->cd_Rom.er_Manufacturer;
+	prod = cd->cd_Rom.er_Product;
+	addr = (u_long)cd->cd_BoardAddr;
+	size = cd->cd_BoardSize;
+	configured = boot_info.bi_amiga.autocon_configured & (1<<devnum) ? '*' : ' ';
+	manufname = prodname = "<UNKNOWN>";
+
+	for (i = 0; i < NUM_MANUF; i++)
+		if (Manufacturers[i].ID == manuf) {
+			manufname = Manufacturers[i].Name;
+			for (j = 0; j < Manufacturers[i].NumProd; j++)
+				if (Manufacturers[i].Products[j].ID == prod) {
+					prodname = Manufacturers[i].Products[j].Name;
+					identified = 1;
+					break;
+				}
+			break;
+		}
+
+	switch (cd->cd_Rom.er_Type & ERT_TYPEMASK) {
+		case ERT_ZORROII:
+			zorro = '2';
+			break;
+		case ERT_ZORROIII:
+			zorro = '3';
+			break;
+		default:
+			zorro = '?';
+			break;
+	}
+	if (size & 0xfffff) {
+		size >>= 10;
+		mag = 'K';
+	} else {
+		size >>= 20;
+		mag = 'M';
+	}
+
+	if (identified)
+		len = sprintf(buf, " %c0x%08lx: %s %s (Z%c, %ld%c)\n", configured, addr,
+						  manufname, prodname, zorro, size, mag);
+	else if (manuf == MANUF_HACKER)
+		len = sprintf(buf, "  0x%08lx: Hacker Test Board 0x%02x (Z%c, %ld%c)\n",
+						  addr, prod, zorro, size, mag);
+	else {
+		len = sprintf(buf, "  0x%08lx: [%04x:%02x] made by %s (Z%c, %ld%c)\n",
+						  addr, manuf, prod, manufname, zorro, size, mag);
+		len += sprintf(buf+len, "  Please report this unknown device to "
+							"Geert.Uytterhoeven@cs.kuleuven.ac.be\n");
+	}
+	return(len);
+}
+
+
+	/*
+	 *		Identify all known AutoConfig Expansion Devices
+	 */
+
+void amiga_zorro_ident(void)
+{
+	int i;
+	char tmp[160];
+
+	printk("Probing AutoConfig expansion device(s):\n");
+	for (i = 0; i < boot_info.bi_amiga.num_autocon; i++) {
+		identify(i, tmp);
+		printk(tmp);
+	}
+	if (!boot_info.bi_amiga.num_autocon)
+		printk("No AutoConfig expansion devices present.\n");
+}
+
+int get_zorro_list(char *buffer)
+{
+	int i, j, len = 0;
+	char tmp[160];
+
+	if (boot_info.machtype == MACH_AMIGA) {
+		len = sprintf(buffer, "AutoConfig expansion devices:\n");
+		for (i = 0; i < boot_info.bi_amiga.num_autocon; i++) {
+			j = identify(i, tmp);
+			if (len+j >= 4075) {
+				len += sprintf(buffer+len, "4K limit reached!\n");
+				break;
+			}
+			strcpy(buffer+len, tmp);
+			len += j;
+		}
+	}
+	return(len);
+}
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/arch/m68k/atari/atafb.c linux-1.2.13pl3/arch/m68k/atari/atafb.c
--- linux-1.2.13pl2/arch/m68k/atari/atafb.c	Tue Sep 12 21:13:58 1995
+++ linux-1.2.13pl3/arch/m68k/atari/atafb.c	Fri Oct 13 19:04:39 1995
@@ -16,12 +16,15 @@
  *   - 07 May 95: Martin: Added colormap operations for the external driver
  *   - 21 May 95: Martin: Added support for overscan
  *		  Andreas: some bug fixes for this
+ *   -    Jul 95: Guenther Kelleter <guenther@pool.informatik.rwth-aachen.de>:
+ *                Programmable Falcon video modes
+ *                (thanks to Christian Cartus for documentation
+ *                of VIDEL registers).
  *
  *
  * To do:
- *   - For the Falcon it is not yet possible to set video modes, only
- *     the one detected at boot time can be used. Seems a bit more
- *     complicated to program the VIDEL...
+ *   - For the Falcon it is not possible to set random video modes on
+ *     SM124 and SC/TV, only the bootup resolution is supported.
  *
  */
 
@@ -64,6 +67,8 @@
 static int ovsc_offset=0, ovsc_addlen=0;
 int        ovsc_switchmode=0;
 
+static int pwrsave = 0;	/* use VESA suspend mode instead of blanking only? */
+
 static struct atari_fb_par {
 	unsigned long screen_base;
 	union {
@@ -71,17 +76,46 @@
 			int mode;
 			int sync;
 		} tt, st;
-		struct {
-			int bpp;
-			/* Sorry, nothing here yet, because mode switching for the
-			 * Falcon isn't implemented yet.
-			 * Here should be fields for storing a video mode, either
-			 * as direct parameters for the hardware or as a mode code.
+		struct falcon_hw {
+			/* Here are fields for storing a video mode, as direct
+			 * parameters for the hardware.
 			 */
+			short sync;
+			short line_width;
+			short line_offset;
+			short st_shift;
+			short f_shift;
+			short vid_control;
+			short vid_mode;
+			short hht, hbb, hbe, hdb, hde, hss;
+			short vft, vbb, vbe, vdb, vde, vss;
+			/* derived parameters */
+			char mono;
+			char ste_mode;
 		} falcon;
 		/* Nothing needed for external mode */
 	} hw;
 } current_par;
+#define HHT hw.falcon.hht
+#define HBB hw.falcon.hbb
+#define HBE hw.falcon.hbe
+#define HDB hw.falcon.hdb
+#define HDE hw.falcon.hde
+#define HSS hw.falcon.hss
+#define VFT hw.falcon.vft
+#define VBB hw.falcon.vbb
+#define VBE hw.falcon.vbe
+#define VDB hw.falcon.vdb
+#define VDE hw.falcon.vde
+#define VSS hw.falcon.vss
+#define VCO_CLOCK25		0x04
+#define VCO_CSYPOS		0x10
+#define VCO_VSYPOS		0x20
+#define VCO_HSYPOS		0x40
+#define VCO_SHORTOFFS	0x100
+#define VMO_DOUBLE		0x01
+#define VMO_INTER		0x02
+#define VMO_PREMASK		0x0c
 
 static struct fb_info fb_info;
 
@@ -171,6 +205,10 @@
  *   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 NULL then blanking
+ *   is done by setting the CLUT to black. Return != 0 if un-/blanking
+ *   failed due to e.g. video mode which doesn't support it.
  */
 
 static struct fb_hwswitch {
@@ -190,6 +228,7 @@
 					   unsigned green, unsigned blue,
 					   unsigned transp );
 	void (*set_screen_base)( unsigned long s_base );
+	int  (*blank)( int blank_mode );
 } *fbhw;
 
 static char *autodetect_names[] = {"autodetect", NULL};
@@ -579,25 +618,53 @@
 
 /* ------------------- Falcon specific functions ---------------------- */
 
+static int mon_type;		/* Falcon connected monitor */
+static int f030_bus_width;	/* Falcon ram bus width (for vid_control) */
+#define F_MON_SM	0
+#define F_MON_SC	1
+#define F_MON_VGA	2
+#define F_MON_TV	3
+
+/* Multisync monitor capabilities */
+/* Atari-TOS defaults if no boot option present */
+static long vfmin=58, vfmax=62, hfmin=31000, hfmax=32000;
+
+static struct pixel_clock {
+	unsigned long f;	/* f/[Hz] */
+	unsigned long t;	/* t/[ps] (=1/f) */
+	short right, hsync, left;	/* standard timing in clock cycles, not pixel */
+		/* hsync initialized in falcon_detect() */
+	short sync_mask;	/* or-mask for hw.falcon.sync to set this clock */
+	short control_mask; /* dito, for hw.falcon.vid_control */
+}
+f25  = {25175000, 39722, 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 short 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, 4700000, 4000000, 4700000};
+
 
 static int falcon_encode_fix( struct fb_fix_screeninfo *fix,
 							  struct atari_fb_par *par )
-
 {
 	strcpy(fix->id,"Atari Builtin");
-	fix->smem_start=real_screen_base;
-	fix->smem_len=screen_len & PAGE_MASK;
-	fix->type=FB_TYPE_INTERLEAVED_PLANES;
-	fix->type_aux=2;
-	fix->visual=FB_VISUAL_PSEUDOCOLOR;
-	if (par->hw.falcon.bpp==1) {
-		fix->type=FB_TYPE_PACKED_PIXELS;
-		fix->type_aux=0;
+	fix->smem_start = real_screen_base;
+	fix->smem_len = screen_len & PAGE_MASK;
+	fix->type = FB_TYPE_INTERLEAVED_PLANES;
+	fix->type_aux = 2;
+	fix->visual = FB_VISUAL_PSEUDOCOLOR;
+	if (par->hw.falcon.mono) {
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->type_aux = 0;
 	}
-	else if (par->hw.falcon.bpp==16) {
-		fix->type=FB_TYPE_PACKED_PIXELS;
-		fix->type_aux=0;
-		fix->visual=FB_VISUAL_TRUECOLOR;  /* is this ok? */
+	else if (par->hw.falcon.f_shift & 0x100) {
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->type_aux = 0;
+		fix->visual = FB_VISUAL_TRUECOLOR;  /* is this ok? */
 	}
 	return 0;
 }
@@ -606,31 +673,477 @@
 static int falcon_decode_var( struct fb_var_screeninfo *var,
 							  struct atari_fb_par *par )
 {
-	struct fb_var_screeninfo *myvar = &atari_fb_predefined[0];
+	int use_default_timing = 0;
+	int bpp = var->bits_per_pixel;
+	int xres = var->xres;
+	int yres = var->yres;
+	int xres_virtual = var->xres_virtual;
+	int left_margin, right_margin, hsync_len;
+	int upper_margin, lower_margin, vsync_len;
 	int linelen;
-	
-	if (var->bits_per_pixel > myvar->bits_per_pixel ||
-		var->xres > myvar->xres ||
-		var->yres > myvar->yres)
+	int interlace = 0, doubleline = 0;
+	struct pixel_clock *pclock;
+	int plen; /* width of pixel in clock cycles */
+	int xstretch;
+	int prescale;
+	int longoffset = 0;
+	int hfreq, vfreq;
+
+/*
+	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, 
+	horizontal timing, vertical timing.
+
+	There is a maximum of screen resolution determined by pixelclock
+	and minimum frame rate -- (X+hmarg.)*(Y+vmarg.)*vfmin <= pixelclock.
+	In interlace mode this is     "     *    "     *vfmin <= pixelclock.
+	Additional constraints: hfreq.
+	Frequency range for multisync monitors is given via command line.
+	For TV and SM124 both frequencies are fixed.
+
+	X % 16 == 0
+	Y % 16 == 0 (to fit 8x16 font)
+	Y % 8 == 0 if Y<400
+
+	Currently interlace and doubleline mode in var are ignored. 
+	On SM124 and TV only the standard resolutions can be used.
+*/
+
+	if (mon_type == F_MON_SM && bpp != 1) {
 		return -EINVAL;
-	linelen=myvar->xres*myvar->bits_per_pixel/8;
-	if ((var->yoffset + myvar->yres)*linelen > screen_len && screen_len)
+	}
+	else if (bpp <= 1) {
+		bpp = 1;
+		par->hw.falcon.f_shift = 0x400;
+		par->hw.falcon.st_shift = 0x200;
+	}
+	else if (bpp <= 2) {
+		bpp = 2;
+		par->hw.falcon.st_shift = 0x100;
+	}
+	else if (bpp <= 4) {
+		bpp = 4;
+		par->hw.falcon.f_shift = 0x000;
+		par->hw.falcon.st_shift = 0x000;
+	}
+	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
 		return -EINVAL;
-	par->screen_base=screen_base+ var->yoffset*linelen;
-	par->hw.falcon.bpp = myvar->bits_per_pixel;
+
+	if (mon_type != F_MON_VGA) {
+		/* Skip all calculations, VGA multisync only yet */
+		struct fb_var_screeninfo *myvar = &atari_fb_predefined[0];
+		
+		if (bpp > myvar->bits_per_pixel ||
+			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 */
+	}
+
+	/* Only some fixed resolutions < 640x480 */
+	if (xres <= 320)
+		xres = 320;
+	else if (xres <= 640 && bpp != 16)
+		xres = 640;
+	if (yres <= 200)
+		yres = 200;
+	else if (yres <= 240)
+		yres = 240;
+	else if (yres <= 400)
+		yres = 400;
+	else if (yres <= 480)
+		yres = 480;
+
+	/* 2 planes must use STE compatibility mode */
+	par->hw.falcon.ste_mode = bpp==2;
+	par->hw.falcon.mono = bpp==1;
+
+	/* Xres MOD 16 must be 0 due to scanline length is multiple of one word,
+	 * except for hicolor.
+	 * The same applies to xres_virtual.
+	 */
+	if (bpp != 16)
+		xres = (xres + 15) & ~15;
+	yres = (yres + 7) & ~7;
+	if (yres >= 400)
+		yres = (yres + 15) & ~15;
+	/* Special case if STE mode: blank and graphic positions don't fit,
+	 * this is to avoid trash at right margin
+	 */
+	if (par->hw.falcon.ste_mode) {
+		xres = (xres + 63) & ~63;
+	}
+	if (xres_virtual < xres)
+		xres_virtual = xres;
+	if (bpp != 16)
+		xres_virtual = (xres_virtual + 15) & ~15;
+#if 0 /* yres_virtual currently determined by screen memory size */
+	if (yres_virtual < yres)
+		yres_virtual = yres;
+#endif
+
+	par->hw.falcon.line_width = bpp * xres / 16;
+	par->hw.falcon.line_offset = bpp * (xres_virtual - xres) / 16;
+
+	/* single or double pixel width */
+	xstretch = (xres == 320) ? 2 : 1;
+
+	/* Default values are used for vert./hor. timing if no pixelclock given. */
+	if (var->pixclock == 0)
+		use_default_timing = 1;
+
+#if 0 /* currently unused */
+	if (mon_type == F_MON_SM) {
+		if (xres != 640 && yres != 400)
+			return -EINVAL;
+		plen = 1;
+		pclock = &f32;
+		/* SM124-mode is special */
+		par->hw.falcon.ste_mode = 1;
+		par->hw.falcon.f_shift = 0x000;
+		par->hw.falcon.st_shift = 0x200;
+		left_margin = right_margin = hsync_len = 128 / plen;
+		/* TODO set all margins */
+	}
+	else if (mon_type == F_MON_SC || mon_type == F_MON_TV) {
+		plen = 2 * xstretch;
+		pclock = &f32;
+		hsync_len = 150 / plen;
+		if (yres > 240)
+			interlace = 1;
+		/* TODO set margins */
+	}
+	else
+#endif
+	{	/* F_MON_VGA */
+		if (bpp == 16)
+			xstretch = 2; /* hicolor only double pixel width */
+		if (use_default_timing) {
+			int linesize;
+
+			/* Choose master pixelclock depending on hor. timing */
+			plen = 1 * xstretch;
+			if ((plen * xres + f25.right+f25.hsync+f25.left) * hfmin < f25.f)
+				pclock = &f25;
+			else if ((plen * xres + f32.right+f32.hsync+f32.left) * hfmin < f32.f)
+				pclock = &f32;
+			else if ((plen * xres + fext.right+fext.hsync+fext.left) * hfmin < fext.f
+			         && fext.f)
+				pclock = &fext;
+			else
+				return -EINVAL;
+
+			left_margin = pclock->left / plen;
+			right_margin = (pclock->right + pclock->hsync) / plen;
+			hsync_len = pclock->hsync / plen;
+			linesize = left_margin + xres + right_margin;
+			upper_margin = 31;
+			lower_margin = 14;
+			vsync_len = 3;
+		}
+		else {
+#if 0 /* TODO enable this (untested yet) */
+			/* Round down pixelclock */
+			int i; unsigned long pcl=0;
+			for (i=1; i<=4; i*=2) {
+				if (f25.t*i<=var->pixclock && pcl<f25.t*i) {
+					pcl=f25.t*i; pclock=&f25;
+				}
+				if (f32.t*i<=var->pixclock && pcl<f32.t*i) {
+					pcl=f32.t*i; pclock=&f32;
+				}
+				if (fext.t && fext.t*i<=var->pixclock && pcl<fext.t*i) {
+					pcl=fext.t*i; pclock=&fext;
+				}
+			}
+			if (!pcl)
+				return -EINVAL;
+			plen = pcl / pclock->t;
+
+#else
+			if (var->pixclock == f25.t || var->pixclock == 2*f25.t)
+				pclock = &f25;
+			else if (var->pixclock == f32.t || var->pixclock == 2*f32.t)
+				pclock = &f32;
+			else if ((var->pixclock == fext.t || var->pixclock == 2*fext.t) && fext.t) {
+				pclock = &fext;
+			}
+			else
+				return -EINVAL;
+			plen = var->pixclock / pclock->t;
+#endif
+
+			left_margin = var->left_margin;
+			right_margin = var->right_margin;
+			hsync_len = var->hsync_len;
+			upper_margin = var->upper_margin;
+			lower_margin = var->lower_margin;
+			vsync_len = var->vsync_len;
+			if (var->vmode & FB_VMODE_INTERLACED) {
+				/* # lines in half frame */
+				upper_margin = (upper_margin + 1) / 2;
+				lower_margin = (lower_margin + 1) / 2;
+				vsync_len = (vsync_len + 1) / 2;
+			}
+		}
+		if (pclock == &fext)
+			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 */
+	if ( pclock->f / plen / 8 * bpp > 32000000L )
+		return -EINVAL;
+
+	if (vsync_len < 1)
+		vsync_len = 1;
+
+	/* ! In all calculations of margins we use # of lines in half frame
+	 * (which is a full frame in non-interlace mode), so we can switch
+	 * between interlace and non-interlace without messing around
+	 * with these.
+	 */
+  again:
+	/* Set base_offset 128 and video bus width */
+	par->hw.falcon.vid_control = mon_type | f030_bus_width;
+	if (!longoffset)
+		par->hw.falcon.vid_control |= VCO_SHORTOFFS;	/* base_offset 64 */
+	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+		par->hw.falcon.vid_control |= VCO_HSYPOS;
+	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+		par->hw.falcon.vid_control |= VCO_VSYPOS;
+	/* Pixelclock */
+	par->hw.falcon.vid_control |= pclock->control_mask;
+	/* External or internal clock */
+	par->hw.falcon.sync = pclock->sync_mask | 0x2;
+	/* Pixellength and prescale */
+	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 * plen]
+
+	1 line = (hht + 2) * 2 * prescale
+
+	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 = par->hw.falcon.ste_mode ? 16 :
+			   vdl_prescale[mon_type][par->hw.falcon.vid_mode >> 2 & 0x3];
+	base_off = par->hw.falcon.vid_control & VCO_SHORTOFFS ? 64 : 128;
+
+	/* Offsets depend on video mode */
+	/* Offsets are in clock cycles, divide by prescale to
+	 * calculate hd[be]-registers
+	 */
+	if (par->hw.falcon.f_shift & 0x100) {
+		align = 1;
+		hde_off = 0;
+		hdb_off = (base_off + 16 * plen) + prescale;
+	}
+	else {
+		align = 128 / bpp;
+		hde_off = ((128 / bpp + 2) * plen);
+		if (par->hw.falcon.ste_mode)
+			hdb_off = (64 + base_off + (128 / bpp + 2) * plen) + prescale;
+		else
+			hdb_off = (base_off + (128 / bpp + 18) * plen) + 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;
+	/* 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->HBE = gstart;
+	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 (hde_off % prescale)
+		par->HBB++;		/* compensate for non matching hde and hbb */
+	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 > hfmax && mon_type!=F_MON_VGA) {
+		/* Too high -> enlarge margin */
+		left_margin += 1;
+		right_margin += 1;
+		goto again;
+	}
+	if (hfreq > hfmax || hfreq < hfmin)
+		return -EINVAL;
+
+	/* Vxx-registers */
+	/* All Vxx must be odd in non-interlace, since frame starts in the middle
+	 * of the first displayed line!
+	 * One frame consists of VFT+1 half lines. VFT+1 must be even in
+	 * non-interlace, odd in interlace mode for synchronisation.
+	 */
+	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 */
+	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);
+	/* vbb,vss,vft must be even in interlace mode */
+	if (interlace) {
+		par->VBB++;
+		par->VSS++;
+		par->VFT++;
+	}
+
+	/* 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 > vfmax && !doubleline && !interlace) {
+		/* Too high -> try again with doubleline */
+		doubleline = 1;
+		goto again;
+	}
+	else if (vfreq < vfmin && !interlace && !doubleline) {
+		/* Too low -> try again with interlace */
+		interlace = 1;
+		goto again;
+	}
+	else if (vfreq < 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)>vfmax; lines++)
+			;
+		upper_margin += lines;
+		lower_margin += lines;
+		goto again;
+	}
+	else if (vfreq > vfmax && interlace) {
+		/* Interlace, too high -> enlarge margins */
+		int lines;
+		for (lines=0; (hfreq*2)/(par->VFT+1+4*lines)>vfmax; lines++)
+			;
+		upper_margin += lines;
+		lower_margin += lines;
+		goto again;
+	}
+	else if (vfreq < vfmin || vfreq > vfmax)
+		return -EINVAL;
+
+  set_screen_base:
+	linelen = xres_virtual * bpp / 8;
+	if ((var->yoffset + yres)*linelen > screen_len && screen_len)
+		return -EINVAL;
+	if (var->yres_virtual * linelen > screen_len && screen_len)
+		return -EINVAL;
+	par->screen_base = screen_base + var->yoffset * linelen;
+
 	return 0;
 }
 
 static int falcon_encode_var( struct fb_var_screeninfo *var,
 							  struct atari_fb_par *par )
 {
-	struct fb_var_screeninfo *myvar = &atari_fb_predefined[0];
+/* !!! only for VGA !!! */
 	int linelen;
+	int prescale, plen;
+	int hdb_off, hde_off, base_off;
+	struct falcon_hw *hw = &par->hw.falcon;
+
+	/* possible frequencies: 25.175 or 32MHz */
+	var->pixclock = hw->sync & 0x1 ? fext.t :
+	                hw->vid_control & VCO_CLOCK25 ? f25.t : f32.t;
+
+	var->height=-1;
+	var->width=-1;
+
+	var->sync=0;
+	if (hw->vid_control & VCO_HSYPOS)
+		var->sync |= FB_SYNC_HOR_HIGH_ACT;
+	if (hw->vid_control & VCO_VSYPOS)
+		var->sync |= FB_SYNC_VERT_HIGH_ACT;
+
+	var->vmode = FB_VMODE_NONINTERLACED;
+	if (hw->vid_mode & VMO_INTER)
+		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
+	 * half lines, else lines.
+	 */
+	var->yres = hw->vde - hw->vdb;
+	if (!(var->vmode & FB_VMODE_INTERLACED))
+		var->yres >>= 1;
+	if (var->vmode & FB_VMODE_DOUBLE)
+		var->yres >>= 1;
+
+	/* 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 */
+		var->bits_per_pixel = 1;
+	else if (hw->f_shift & 0x100)	/* hicolor */
+		var->bits_per_pixel = 16;
+	else if (hw->f_shift & 0x010)	/* 8 bitplanes */
+		var->bits_per_pixel = 8;
+	else if (hw->st_shift == 0)
+		var->bits_per_pixel = 4;
+	else if (hw->st_shift == 0x100)
+		var->bits_per_pixel = 2;
+	else /* if (hw->st_shift == 0x200) */
+		var->bits_per_pixel = 1;
 
-	if (myvar->bits_per_pixel==16) {
+	var->xres = hw->line_width * 16 / var->bits_per_pixel;
+	var->xres_virtual = var->xres + hw->line_offset * 16 / var->bits_per_pixel;
+
+	if (var->bits_per_pixel == 16) {
 		var->red.offset=11;
 		var->red.length=5;
-		var->green.msb_right=0;
+		var->red.msb_right=0;
 		var->green.offset=5;
 		var->green.length=6;
 		var->green.msb_right=0;
@@ -640,45 +1153,72 @@
 	}
 	else {
 		var->red.offset=0;
-		var->red.length= (myvar->bits_per_pixel == 2) ? 4 : 6;
+		var->red.length = hw->ste_mode ? 4 : 6;
 		var->red.msb_right=0;
+		var->grayscale=0;
 		var->blue=var->green=var->red;
 	}
-	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->height=-1;
-	var->width=-1;
-
-	var->sync=0;
-
-	var->xres = myvar->xres;
-	var->yres = myvar->yres;
-	var->bits_per_pixel = myvar->bits_per_pixel;
-	
 	var->transp.offset=0;
 	var->transp.length=0;
 	var->transp.msb_right=0;
-	var->xres_virtual=var->xres;
-	linelen=var->xres_virtual * var->bits_per_pixel / 8;
+
+	linelen = var->xres_virtual * var->bits_per_pixel / 8;
 	if (screen_len)
 		var->yres_virtual=screen_len/linelen;
 	else {
-			if (hwscroll < 0)
-				var->yres_virtual = 2 * var->yres;
-			else if (default_font > 0)
-				var->yres_virtual=var->yres+hwscroll * default_font;
-			else
-				var->yres_virtual=var->yres+hwscroll * 16;
-		}
+		if (hwscroll < 0)
+			var->yres_virtual = 2 * var->yres;
+		else if (default_font > 0)
+			var->yres_virtual=var->yres+hwscroll * default_font;
+		else
+			var->yres_virtual=var->yres+hwscroll * 16;
+	}
 	var->xoffset=0;
+
+	/* hdX-offsets */
+	prescale = hw->ste_mode ? 16 :
+			   vdl_prescale[mon_type][hw->vid_mode >> 2 & 0x3];
+	plen = 4 >> (hw->vid_mode >> 2 & 0x3);
+	base_off = hw->vid_control & VCO_SHORTOFFS ? 64 : 128;
+	if (hw->f_shift & 0x100) {
+		hde_off = 0;
+		hdb_off = (base_off + 16 * plen) + prescale;
+	}
+	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)
+					 + prescale;
+		else
+			hdb_off = (base_off + (128 / var->bits_per_pixel + 18) * plen)
+					 + prescale;
+	}
+
+	/* 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)
+		var->right_margin = prescale * (hw->hht + 2 - hw->hde) - hde_off;
+	else
+		/* cant use this in ste_mode, because hbb is +1 off */
+		var->right_margin = prescale * (hw->hht + 2 - hw->hbb);
+	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 */
+	if (var->vmode & FB_VMODE_INTERLACED) {
+		var->upper_margin *= 2;
+		var->lower_margin *= 2;
+		var->vsync_len *= 2;
+	}
+
+	var->pixclock *= plen;
+	var->left_margin /= plen;
+	var->right_margin /= plen;
+	var->hsync_len /= plen;
+
 	if (screen_base)
 		var->yoffset=(par->screen_base - screen_base)/linelen;
 	else
@@ -692,17 +1232,92 @@
 static void falcon_get_par( struct atari_fb_par *par )
 {
 	unsigned long addr;
-	addr = ((shifter.bas_hi & 0xff) << 16) |
-	       ((shifter.bas_md & 0xff) << 8)  |
-	       ((shifter.bas_lo & 0xff));
+	struct falcon_hw *hw = &par->hw.falcon;
+
+	hw->line_width = shifter_f030.scn_width;
+	hw->line_offset = shifter_f030.off_next;
+	hw->st_shift = videl.st_shift & 0x300;
+	hw->f_shift = videl.f_shift;
+	hw->vid_control = videl.control;
+	hw->vid_mode = videl.mode;
+	hw->sync = shifter.syncmode & 0x1;
+	hw->hht = videl.hht;
+	hw->hbb = videl.hbb;
+	hw->hbe = videl.hbe;
+	hw->hdb = videl.hdb;
+	hw->hde = videl.hde;
+	hw->hss = videl.hss;
+	hw->vft = videl.vft;
+	hw->vbb = videl.vbb;
+	hw->vbe = videl.vbe;
+	hw->vdb = videl.vdb;
+	hw->vde = videl.vde;
+	hw->vss = videl.vss;
+
+	addr = (shifter.bas_hi & 0xff) << 16 |
+	       (shifter.bas_md & 0xff) << 8  |
+	       (shifter.bas_lo & 0xff);
 	par->screen_base = PTOV(addr);
+
+	/* derived parameters */
+	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);
 }
 
 static void falcon_set_par( struct atari_fb_par *par )
 {
+	struct falcon_hw *hw = &par->hw.falcon;
+
 	/* only set screen_base if really necessary */
 	if (current_par.screen_base != par->screen_base)
 		fbhw->set_screen_base(par->screen_base);
+
+	videl.hht = hw->hht;
+	videl.hbb = hw->hbb;
+	videl.hbe = hw->hbe;
+	videl.hdb = hw->hdb;
+	videl.hde = hw->hde;
+	videl.hss = hw->hss;
+	videl.vft = hw->vft;
+	videl.vbb = hw->vbb;
+	videl.vbe = hw->vbe;
+	videl.vdb = hw->vdb;
+	videl.vde = hw->vde;
+	videl.vss = hw->vss;
+
+	shifter.syncmode = hw->sync;
+	if (hw->sync & 0x1) {
+		/* Turn on external pixelclock. This works for ScreenWonder */
+		*(unsigned short*)0xffff9202 = 0xffbf;
+	}
+	else {
+		/* Turn off external clocks. Read sets all output bits to 1. */
+		int dummy = *(volatile unsigned short*)0xffff9202;
+	}
+
+	/*f030_sreg[2] = 0;*/
+
+	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 {
+		/* IMPORTANT:
+		 * 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 with
+		 * Falcon palette.
+		 */
+		videl.st_shift = 0;
+		/* now back to Falcon palette mode */
+		videl.f_shift = hw->f_shift;
+	}
+	/* writing to st_shift changes scn_width and vid_mode */
+	shifter_f030.scn_width = hw->line_width;
+	shifter_f030.off_next = hw->line_offset;
+	videl.control = hw->vid_control;
+	videl.mode = hw->vid_mode;
 }
 
 
@@ -710,13 +1325,13 @@
 unsigned short packed16_cmap[256];
 
 static int falcon_getcolreg( unsigned regno, unsigned *red,
-							 unsigned *green, unsigned *blue,
-							 unsigned *transp )
+				 unsigned *green, unsigned *blue,
+				 unsigned *transp )
 {	unsigned long col;
 	
 	if (regno > 255)
 		return 1;
-	/* this works in ste-mode (with 4bit/color) since f030_col-registers
+	/* 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!
 	 */
@@ -745,84 +1360,67 @@
 	return 0;
 }
 
-						  
-static int falcon_detect( void )
 
+static int falcon_blank( int blank_mode )
 {
-	int xres;
-	int yres;
-	int depth;
-	int interlace;
-	int doubleline;
-	int spshift, shift;
-	int compatibility = 0;
-	struct fb_var_screeninfo *myvar = &atari_fb_predefined[0];
-	struct atari_fb_par dummy_par;
-	
-	interlace = (f030_creg[1] & 0x2) >> 1;
-	doubleline = f030_creg[1] & 0x1;
+/* ++guenther: we can switch off graphics by changing VDB and VDE,
+ * so VIDEL doesn't hog the bus while saving.
+ * (this affects usleep()).
+ */
+	if (mon_type == F_MON_SM)	/* this doesn't work on SM124 */
+		return 1;
+	if (blank_mode) {
+		/* disable graphics output (this speeds up the VIDEL) ... */
+		videl.vdb = current_par.VFT + 1;
+		/* ... and blank all lines */
+		videl.hbe = current_par.HHT + 2;
+		/* VESA suspend mode, switch off HSYNC */
+		if (pwrsave && mon_type == F_MON_VGA)
+			videl.hss = current_par.HHT + 2;
+	}
+	else {
+		videl.vdb = current_par.VDB;
+		videl.hbe = current_par.HBE;
+		videl.hss = current_par.HSS;
+	}
+	return 0;
+}
 
-	/* to get depth of display, we must examine spshift and shift.
-	 * spshift has priority over shift, if any of bits no. 10, 8 or 4
-	 * is set. Priority in spshift is: 10 ">" 8 ">" 4, that means
-	 * if bit 10 set then bit 8 and bit 4 don't care.
-	 * If all these bits are 0, then display depth is coded in shift
-	 * (as for ST and STE)
-	 */
-	spshift = f030_sreg[3];
-	shift = (f030_sreg[0] >> 8) & 0x3;
-	if (spshift & 0x400)		/* 2 color mode */
-		depth = 1;
-	else if (spshift & 0x100)	/* truecolor mode */
-		depth = 16;
-	else if (spshift & 0x010)	/* 8 bitplane mode */
-		depth = 8;
-	else if (shift == 0)
-		depth = 4;
-	else if (shift == 1)
-	{
-		depth = 2;
-		/* 4-color mode uses ST palette, even on VGA! */
-		compatibility = 1;
-	}
-	else /* if (shift == 2) */
-		depth = 1;
-#if 0
-	else
-		/* shift==3 is reserved,illegal. This should not happen */
-		return 0;
-#endif
-	
-	/* Y resolution is calculated from vertical control registers:
-	 * Displaying pixels starts at line f030_yreg[4] and ends at line
-	 * f030_yreg[3]. If interlace mode off  the VC-registers count
-	 * half lines, if interlace on they count whole lines.
-	 * If doubleline mode on, every line is displayed 2 times.
-	 */
-	yres = f030_yreg[4] - f030_yreg[3];
-	if ( !interlace )
-		yres >>= 1;
-	if ( doubleline )
-		yres >>= 1;
-
-	/* X resolution is calculated from screen width in words, and
-	 * display depth.
-	 * I can't use horizontal control registers as in calculation of yres,
-	 * since I dont know the unit of these counters.
-	 * Who knows?
-	 */
-	xres = shifter_f030.scn_width * 16 / depth;
+ 
+static int falcon_detect( void )
+{
+	struct atari_fb_par par;
+	unsigned char fhw;
 
-/*	printk("Detected FALCON screen mode: X=%d Y=%d D=%d "
-	       "IL=%d DL=%d \n",
-	       xres, yres, depth, interlace, doubleline);*/
-
-	myvar->xres = xres;
-	myvar->yres = yres;
-	myvar->bits_per_pixel = depth;
-	falcon_encode_var( myvar, &dummy_par );
+	/* Determine connected monitor and set monitor parameters */
+	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;
+	switch (mon_type) {
+	case F_MON_SM:
+		vfmin = 70;
+		vfmax = 72;
+		hfmin = hfmax = 35714;
+		break;
+	case F_MON_SC:
+	case F_MON_TV:
+		vfmin = 50;
+		vfmax = 60;
+		hfmin = 15625;
+		hfmax = 15625;
+		break;
+	}
+	/* initialize hsync-len */
+	f25.hsync = h_syncs[mon_type] / f25.t;
+	f32.hsync = h_syncs[mon_type] / f32.t;
+	if (fext.t)
+		fext.hsync = h_syncs[mon_type] / fext.t;
 
-	return( 1 );
+	falcon_get_par(&par);
+	falcon_encode_var(&atari_fb_predefined[0], &par);
+
+	return 1;
 }
 
 
@@ -1326,24 +1924,24 @@
 struct fb_hwswitch tt_switch = {
 	tt_detect, tt_encode_fix, tt_decode_var, tt_encode_var,
 	tt_get_par, tt_set_par, tt_getcolreg, tt_setcolreg,
-	set_screen_base
+	set_screen_base, NULL
 };
 
 struct fb_hwswitch falcon_switch = {
 	falcon_detect, falcon_encode_fix, falcon_decode_var, falcon_encode_var,
 	falcon_get_par, falcon_set_par, falcon_getcolreg,
-	falcon_setcolreg, set_screen_base
+	falcon_setcolreg, set_screen_base, falcon_blank
 };
 
 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_setcolreg,
-	stste_set_screen_base
+	stste_set_screen_base, NULL
 };
 
 struct fb_hwswitch ext_switch = {
 	ext_detect, ext_encode_fix, ext_decode_var, ext_encode_var,
-	ext_get_par, ext_set_par, ext_getcolreg, ext_setcolreg, NULL
+	ext_get_par, ext_set_par, ext_getcolreg, ext_setcolreg, NULL, NULL
 };
 
 
@@ -1688,17 +2286,19 @@
 static int
 atari_fb_set_var(struct fb_var_screeninfo *var, int con)
 {
-	int err,oldxres,oldyres,oldbpp;
+	int err,oldxres,oldyres,oldbpp,oldxres_virtual;
 	if ((err=do_fb_set_var(var, con==currcon)))
 		return err;
 	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
 		oldxres=disp[con].var.xres;
 		oldyres=disp[con].var.yres;
+		oldxres_virtual=disp[con].var.xres_virtual;
 		oldbpp=disp[con].var.bits_per_pixel;
 		disp[con].var=*var;
 		disp[con].bitplane=disp[con].screen_base+
 			disp[con].var.yoffset*disp[con].bytes_per_row;
 		if (oldxres != var->xres || oldyres != var->yres 
+		    || oldxres_virtual != var->xres_virtual
 		    || oldbpp != var->bits_per_pixel) {
 			atari_fb_set_disp(con);
 			(*fb_info.changevar)(con);
@@ -1813,6 +2413,8 @@
 {
 	unsigned short black[16];
 	struct fb_cmap cmap;
+	if (fbhw->blank && !fbhw->blank(blank))
+		return;
 	if (blank) {
 		memset(black, 0, 16*sizeof(unsigned short));
 		cmap.red=black;
@@ -1921,15 +2523,16 @@
 }
 
 void atari_video_setup( char *options, int *ints )
-{	
+{
     char *this_opt;
     int temp;
     char ext_str[80], int_str[100];
+    char mcap_spec[80];
 
-    ext_str[0] = int_str[0] = 0;
+    ext_str[0] = int_str[0] = mcap_spec[0] = 0;
 
     if (!options || !*options)
-        return;
+	return;
      
     for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
 	if (!*this_opt) continue;
@@ -1960,115 +2563,154 @@
 	else if (!strncmp( this_opt,"external:",9)) {
 		strcpy( ext_str, this_opt+9 );
 	}
- 	else if (!strncmp( this_opt,"internal:",9)) {
- 		strcpy( int_str, this_opt+9 );
-	} 
-	}
- 	if (*int_str) {
- 		/* Format to config extended internal video hardware like OverScan:
- 		"<switch-type>,internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>"
- 		Explanation:
- 		<switch-type> type to switch on higher resolution
- 				sw_acia : via keyboard ACIA
- 				sw_snd6 : via bit 6 of the soundchip port
- 				sw_snd7 : via bit 7 of the soundchip port
- 		<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
- 		*/
- 		char *p;
-  
-		if (!(p = strtoke(int_str, ";")) || !*p) goto int_invalid;
-		sttt_xres = sttt_xres_virtual = simple_strtoul(p, NULL, 10);
+	else if (!strncmp( this_opt,"internal:",9)) {
+		strcpy( int_str, this_opt+9 );
+	}
+	else if (!strcmp(this_opt, "pwrsave")) {
+		pwrsave = 1;
+	}
+	else if (!strncmp(this_opt, "eclock:", 7)) {
+		fext.f = simple_strtoul(this_opt+7, NULL, 10);
+		/* external pixelclock in kHz --> ps */
+		fext.t = (2000000000UL/fext.f+1)/2;
+		fext.f *= 1000;
+	}
+	else if (!strncmp(this_opt, "monitorcap:", 11)) {
+		strcpy(mcap_spec, this_opt+11);
+	}
+    }
+    if (*int_str) {
+	/* Format to config extendet internal video hardware like OverScan:
+	"<switch-type>,internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>"
+	Explanation:
+	<switch-type> type to switch on higher resolution
+			sw_acia : via keyboard ACIA
+			sw_snd6 : via bit 6 of the soundchip port
+			sw_snd7 : via bit 7 of the soundchip port
+	<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;
 
- 		if (!(p = strtoke(NULL, ";")) || !*p) goto int_invalid;
-		tt_yres = st_yres = sttt_yres_virtual =
-		  simple_strtoul(p, NULL, 10);
-
- 		if ((p=strtoke( NULL, ";")) && *p) {
- 			sttt_xres_virtual=simple_strtoul(p, NULL, 10);
- 		}
-		if ((p=strtoke( NULL, ";")) && *p) {
- 			sttt_yres_virtual=simple_strtoul(p, NULL, 0);
-  		}
-  		if ((p=strtoke( NULL, ";")) && *p) {
- 			ovsc_offset=simple_strtoul(p, NULL, 0);
- 		}
- 
- 		if (ovsc_offset || (sttt_yres_virtual != st_yres))
- 			use_hwscroll=0;
- 	}
-	else 
-
-int_invalid:	ovsc_switchmode = SWITCH_NONE;
-
-	if (*ext_str) {
-		int		xres, yres, depth, planes;
-		unsigned long addr, len;
-		char *p;
-
-		/* Format is: <xres>;<yres>;<depth>;<plane organ.>;
-		 *            <screen mem addr>
-		 *	      [;[<screen mem length>][;<vgaiobase>]]
-		 */
-		if (!(p = strtoke( ext_str, ";" )) ||!*p) goto ext_invalid;
-		xres = simple_strtoul(p, NULL, 10);
-		if (xres <= 0) goto ext_invalid;
-
-		if (!(p = strtoke( NULL, ";" )) ||!*p) goto ext_invalid;
-		yres = simple_strtoul(p, NULL, 10);
-		if (yres <= 0) goto ext_invalid;
-
-		if (!(p = strtoke( NULL, ";" )) ||!*p) goto ext_invalid;
-		depth = simple_strtoul(p, NULL, 10);
-		if (depth != 1 && depth != 2 && depth != 4 && depth != 8 &&
-			depth != 16 && depth != 24) goto ext_invalid;
-
-		if (!(p = strtoke( NULL, ";" )) ||!*p) goto ext_invalid;
-		if (*p == 'i')
-			planes = FB_TYPE_INTERLEAVED_PLANES;
-		else if (*p == 'p')
-			planes = FB_TYPE_PACKED_PIXELS;
-		else if (*p == 'n')
-			planes = FB_TYPE_PLANES;
-		else if (*p == 't')
-			planes = -1; /* true color */
-		else
-			goto ext_invalid;
+	if (!(p = strtoke( int_str, ";" )) ||!*p) goto int_invalid;
+	xres = simple_strtoul(p, NULL, 10);
+	if (!(p = strtoke( NULL, ";")) || !*p) goto int_invalid;
+	sttt_xres=xres;
+	tt_yres=st_yres=simple_strtoul(p, NULL, 10);
+	if ((p=strtoke( NULL, ";")) && *p) {
+		sttt_xres_virtual=simple_strtoul(p, NULL, 10);
+	}
+	if ((p=strtoke( NULL, ";")) && *p) {
+		sttt_yres_virtual=simple_strtoul(p, NULL, 0);
+	}
+	if ((p=strtoke( NULL, ";")) && *p) {
+		ovsc_offset=simple_strtoul(p, NULL, 0);
+	}
 
-		if (!(p = strtoke( NULL, ";" )) ||!*p) goto ext_invalid;
-		addr = simple_strtoul(p, NULL, 0);
+	if (ovsc_offset || (sttt_yres_virtual != st_yres))
+		use_hwscroll=0;
+    }
+    else 
+      int_invalid:	ovsc_switchmode = SWITCH_NONE;
 
-		if (!(p = strtoke( NULL, ";" )) ||!*p)
-			len = xres*yres*depth/8;
-		else
-			len = simple_strtoul(p, NULL, 0);
+    if (*ext_str) {
+	int		xres, yres, depth, planes;
+	unsigned long addr, len;
+	char *p;
+
+	/* Format is: <xres>;<yres>;<depth>;<plane organ.>;
+	 *            <screen mem addr>
+	 *	      [;[<screen mem length>][;<vgaiobase>]]
+	 */
+	if (!(p = strtoke( ext_str, ";" )) ||!*p) goto ext_invalid;
+	xres = simple_strtoul(p, NULL, 10);
+	if (xres <= 0) goto ext_invalid;
+
+	if (!(p = strtoke( NULL, ";" )) ||!*p) goto ext_invalid;
+	yres = simple_strtoul(p, NULL, 10);
+	if (yres <= 0) goto ext_invalid;
+
+	if (!(p = strtoke( NULL, ";" )) ||!*p) goto ext_invalid;
+	depth = simple_strtoul(p, NULL, 10);
+	if (depth != 1 && depth != 2 && depth != 4 && depth != 8 &&
+		depth != 16 && depth != 24) goto ext_invalid;
+
+	if (!(p = strtoke( NULL, ";" )) ||!*p) goto ext_invalid;
+	if (*p == 'i')
+		planes = FB_TYPE_INTERLEAVED_PLANES;
+	else if (*p == 'p')
+		planes = FB_TYPE_PACKED_PIXELS;
+	else if (*p == 'n')
+		planes = FB_TYPE_PLANES;
+	else if (*p == 't')
+		planes = -1; /* true color */
+	else
+		goto ext_invalid;
 
-		if ((p = strtoke( NULL, ";" )) && *p)
-			external_vgaiobase=simple_strtoul(p, NULL, 0);
 
-		if( ( p = strtoke( NULL, ";" ) ) && *p )
-			external_bitspercol = simple_strtoul( p, NULL, 0 );
-			if( external_bitspercol > 8 )
-				external_bitspercol = 8;
-			else if( external_bitspercol < 1 )
-				external_bitspercol = 1;
-
-		external_xres  = xres;
-		external_yres  = yres;
-		external_depth = depth;
-		external_pmode = planes;
-		external_addr  = addr;
-		external_len   = len;
+	if (!(p = strtoke( NULL, ";" )) ||!*p) goto ext_invalid;
+	addr = simple_strtoul(p, NULL, 0);
 
-	  ext_invalid:
-		;
-	}
-}
+	if (!(p = strtoke( NULL, ";" )) ||!*p)
+		len = xres*yres*depth/8;
+	else
+		len = simple_strtoul(p, NULL, 0);
 
+	if ((p = strtoke( NULL, ";" )) && *p)
+		external_vgaiobase=simple_strtoul(p, NULL, 0);
+
+	if( ( p = strtoke( NULL, ";" ) ) && *p )
+		external_bitspercol = simple_strtoul( p, NULL, 0 );
+		if( external_bitspercol > 8 )
+			external_bitspercol = 8;
+		else if( external_bitspercol < 1 )
+			external_bitspercol = 1;
+
+	external_xres  = xres;
+	external_yres  = yres;
+	external_depth = depth;
+	external_pmode = planes;
+	external_addr  = addr;
+	external_len   = len;
+
+      ext_invalid:
+	;
+    }
+
+    if (*mcap_spec) {
+	char *p;
+	int vmin, vmax, hmin, hmax;
+
+	/* Format for monitor capabilities is: <Vmin>;<Vmax>;<Hmin>;<Hmax>
+	 * <V*> vertical freq. in Hz
+	 * <H*> horizontal freq. in kHz
+	 */
+	if (!(p = strtoke(mcap_spec, ";")) || !*p) goto cap_invalid;
+	vmin = simple_strtoul(p, NULL, 10);
+	if (vmin <= 0) goto cap_invalid;
+	if (!(p = strtoke(NULL, ";")) || !*p) goto cap_invalid;
+	vmax = simple_strtoul(p, NULL, 10);
+	if (vmax <= 0 || vmax <= vmin) goto cap_invalid;
+	if (!(p = strtoke(NULL, ";")) || !*p) goto cap_invalid;
+	hmin = 1000 * simple_strtoul(p, NULL, 10);
+	if (hmin <= 0) goto cap_invalid;
+	if (!(p = strtoke(NULL, "")) || !*p) goto cap_invalid;
+	hmax = 1000 * simple_strtoul(p, NULL, 10);
+	if (hmax <= 0 || hmax <= hmin) goto cap_invalid;
+
+	vfmin = vmin;
+	vfmax = vmax;
+	hfmin = hmin;
+	hfmax = hmax;
+      cap_invalid:
+	;
+    }
+}
 
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/arch/m68k/atari/atakeyb.c linux-1.2.13pl3/arch/m68k/atari/atakeyb.c
--- linux-1.2.13pl2/arch/m68k/atari/atakeyb.c	Tue Sep 12 21:13:59 1995
+++ linux-1.2.13pl3/arch/m68k/atari/atakeyb.c	Fri Oct 13 19:04:40 1995
@@ -465,7 +465,7 @@
 
     if (acia_stat & (ACIA_FE | ACIA_PE))
     {
-	printk("Error in keyboard communication");
+	printk("Error in keyboard communication\n");
     }
 
     /* process_keycode() can take a lot of time, so check again if
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/arch/m68k/atari/atasound.c linux-1.2.13pl3/arch/m68k/atari/atasound.c
--- linux-1.2.13pl2/arch/m68k/atari/atasound.c	Tue Sep 12 21:14:01 1995
+++ linux-1.2.13pl3/arch/m68k/atari/atasound.c	Fri Oct 13 19:04:42 1995
@@ -31,6 +31,20 @@
 
 1995/9/02	++roman: fixed atari_stram_alloc() call, the timer programming and
 			several race conditions
+
+1995/9/14	++roman: After some discussion with Michael Schlueter, revised the
+			interrupt disabling
+			Slightly speeded up U8->S8 translation by using long operations
+			where possible
+			Added 4:3 interpolation for /dev/audio
+
+1995/9/20	++TeSche: fixed a bug in sq_write and changed /dev/audio
+			converting to play at 12517Hz instead of 6258Hz
+
+1995/9/23	++TeSche: Changed sq_interrupt() and sq_play() to pre-program
+			the DMA for another frame while there's still one
+			running. This allows the IRQ response to be arbitrarily
+			delayed and playing will still continue.
 */
 
 
@@ -321,45 +335,133 @@
 
 
 static void
-sound_translate (unsigned char *buff, unsigned long n)
+sound_copy_translate (unsigned char *buff, const unsigned char *src,
+		      unsigned long n)
 {
-	unsigned long i;
+	long tmp1;
+	int bal = 0;
+	unsigned char c = 0;	/* to keep gcc happy */
 
 	switch (sound.format) {
 
 	case AFMT_MU_LAW:
-		n /= 8;
-		for (i = 0; i < n; ++i) {
-			*buff = ulaw_2_dma [*buff]; buff++;
-			*buff = ulaw_2_dma [*buff]; buff++;
-			*buff = ulaw_2_dma [*buff]; buff++;
-			*buff = ulaw_2_dma [*buff]; buff++;
-			*buff = ulaw_2_dma [*buff]; buff++;
-			*buff = ulaw_2_dma [*buff]; buff++;
-			*buff = ulaw_2_dma [*buff]; buff++;
-			*buff = ulaw_2_dma [*buff]; buff++;
+		/* mu-law is for Sun-compatible /dev/audio whose samples always
+		 * have a frequency of 8 kHz, but we just can only play either
+		 * 6258Hz or 12517Hz. :(
+		 *
+		 * ++TeSche: From the two possible solutions we choose to
+		 * expand data to the higher sample rate. Expanding is done
+		 * by simply doubling every second sample to keep this loop
+		 * short and quick. This yields a sample rate of 12000Hz
+		 * so samples will be played 4.3% too fast. I heavily
+		 * doubt that any further mathematics like using an exact
+		 * ratio or not simply doubling sampling but really inter-
+		 * polating them will be worth the effort. (This loop can
+		 * surely be optimized in assembler too, especially the
+		 * get_user_byte() construct translates silly...)
+		 */
+		while(n--) {
+			if ((bal -= 2) < 0) {
+				bal += 3;
+				c = ulaw_2_dma[get_user_byte(src++)];
+			}
+			*buff++ = c;
 		}
 		break;
 
 	case AFMT_U8:
-		n /= 8;
-		for (i = 0; i < n; ++i) {
-			*buff -= 128; buff ++;
-			*buff -= 128; buff ++;
-			*buff -= 128; buff ++;
-			*buff -= 128; buff ++;
-			*buff -= 128; buff ++;
-			*buff -= 128; buff ++;
-			*buff -= 128; buff ++;
-			*buff -= 128; buff ++;
+		memcpy_fromfs( buff, src, n );
+		/* To convert from unsigned to signed data, we would have to subtract
+		 * 128 from each byte. But this is easier done by toggling bit 7,
+		 * since we do not care for overflows. And eor can be done on 32 bit
+		 * units, which is much faster.
+		 */
+		if (n >= 4) {
+#if 0
+			if ((unsigned long)buff & 1)
+				*buff++ ^= 0x80, --n;
+			if ((unsigned long)buff & 2)
+				*((unsigned short *)buff)++ ^= 0x8080, n -= 2;
+			m = n/4;
+			while( m-- )
+				*((unsigned long *)buff)++ ^= 0x80808080;
+#else
+			/* The code for the above wasn't as bad as the one for the
+			 * interpolation, but improvable, too :-) */
+			__asm__ __volatile__
+				("movel %0,%2		\n\t"
+				 "btst  #0,%2		\n\t"
+				 "beq   1f			\n\t"
+				 "eorb  %3,%0@+		\n\t"
+				 "subql	#1,%1		\n"
+				 "1:				\n\t"
+				 "movel %0,%2		\n\t"
+				 "btst  #1,%2		\n\t"
+				 "beq   1f			\n\t"
+				 "eorw  %3,%0@+		\n\t"
+				 "subql	#2,%1		\n"
+				 "1:				\n\t"
+				 "movel %1,%2		\n\t"
+				 "lsrl  #2,%2		\n\t"
+				 "beq   1f			\n\t"
+				 "subqw #1,%2		\n"
+				 "2:				\n\t"
+				 "eorl  %3,%0@+		\n\t"
+				 "dbra  %2,2b		\n"
+				 "1:"
+				 : "=&a" (buff), "=&d" (n), "=&d" (tmp1)
+				 : "d" (0x80808080), "0" (buff), "1" (n) );
+#endif
+			n = n%4;
 		}
+		while( n-- )
+			*buff++ ^= 0x80;
 		break;
 
-	case AFMT_S8: break;
+	case AFMT_S8:
+		memcpy_fromfs( buff, src, n );
+		/* no translation needed */
+		break;
+		
+	}
+}
+
+static unsigned long usize2b( unsigned long n ) __attribute__ ((const));
+static unsigned long bsize2u( unsigned long n ) __attribute__ ((const));
+
+/* In case of interpolation, return the number of buffer bytes for an amount
+ * of user bytes. */
+
+static unsigned long usize2b( unsigned long n )
+{
+	switch (sound.format) {
 
+	  case AFMT_MU_LAW:
+		return n*3/2;
+		
+	  case AFMT_S8:
+	  case AFMT_U8:
+	  default:
+		return( n );
 	}
 }
 
+/* The inverse function of the above */
+
+static unsigned long bsize2u( unsigned long n )
+
+{
+	switch (sound.format) {
+
+	  case AFMT_MU_LAW:
+		return (n*2+2)/3;
+		
+	  case AFMT_S8:
+	  case AFMT_U8:
+	  default:
+		return( n );
+	}
+}
 
 /*
 /dev/mixer abstraction
@@ -441,126 +543,6 @@
 
 
 /*
-/dev/sndstat
-*/
-
-
-struct sound_state {
-	int busy;
-	char buf [512];
-	int len, ptr;
-};
-
-
-struct sound_state state;
-
-
-static int state_puts (const char *s)
-{
-	int l;
-	for (l = 0; l < 256 && s [l]; l++);
-		/* l = max (256, strlen (s)) */
-	if (state.len + l > sizeof (state.buf)) return 0;
-	memcpy (&state.buf [state.len], s, l);
-	state.len += l;
-	return 1;
-}
-
-
-static int state_puti (int i, int radix)
-{
-	int l;
-	static char digit [] = "0123456789abcdef";
-	char buf [11];
-
-	l = 0; buf [sizeof (buf) - 1] = 0;
-
-	if (i < 0) {
-		state_puts ("-");
-		i = -i;
-	}
-
-	do {
-		buf [sizeof (buf) - 2 - l] = digit [i % radix]; l++;
-		i /= radix;
-	} while (i);
-
-	return state_puts (&buf [sizeof (buf) - 1 - l]);
-}
-
-
-static void state_init (void)
-{
-	state.busy = 0;
-}
-
-
-static int state_open (int open_mode)
-{
-	if (state.busy) return -EBUSY;
-
-	state.len = 0;
-	state.ptr = 0;
-	state.busy = 1;
-
-	state_puts ("Atari DMA sound driver:\n");
-
-	state_puts ("\tmfp.int_en_a & 0x20 = 0x");
-	state_puti (mfp.int_en_a & 0x20, 16); state_puts ("\n");
-
-	state_puts ("\tmfp.int_mk_a & 0x20 = 0x");
-	state_puti (mfp.int_mk_a & 0x20, 16); state_puts ("\n");
-
-	state_puts ("\tmfp.tim_ct_a = ");
-	state_puti (mfp.tim_ct_a, 10); state_puts ("\n");
-
-	state_puts ("\tmfp.tim_dt_a = ");
-	state_puti (mfp.tim_dt_a, 10); state_puts ("\n");
-
-	state_puts ("\tsound.format = 0x");
-	state_puti (sound.format, 16); state_puts ("\n");
-
-	state_puts ("\tsound.speed = 0x");
-	state_puti (sound.speed, 16); state_puts ("\n");
-
-	state_puts ("\tsound.stereo = 0x");
-	state_puti (sound.stereo, 16); state_puts ("\n");
-
-	state_puts ("\tsound.volume_left = ");
-	state_puti (sound.volume_left, 10); state_puts (" db\n");
-
-	state_puts ("\tsound.volume_right = ");
-	state_puti (sound.volume_right, 10); state_puts (" db\n");
-
-	state_puts ("\tsound.bass = ");
-	state_puti (sound.bass, 10); state_puts (" db\n");
-
-	state_puts ("\tsound.treble = ");
-	state_puti (sound.treble, 10); state_puts (" db\n");
-
-	return 0;
-}
-
-
-static int state_release (void)
-{
-	state.busy = 0;
-	return 0;
-}
-
-
-static int state_read (char *dest, int count)
-{
-	int n = state.len - state.ptr;
-	if (n > count) n = count;
-	if (n <= 0) return 0;
-	memcpy_tofs (dest, &state.buf [state.ptr], n);
-	state.ptr += n;
-	return n;
-}
-
-
-/*
 sound queue stuff, the heart of the driver
 */
 
@@ -589,14 +571,14 @@
 #define sq_block_address(i) ((char *)sq.buf.start + (i) * sq.block_size)
 #define SIGNAL_RECEIVED (current->signal & ~current->blocked)
 #define NON_BLOCKING(open_mode) (open_mode & O_NONBLOCK)
-#define ONE_SECOND 100	/* in jiffies (100ths of a second) */
+#define ONE_SECOND HZ	/* in jiffies (100ths of a second) */
 #define NO_TIME_LIMIT 0xffffffff
 #define SLEEP(queue, time_limit) \
 	current->timeout = jiffies + (time_limit); \
 	interruptible_sleep_on (&queue);
 #define WAKE_UP(queue) (wake_up_interruptible (&queue))
-#define QUEUE_BLOCK_SIZE 1024
-#define SOUND_BUFFER_SIZE (100 * QUEUE_BLOCK_SIZE)
+#define QUEUE_BLOCK_SIZE 4096
+#define SOUND_BUFFER_SIZE (25 * QUEUE_BLOCK_SIZE)
 
 #define	DISABLE_IRQ()			\
 	do {				\
@@ -624,126 +606,207 @@
 }
 
 
-static void sq_delete_front (void)
+static void sq_play_next_frame (int index)
 {
-	if (sq.count <= 0) return;
-	sq.count --;
+	char *start, *end;
+
+	/* used by sq_play() if all doubts whether there really is
+	   something to be played are already wiped out. */
+	start = sq_block_address (sq.front);
+	end = start + ((sq.count == index)? sq.rear_size: sq.block_size);
+	DMASNDSetEnd (VTOP (end));
+	DMASNDSetBase (VTOP (start));
+	/* Since only an even number of samples per frame can be
+	   played, we might loose one byte here. (TO DO) */
 	sq.front = (sq.front + 1) % sq.max_count;
+	if (++sq.playing == 1)
+		tt_dmasnd.ctrl = DMASND_CTRL_ON;
+	else /* sq.playing == 2 */
+		tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT;
 }
 
 
 static void sq_play (void)
 {
-	char *start, *end;
-
+	/* ++TeSche: Note that sq.playing is no longer just a flag but holds
+	   the number of frames the DMA is currently programmed for instead,
+	   may be 0, 1 (currently being played) or 2 (pre-programmed).
+
+	   Chances done to sq.count and sq.playing are a bit more subtle again
+	   so now I must admit I also prefer disabling the irq here rather than
+	   considering all possible situations.  But the point is that
+	   disabling the irq doesn't have any bad influence on this version of
+	   the driver as we benefit from having pre-programmed the DMA
+	   whereever possible: There's no need to reload the DMA at the exact
+	   time of an interrupt but only at some time while the pre-programmed
+	   frame in playing! */
 	DISABLE_IRQ();
-	if (sq.playing || sq.count <= 0 ||
-	    (sq.count == 1 && sq.rear_size < sq.block_size && !sq.syncing)) {
+
+	if (sq.playing == 2 ||	/* DMA is 'full' */
+	    sq.count <= 0) {	/* nothing to do */
 		ENABLE_IRQ();
 		return;
 	}
 
-	start = sq_block_address (sq.front);
-	end = start + ((sq.count == 1)? sq.rear_size: sq.block_size);
-	DMASNDSetBase (VTOP (start));
-	DMASNDSetEnd (VTOP (end));
-		/* Since only an even number of samples per frame can
-		   be played, we might loose one byte here. (TO DO) */
-	tt_dmasnd.ctrl = DMASND_CTRL_ON ;
-	sq.playing = 1;
-
+	if (sq.playing == 0) {
+		/* looks like there's nothing 'in' the DMA yet, so try to put
+		   two frames into it (at least one is available). */
+		if (sq.count == 1 && sq.rear_size < sq.block_size &&
+		    !sq.syncing) {
+			/* hmmm, the only existing frame is not yet filled and
+			   we're not syncing? */
+			ENABLE_IRQ();
+			return;
+		}
+		sq_play_next_frame(1);
+		if (sq.count == 1) {
+			/* no more frames */
+			ENABLE_IRQ();
+			return;
+		}
+		if (sq.count == 2 && sq.rear_size < sq.block_size &&
+		    !sq.syncing) {
+			/* hmmm, there were two frames, but the second one is
+			   not yet filled and we're not syncing? */
+			ENABLE_IRQ();
+			return;
+		}
+		sq_play_next_frame(2);
+	} else {
+		/* there's already a frame being played so we may only stuff
+		   one new into the DMA, but even if this may be the last frame
+		   existing the previous one is still on sq.count. */
+		if (sq.count == 2 && sq.rear_size < sq.block_size &&
+		    !sq.syncing) {
+			/* hmmm, the only existing frame is not yet filled and
+			   we're not syncing? */
+			ENABLE_IRQ();
+			return;
+		}
+		sq_play_next_frame(2);
+	}
 	ENABLE_IRQ();
 }
 
 
 static void sq_interrupt (void)
 {
-	if (sq.playing) {
-		sq.playing = 0;
-		sq_delete_front ();
-		WAKE_UP (sq.write_queue);
-			/* At least one block of the queue is free
-			   now, so wake up a writing process blocked
-			   because of a full queue. */
-		sq_play ();
-		if (!sq.playing) WAKE_UP (sq.sync_queue);
-			/* We are not playing after sq_play (), so
-			   there is nothing to play any more.  Wake up
-			   a process waiting for audio output to
-			   drain. */
-	}
-
 #if 0
-	mfp.int_sv_a = 0xdf;
-		/* Clear the interrupt-in-service bit.  This allows
-		   for interrupt requests by the MFP to the CPU for
-		   pending interrupts. */
+	/* if you should want to test this... */
+	static int cnt = 0;
+	if (sq.playing == 2)
+		if (++cnt == 10) {
+			/* simulate loosing an interrupt */
+			cnt = 0;
+			return;
+		}
 #endif
-}
 
+	/* disable repeats */
+	tt_dmasnd.ctrl &= ~DMASND_CTRL_REPEAT;
 
+	if (!sq.playing) {
+		/* playing was interrupted and sq_reset() has already cleared
+		 * the sq variables, so better don't do anything here.
+		 */
+		WAKE_UP (sq.sync_queue);
+		return;
+	}
 
+	/* Probably ;) one frame is finished. Well, in fact it may be that a
+	 * pre-programmed one is also finished because there has been a long
+	 * delay in interrupt delivery and we've completely lost one, but
+	 * there's no way to detect such a situation. In such a case the last
+	 * frame will be played more than once and the situation will recover
+	 * as soon as the irq gets through.
+	 */
+	sq.count--;
+	sq.playing--;
+
+	WAKE_UP (sq.write_queue);
+	/* At least one block of the queue is free now so wake up a writing
+	   process blocked because of a full queue.  */
+
+	if ((sq.playing != 1) || (sq.count != 1))
+		/* We must be a bit carefully here: sq.count indicates the
+		   number of buffers used and not the number of frames to be
+		   played.  If sq.count==1 and sq.playing==1 that means the
+		   only remaining frame was already programmed earlier (and is
+		   currently running) so we mustn't call sq_play() here,
+		   otherwise we'll play one frame too much. */
+		sq_play();
+
+	if (!sq.playing) WAKE_UP (sq.sync_queue);
+	/* We are not playing after sq_play (), so there is nothing to play any
+	   more.  Wake up a process waiting for audio output to drain.  */
+}
 
-static int sq_write (const char *src, int count)
+
+/* ++roman: Note: Since we can interpolate incoming data, we have to
+ * distinguish carefully between user byte counts and buffer byte counts. To
+ * make this easier, I prefixed the former with "u_", the latter with "b_".
+ */
+
+static int sq_write (const char *src, int u_count)
 {
-	int written = 0, left;
+	int u_written = 0, b_left, u_left;
+	char *dest;
+
+	/* ++TeSche: Is something like this necessary? */
+	if (u_count < 1)
+		return 0;
 	
-	/* ++roman: We can append to the last incomplete frame only if
-	   isn't already played.  So sq.count must be more than 1...
-	   Also, we must disable the interrupt after discovering an
-	   incomplete frame, else it could finish while we append to
-	   it.  */
-	DISABLE_IRQ();
-	if (sq.count > 1) {
-		left = sq.block_size - sq.rear_size;
-		if (left > count) left = count;
-		if (left > 0) {
-			char *dest = sq_block_address (sq.rear) + sq.rear_size;
-			memcpy_fromfs (dest, src, left);
-			sound_translate (dest, left);
-			sq.rear_size = sq.block_size;
-			count -= left;
-			src += left;
-			written += left;
+	/* The interrupt doesn't start to play the last, incomplete frame.
+	   Thus, we can append to it without disabling the interrupts!  (Note
+	   also, that sq.rear isn't affected by the interrupt.)  */
+	if ((sq.count > 0) && ((b_left = sq.block_size - sq.rear_size) > 0)) {
+		u_left = bsize2u( b_left );
+		if (u_left > u_count) {
+			u_left = u_count;
+			b_left = usize2b( u_count );
 		}
+		dest = sq_block_address (sq.rear) + sq.rear_size;
+		sound_copy_translate (dest, src, b_left);
+		sq.rear_size += b_left;
+		u_count -= u_left;
+		src += u_left;
+		u_written += u_left;
 	}
-	ENABLE_IRQ();
-	
-	sq_play ();
 
-	while (count > 0) {
+	while (u_count > 0) {
 		if (sq.count == sq.max_count) {
+			sq_play();
 			if (NON_BLOCKING (sq.open_mode))
-				return (written > 0)? written: -EAGAIN;
+				return (u_written > 0) ? u_written: -EAGAIN;
 			SLEEP (sq.write_queue, ONE_SECOND);
 			if (SIGNAL_RECEIVED)
-				return (written > 0)? written: -EINTR;
+				return (u_written > 0) ? u_written: -EINTR;
 		} else {
-			char *dest;
-			DISABLE_IRQ();
-			sq.count ++;
+			/* Here, we can avoid disabling the interrupt by first
+			   copying and translating the data, and then updating
+			   the sq variables.  Until this is done, the interrupt
+			   won't see the new frame and we can work on it
+			   undisturbed.  */
+			b_left = sq.block_size;
+			u_left = bsize2u( b_left );
+			if (u_left > u_count) {
+				u_left = u_count;
+				b_left = usize2b( u_count );
+			}
 			sq.rear = (sq.rear + 1) % sq.max_count;
-			left = (sq.block_size > count)? count: sq.block_size;
 			dest = sq_block_address (sq.rear);
-			sq.rear_size = left;
-			/* ++roman: If there are at least 2 frames to
-			   play before the one we're going to copy and
-			   translate now, it seems safe to enable the
-			   interrupt already here, assuming that it
-			   won't start to play this frame before we're
-			   done here.  */
-			if (sq.count > 3) ENABLE_IRQ();
-			memcpy_fromfs (dest, src, left);
-			sound_translate (dest, left);
-			ENABLE_IRQ();
-			count -= left;
-			src += left;
-			written += left;
-			sq_play ();
+			sound_copy_translate (dest, src, b_left);
+			sq.rear_size = b_left;
+			sq.count ++;
+			u_count -= u_left;
+			src += u_left;
+			u_written += u_left;
 		}
 	}
 
-	return written;
+	sq_play();
+
+	return u_written;
 }
 
 
@@ -766,7 +829,8 @@
 {
 	sound_silence ();
 	sq.playing = 0;
-	while (sq.count > 0) sq_delete_front ();
+	sq.count = 0;
+	sq.front = (sq.rear + 1) % sq.max_count;
 }
 
 
@@ -775,14 +839,14 @@
 	int rc = 0;
 
 	sq.syncing = 1;
-	sq_play ();
+	sq_play();	/* there may be an incomplete frame waiting */
 
 	while (sq.playing) {
 		SLEEP (sq.sync_queue, ONE_SECOND);
 		if (SIGNAL_RECEIVED) {
 			/* While waiting for audio output to drain, an
-			   interrupt occured.  Stop audio output
-			   immediately and clear the queue.  */
+			   interrupt occured.  Stop audio output immediately
+			   and clear the queue.  */
 			sq_reset ();
 			rc = -EINTR;
 			break;
@@ -801,16 +865,165 @@
 		rc = sq_sync ();
 		sq.busy = 0;
 		WAKE_UP (sq.open_queue);
-			/* Wake up a process waiting for the queue
-			   beeing released.  Note: There may be
-			   several processes waiting for a call to
-			   open () returning.  */
+		/* Wake up a process waiting for the queue beeing released.
+		   Note: There may be several processes waiting for a call to
+		   open () returning.  */
 	}
 	return rc;
 }
 
 
 /*
+/dev/sndstat
+*/
+
+
+struct sound_state {
+	int busy;
+	char buf [512];
+	int len, ptr;
+};
+
+
+struct sound_state state;
+
+
+static int state_puts (const char *s)
+{
+	int l;
+	for (l = 0; l < 256 && s [l]; l++);
+		/* l = max (256, strlen (s)) */
+	if (state.len + l > sizeof (state.buf)) return 0;
+	memcpy (&state.buf [state.len], s, l);
+	state.len += l;
+	return 1;
+}
+
+
+static int state_puti (int i, int radix)
+{
+	int l;
+	static char digit [] = "0123456789abcdef";
+	char buf [11];
+
+	l = 0; buf [sizeof (buf) - 1] = 0;
+
+	if (i < 0) {
+		state_puts ("-");
+		i = -i;
+	}
+
+	do {
+		buf [sizeof (buf) - 2 - l] = digit [i % radix]; l++;
+		i /= radix;
+	} while (i);
+
+	return state_puts (&buf [sizeof (buf) - 1 - l]);
+}
+
+
+static void state_init (void)
+{
+	state.busy = 0;
+}
+
+
+static int state_open (int open_mode)
+{
+	int	count, rear_size, playing, syncing;
+	
+	if (state.busy) return -EBUSY;
+
+	state.len = 0;
+	state.ptr = 0;
+	state.busy = 1;
+
+	state_puts ("Atari DMA sound driver:\n");
+
+	state_puts ("\tsound.format = 0x");
+	state_puti (sound.format, 16); 
+	switch( sound.format ) {
+	  case AFMT_MU_LAW:	state_puts( " (mu-law, interpolated)" ); break;
+	  case AFMT_U8:		state_puts( " (unsigned 8 bit)" ); break;
+	  case AFMT_S8:		state_puts( " (signed 8 bit)" ); break;
+	}
+	state_puts ("\n");
+	
+	state_puts ("\tsound.speed = 0x");
+	state_puti (sound.speed, 16);
+	switch( sound.speed ) {
+	  case DMASND_MODE_6KHZ:	state_puts( " (6.26 kHz)" ); break;
+	  case DMASND_MODE_12KHZ:	state_puts( " (12.5 kHz)" ); break;
+	  case DMASND_MODE_25KHZ:	state_puts( " (25.0 kHz)" ); break;
+	  case DMASND_MODE_50KHZ:	state_puts( " (50.1 kHz)" ); break;
+	}
+	state_puts ("\n");
+
+	state_puts ("\tsound.stereo = 0x");
+	state_puti (sound.stereo, 16);
+	state_puts (sound.stereo == DMASND_MODE_STEREO ? " (stereo)\n" :
+		    " (mono)\n" );
+
+	state_puts ("\tsound.volume_left = ");
+	state_puti (sound.volume_left, 10); state_puts (" db [-40...0]\n");
+
+	state_puts ("\tsound.volume_right = ");
+	state_puti (sound.volume_right, 10); state_puts (" db [-40...0]\n");
+
+	state_puts ("\tsound.bass = ");
+	state_puti (sound.bass, 10); state_puts (" db [-12...+12]\n");
+
+	state_puts ("\tsound.treble = ");
+	state_puti (sound.treble, 10); state_puts (" db [-12...+12]\n");
+
+	state_puts( "\tsq.block_size = ");
+	state_puti( sq.block_size, 10 );
+	state_puts( " sq.max_count = ");
+	state_puti( sq.max_count, 10 );
+	state_puts( "\n" );
+
+	DISABLE_IRQ();
+	count     = sq.count;
+	rear_size = sq.rear_size;
+	playing   = sq.playing;
+	syncing   = sq.syncing;
+	ENABLE_IRQ();
+
+	state_puts( "\tsq.count = ");
+	state_puti( count, 10 );
+	state_puts( " sq.rear_size = ");
+	state_puti( rear_size, 10 );
+	state_puts( "\n" );
+
+	state_puts( "\tsq.playing = ");
+	state_puti( playing, 10 );
+	state_puts( " sq.syncing = ");
+	state_puti( syncing, 10 );
+	state_puts( "\n" );
+
+	return 0;
+}
+
+
+static int state_release (void)
+{
+	state.busy = 0;
+	return 0;
+}
+
+
+static int state_read (char *dest, int count)
+{
+	int n = state.len - state.ptr;
+	if (n > count) n = count;
+	if (n <= 0) return 0;
+	memcpy_tofs (dest, &state.buf [state.ptr], n);
+	state.ptr += n;
+	return n;
+}
+
+
+/*
 high level sound stuff
 */
 
@@ -818,17 +1031,19 @@
 static int
 sound_open (struct inode *inode, struct file *file)
 {
-	int dev = MINOR (inode->i_rdev);
+	int dev = MINOR (inode->i_rdev) & 0x0f;
 
-	switch (dev & 0x0f) {
+	switch (dev) {
 	case SND_DEV_STATUS: return state_open (file->f_flags);
 	case SND_DEV_CTL: return mixer_open (file->f_flags);
 	case SND_DEV_DSP:
 	case SND_DEV_AUDIO: {
 	    	int rc = sq_open (file->f_flags);
 	    	if (rc == 0) {
-			sound.format = ((dev & 0x0f) == SND_DEV_AUDIO)? AFMT_MU_LAW: AFMT_U8;
+			sound.format = (dev == SND_DEV_AUDIO) ? AFMT_MU_LAW : AFMT_U8;
 			sound_init ();
+			if (dev == SND_DEV_AUDIO)
+				sound_set_speed(12517);
 		}
 		return rc;
 	}
@@ -998,17 +1213,21 @@
 			register_chrdev (SOUND_MAJOR, "sound", &sound_fops);
 			printk ("Atari DMA sound driver installed.\n");
 
-			/* Set up sound queue, /dev/audio and
-			   /dev/dsp.  TO DO: Allocate buffer space
-			   dynamically.  But I do not see how to do
-			   this, since kmalloc will not allocate more
-			   than 4K and vmalloc does not guarantee
-			   memory to be physically contiguous, which
-			   is necessary for DMA transfer. */
-			/* ++roman: It would be veeery difficult to
-			   allocate these buffers dynamically...  Need
-			   not only contigous pages, but also in
-			   ST-Ram...  */
+			/* Set up sound queue, /dev/audio and /dev/dsp.  TO DO:
+			   Allocate buffer space dynamically.  But I do not see
+			   how to do this, since kmalloc will not allocate more
+			   than 4K and vmalloc does not guarantee memory to be
+			   physically contiguous, which is necessary for DMA
+			   transfer. */
+			/* ++roman: It would be veeery difficult to allocate
+			   these buffers dynamically...  Need not only
+			   contigous pages, but also in ST-Ram...
+
+			   ++TeSche: There's no physical need to have
+			   subsequent buffers on contiguous pages (would just
+			   require a different buffer adress handling) so this
+			   could be dealt with, but the ST-RAM really is a
+			   problem... */
 			buf.start = (char *) atari_stram_alloc (
 				SOUND_BUFFER_SIZE, &mem_start);
 			buf.size = SOUND_BUFFER_SIZE;
@@ -1020,14 +1239,13 @@
 			/* Set up /dev/mixer. */
 			mixer_init ();
 
-			/* Set up timer A.  Timer A will receive a
-			   signal upon end of playing from the sound
-			   hardware.  Furthermore Timer A is able to
-			   count events and will cause an interrupt
-			   after a programmed number of events.  So
-			   all we need to keep the music playing is to
-			   provide the sound hardware with new data
-			   upon an interrupt from timer A. */
+			/* Set up timer A.  Timer A will receive a signal upon
+			   end of playing from the sound hardware.  Furthermore
+			   Timer A is able to count events and will cause an
+			   interrupt after a programmed number of events.  So
+			   all we need to keep the music playing is to provide
+			   the sound hardware with new data upon an interrupt
+			   from timer A. */
 			mfp.tim_ct_a = 0;	/* ++roman: Stop timer before programming! */
 			mfp.tim_dt_a = 1;	/* Cause interrupt after first event. */
 			mfp.tim_ct_a = 8;	/* Turn on event counting. */
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/arch/m68k/atari/config.c linux-1.2.13pl3/arch/m68k/atari/config.c
--- linux-1.2.13pl2/arch/m68k/atari/config.c	Tue Sep 12 21:14:02 1995
+++ linux-1.2.13pl3/arch/m68k/atari/config.c	Fri Oct 13 19:04:43 1995
@@ -156,10 +156,42 @@
 	return( ret );
 }
 
+/* Read the MFP data register to get a delay for the SCC. udelay()'s delay
+ * loop isn't calibrated yet and NOPs loose on a '040. */
+#define	MFPDELAY() ((void)mfp.par_dt_reg)
+
+/* ++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
+ * resides generate DTACK without the chip, too.
+ * The method is to write values into the interrupt vector register, that
+ * should be readable without trouble (from channel A!).
+ */
+
+static int scc_test( volatile char *ctla )
+{
+	if (!hwreg_present( ctla ))
+		return( 0 );
+	MFPDELAY();
+
+	*ctla = 2; MFPDELAY();
+	*ctla = 0x40; MFPDELAY();
+	
+	*ctla = 2; MFPDELAY();
+	if (*ctla != 0x40) return( 0 );
+	MFPDELAY();
+
+	*ctla = 2; MFPDELAY();
+	*ctla = 0x60; MFPDELAY();
+	
+	*ctla = 2; MFPDELAY();
+	if (*ctla != 0x60) return( 0 );
+
+	return( 1 );
+}
+
 
 extern int is_medusa;
-static unsigned short tos_version;
-static long reset_addr;
 
 void config_atari(void)
 {
@@ -263,14 +295,27 @@
 	printk( "CODEC " );
     }
 #endif
-    if (!is_medusa && hwreg_present( &tt_scc_dma.dma_addr_hi )) {
+#if 0 /* This does not work any more if the kernel is in tt ram ??? */
+    if (hwreg_present( &tt_scc_dma.dma_ctrl ) &&
+	(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)) {
+	ATARIHW_SET(SCC_DMA);
+        printk( "SCC_DMA " );
+    }
+#else
+    if (hwreg_present(&tt_scc_dma.dma_addr_hi)) {
 	ATARIHW_SET(SCC_DMA);
         printk( "SCC_DMA " );
     }
-    if (!is_medusa && hwreg_present( &scc.cha_a_ctrl )) {
+#endif
+    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 (hwreg_present( &tt_scu.sys_mask )) {
 	ATARIHW_SET(VME);
 	ATARIHW_SET(SCU);
@@ -325,7 +370,6 @@
     }
     printk("\n");
 
-#if 0
     if (boot_info.cputype & CPU_68040)
         /* Now it seems to be safe to turn of the tt0 transparent
          * translation (the one that must not be turned off in
@@ -337,7 +381,6 @@
 						  : /* no outputs */
 						  : /* no inputs */
 						  : "d0");
-#endif
 	
     /* allocator for memory that must reside in st-ram */
     atari_stram_init ();
@@ -372,11 +415,6 @@
               : "d0" );
 
     }
-    /* Fetch tos version at Physical 2 */
-    tos_version = *(unsigned short *)PTOV( 2 );
-	
-    /* On the Medusa, phys. 0x4 may contain garbage because it's no ROM */
-    reset_addr = is_medusa ? 0xe00030 : *(unsigned long *) PTOV (4);
 }
 
 extern long time_finetune;	/* from kernel/sched.c */
@@ -498,6 +536,7 @@
 		   int *hourp, int *minp, int *secp)
 {
     unsigned char	ctrl;
+    unsigned short tos_version;
 		
     while (!(RTC_READ(RTC_FREQ_SELECT) & RTC_UIP)) ;
     while (RTC_READ(RTC_FREQ_SELECT) & RTC_UIP) ;
@@ -526,6 +565,16 @@
         }
     }
     /* Adjust values (let the setup valid) */
+
+    /* 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 = is_medusa ? 0xfff : *(unsigned short *)0xFF000002;
     *yearp += (tos_version < 0x306) ? 70 : 68;
 }
 
@@ -592,7 +641,12 @@
 {
     int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0; 
     unsigned long 	flags;
+    unsigned short	tos_version;
     unsigned char	ctrl;
+	
+    /* Tos version at Physical 2.  See above for explanation why we
+       cannot use PTOV(2).  */
+    tos_version = is_medusa ? 0xfff : *(unsigned short *)0xff000002;
 
     ctrl = RTC_READ(RTC_CONTROL); /* control registers are
                                    * independant from the UIP */
@@ -818,6 +872,11 @@
 void atari_reset (void)
 {
     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 = is_medusa ? 0xe00030 : *(unsigned long *) 0xff000004;
 
     acia.key_ctrl = ACIA_RESET;             /* reset ACIA for switch off OverScan, if it's active */
  
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/arch/m68k/boot/Makefile linux-1.2.13pl3/arch/m68k/boot/Makefile
--- linux-1.2.13pl2/arch/m68k/boot/Makefile	Mon Jun 19 18:22:37 1995
+++ linux-1.2.13pl3/arch/m68k/boot/Makefile	Mon Oct 23 20:38:53 1995
@@ -7,6 +7,8 @@
 
 ifdef CONFIG_AMIGA
 AMIGA_BOOTOBJS := amiga/bootstrap.o
+HOSTCC += -b amigados
+HOSTFLAGS=-m68030 -noixemul -Dlinux -O2 -Wall -Wstrict-prototypes
 endif
 
 ifdef CONFIG_ATARI
@@ -14,24 +16,29 @@
 HOSTCC += -b m68k-mint
 endif
 
+bootstrap::
+
 ifdef CONFIG_ATARI
 atari_bootstrap: $(ATARI_BOOTOBJS)
 	$(HOSTCC) $(HOSTFLAGS) -o $@ $(ATARI_BOOTOBJS)
 	rm -f ../../../bootstrap
 	ln $@ ../../../bootstrap
+all:: atari_bootstrap
 endif
 
 ifdef CONFIG_AMIGA
 amiga_bootstrap: $(AMIGA_BOOTOBJS)
-	$(HOSTCC) $(HOSTFLAGS) -o $@ $(AMIGA_BOOTOBJS)
+	$(HOSTCC) $(HOSTFLAGS) -o $@ -s $(AMIGA_BOOTOBJS)
+	chmod +x $@
 	rm -f ../../../bootstrap
 	ln $@ ../../../bootstrap
+all:: amiga_bootstrap
 endif
 
 $(AMIGA_BOOTOBJS) $(ATARI_BOOTOBJS): %.o: %.c
 	$(HOSTCC) $(HOSTFLAGS) -c $< -o $@
 
 clean:
-	rm -f *.o
+	rm -f *.o amiga/*.o atari/*.o amiga_bootstrap atari_bootstrap
 
 dep:
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/arch/m68k/boot/amiga/bootstrap.c linux-1.2.13pl3/arch/m68k/boot/amiga/bootstrap.c
--- linux-1.2.13pl2/arch/m68k/boot/amiga/bootstrap.c	Wed Sep 20 18:52:37 1995
+++ linux-1.2.13pl3/arch/m68k/boot/amiga/bootstrap.c	Mon Oct 23 20:38:28 1995
@@ -38,6 +38,9 @@
 #include <linux/elf.h>
 #include <asm/bootinfo.h>
 
+#undef custom
+#define custom ((*(volatile struct CUSTOM *)(CUSTOM_PHYSADDR)))
+
 /* temporary stack size */
 #define TEMP_STACKSIZE	256
 
@@ -184,7 +187,7 @@
 	rte
 ");
 
-extern unsigned long maprommed();
+extern unsigned long maprommed(void);
 
 
 extern char copyall, copyallend;
@@ -207,7 +210,7 @@
 	unsigned char *rb3_reg = NULL, *piccolo_reg = NULL, *sd64_reg = NULL;
 
 	/* print the greet message */
-	puts("Linux/68k Amiga Bootstrap version 2.0");
+	puts("Linux/68k Amiga Bootstrap version 2.1");
 	puts("Copyright 1993,1994 by Hamish Macdonald and Greg Harp\n");
 
 	/* machine is Amiga */
@@ -247,6 +250,7 @@
 	}
 
 	/* find all of the autoconfig boards in the system */
+	bi.bi_amiga.autocon_configured = 0;
 	cdp = (struct ConfigDev *)FindConfigDev(cdp, -1, -1);
 	for (i=0; (i < NUM_AUTO) && cdp; i++) {
 		/* copy the contents of each structure into our boot info */
@@ -482,8 +486,7 @@
 	/* display the clock statistics */
 	printf("Vertical Blank Frequency: %dHz\nPower Supply Frequency: %dHz\n",
 	       bi.bi_amiga.vblank, bi.bi_amiga.psfreq);
-	printf("EClock Frequency: %7.5fKHz\n\n",
-	       (float)bi.bi_amiga.eclock / 1000);
+	printf("EClock Frequency: %dKHz\n\n", (int)bi.bi_amiga.eclock / 1000);
 
 	/* display autoconfig devices */
 	if (bi.bi_amiga.num_autocon) {
@@ -965,8 +968,7 @@
     the new indices of the non-options in ARGV after they are moved.  */
 
 static void
-exchange (argv)
-     char **argv;
+exchange (char * const *argv)
 {
   int nonopts_size
     = (last_nonopt - first_nonopt) * sizeof (char *);
@@ -975,9 +977,9 @@
   /* Interchange the two blocks of data in argv.  */
 
   bcopy (&argv[first_nonopt], temp, nonopts_size);
-  bcopy (&argv[last_nonopt], &argv[first_nonopt],
+  bcopy (&argv[last_nonopt], (char **)&argv[first_nonopt],
 	 (optind - last_nonopt) * sizeof (char *));
-  bcopy (temp, &argv[first_nonopt + optind - last_nonopt],
+  bcopy (temp, (char **)&argv[first_nonopt + optind - last_nonopt],
 	 nonopts_size);
 
   /* Update records for the slots the non-options now occupy.  */
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/arch/m68k/boot/amiga/bootstrap.h linux-1.2.13pl3/arch/m68k/boot/amiga/bootstrap.h
--- linux-1.2.13pl2/arch/m68k/boot/amiga/bootstrap.h	Wed Sep 20 18:57:03 1995
+++ linux-1.2.13pl3/arch/m68k/boot/amiga/bootstrap.h	Mon Oct 23 20:33:45 1995
@@ -274,11 +274,11 @@
   return _res;
 }
 static __inline unsigned long
-Supervisor (unsigned long (*userfunc)())
+Supervisor (unsigned long (*userfunc)(void))
 {
   register unsigned long _res __asm("d0");
   register struct ExecBase *a6 __asm("a6") = SysBase;
-  register unsigned long (*a0)() __asm("a0") = userfunc;
+  register unsigned long (*a0)(void) __asm("a0") = userfunc;
 	/* gcc doesn't seem to like asm parameters in a5 */
   __asm __volatile ("movel a5,sp@-;movel a0,a5;jsr a6@(-0x1e);movel sp@+,a5"
   : "=r" (_res)
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/arch/m68k/boot/atari/bootstrap.c linux-1.2.13pl3/arch/m68k/boot/atari/bootstrap.c
--- linux-1.2.13pl2/arch/m68k/boot/atari/bootstrap.c	Tue Sep 12 21:14:05 1995
+++ linux-1.2.13pl3/arch/m68k/boot/atari/bootstrap.c	Fri Oct 13 19:04:44 1995
@@ -8,6 +8,7 @@
 ** for more details.
 **
 ** History:
+**	03 Oct 1995 Allow kernel to be loaded to TT ram again (Andreas)
 **	11 Jul 1995 Add support for ELF format kernel (Andreas)
 **	16 Jun 1995 Adapted to Linux 1.2: kernel always loaded into ST ram
 **		    (Andreas)
@@ -77,7 +78,7 @@
 static void usage(void)
 {
     fprintf(stderr, "Usage:\n"
-	    "\tbootstrap [-d] [-k kernel_executable] [-r ramdisk_file]"
+	    "\tbootstrap [-dst] [-k kernel_executable] [-r ramdisk_file]"
 	    " [option...]\n");
     exit(EXIT_FAILURE);
 }
@@ -266,7 +267,7 @@
     kernel_name = "vmlinux";
 
     /* print the startup message */
-    puts("\fLinux/68k Atari Bootstrap version 1.2");
+    puts("\fLinux/68k Atari Bootstrap version 1.3");
     puts("Copyright 1993,1994 by Arjan Knor, Robert de Vries, Roman Hodek, Andreas Schwab\n");
 
 	/* ++roman: If no arguments on the command line, read them from
@@ -391,12 +392,6 @@
     i = 0;
 	
     if (!test_medusa()) {
-        bi.memory[i].addr = 0;
-        bi.memory[i].size = *phystop & ~(MB - 1);
-        ST_ramsize = bi.memory[i].size / MB;
-        i++;
-        printf("ST-RAM: %ld Mb", ST_ramsize );
-
         TT_ramsize = 0;
         if (!ignore_ttram && *ramtop) {
             /* the 'ramtop' variable at 0x05a4 is not
@@ -408,10 +403,23 @@
             bi.memory[i].size = (*ramtop - TT_RAM_BASE) & ~(MB - 1);
             TT_ramsize = bi.memory[i].size / MB;
             i++;
-            printf("; TT-RAM: %ld Mb", TT_ramsize);
+            printf("TT-RAM: %ld Mb; ", TT_ramsize);
         }
-        printf ("\n");
+
+        bi.memory[i].addr = 0;
+        bi.memory[i].size = *phystop & ~(MB - 1);
+        ST_ramsize = bi.memory[i].size / MB;
+        i++;
+        printf("ST-RAM: %ld Mb\n", ST_ramsize );
+
         bi.num_memory = i;
+
+	if (load_to_stram && i > 1) {
+	    /* Put ST-RAM first in the list of mem blocks */
+	    struct mem_info temp = bi.memory[i - 1];
+	    bi.memory[i - 1] = bi.memory[0];
+	    bi.memory[0] = temp;
+	}
     }
     else {
         u_long	bank1, bank2;
@@ -448,16 +456,6 @@
         bi.num_memory = i;
         printf("\n");
     }
-
-#if 0
-    if (load_to_stram && i > 1)
-      {
-	/* Put ST-RAM first in the list of mem blocks */
-	struct mem_info temp = bi.memory[i - 1];
-	bi.memory[i - 1] = bi.memory[0];
-	bi.memory[0] = temp;
-      }
-#endif
 
     /* verify that there is enough RAM; ST- and TT-RAM combined */
     if (ST_ramsize + TT_ramsize < MIN_RAMSIZE) {
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/arch/m68k/config.in linux-1.2.13pl3/arch/m68k/config.in
--- linux-1.2.13pl2/arch/m68k/config.in	Tue Sep 12 21:14:05 1995
+++ linux-1.2.13pl3/arch/m68k/config.in	Fri Oct 13 19:04:45 1995
@@ -15,6 +15,7 @@
 bool 'Floppy support' CONFIG_BLK_DEV_FD y
 if [ "$CONFIG_AMIGA" = "y" ]; then
 bool 'Amiga Gayle IDE harddisk support' CONFIG_AMIGA_IDE y
+bool 'Amiga AutoConfig Identification' CONFIG_ZORRO y
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
 bool 'Atari Falcon IDE harddisk support' CONFIG_ATARI_FALCON_IDE y
@@ -83,6 +84,9 @@
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
 bool 'Atari native SCSI support' CONFIG_ATARI_SCSI y
+if [ "$CONFIG_ATARI_SCSI" = "y" ]; then
+bool ' Use longer delay for Toshiba CD-ROMs' CONFIG_ATARI_SCSI_TOSHIBA_DELAY y
+fi
 fi
 #bool 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG n
 fi
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/arch/m68k/kernel/Makefile linux-1.2.13pl3/arch/m68k/kernel/Makefile
--- linux-1.2.13pl2/arch/m68k/kernel/Makefile	Sat Jun 17 10:31:07 1995
+++ linux-1.2.13pl3/arch/m68k/kernel/Makefile	Fri Oct 13 19:04:45 1995
@@ -9,7 +9,7 @@
 .c.o:
 	$(CC) $(CFLAGS) -c $<
 .S.o:
-	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
+	$(CC) -D__ASSEMBLY__ -traditional -Wa,-m68030 -c $< -o $*.o
 
 OBJS	= entry.o process.o machasm.o traps.o ints.o signal.o ptrace.o \
 	setup.o bios32.o
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/arch/m68k/kernel/entry.S linux-1.2.13pl3/arch/m68k/kernel/entry.S
--- linux-1.2.13pl2/arch/m68k/kernel/entry.S	Tue Sep 12 21:17:34 1995
+++ linux-1.2.13pl3/arch/m68k/kernel/entry.S	Fri Oct 13 19:04:46 1995
@@ -114,7 +114,7 @@
 	subql	#8,%sp			| make room for usp and orig_d0
 	movel	%d0,%sp@-
 	moveml	%d1-%a6,%sp@-
-	movec	%usp,%a0
+	move	%usp,%a0
 	movel	%a0,%sp@(LOFF_USP)
 	moveq	#-1,%d0
 	movel	%d0,%sp@(LOFF_ORIG_D0)	| a -1 in the ORIG_D0 field
@@ -131,7 +131,7 @@
 	subql	#8,%sp			| make room for usp and orig_d0
 	movel	%d0,%sp@-
 	moveml	%d1-%a6,%sp@-
-	movec	%usp,%a0
+	move	%usp,%a0
 	movel	%a0,%sp@(LOFF_USP)
 	moveq	#-1,%d0
 	movel	%d0,%sp@(LOFF_ORIG_D0)	| a -1 in the ORIG_D0 field
@@ -152,7 +152,7 @@
 	subql	#8,%sp			| make room for usp and orig_d0
 	pea	(-LENOSYS):w		| default return value in D0
 	moveml	%d1-%a6,%sp@-		| save registers
-	movec	%usp,%a0
+	move	%usp,%a0
 	movel	%a0,%sp@(LOFF_USP)	| save User Stack Pointer
 	movel	%d0,%sp@(LOFF_ORIG_D0)	| save original D0 (syscall #)
 	movel	%d0,%d2
@@ -225,7 +225,7 @@
 	andl	%a2@(LTS_SIGNAL),%d0
 	jne	Lsignal_return
 2:	movel	%sp@(LOFF_USP),%a0
-	movec	%a0,%usp
+	move	%a0,%usp
 	moveml	%sp@+,%d1-%a6
 	movel	%sp@+,%d0 		| restore d0
 	addql	#8,%sp			| skip the usp and orig_d0
@@ -346,7 +346,7 @@
 	moveml	%d1-%a6,%sp@-
 	moveq	#-1,%d0
 	movel	%d0,%sp@(LOFF_ORIG_D0)	| indicate stack frame not for syscall
-	movec	%usp,%a0
+	move	%usp,%a0
 	movel	%a0,%sp@(LOFF_USP)	| save usp
 
 	| save top of frame
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/arch/m68k/kernel/head.S linux-1.2.13pl3/arch/m68k/kernel/head.S
--- linux-1.2.13pl2/arch/m68k/kernel/head.S	Tue Sep 12 21:22:33 1995
+++ linux-1.2.13pl3/arch/m68k/kernel/head.S	Fri Oct 13 19:04:47 1995
@@ -623,32 +623,23 @@
 	cmpl	#MACH_ATARI,%d4
 	bne	Lmapphysnotatari
 
-#if 0
-
-/*
- * ALL THIS CODE SHOULD BE CHANGED TO DO THE RIGHT THING ON
- * THE ATARI PLATFORM!  NOTE: THE KERNEL VIRTUAL ADDRESS OF _START
- * IS 0x1000.  IF THE KERNEL IS LOADED AT THIS PHYSICAL ADDRESS,
- * THERE IS NO WORK TO DO.  OTHERWISE, SOMETHING LIKE WAS ORIGINALLY
- * DONE ON THE ATARI IN LINUX/68K 0.9 MUST BE DONE.
- */
-
-/* Andreas: I think it's ok to load the kernel at 0x1000, and leave
-   the mapping alone.  */
-
-	/* Temporarily set up an identity mapping of the 32MB chunk
-	   where the kernel is executing */
+	lea	%pc@(SYMBOL_NAME(_start)-PAGESIZE),%a0
+	tstl	%a0
+	jeq	Lnophys2
+
+	/* The kernel physical address is different from its virtual
+	   address.  Temporarily set up an identity mapping of the
+	   16MB chunk where the kernel is executing. */
 
 	/* 68040? */
 	btst	#BIT040,%d6
 	jeq	1f
 
-	/* same as Amiga code (transparent translation)
+	/*
 	 * For the 68040, we will use the transparent translation
 	 * registers to identity map the 16M chunk that contains
 	 * the physical memory.
 	 */
-	lea	%pc@(SYMBOL_NAME(_start)-PAGESIZE:w),%a0
 	movel	%a0,%d2
 	andl	#0xff000000,%d2		/* logical address base */
 	orw	#0xc040,%d2		/* add in magic bits */
@@ -661,22 +652,21 @@
 	 */
 	jra	Lnophys2
 
-	/* Transparent translation for the 68030 via early termination */
+	/* Transparent translation for the 68030 via transparent translation
+	   register */
 
+1:
 	/* cleanup is needed; note it */
 	moveq	#1,%d5
 
-1:	lea	%pc@(SYMBOL_NAME(_start)-PAGESIZE:w),%a0
 	movel	%a0,%d2
-	moveq	#25,%d3		/* find appropriate index in root table */
-	lsrl	%d3,%d2
-	movel	%d2,%d0
-	lsll	%d3,%d0		/* convert address into descriptor */
-	addql	#PAGEDESC,%d0
-	movel	%d0,%a5@(%d2:l:4)  /* store mapping */
-
-#endif
+	andl	#0xff000000,%d2		/* logical address base */
+	orw	#0x8143,%d2		/* add in magic bits */
+	lea	%pc@(mmu),%a0
+	movel	%d2,%a0@
+	pmove	%a0@,%tt0
 
+Lnophys2:
 	/*
  	 * save physaddr of phys mem in register a3
 	 */
@@ -700,7 +690,8 @@
 	movel	#0x82c07760,%a0@
 	pmove	%a0@,%tc		/* enable the MMU */
 
-	jra	LdoneMMUenable
+	/* Jump to the virtual address of continuation of startup. */
+	jmp	LdoneMMUenable
 
 Latarimmu68040:
 	moveq	#'L',%d7
@@ -712,7 +703,8 @@
 	.long	0x4e7bd806	/* movec a5,urp */
 	movel	#(TC_ENABLE+TC_PAGE4K),%d0
 	.long	0x4e7b0003	/* movec d0,tc  (enable the MMU) */
-	jra	LdoneMMUenable	/* branch to continuation of startup */
+	jmp	LdoneMMUenable	/* jump to virtual address of
+				   continuation of startup */
 
 Lmapphysnotatari:
 
@@ -772,8 +764,14 @@
 	cmpl	#MACH_ATARI,%d4
 	jne	Lnoclean
 
+	/* clear transparent translation register */
+	lea	%pc@(mmu),%a0
+	clrl	%a0@
+	pmove	%a0@,%tt0
+	jra	Lnoclean
+
 Lclean030:
-	movel	%a0,%d2		/* a0 contains physical start address */
+	movel	%a3,%d2		/* a3 contains physical start address */
 	moveq	#25,%d3		/* find appropriate index in root table */
 	lsrl	%d3,%d2
 	moveq	#0,%d0
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/arch/m68k/kernel/process.c linux-1.2.13pl3/arch/m68k/kernel/process.c
--- linux-1.2.13pl2/arch/m68k/kernel/process.c	Thu Sep 21 19:43:11 1995
+++ linux-1.2.13pl3/arch/m68k/kernel/process.c	Fri Oct 13 19:04:47 1995
@@ -81,7 +81,17 @@
 	p->tss.sr = 0x3000;
 	if (current->pid != 0 && user_mode(regs))
 		p->tss.fs = USER_DS;
-	p->tss.fpstate[0] = 0;
+
+	/* Copy the current fpu state */
+	asm volatile ("fsave %0" : : "m" (p->tss.fpstate[0]) : "memory");
+	if (p->tss.fpstate[0])
+	  asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
+			"fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
+			: : "m" (p->tss.fpregs[0]), "m" (p->tss.fpcntl[0])
+			: "memory");
+	/* Restore the state in case the fpu was busy */
+	asm volatile ("frestore %0" : : "m" (p->tss.fpstate[0]));
+
 	childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1;
 	*childregs = *regs;
 	childregs->d0 = 0;
@@ -94,6 +104,13 @@
 
 int dump_fpu (struct user_m68kfp_struct *fpu)
 {
+  char fpustate[216];
+
+  /* First dump the fpu context to avoid protocol violation.  */
+  asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
+  if (!fpustate[0])
+    return 0;
+
   asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
 		:: "m" (fpu->fpcntl[0])
 		: "memory");
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/arch/m68k/kernel/ptrace.c linux-1.2.13pl3/arch/m68k/kernel/ptrace.c
--- linux-1.2.13pl2/arch/m68k/kernel/ptrace.c	Tue Sep 12 21:17:39 1995
+++ linux-1.2.13pl3/arch/m68k/kernel/ptrace.c	Fri Oct 13 19:04:48 1995
@@ -462,6 +462,8 @@
 		case PTRACE_KILL: {
 			long tmp;
 
+			if (child->state == TASK_ZOMBIE) /* already dead */
+				return 0;
 			child->state = TASK_RUNNING;
 			child->exit_code = SIGKILL;
 	/* make sure the single step bit is not set. */
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/arch/m68k/kernel/traps.c linux-1.2.13pl3/arch/m68k/kernel/traps.c
--- linux-1.2.13pl2/arch/m68k/kernel/traps.c	Tue Sep 12 21:17:48 1995
+++ linux-1.2.13pl3/arch/m68k/kernel/traps.c	Fri Oct 13 19:04:49 1995
@@ -4,6 +4,7 @@
  *  Copyright (C) 1993, 1994 by Hamish Macdonald
  *
  *  68040 fixes by Michael Rausch
+ *  68040 fixes by Martin Apel
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file README.legal in the main directory of this archive
@@ -174,8 +175,7 @@
 	return mmusr;
 }
 
-static void do_040writeback (unsigned short itsnotme,
- 			     unsigned short ssw,
+static void do_040writeback (unsigned short ssw,
 			     unsigned short wbs,
 			     unsigned long wba,
 			     unsigned long wbd,
@@ -183,39 +183,18 @@
 {
 	unsigned long fs = get_fs ();
 	unsigned long mmusr;
-	unsigned long wba_2ndpage;
 	unsigned long errorcode;
 
-	if(itsnotme)
-	{
-		/*
-		 * to avoid another page fault, check the address we're going
-		 * to, and map it in
-		 */
-		mmusr = probe040 (1, wbs & WBTM_040,  wba);
-		errorcode = (mmusr & MMU_R_040) ? 3 : 2;
-		if (do_page_fault ((struct pt_regs *)fp, wba, errorcode))
-			/* just return if we can't perform the writeback */
-			return;
-	}
-
-	/*
-	 * if the write spans a page, make sure that the extra page
-	 * is mapped in.
-	 * MR: information concerning this may be retrieved from the SSW;
-	 * thus we can save us the page comparison
+	/* No special handling for the second writeback anymore.
+	 * It misinterpreted the misaligned status sometimes.
+	 * This way an extra pgae-fault may be caused (Martin Apel).
 	 */
-	if(ssw & MA_040)
-	{
-		/* Added missing parentheses (MA) */
-		wba_2ndpage = wba + (((wbs & WBSIZ_040)==BA_SIZE_WORD)?1:3);
-		mmusr = probe040 (1, wbs & WBTM_040, wba_2ndpage);
-		errorcode = (mmusr & MMU_R_040) ? 3 : 2;
-		if (do_page_fault ((struct pt_regs *)fp, wba_2ndpage,
-				   errorcode))
-			/* just return if we can't perform the writeback */
-			return;
-	}
+
+	mmusr = probe040 (1, wbs & WBTM_040,  wba);
+	errorcode = (mmusr & MMU_R_040) ? 3 : 2;
+	if (do_page_fault ((struct pt_regs *)fp, wba, errorcode))
+		/* just return if we can't perform the writeback */
+		return;
 
 	set_fs (wbs & WBTM_040);
 	switch (wbs & WBSIZ_040) {
@@ -239,15 +218,27 @@
 
 #ifdef DEBUG
 	printk("ssw=%#x, fa=%#lx\n", ssw, fp->un.fmt7.faddr);
+/*
+        printk("wb1s=%#x, wb2s=%#x, wb3s=%#x\n", fp->un.fmt7.wb1s,  
+		fp->un.fmt7.wb2s, fp->un.fmt7.wb3s);
+	printk ("wb2a=%lx, wb3a=%lx, wb2d=%lx, wb3d=%lx\n", 
+		fp->un.fmt7.wb2a, fp->un.fmt7.wb3a,
+		fp->un.fmt7.wb2d, fp->un.fmt7.wb3d);
+*/
 #endif
 
 	if (ssw & ATC_040) {
 		unsigned long addr = fp->un.fmt7.faddr;
 		unsigned long errorcode;
 
+		/* The MMU status has to be determined AFTER the address
+		 * has been corrected if there was a misaligned access (MA).
+		 */
+		if (ssw & MA_040)
+			addr = PAGE_ALIGN (addr);
+
 		/* MMU error, get the MMUSR info for this access */
 		mmusr = probe040 (!(ssw & RW_040), ssw & TM_040, addr);
-
 #ifdef DEBUG
 		printk("mmusr = %lx\n", mmusr);
 #endif
@@ -275,11 +266,11 @@
 	 */
 
 	if (fp->un.fmt7.wb2s & WBV_040 && (fp->un.fmt7.wb2s & WBTT_040) != BA_TT_MOVE16)
-		do_040writeback (!(ssw & RW_040), ssw,
+		do_040writeback (ssw,
 				 fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, fp->un.fmt7.wb2d, fp);
 
 	if (fp->un.fmt7.wb3s & WBV_040)
-		do_040writeback (1, ssw,
+		do_040writeback (ssw,
 				 fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, fp->un.fmt7.wb3d, fp);
 }
 
@@ -373,12 +364,12 @@
 #endif
 
 	    errorcode = (mmusr & MMU_I) ? 0 : 1;
-	    if (!(ssw & RW))
+	    if (!(ssw & RW) || ssw & RM)
 		    errorcode |= 2;
 
 	    if (mmusr & MMU_I)
 		    do_page_fault ((struct pt_regs *)fp, addr, errorcode);
-	    else if ((mmusr & MMU_WP) && !(ssw & RW))
+	    else if ((mmusr & MMU_WP) && (!(ssw & RW) || ssw & RM))
 		    do_page_fault ((struct pt_regs *)fp, addr, errorcode);
 	    else if (mmusr & (MMU_B|MMU_L|MMU_S)) {
 		    printk ("invalid %s access at %#lx from pc %#lx\n",
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/arch/m68k/mm/fault.c linux-1.2.13pl3/arch/m68k/mm/fault.c
--- linux-1.2.13pl2/arch/m68k/mm/fault.c	Fri Aug 18 20:01:12 1995
+++ linux-1.2.13pl3/arch/m68k/mm/fault.c	Fri Oct 13 19:04:49 1995
@@ -45,6 +45,14 @@
 		goto bad_area;
 	if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur)
 		goto bad_area;
+	if (user_mode(regs)) {
+		/* Accessing the stack below usp is always a bug.  The
+		   "+ 256" is there due to some instructions doing
+		   pre-decrement on the stack and that doesn't show up
+		   until later.  */
+		if (address + 256 < regs->usp)
+			goto bad_area;
+	}
 	vma->vm_offset -= vma->vm_start - (address & PAGE_MASK);
 	vma->vm_start = (address & PAGE_MASK);
 /*
@@ -70,6 +78,13 @@
 		return 0;
 	}
 	do_no_page(vma, address, error_code & 2);
+
+	/* There seems to be a missing invalidate somewhere in do_no_page.
+	 * Until I found it, this one cures the problem and makes
+	 * 1.2 run on the 68040 (Martin Apel).
+	 */
+	invalidate ();
+
 	return 0;
 
 /*
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/arch/m68k/mm/memory.c linux-1.2.13pl3/arch/m68k/mm/memory.c
--- linux-1.2.13pl2/arch/m68k/mm/memory.c	Tue Sep 12 21:17:50 1995
+++ linux-1.2.13pl3/arch/m68k/mm/memory.c	Sat Sep 30 10:01:13 1995
@@ -591,132 +591,3 @@
 
 	return( retaddr );
 }
-
-
-
-
-/* OLD CODE AFTER THIS */
-
-
-#if 0
-	/* the code from clone_page_tables */
-
-	unsigned long *root;
-
-	root = current->tss.pagedir_v;
-
-	/* XXX */
-	/*
-	 * root tables haven't got a use count in the mem_map
-	 * since there isn't a 1-1 relationship between pages
-	 * and root tables.
-	 *
-	 * Because of this, we will use a bletcherous hack where
-	 * the last entry in the root table (entry 127) contains
-	 * the number of uses - 1.
-	 * Thus a regular root table will have 0 in this entry.
-	 * A cloned root table will have > 0 in this entry.
-	 *
-	 * Note that this entry is never used by a user process.
-	 */
-	root[NUM_L1_ENTRIES-1]++;
-	tsk->tss.pagedir_v = root;
-	tsk->tss.pagedir_p = VTOP (root);
-	tsk->tss.crp[0] = 0x80000000 | PAGE_SHORT;
-	tsk->tss.crp[1] = tsk->tss.pagedir_p;
-	return 0;
-
-/* code from clear_page_tables */
-	/*
-	 * setup the user-mode root table, in case we were using the
-	 * swapper root table.
-	 */
-	tsk->tss.crp[1] = tsk->tss.pagedir_p;
-	if (tsk == current)
-		if (m68k_is040)
-			asm ("movel %0,%/d0\n\t"
-			     ".long 0x4e7b0806" /* movec d0,urp */
-			     : /* no outputs */
-			     : "g" (tsk->tss.crp[1])
-			     : "d0");
-		else
-			asm ("pmove %0@,%/crp"
-			     : /* no outputs */
-			     : "a" (tsk->tss.crp));
-
-	/* XXX */
-	/*
-	 * root tables haven't got a use count in the mem_map
-	 * since there isn't a 1-1 relationship between pages
-	 * and root tables.
-	 *
-	 * Because of this, we will use a bletcherous hack where
-	 * the last entry in the root table (entry 127) contains
-	 * the number of uses - 1.
-	 * Thus a regular root table will have 0 in this entry.
-	 * A cloned root table will have > 0 in this entry.
-	 *
-	 * Note that this entry is never used by a user process.
-	 */
-	if (page_dir[NUM_L1_ENTRIES-1] > 0) {
-		unsigned long *new_root;
-
-		if (!(new_root = get_root_table ())) {
-			oom(tsk);
-			return;
-		}
-		for (i = 0; i < NUM_L1_ENTRIES-1; i++)
-			new_root[i] = page_dir[i];
-		new_root[NUM_L1_ENTRIES-1] = 0;
-		page_dir[NUM_L1_ENTRIES-1]--;
-#if 0 /* XXX */
-		SET_PAGE_DIR(tsk, new_root);
-#endif
-		tsk->tss.pagedir_v = new_root;
-		tsk->tss.pagedir_p = VTOP(new_root);
-		return;
-	}
-	for (i = 0 ; i < NUM_L1_ENTRIES-1; i++, root++)
-		free_one_ptr_table(page_dir);
-	invalidate();
-	return;
-
-/* from free_page_tables */
-	root = tsk->tss.pagedir_v;
-	if (!root)
-	  return;
-	if (root == task[0]->tss.pagedir_v) {
-		printk("Trying to free kernel root table: not good\n");
-		return;
-	}
-	/* XXX */
-	/*
-	 * root tables haven't got a use count in the mem_map
-	 * since there isn't a 1-1 relationship between pages
-	 * and root tables.
-	 *
-	 * Because of this, we will use a bletcherous hack where
-	 * the last entry in the root table (entry 127) contains
-	 * the number of uses - 1.
-	 * Thus a regular root table will have 0 in this entry.
-	 * A cloned root table will have > 0 in this entry.
-	 *
-	 * Note that this entry is never used by a user process.
-	 */
-	if (root[NUM_L1_ENTRIES-1] > 0) {
-		root[NUM_L1_ENTRIES-1]--;
-		tsk->tss.pagedir_v = 0;
-		tsk->tss.pagedir_p = 0;
-		return;
-	}
-
-	for (i = 0 ; i < NUM_L1_ENTRIES-1; i++, root++)
-		free_one_ptr_table(root);
-
-	free_root_table (tsk->tss.pagedir_v);
-	tsk->tss.pagedir_v = 0;
-	tsk->tss.pagedir_p = 0;
-	invalidate();
-
-
-#endif
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/drivers/block/amiflop.c linux-1.2.13pl3/drivers/block/amiflop.c
--- linux-1.2.13pl2/drivers/block/amiflop.c	Tue Sep 12 21:17:56 1995
+++ linux-1.2.13pl3/drivers/block/amiflop.c	Sun Oct  1 11:49:58 1995
@@ -1546,6 +1546,7 @@
 
 void amifd_setup (char *str, int *ints)
 {
+printk ("amiflop: Setting default df0 to %x\n", ints[1]);
 fd_def_df0 = ints[1];
 }
 
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/drivers/block/ataflop.c linux-1.2.13pl3/drivers/block/ataflop.c
--- linux-1.2.13pl2/drivers/block/ataflop.c	Tue Sep 12 21:17:58 1995
+++ linux-1.2.13pl3/drivers/block/ataflop.c	Fri Oct 13 19:04:50 1995
@@ -438,17 +438,16 @@
 	if (++drive > 1 || !unit[drive].connected)
 		drive = 0;
 
-	if (!stdma_islocked()) {
+	save_flags(flags);
+	cli();
 
-		save_flags(flags);
-		cli();
+	if (!stdma_islocked()) {
 		sound_ym.rd_data_reg_sel = 14;
 		old_porta = sound_ym.rd_data_reg_sel;
 		sound_ym.wd_data = (old_porta | DSKDRVNONE) &
 			               ~(drive == 0 ? DSKDRV0 : DSKDRV1);
 		stat = !!(FDC_READ( FDCREG_STATUS ) & FDCSTAT_WPROT);
 		sound_ym.wd_data = old_porta;
-		restore_flags(flags);
 
 		if (stat != unit[drive].wpstat) {
 			DPRINT(( "wpstat[%d] = %d\n", drive, stat ));
@@ -456,7 +455,8 @@
 			set_bit (drive, &changed_floppies);
 		}
 	}
-	
+	restore_flags(flags);
+
 	START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY );
 }
 
@@ -1571,7 +1571,7 @@
 	BufferDrive = -1;
 #endif
 
-	/* initialize motor-off timer */
+	/* initialize check_change timer */
 	timer_table[FLOPPY_TIMER].fn = check_change;
 	timer_active &= ~(1 << FLOPPY_TIMER);
 
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/drivers/char/Makefile linux-1.2.13pl3/drivers/char/Makefile
--- linux-1.2.13pl2/drivers/char/Makefile	Fri Aug 18 17:38:21 1995
+++ linux-1.2.13pl3/drivers/char/Makefile	Wed Sep 27 07:46:22 1995
@@ -58,8 +58,6 @@
 ifdef CONFIG_PRINTER
 OBJS := $(OBJS) lp.o
 SRCS := $(SRCS) lp.c
-else
-MODULES := $(MODULES) lp.o
 endif
 
 ifdef CONFIG_MS_BUSMOUSE
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/drivers/char/atari_SCC.c linux-1.2.13pl3/drivers/char/atari_SCC.c
--- linux-1.2.13pl2/drivers/char/atari_SCC.c	Tue Sep 12 21:18:02 1995
+++ linux-1.2.13pl3/drivers/char/atari_SCC.c	Fri Oct 13 19:04:51 1995
@@ -269,6 +269,10 @@
 /* For which line has channel A been opened? */
 static int SCC_chan_a_line;
 
+/* Are the register addresses for the channels reversed? (B before A). This is
+ * the case for the ST_ESCC. */
+static int ChannelsReversed;
+
 /* This macro sets up the 'info' pointer for the interrupt functions of
  * channel A. It addresses the following problem: The isrs were registered
  * with callback_data == &rs_table[3] (= Serial2). But they can also be for
@@ -362,11 +366,21 @@
 		return;
 
 	info->type            = type;
-	info->port            = (int)(channel ? &scc.cha_b_ctrl
-					      : &scc.cha_a_ctrl);
 	info->sw              = &SCC_switch;
 	/* The SERTYPE (with or without DMA) is ignored for now... */
 
+	if (ATARIHW_PRESENT( ST_ESCC )) {
+		/* The ST_ESCC has the addresses for its channels reversed! */
+		info->port = (int)(channel ? &st_escc.cha_a_ctrl :
+				   &st_escc.cha_b_ctrl);
+		ChannelsReversed = 1;
+	}
+	else {
+		info->port = (int)(channel ? &scc.cha_b_ctrl :
+				   &scc.cha_a_ctrl);
+		ChannelsReversed = 0;
+	}
+
 	/* set ISRs, but don't enable interrupts yet (done in init()) */
 	if (channel == CHANNEL_B || !ch_a_inited) {
 		add_isr (channel ? IRQ_SCCB_TX : IRQ_SCCA_TX,
@@ -693,8 +707,8 @@
 		{ COMMAND_REG, CR_EXTSTAT_RESET },
 		/* ...again */
 		{ COMMAND_REG, CR_EXTSTAT_RESET },
-		/* Rx int always, TX int on, Ext/Stat int on */
-		{ INT_AND_DMA_REG, IDR_EXTSTAT_INT_ENAB | IDR_TX_INT_ENAB |
+		/* 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 }
 	};
 
@@ -1044,7 +1058,7 @@
 
 static unsigned int SCC_get_modem_info( struct async_struct *info )
 {
-	unsigned	sr, tcr, ri;
+	unsigned	sr, tcr, ri, dsr;
 	unsigned long	flags;
 
 	save_flags(flags);
@@ -1063,12 +1077,16 @@
 	else
 	  ri = mfp.par_dt_reg & (1 << 6) ? 0 : TIOCM_RNG;
 
+	if (ATARIHW_PRESENT (ST_ESCC))
+	  dsr = st_escc_dsr & (1 << (3 - CHANNR(info))) ? TIOCM_DSR : 0;
+	else
+	  dsr = sr & SR_SYNC_ABORT ? TIOCM_DSR : 0;
+
 	return (((tcr & TCR_RTS) ? TIOCM_RTS : 0) |
 		((tcr & TCR_DTR) ? TIOCM_DTR : 0) |
 		((sr & SR_DCD ) ? TIOCM_CAR : 0) |
 		((sr & SR_CTS ) ? TIOCM_CTS : 0) |
-		(sr & SR_SYNC_ABORT ? TIOCM_DSR : 0) |
-		ri);
+		dsr | ri);
 }
 
 
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/drivers/char/atari_SCC.h linux-1.2.13pl3/drivers/char/atari_SCC.h
--- linux-1.2.13pl2/drivers/char/atari_SCC.h	Thu Aug 10 18:34:21 1995
+++ linux-1.2.13pl3/drivers/char/atari_SCC.h	Fri Oct 13 19:04:52 1995
@@ -1,5 +1,5 @@
 /*
- * atari_SCC.h: Definitions for the Am8530 Serial Communcications Controller
+ * atari_SCC.h: Definitions for the Am8530 Serial Communications Controller
  *
  * Copyright 1994 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
  *
@@ -316,7 +316,7 @@
 
 /* Compute the channel number from the base address */
 
-#define CHANNR(info)	(((info)->port & 4) != 0)
+#define CHANNR(info)	(((info)->port & 4) != ChannelsReversed)
 
 
 /***********************************************************************/
@@ -369,6 +369,7 @@
 
 
 extern unsigned char	SCC_shadow[16];
+extern int ChannelsReversed;
 
 
 /* The following functions should relax the somehow complicated
@@ -516,7 +517,8 @@
 		
 	  case INT_PENDING_REG:
 		/* RR3: read only from Channel A! */
-		sc = (volatile struct PARTIAL_SCC *)(info->port & ~4);
+		sc = (volatile struct PARTIAL_SCC *)
+			((info->port & ~4) ^ (ChannelsReversed << 2));
 		goto normal_case;
 
 	  case RX_DATA_REG:
@@ -526,7 +528,8 @@
 
 	  case CURR_VECTOR_REG:
 		/* RR2 (vector including status) from Ch. B */
-		sc = (volatile struct PARTIAL_SCC *)(info->port | 4);
+		sc = (volatile struct PARTIAL_SCC *)
+			((info->port | 4) ^ (ChannelsReversed << 2));
 		goto normal_case;
 		
 		/* --- reading write registers: access the shadow --- */
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/drivers/char/fbmem.c linux-1.2.13pl3/drivers/char/fbmem.c
--- linux-1.2.13pl2/drivers/char/fbmem.c	Thu Jul 27 19:20:40 1995
+++ linux-1.2.13pl3/drivers/char/fbmem.c	Fri Oct 13 18:50:15 1995
@@ -46,6 +46,10 @@
 	if (!current->tty)
 		return fg_console;
 
+	if (current->tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
+		/* XXX Should report error here? */
+		return fg_console;
+
 	if (MINOR(current->tty->device) < 1)
 		return fg_console;
 
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/drivers/char/serial.c linux-1.2.13pl3/drivers/char/serial.c
--- linux-1.2.13pl2/drivers/char/serial.c	Tue Sep 12 21:18:06 1995
+++ linux-1.2.13pl3/drivers/char/serial.c	Fri Oct 13 19:04:53 1995
@@ -1083,6 +1083,8 @@
 	if ((line < 0) || (line >= NR_PORTS))
 		return -ENODEV;
 	info = rs_table + line;
+	if (!info->port)
+		return -ENODEV;
 	if (serial_paranoia_check(info, tty->device, "rs_open"))
 		return -ENODEV;
 
@@ -1284,7 +1286,7 @@
 	    case MACH_ATARI:
 #ifdef CONFIG_ATARI
 		{
-		int sccp = ATARIHW_PRESENT(SCC);
+		int sccp = ATARIHW_PRESENT(SCC) || ATARIHW_PRESENT(ST_ESCC);
 		int sccdma = ATARIHW_PRESENT(SCC_DMA);
 		int stmfp = ATARIHW_PRESENT(ST_MFP);
 		int ttmfp = ATARIHW_PRESENT(TT_MFP);
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/drivers/net/a2065.c linux-1.2.13pl3/drivers/net/a2065.c
--- linux-1.2.13pl2/drivers/net/a2065.c	Thu Jun 22 21:01:43 1995
+++ linux-1.2.13pl3/drivers/net/a2065.c	Fri Oct 13 18:11:40 1995
@@ -174,6 +174,7 @@
 			dev->get_stats = &a2065_get_stats;
 			dev->set_multicast_list = &set_multicast_list;
 
+			boot_info.bi_amiga.autocon_configured |= 1<<i;
 			i++;									/* Mark this board as visited */
 			return(0);
 		}
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/drivers/net/ariadne.c linux-1.2.13pl3/drivers/net/ariadne.c
--- linux-1.2.13pl2/drivers/net/ariadne.c	Tue Sep 12 22:24:52 1995
+++ linux-1.2.13pl3/drivers/net/ariadne.c	Fri Oct 13 18:11:41 1995
@@ -152,7 +152,7 @@
 	for (; i < boot_info.bi_amiga.num_autocon; i++) {
 		manuf = boot_info.bi_amiga.autocon[i].cd_Rom.er_Manufacturer;
 		product = boot_info.bi_amiga.autocon[i].cd_Rom.er_Product;
-		if ((manuf == MANUF_VILLAGETRONIC) && (product == PROD_ARIADNE) &&
+		if ((manuf == MANUF_VILLAGE_TRONIC) && (product == PROD_ARIADNE) &&
 			 (board = (u_long)boot_info.bi_amiga.autocon[i].cd_BoardAddr)) {
 			dev->dev_addr[0] = 0x00;
 			dev->dev_addr[1] = 0x80;
@@ -178,6 +178,7 @@
 			dev->get_stats = &ariadne_get_stats;
 			dev->set_multicast_list = &set_multicast_list;
 
+			boot_info.bi_amiga.autocon_configured |= 1<<i;
 			i++;									/* Mark this board as visited */
 			return(0);
 		}
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/drivers/net/hydra.c linux-1.2.13pl3/drivers/net/hydra.c
--- linux-1.2.13pl2/drivers/net/hydra.c	Tue Sep 12 22:24:53 1995
+++ linux-1.2.13pl3/drivers/net/hydra.c	Fri Oct 13 18:11:47 1995
@@ -100,18 +100,20 @@
 #endif
 
 
-/* this is not (yet) coherent to the C version below, do not use. */
-/* i will complete this as soon as the other bugs have been fixed */
-/* the speed difference won't be huge anyways */
+/* this is now coherent to the C version below, */
+/* compile the source with -D__USE_ASM__ if you */
+/* want it - it'll only be some 10% faster thou */
 
-#if defined (__GNUC__) && defined (__mc68000__) && defined (USE_ASM)
+#if defined (__GNUC__) && defined (__mc68000__) && defined (__USE_ASM__)
 
 static __inline__ void *memcpyw(u_short *dest, u_short *src, int len)
     {
     __asm__("   move.l %0,%/a1; move.l %1,%/a0; move.l %2,%/d0 \n\t"
-	    "   lsr.l  #1,%/d0 \n\t"
+	    "   btst.l #0,%/d0 \n\t"
+	    "   beq.s  1f \n\t"
+	    "   addq.l #1,%/d0 \n\t"
             "1: move.w %/a0@+,%/a1@+ \n\t"
-	    "   subq.l #1,%/d0 \n\t"
+	    "   subq.l #2,%/d0 \n\t"
 	    "   bne.s  1b \n\t"
 	  :
 	  : "g" (dest), "g" (src), "g" (len)
@@ -152,7 +154,7 @@
         manuf = boot_info.bi_amiga.autocon[i].cd_Rom.er_Manufacturer;
 	product = boot_info.bi_amiga.autocon[i].cd_Rom.er_Product;
 	if((manuf == MANUF_HYDRA_SYSTEMS) && (product == PROD_AMIGANET) &&
-	   (board = (u_long) boot_info.bi_amiga.autocon[i].cd_BoardAddr))
+	   (board = (u_long) ZTWO_VADDR(boot_info.bi_amiga.autocon[i].cd_BoardAddr)))
 	    {
 	    for(j = 0; j < ETHER_ADDR_LEN; j++)
                 dev->dev_addr[j] = *((u_char *)(board + HYDRA_ADDRPROM + 2*j));
@@ -167,7 +169,7 @@
 	    priv = (struct hydra_private *)dev->priv;
 	    memset(priv, 0, sizeof(struct hydra_private));
 	    
-	    priv->hydra_base = (u_char *)ZTWO_VADDR(board);
+	    priv->hydra_base = (u_char *) board;
 	    priv->hydra_nic_base = (u_char *) board + HYDRA_NIC_BASE;
 	    
 	    dev->open = &hydra_open;
@@ -177,6 +179,7 @@
 #ifdef HAVE_MULTICAST
 	    dev->set_multicast_list = &hydra_set_multicast_list;
 #endif
+	    boot_info.bi_amiga.autocon_configured |= 1<<i;
 	    i++;	      		/* Mark this board as visited */
 	    return(0);
             }
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/drivers/net/slhc.c linux-1.2.13pl3/drivers/net/slhc.c
--- linux-1.2.13pl2/drivers/net/slhc.c	Tue Sep 12 21:18:10 1995
+++ linux-1.2.13pl3/drivers/net/slhc.c	Fri Oct 13 19:04:54 1995
@@ -255,7 +255,7 @@
 	ip = (struct iphdr *) icp;
 
 	/* Bail if this packet isn't TCP, or is an IP fragment */
-	if(ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x1fff) ||
+	if(ip->protocol != IPPROTO_TCP || (ip->frag_off & htons(IP_OFFSET)) ||
 				       (ip->frag_off & htons (IP_MF))){
 		/* Send as regular IP */
 		if(ip->protocol != IPPROTO_TCP)
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/drivers/scsi/a2091.c linux-1.2.13pl3/drivers/scsi/a2091.c
--- linux-1.2.13pl2/drivers/scsi/a2091.c	Tue Sep 12 21:18:11 1995
+++ linux-1.2.13pl3/drivers/scsi/a2091.c	Fri Oct 13 18:11:47 1995
@@ -208,6 +208,7 @@
 		add_isr(IRQ_AMIGA_PORTS, a2091_intr, 0, NULL);
 	    }
 	    DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
+	    boot_info.bi_amiga.autocon_configured |= 1<<i;
 	}
     }
 
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/drivers/scsi/a3000.c linux-1.2.13pl3/drivers/scsi/a3000.c
--- linux-1.2.13pl2/drivers/scsi/a3000.c	Tue Sep 12 21:18:12 1995
+++ linux-1.2.13pl3/drivers/scsi/a3000.c	Fri Oct 13 17:37:49 1995
@@ -87,13 +87,27 @@
     /* setup DMA *physical* address */
     DMA(a3000_host)->ACR = addr;
 
-    if (dir_in){
-	/* invalidate any cache */
-	cache_clear (addr, cmd->SCp.this_residual);
-    }else{
-	/* push any dirty cache */
-	cache_push (addr, cmd->SCp.this_residual);
+
+    if (dir_in)
+      {
+  	/* invalidate any cache */
+        /*
+         * On the 68040 it's not ok to use cache_clear, as it just invalidates
+         * cache-lines, and thereby trashing them. We need to use cache_push
+         * to avoid problems/crashes.
+         * This was a real bitch to catch :-( -Jes
+         */
+
+        if (boot_info.cputype & CPU_68040)
+	  cache_push (addr, cmd->SCp.this_residual);
+	else
+	  cache_clear (addr, cmd->SCp.this_residual);
       }
+    else
+      /* push any dirty cache */
+      cache_push (addr, cmd->SCp.this_residual);
+      
+
     /* start DMA */
     DMA(a3000_host)->ST_DMA = 1;
 
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/drivers/scsi/atari_NCR5380.c linux-1.2.13pl3/drivers/scsi/atari_NCR5380.c
--- linux-1.2.13pl2/drivers/scsi/atari_NCR5380.c	Tue Sep 12 21:18:15 1995
+++ linux-1.2.13pl3/drivers/scsi/atari_NCR5380.c	Fri Oct 13 19:04:58 1995
@@ -695,6 +695,8 @@
     struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
 	cmd->host->hostdata;
     Scsi_Cmnd *tmp;
+    int oldto;
+    extern int update_timeout(Scsi_Cmnd * SCset, int timeout);
 
 #if (NDEBUG & NDEBUG_NO_WRITE)
     switch (cmd->cmnd[0]) {
@@ -728,6 +730,20 @@
      */
 
     cli();
+    /* ++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.
+     */
+    if (!IS_A_TT()) {
+	oldto = update_timeout(cmd, 0);
+	falcon_get_lock();
+	update_timeout(cmd, oldto);
+    }
     if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
 	cmd->host_scribble = (unsigned char *) hostdata->issue_queue;
 	hostdata->issue_queue = cmd;
@@ -736,10 +752,6 @@
 		tmp = (Scsi_Cmnd *) tmp->host_scribble);
 	tmp->host_scribble = (unsigned char *) cmd;
     }
-    /* ++guenther: now that the issue queue is set up, we can lock ST-DMA.
-     * Otherwise NCR5380_information_transfer may steal the lock.
-     */
-    falcon_get_lock();
 /*    sti(); */
 
 #if (NDEBUG & NDEBUG_QUEUES)
@@ -806,11 +818,13 @@
 		    /*  When we find one, remove it from the issue queue. */
 		    /* ++guenther: possible race with Falcon locking */
 		    if (!(hostdata->busy[tmp->target] & (1 << tmp->lun))) {
-			    if (prev)
-				prev->host_scribble = tmp->host_scribble;
-			    else
-				hostdata->issue_queue = (Scsi_Cmnd *) tmp->host_scribble;
+			cli(); /* ++guenther: just to be sure, this must be atomic */
+			if (prev)
+			    prev->host_scribble = tmp->host_scribble;
+			else
+			    hostdata->issue_queue = (Scsi_Cmnd *) tmp->host_scribble;
 			tmp->host_scribble = NULL;
+			falcon_dont_release++;
 
 			/* reenable interrupts after finding one */
 			acknowledge_scsi_int();
@@ -836,6 +850,8 @@
 			if (!NCR5380_select(instance, tmp, 
 			    (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : 
 			    TAG_NEXT)) {
+			    cli();falcon_dont_release--;sti();
+			    /* release if target did not response! */
 			    falcon_release_lock_if_possible( hostdata );
 			    break;
 			} else {
@@ -843,6 +859,7 @@
 			    tmp->host_scribble = (unsigned char *) 
 				hostdata->issue_queue;
 			    hostdata->issue_queue = tmp;
+			    falcon_dont_release--;
 			    sti();
 #if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES))
 			printk("scsi%d : main(): select() failed, returned to issue_queue\n",
@@ -852,7 +869,7 @@
 				break;
 			}
 		    } /* if target/lun is not busy */
-		}
+		} /* for issue_queue */
 	    } /* if (!hostdata->connected) */
 		
 	    if (hostdata->connected 
@@ -871,8 +888,10 @@
 		printk("scsi%d : main() : done set false\n", instance->host_no);
 #endif
 		done = 0;
-	    } else 
+	    } else {
+		cli(); /* ++guenther: be sure to protect main_running */
 		break;
+	    }
 	} /* for instance */
     } while (!done);
     main_running = 0;
@@ -1172,9 +1191,11 @@
 	return -1;
     }
 
-
-
-    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL);
+     /* 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) {
@@ -1191,10 +1212,14 @@
      * Again, bus clear + bus settle time is 1.2us, however, this is 
      * a minimum so we'll udelay ceil(1.2)
      */
-    /* ++roman: But some targets seem to need a bit more... */
-	
-    udelay(9);	
 
+#ifdef CONFIG_ATARI_SCSI_TOSHIBA_DELAY
+    /* ++roman: But some targets (see above :-) seem to need a bit more... */
+    udelay(15);
+#else
+    udelay(2);
+#endif
+    
     if (hostdata->connected) {
 	NCR5380_write(MODE_REG, MR_BASE);
 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
@@ -1810,7 +1835,10 @@
 		    /* Accept message by clearing ACK */
 		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 		    /* ++guenther: possible race with Falcon locking */
+		    cli();
+		    falcon_dont_release++;
 		    hostdata->connected = NULL;
+		    sti();
 #if (NDEBUG & NDEBUG_QUEUES)
 		    printk("scsi%d : command for target %d, lun %d completed\n",
 			instance->host_no, cmd->target, cmd->lun);
@@ -1883,7 +1911,8 @@
 		    while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
 			barrier();
 
-		    /* ++roman: For Falcon SCSI, release the lock an on the
+		    cli();falcon_dont_release--;sti();
+		    /* ++roman: For Falcon SCSI, release the lock on the
 		     * ST-DMA here if no other commands are waiting on the
 		     * disconnected queue.
 		     */
@@ -2177,9 +2206,6 @@
 	 * just reestablished, and remove it from the disconnected queue.
 	 */
 
-
-	save_flags(flags);
-	cli(); /* ++guenther: prevent race with falcon_release_lock */
 	for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; 
 	    tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) 
 	    if ((target_mask == (1 << tmp->target)) && (lun == tmp->lun)
@@ -2187,6 +2213,10 @@
 	    && (tag == tmp->tag) 
 #endif
 ) {
+	    save_flags(flags);
+	    cli(); /* ++guenther: prevent race with falcon_release_lock */
+	    falcon_dont_release++;
+	    restore_flags(flags);
 	    if (prev)
 		prev->host_scribble = tmp->host_scribble;
 	    else
@@ -2196,7 +2226,6 @@
 	}
 
 	if (!tmp) {
-	    restore_flags(flags);
 #ifdef SCSI2
 	    printk("scsi%d : warning : target bitmask %02x lun %d tag %d not in disconnect_queue.\n",
 		    instance->host_no, target_mask, lun, tag);
@@ -2221,11 +2250,14 @@
 	NCR5380_transfer_pio(instance, &phase, &len, &data);
     } else {
 	hostdata->connected = tmp;
-	restore_flags(flags);
 #if (NDEBUG & NDEBUG_RESELECTION)
 	printk("scsi%d : nexus established, target = %d, lun = %d, tag = %d\n",
 	    instance->host_no, tmp->target, tmp->lun, tmp->tag);
 #endif
+	save_flags(flags);
+	cli();
+	falcon_dont_release--;
+	restore_flags(flags);
     }
 }
 
@@ -2270,6 +2302,9 @@
     cli();
     NCR5380_setup(instance);
     
+    if (!IS_A_TT() && !falcon_got_lock)
+	printk("!!BINGO!! Falcon has no lock in NCR5380_abort\n");
+
 #if (NDEBUG & NDEBUG_ABORT)
     printk("scsi%d : abort called\n", instance->host_no);
     printk("        basr 0x%X, sr 0x%X\n", 
@@ -2460,6 +2495,9 @@
     NCR5380_local_declare();
     NCR5380_setup(cmd->host);
 
+    if (!IS_A_TT() && !falcon_got_lock)
+	printk("!!BINGO!! Falcon has no lock in NCR5380_reset\n");
+
     NCR5380_print_status (cmd->host);
 
     /* get in phase */
@@ -2506,10 +2544,18 @@
 #if defined(REAL_DMA)
     hostdata->dma_len = 0;
 #endif
-    
+
+    /* ++guenther: main may not be running, the scsi_done's above inserted
+     * the commands on the issue queue, but if the lun's were busy, main
+     * left without doing anything. Restart it now.
+     */
+    run_main();
 /* The Falcon lock should be released after a reset...
  */
-    falcon_release_lock_if_possible( hostdata );
+/* ++guenther: moved to atari_scsi_reset(), to prevent a race between
+ * unlocking and enabling dma interrupt.
+ */
+/*    falcon_release_lock_if_possible( hostdata );*/
 
     return SCSI_RESET_WAKEUP;
 }
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/drivers/scsi/atari_scsi.c linux-1.2.13pl3/drivers/scsi/atari_scsi.c
--- linux-1.2.13pl2/drivers/scsi/atari_scsi.c	Tue Sep 12 21:18:17 1995
+++ linux-1.2.13pl3/drivers/scsi/atari_scsi.c	Fri Oct 13 19:04:58 1995
@@ -406,6 +406,7 @@
 static struct wait_queue	*falcon_fairness_wait = NULL;
 static int					falcon_trying_lock = 0;
 static struct wait_queue	*falcon_try_wait = NULL;
+static int			falcon_dont_release = 0;
 
 /* This function releases the lock on the DMA chip if there is no
  * connected command and the disconnected queue is empty. On
@@ -418,24 +419,31 @@
 falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata )
 
 {
+	unsigned long	oldflags;
+		
 	if (IS_A_TT()) return;
 	
+	save_flags(oldflags);
+	cli();
+
 	if (falcon_got_lock &&
 		!hostdata->disconnected_queue &&
 		!hostdata->issue_queue &&
 		!hostdata->connected) {
 
-		unsigned long	oldflags;
-
-		save_flags(oldflags);
-		cli();
-		
+		if (falcon_dont_release) {
+#if 0
+			printk("WARNING: Lock release not allowed. Ignored\n");
+#endif
+			restore_flags(oldflags);
+			return;
+		}
 		falcon_got_lock = 0;
 		stdma_release();
 		wake_up( &falcon_fairness_wait );
-
-		restore_flags(oldflags);
 	}
+
+	restore_flags(oldflags);
 }
 
 /* This function manages the locking of the ST-DMA.
@@ -457,12 +465,12 @@
 
 {
 	unsigned long	oldflags;
-	
+
 	if (IS_A_TT()) return;
 
 	save_flags(oldflags);
 	cli();
-	
+
 	while( intr_count == 0 && falcon_got_lock && stdma_others_waiting() )
 		sleep_on( &falcon_fairness_wait );
 
@@ -619,33 +627,38 @@
 int atari_scsi_reset( Scsi_Cmnd *cmd )
 {
 	int		rv;
+	struct NCR5380_hostdata *hostdata =
+		(struct NCR5380_hostdata *)cmd->host->hostdata;
 
 	/* For doing the reset, SCSI interrupts must be disabled first,
 	 * since the 5380 raises its IRQ line while _RST is active and we
 	 * can't disable interrupts completely, since we need the timer.
 	 */
-	
-	if (IS_A_TT())
-		tt_mfp.int_en_a &= ~0x80;
-	else
-		mfp.int_en_b &= ~0x80;
-
-	rv = NCR5380_reset( cmd );
-
-	/* Re-enable ints and abort a maybe active DMA transfer */
+	/* And abort a maybe active DMA transfer */
 	if (IS_A_TT()) {
+		tt_mfp.int_en_a &= ~0x80;
 #ifdef REAL_DMA
 		tt_scsi_dma.dma_ctrl = 0;
 #endif /* REAL_DMA */
-		tt_mfp.int_en_a |= 0x80;
 	}
 	else {
+		mfp.int_en_b &= ~0x80;
 #ifdef REAL_DMA
 		st_dma.dma_mode_status = 0x90;
 		atari_dma_active = 0;
 #endif /* REAL_DMA */
+	}
+
+	rv = NCR5380_reset( cmd );
+
+	/* Re-enable ints */
+	if (IS_A_TT()) {
+		tt_mfp.int_en_a |= 0x80;
+	}
+	else {
 		mfp.int_en_b |= 0x80;
 	}
+	falcon_release_lock_if_possible(hostdata);
 
 	return( rv );
 }
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/drivers/scsi/gvp11.c linux-1.2.13pl3/drivers/scsi/gvp11.c
--- linux-1.2.13pl2/drivers/scsi/gvp11.c	Mon Jun 19 19:19:18 1995
+++ linux-1.2.13pl3/drivers/scsi/gvp11.c	Fri Oct 13 18:11:48 1995
@@ -213,6 +213,7 @@
 		add_isr(IRQ_AMIGA_PORTS, gvp11_intr, 0, NULL);
 	    }
 	    DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
+	    boot_info.bi_amiga.autocon_configured |= 1<<i;
 	}
     }
 
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/drivers/scsi/hosts.c linux-1.2.13pl3/drivers/scsi/hosts.c
--- linux-1.2.13pl2/drivers/scsi/hosts.c	Wed Feb 22 16:45:53 1995
+++ linux-1.2.13pl3/drivers/scsi/hosts.c	Fri Oct 13 17:50:38 1995
@@ -57,7 +57,7 @@
 #endif
 
 /*
-static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/hosts.c,v 1.3 1993/09/24 12:21:00 drew Exp drew $";
+static const char RCSid[] = "$Header: /root/linux/drivers/scsi/RCS/hosts.c,v 1.1 1995/08/12 14:55:19 root Exp root $";
 */
 
 /*
@@ -155,6 +155,7 @@
 						      (tpnt->unchecked_isa_dma && j ? GFP_DMA : 0) | GFP_ATOMIC);
 	retval->host_busy = 0;
 	retval->block = NULL;
+ 	retval->disabled = 0;
 	retval->wish_block = 0;
 	if(j > 0xffff) panic("Too many extra bytes requested\n");
 	retval->extra_bytes = j;
@@ -248,7 +249,7 @@
 		name = shpnt->hostt->info(shpnt);
 	      else
 		name = shpnt->hostt->name;
-	      printk ("scsi%d : %s\n", /* And print a little message */
+	      printk ("scsi%d: %s\n", /* And print a little message */
 		      shpnt->host_no, name);
 	    }
 
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/drivers/scsi/hosts.h linux-1.2.13pl3/drivers/scsi/hosts.h
--- linux-1.2.13pl2/drivers/scsi/hosts.h	Wed Feb 22 16:45:54 1995
+++ linux-1.2.13pl3/drivers/scsi/hosts.h	Fri Oct 13 17:51:20 1995
@@ -17,7 +17,7 @@
 #define _HOSTS_H
 
 /*
-	$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/hosts.h,v 1.3 1993/09/24 12:21:00 drew Exp drew $
+	$Header: /root/linux/drivers/scsi/RCS/hosts.h,v 1.1 1995/08/12 14:53:09 root Exp root $
 */
 
 
@@ -244,6 +244,7 @@
 		   command on this host. */
 		struct Scsi_Host * block;
 		unsigned wish_block:1;
+ 		unsigned disabled:1;
 
 		/* These parameters should be set by the detect routine */
 		unsigned char *base;
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/drivers/scsi/scsi.c linux-1.2.13pl3/drivers/scsi/scsi.c
--- linux-1.2.13pl2/drivers/scsi/scsi.c	Tue Sep 12 21:18:19 1995
+++ linux-1.2.13pl3/drivers/scsi/scsi.c	Fri Oct 13 19:05:00 1995
@@ -44,7 +44,7 @@
 #define INTERNAL_ERROR (panic ("Internal error in file %s, line %d.\n", __FILE__, __LINE__))
 
 static void scsi_done (Scsi_Cmnd *SCpnt);
-static int update_timeout (Scsi_Cmnd *, int);
+int update_timeout (Scsi_Cmnd *, int);
 static void print_inquiry(unsigned char *data);
 static void scsi_times_out (Scsi_Cmnd * SCpnt, int pid);
 
@@ -1798,7 +1798,7 @@
 	set the timer, we want to take this value into account.
 */
 
-static int update_timeout(Scsi_Cmnd * SCset, int timeout)
+int update_timeout(Scsi_Cmnd * SCset, int timeout)
 	{
 	unsigned int least, used;
 	unsigned int oldto;
@@ -2033,7 +2033,8 @@
  	scsi_devices = (Scsi_Device *) NULL;
 
 	for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
-	  scan_scsis(shpnt);           /* scan for scsi devices */
+		if(!shpnt->disabled)
+			scan_scsis(shpnt);	/* scan for scsi devices */
 
 	printk("scsi : detected ");
 	for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/drivers/scsi/sg.c linux-1.2.13pl3/drivers/scsi/sg.c
--- linux-1.2.13pl2/drivers/scsi/sg.c	Wed Feb 22 16:46:13 1995
+++ linux-1.2.13pl3/drivers/scsi/sg.c	Fri Oct 13 19:05:02 1995
@@ -171,17 +171,27 @@
  {
   int dev=MINOR(inode->i_rdev);
   int i;
+  unsigned long flags;
   struct scsi_generic *device=&scsi_generics[dev];
   if ((i=verify_area(VERIFY_WRITE,buf,count)))
    return i;
+  save_flags(flags);
+  cli();
   while(!device->pending || !device->complete)
    {
     if (filp->f_flags & O_NONBLOCK)
+    {
+     restore_flags(flags);
      return -EWOULDBLOCK;
+    }
     interruptible_sleep_on(&device->read_wait);
     if (current->signal & ~current->blocked)
+    {
+     restore_flags(flags);
      return -ERESTARTSYS;
+    }
    }
+  restore_flags(flags);
   device->header.pack_len=device->header.reply_len;
   device->header.result=0;
   if (count>=sizeof(struct sg_header))
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/drivers/scsi/wd33c93.c linux-1.2.13pl3/drivers/scsi/wd33c93.c
--- linux-1.2.13pl2/drivers/scsi/wd33c93.c	Tue Jul 11 21:30:39 1995
+++ linux-1.2.13pl3/drivers/scsi/wd33c93.c	Fri Oct 13 17:49:06 1995
@@ -449,6 +449,15 @@
 	sr = read_WD33C93(regp, WD_SCSI_STATUS);
 	printk (KERN_ERR "scsi%d: interrupt when not connected (%x %x)\n",
 		    instance->host_no, asr, sr);
+	instance->disabled = 1;  /* It seems like there are no devices
+				  * connected to the host - this is marked
+				  * so the scsi-init won't try INQUIRE
+				  * on this host - as some hosts hangs
+				  * when this is done (atleast the A2091).
+				  * - Jes 29/7-95 (jds@kom.auc.dk).
+				  */
+	printk ("scsi%d: host will be marked 'disabled'.\n",
+		instance->host_no);
 	restore_flags (flags);
 	return;
     }
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/fs/binfmt_elf.c linux-1.2.13pl3/fs/binfmt_elf.c
--- linux-1.2.13pl2/fs/binfmt_elf.c	Fri Aug 18 17:38:31 1995
+++ linux-1.2.13pl3/fs/binfmt_elf.c	Fri Oct 13 19:05:04 1995
@@ -348,7 +348,7 @@
 	
 	
 	/* First of all, some simple consistency checks */
-	if(elf_ex.e_type != ET_EXEC || 
+	if((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || 
 	   elf_ex.e_machine != EM_68K ||
 	   (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
 	    !bprm->inode->i_op->default_file_ops->mmap)){
@@ -360,6 +360,10 @@
 	
 	elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize * 
 						 elf_ex.e_phnum, GFP_KERNEL);
+	if (elf_phdata == NULL) {
+		MOD_DEC_USE_COUNT;
+		return -ENOMEM;
+	}
 	
 	old_fs = get_fs();
 	set_fs(get_ds());
@@ -403,15 +407,22 @@
 			
 			elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz, 
 							   GFP_KERNEL);
+			if (elf_interpreter == NULL) {
+				kfree (elf_phdata);
+				MOD_DEC_USE_COUNT;
+				return -ENOMEM;
+			}
 			
 			retval = read_exec(bprm->inode,elf_ppnt->p_offset,elf_interpreter,
 					   elf_ppnt->p_filesz);
+#ifdef __i386__
 			/* If the program interpreter is one of these two,
 			   then assume an iBCS2 image. Otherwise assume
 			   a native linux image. */
 			if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
 			    strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0)
 			  ibcs2_interpreter = 1;
+#endif
 #if 0
 			printk("Using ELF interpreter %s\n", elf_interpreter);
 #endif
@@ -710,6 +721,10 @@
 	
 	elf_phdata =  (struct elf_phdr *) 
 		kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL);
+	if (elf_phdata == NULL) {
+		MOD_DEC_USE_COUNT;
+		return -ENOMEM;
+	}
 	
 	old_fs = get_fs();
 	set_fs(get_ds());
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/fs/exec.c linux-1.2.13pl3/fs/exec.c
--- linux-1.2.13pl2/fs/exec.c	Thu Aug 10 18:33:00 1995
+++ linux-1.2.13pl3/fs/exec.c	Fri Oct 13 19:05:05 1995
@@ -228,6 +228,13 @@
 	    current->rlim[RLIMIT_CORE].rlim_cur)
 		dump.u_ssize = 0;
 
+/* make sure we actually have a data and stack area to dump */
+	set_fs(USER_DS);
+	if (verify_area(VERIFY_READ, (void *) (dump.u_tsize << PAGE_SHIFT), dump.u_dsize << PAGE_SHIFT))
+		dump.u_dsize = 0;
+	if (verify_area(VERIFY_READ, (void *) dump.start_stack, dump.u_ssize << PAGE_SHIFT))
+		dump.u_ssize = 0;
+
 	set_fs(KERNEL_DS);
 /* struct user */
 	DUMP_WRITE(&dump,sizeof(dump));
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/fs/nfs/dir.c linux-1.2.13pl3/fs/nfs/dir.c
--- linux-1.2.13pl2/fs/nfs/dir.c	Thu Aug 10 18:33:43 1995
+++ linux-1.2.13pl3/fs/nfs/dir.c	Fri Oct 13 19:05:06 1995
@@ -82,6 +82,8 @@
 	return -EISDIR;
 }
 
+static struct nfs_entry *c_entry = NULL;
+
 /*
  * We need to do caching of directory entries to prevent an
  * incredible amount of RPC traffic.  Only the most recent open
@@ -96,7 +98,6 @@
 	static int c_dev = 0;
 	static int c_ino;
 	static int c_size;
-	static struct nfs_entry *c_entry = NULL;
 
 	int result;
 	int i;
@@ -112,9 +113,21 @@
 	if (c_entry == NULL) {
 		i = sizeof (struct nfs_entry)*NFS_READDIR_CACHE_SIZE;
 		c_entry = (struct nfs_entry *) kmalloc(i, GFP_KERNEL);
+		if (c_entry == NULL) {
+			printk("nfs_readdir: no MEMORY for cache\n");
+			return -ENOMEM;
+		}
 		for (i = 0; i < NFS_READDIR_CACHE_SIZE; i++) {
 			c_entry[i].name = (char *) kmalloc(NFS_MAXNAMLEN + 1,
 				GFP_KERNEL);
+			if (c_entry[i].name == NULL) {
+				printk("nfs_readdir: no MEMORY for cache\n");
+				while (--i>=0)
+					kfree(c_entry[i].name);
+				kfree(c_entry);
+				c_entry = NULL;
+				return -ENOMEM;
+			}
 		}
 	}
 	entry = NULL;
@@ -164,6 +177,24 @@
 	}
 	return 0;
 }
+
+/*
+ * free cache memory
+ * called from cleanup_module
+ */
+
+void nfs_kfree_cache(void)
+{
+        int i;
+
+	if (c_entry == NULL)
+		return;
+	for (i = 0; i < NFS_READDIR_CACHE_SIZE; i++)
+		kfree(c_entry[i].name);
+	kfree(c_entry);
+	c_entry = NULL;
+}
+ 
 
 /*
  * Lookup caching is a big win for performance but this is just
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/fs/nfs/inode.c linux-1.2.13pl3/fs/nfs/inode.c
--- linux-1.2.13pl2/fs/nfs/inode.c	Sun Mar 12 09:31:35 1995
+++ linux-1.2.13pl3/fs/nfs/inode.c	Fri Oct 13 19:05:07 1995
@@ -274,6 +274,7 @@
 void cleanup_module(void)
 {
 	unregister_filesystem(&nfs_fs_type);
+	nfs_kfree_cache();
 }
 
 #endif
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/fs/proc/array.c linux-1.2.13pl3/fs/proc/array.c
--- linux-1.2.13pl2/fs/proc/array.c	Thu Jul 27 19:20:50 1995
+++ linux-1.2.13pl3/fs/proc/array.c	Fri Oct 13 18:11:48 1995
@@ -48,6 +48,7 @@
 #include <asm/io.h>
 #include <asm/traps.h>
 #include <asm/bootinfo.h>
+#include <asm/amigahw.h>
 
 #define LOAD_INT(x) ((x) >> FSHIFT)
 #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
@@ -321,17 +322,32 @@
 		              loops_per_sec/500000, (loops_per_sec/5000) % 100
 			      );
 #elif defined __mc68000__
-	char *cpu, *fpu;
-	if (boot_info.cputype & CPU_68020)
-	  cpu = "68020";
-	else if (boot_info.cputype & CPU_68030)
-	  cpu = "68030";
-	else if (boot_info.cputype & CPU_68040)
-	  cpu = "68040";
-	else if (boot_info.cputype & CPU_68060)
-	  cpu = "68060";
-	else
-	  cpu = "680?0";
+	char *cpu, *mmu, *fpu;
+	u_long clockfreq, clockfactor;
+
+#define CLOCK_FACTOR_68020		(15000)	/* please correct me */
+#define CLOCK_FACTOR_68030		(8010)	/* 3994575 loops/s @ 32 MHz */
+#define CLOCK_FACTOR_68040		(3010)	/* 8305552 loops/s @ 25 MHz */
+#define CLOCK_FACTOR_68060		(2000)	/* please correct me */
+
+	if (boot_info.cputype & CPU_68020) {
+	    cpu = "68020";
+	    mmu = "68851";
+	    clockfactor = CLOCK_FACTOR_68020;
+	} else if (boot_info.cputype & CPU_68030) {
+	    cpu = mmu = "68030";
+	    clockfactor = CLOCK_FACTOR_68030;
+	} else if (boot_info.cputype & CPU_68040) {
+	    cpu = mmu = "68040";
+	    clockfactor = CLOCK_FACTOR_68040;
+	} else if (boot_info.cputype & CPU_68060) {
+	    cpu = mmu = "68060";
+	    clockfactor = CLOCK_FACTOR_68060;
+	} else {
+	    cpu = mmu = "680x0";
+	    clockfactor = 0;
+	}
+
 	if (boot_info.cputype & FPU_68881)
 	  fpu = "68881";
 	else if (boot_info.cputype & FPU_68882)
@@ -342,18 +358,261 @@
 	  fpu = "68060";
 	else
 	  fpu = "none";
+
+	clockfreq = loops_per_sec/1000*clockfactor;
+
 	return sprintf (buffer,
 			"cpu:\t\t%s\n"
+			"mmu:\t\t%s\n"
 			"fpu:\t\t%s\n"
-			"BogoMips:\t%lu.%02lu\n",
-			cpu, fpu,
+			"Clockspeed:\t%lu.%1luMHz\n"
+			"BogoMips:\t%lu.%02lu\n"
+	/* CLOCK_FACTOR_* debug. Will be removed when I know all factors :-) */
+			"Loops:\t\t%lu (DEBUG)\n",
+			cpu, mmu, fpu,
+			(clockfreq + 500000) / 1000000,
+			((clockfreq + 50000) / 100000) % 10,
 			loops_per_sec / 500000,
-			(loops_per_sec / 5000) % 100);
+			(loops_per_sec / 5000) % 100,
+			loops_per_sec);
 #else
 	return 0;
 #endif
 }
 
+static int get_hardware_list(char *buffer)
+{
+	int len = 0;
+
+#if defined(__mc68000__)
+	char model[16];
+	u_long mem;
+	int i;
+
+	switch (boot_info.machtype) {
+#ifdef CONFIG_AMIGA
+	case MACH_AMIGA:
+	    strcpy(model, "Amiga ");
+	    switch (boot_info.bi_amiga.model) {
+	    case AMI_500:
+		strcat(model, "500");
+		break;
+	    case AMI_2000:
+		strcat(model, "2000");
+		break;
+	    case AMI_3000:
+		strcat(model, "3000");
+		break;
+	    case AMI_4000:
+		strcat(model, "4000");
+		break;
+	    case AMI_1200:
+		strcat(model, "1200");
+		break;
+	    }
+	    break;
+#endif
+#ifdef CONFIG_ATARI
+	case MACH_ATARI:
+	    strcpy(model, "Atari ");
+	    switch (boot_info.bi_atari.mch_cookie >> 16) {
+	    case 0:
+		if (ATARIHW_PRESENT(MSTE_CLK))
+		    strcat (model, "Mega ST");
+		else
+		    strcat (model, "ST");
+		break;
+	    case 1:
+		if ((boot_info.bi_atari.mch_cookie & 0xffff) == 0x10)
+		    strcat (model, "Mega STE");
+		else
+		    strcat (model, "STE");
+		break;
+	    case 2:
+		strcat (model, "TT");
+		break;
+	    case 3: /* XXX */
+		strcat (model, "Falcon");
+		break;
+	    default:
+		sprintf (model + strlen (model), "(unknown mach cookie 0x%lx)",
+			 boot_info.bi_atari.mch_cookie);
+		break;
+	    }
+	    break;
+#endif
+#ifdef CONFIG_MAC
+	case MACH_MAC:
+	    strcpy(model, "Mac");
+	    break;
+#endif
+	default:
+	    strcpy(model, "Unknown m68k");
+	} /* boot_info.machtype */
+
+	len += sprintf(buffer+len, "Model:\t\t%s\n", model);
+	len += get_cpuinfo(buffer+len);
+	for (mem = 0, i = 0; i < boot_info.num_memory; i++)
+	    mem += boot_info.memory[i].size;
+	len += sprintf(buffer+len, "System Memory:\t%ldK\n", mem>>10);
+
+	switch (boot_info.machtype) {
+#ifdef CONFIG_AMIGA
+	case MACH_AMIGA:
+	    {
+		u_char deniseid, agnusid;
+		char *type;
+		int orig_denise = 0;
+
+		len += sprintf(buffer+len, "Chip RAM:\t%ldK\n"
+			       "PS Freq:\t%dHz\n"
+			       "EClock Freq:\t%ldHz\n",
+			       boot_info.bi_amiga.chip_size>>10,
+			       boot_info.bi_amiga.psfreq,
+			       boot_info.bi_amiga.eclock);
+		deniseid = custom.deniseid & 0xff;
+		agnusid = (custom.vposr>>8) & 0x7f;
+		switch(boot_info.bi_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";
+		    orig_denise = 1;
+		    break;
+		}
+		len += sprintf(buffer+len, "Graphics:\t%s (", type);
+		if (orig_denise)
+		    len += sprintf(buffer+len, "Denise (8362), ");
+		else
+		    switch (deniseid & 0xf) {
+		    case 0x0c:
+			len += sprintf(buffer+len, "Denise (8373 rev %u), ",
+				       15-(deniseid>>4));
+			break;
+		    case 0x08:
+			len += sprintf(buffer+len, "Lisa (8375 rev %u), ",
+				       15-(deniseid>>4));
+			break;
+		    default:
+			len += sprintf(buffer+len, "Unknown Denise, ");
+			break;
+		    }
+		if (agnusid & 0x10)
+		    type = "NTSC";
+		else
+		    type = "PAL";
+		switch (agnusid) {
+		case 0x00:
+		    len += sprintf(buffer+len,
+				   "Normal or Fat PAL Agnus (8367/8371))\n");
+		    break;
+		case 0x10:
+		    len += sprintf(buffer+len,
+				   "Normal or Fat NTSC Agnus (8361/8370))\n");
+		    break;
+		case 0x20:
+		case 0x30:
+		    len += sprintf(buffer+len,
+				   "Fat Hires %s Agnus (8372 rev 0-4))\n", type);
+		    break;
+		case 0x21:
+		case 0x31:
+		    len += sprintf(buffer+len,
+				   "Fat Hires %s Agnus (8372 rev 5))\n", type);
+		    break;
+		case 0x22:
+		case 0x32:
+		    len += sprintf(buffer+len, "%s Alice (8374 rev 0-2))\n",
+				   type);
+		    break;
+		case 0x23:
+		case 0x33:
+		    len += sprintf(buffer+len, "%s Alice (8374 rev 3-4))\n",
+				   type);
+		    break;
+		default:
+		    len += sprintf(buffer+len, "Unknown %s Agnus)\n", type);
+		    break;
+		}
+		len += sprintf(buffer+len, "Internal floppy controller\n"
+			       "Internal mouse port\n"
+			       "Internal printer port\n"
+			       "Internal serial port\n");
+		switch (boot_info.bi_amiga.model) {
+		case AMI_3000:
+		    len += sprintf(buffer+len, "Internal SCSI controller\n");
+		    break;
+		case AMI_4000:
+		case AMI_1200:
+		    len += sprintf(buffer+len, "Internal IDE controller\n");
+		    break;
+		}
+		len += sprintf(buffer+len, "%d AutoConfig expansion device%s\n",
+			       boot_info.bi_amiga.num_autocon,
+			       boot_info.bi_amiga.num_autocon == 1 ? "" : "s");
+		break;
+	    }
+#endif
+#ifdef CONFIG_ATARI
+	case MACH_ATARI:
+	    {
+#define ATARIHW_ANNOUNCE(name,str)				\
+		if (ATARIHW_PRESENT(name))			\
+		    len += sprintf (buffer + len, "%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)");
+		ATARIHW_ANNOUNCE(ST_SCSI, "SCSI Controller NCR5380 (Falcon)");
+		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");
+		break;
+	    }
+#endif
+#ifdef CONFIG_MAC
+	case MACH_MAC:
+	    {
+		break;
+	    }
+#endif
+	} /* boot_info.machtype */
+
+#elif defined(__i386__)
+	len += sprintf(buffer+len, "Model:\t\tPC Clone\n");
+	len += get_cpuinfo(buffer+len);
+#endif
+	return(len);
+}
+
 static struct task_struct ** get_task(pid_t pid)
 {
 	struct task_struct ** p;
@@ -827,6 +1086,7 @@
 extern int get_dma_list(char *);
 extern int get_cpuinfo(char *);
 extern int get_pci_list(char*);
+extern int get_zorro_list(char*);
 
 static int get_root_array(char * page, int type)
 {
@@ -879,6 +1139,14 @@
 
 		case PROC_IOPORTS:
 			return get_ioport_list(page);
+
+		case PROC_HARDWARE:
+			return get_hardware_list(page);
+
+#ifdef CONFIG_ZORRO
+  	        case PROC_ZORRO:
+			return get_zorro_list(page);
+#endif
 	}
 	return -EBADF;
 }
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/fs/proc/root.c linux-1.2.13pl3/fs/proc/root.c
--- linux-1.2.13pl2/fs/proc/root.c	Sat May 27 09:07:23 1995
+++ linux-1.2.13pl3/fs/proc/root.c	Fri Oct 13 18:11:48 1995
@@ -80,6 +80,10 @@
 #ifdef CONFIG_PROFILE
 	{ PROC_PROFILE,		7, "profile"},
 #endif
+	{ PROC_HARDWARE,	8, "hardware" },
+#ifdef CONFIG_ZORRO
+	{ PROC_ZORRO,		5, "zorro" },
+#endif
 };
 
 #define NR_ROOT_DIRENTRY ((sizeof (root_dir))/(sizeof (root_dir[0])))
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/include/asm-m68k/amigatypes.h linux-1.2.13pl3/include/asm-m68k/amigatypes.h
--- linux-1.2.13pl2/include/asm-m68k/amigatypes.h	Sun Sep 17 16:36:23 1995
+++ linux-1.2.13pl3/include/asm-m68k/amigatypes.h	Fri Oct 13 18:11:49 1995
@@ -26,16 +26,10 @@
 };
 
 /* defined board manufacturers */
-#define MANUF_COMMODORE      (0x0202)
-#define MANUF_COMMODORE2     (0x0201)	/* for Bridgeboards */
-#define MANUF_U_LOWELL       (0x0406)	/* for A2410 */
-#define MANUF_AMERISTAR      (0x041D)
-#define MANUF_HELFRICH1      (2145)
-#define MANUF_HELFRICH2      (2195)
-#define MANUF_GVP            (0x07E1)
-#define MANUF_VILLAGETRONIC  (0x0877)
-#define MANUF_HYDRA_SYSTEMS  (2121)
+/* ++Geert: Please update amiga/zorro.c if you make changes here */
+/*          Many IDs were obtained by using ExpName V1.4 ((C) Richard Körber) */
 
+#define MANUF_COMMODORE      (0x0202)	/* Commodore USA */
 #define PROD_A2090A          (0x01)	/* CBM A2090/A2090A HD controller */
 #define PROD_A2091           (0x02)	/* CBM A2091 HD controller */
 #define PROD_A590            (0x03)	/* CBM A590 HD controller */
@@ -47,27 +41,122 @@
 #define PROD_A2232           (0x46)	/* CBM A2232 serial production */
 #define PROD_A2620           (0x50)	/* CBM A2620 68020/RAM card */
 #define PROD_A2630           (0x51)	/* CBM A2630 68030/RAM card */
+#define PROD_A4091           (0x54)	/* CBM A4091 SCSI HD controller */
 #define PROD_ROMULATOR       (0x60)	/* CBM Romulator card */
 #define PROD_A3000TESTFIX    (0x61)	/* CBM A3000 test fixture */
 #define PROD_A2065           (0x70)	/* CBM A2065 Ethernet card */
-#define PROD_A4091           (0x54)	/* CBM A4091 SCSI HD controller */
-#define PROD_A2386SX         (0x67)	/* CBM A2386-SX Bridgeboard */
+
+#define MANUF_COMMODORE2     (0x0201)	/* Commodore Germany */
 #define PROD_BRIDGEBOARD     (0x01)	/* CBM Bridgeboard */
+#define PROD_A2386SX         (0x67)	/* CBM A2386-SX Bridgeboard */
+
+#define MANUF_U_LOWELL       (0x0406)	/* University of Lowell */
 #define PROD_A2410           (0x00)	/* CBM A2410 Hires Graphics card */
-#define PROD_AMERISTAR2065   (0x01)	/* Ameristar Ethernet card */
 
-#define PROD_GVPIISCSI       (0x0B)
+#define MANUF_AMERISTAR      (0x041D)	/* Ameristar */
+#define PROD_AMERISTAR2065   (0x01)	/* Ethernet card */
+
+#define MANUF_GVP            (0x07E1)	/* Great Valley Products */
+#define PROD_GVPIISCSI       (0x0B)	/* GVP Series II SCSI */
 #define PROD_GVPIISCSI_2     (0x09)	/* evidence that the driver works
 					   for this product code also */
-#define PROD_ARIADNE         (0xC9)	/* Village Tronic Ariadne Ethernet */
+#define PROD_GVPIIRAM        (0x0A)	/* GVP Series II RAM */
+#define PROD_GVPIV_24        (0x20)	/* GVP IV-24 Graphics Board */
+#define PROD_GVPIO_EXT       (0xFF)	/* GVP I/O Extender */
+
+#define MANUF_GVP2           (0x0891)	/* Great Valley Products */
+#define PROD_SPECTRUM_RAM    (0x01)	/* GVP Spectrum Graphics Board */
+#define PROD_SPECTRUM_REG    (0x02)
+
+#define MANUF_VILLAGE_TRONIC (0x0877)	/* Village Tronic */
+#define PROD_ARIADNE         (0xC9)	/* Ariadne Ethernet */
+#define PROD_PICASSO_II_RAM  (0x0B)	/* Picasso II Graphics Board */
+#define PROD_PICASSO_II_REG  (0x0C)
+
+#define MANUF_HELFRICH1      (0x0861)	/* Helfrich */
+#define PROD_RAINBOW3        (0x21)	/* Rainbow3 Graphics Board */
+
+#define MANUF_HELFRICH2      (0x0893)
+#define PROD_PICCOLO_RAM     (0x05)	/* Piccolo Graphics Board */
+#define PROD_PICCOLO_REG     (0x06)
+#define PROD_PEGGY_PLUS      (0x07)	/* PeggyPlus MPEG Decoder Board */
+#define PROD_SD64_RAM        (0x0A)	/* SD64 Graphics Board */
+#define PROD_SD64_REG        (0x0B)
+
+#define MANUF_HYDRA_SYSTEMS  (0x0849)	/* Hydra Systems */
+#define PROD_AMIGANET        (0x01)	/* Amiganet Board */
+
+#define MANUF_MEMPHIS        (0x0100)	/* Memphis */
+#define PROD_STORMBRINGER    (0x00)	/* Stormbringer */
+
+#define MANUF_SUPRA          (0x0420)	/* Supra */
+#define PROD_SUPRA_2400MODEM (0x10)	/* Supra 2400 Modem */
+
+#define MANUF_BSC            (0x07FE)
+#define PROD_ALF_3_SCSI      (0x03)	/* BSC ALF 3 SCSI Controller */
+
+#define MANUF_BSC2           (0x082C)
+#define PROD_OKTAGON_2008    (0x05)	/* BSC Oktagon 2008 SCSI Controller */
+#define PROD_TANDEM          (0x06)	/* BSC Tandem */
+#define PROD_PAR_SER_CARD    (0x10)	/* BSC Par/Ser Card */
+#define PROD_MULTIFACE_III   (0x12)	/* BSC MultiFace III */
+#define PROD_ISDN_MASTER     (0x40)	/* BSC ISDN Master */
 
-#define PROD_RAINBOW3        (33)
-#define PROD_PICCOLO_RAM     (5)
-#define PROD_PICCOLO_REG     (6)
-#define PROD_SD64_RAM        (10)
-#define PROD_SD64_REG        (11)
+#define MANUF_JOCHHEIM       (0x0804)	/* Jochheim */
+#define PROD_JOCHHEIM_RAM    (0x01)	/* Jochheim RAM */
+
+#define MANUF_CHECKPOINT     (0x0807)	/* Checkpoint Technologies */
+#define PROD_SERIAL_SOLUTION (0x00)	/* Serial Solution */
+
+#define MANUF_GOLEM          (0x0819)	/* Golem */
+#define PROD_GOLEM_SCSI_II   (0x02)	/* Golem SCSI-II Controller */
+
+#define MANUF_ADV_SYS_SOFT   (0x0836)	/* Advanced Systems & Software */
+#define PROD_NEXUS_SCSI      (0x01)	/* Nexus SCSI Controller */
+#define PROD_NEXUS_RAM       (0x08)	/* Nexus RAM */
+
+#define MANUF_XPERT_PRODEV   (0x0845)	/* XPert/ProDev */
+#define PROD_MERLIN_RAM      (0x03)	/* Merlin Graphics Board */
+#define PROD_MERLIN_REG      (0x04)
+
+#define MANUF_UTILITIES_ULTD (0x087B)	/* Utilities Unlimited */
+#define PROD_EMPLANT_DELUXE  (0x15)	/* Emplant Deluxe */
+#define PROD_EMPLANT_DELUXE2 (0x20)	/* Emplant Deluxe */
+
+#define MANUF_HARMS_PROF     (0x0A00)	/* Harms Professional */
+#define PROD_3500_TURBO      (0xd0)	/* 3500 Turbo board */
+
+#define MANUF_VORTEX         (0x2017)	/* Vortex */
+#define PROD_GOLDEN_GATE_386 (0x07)	/* Golden Gate 80386 Board */
+#define PROD_GOLDEN_GATE_RAM (0x08)	/* Golden Gate RAM */
+#define PROD_GOLDEN_GATE_486 (0x09)	/* Golden Gate 80486 Board */
+
+#define MANUF_PHASE5         (0x2140)	/* Phase5 */
+#define PROD_FASTLANE_RAM    (0x0a)	/* FastLane RAM */
+#define PROD_FASTLANE_SCSI   (0x0b)	/* FastLane SCSI */
+#define PROD_CYBERVISION     (0x22)	/* CyberVision64 Graphics Board */
+
+#define MANUF_APOLLO         (0x2222)	/* Apollo */
+#define PROD_AT_APOLLO       (0x22)	/* AT-Apollo */
+
+#define MANUF_UWE_GERLACH    (0x3FF7)	/* Uwe Gerlach */
+#define PROD_UG_RAM_ROM      (0xd4)	/* RAM/ROM */
+
+#define MANUF_MACROSYSTEMS   (0x089B)	/* MacroSystems USA */
+#define PROD_WARP_ENGINE     (0x13)	/* Warp Engine */
+
+#define MANUF_MACROSYSTEMS2  (0x4754)	/* MacroSystems Germany */
+#define PROD_MAESTRO         (0x03)	/* Maestro */
+#define PROD_VLAB            (0x04)	/* VLab */
+#define PROD_MAESTRO_PRO     (0x05)	/* Maestro Pro */
+#define PROD_RETINA_Z2       (0x06)	/* Retina Z2 Graphics Board */
+#define PROD_MULTI_EVOLUTION (0x08)	/* MultiEvolution */
+
+#define MANUF_MICROBOTICS    (0x03F2)	/* MicroBotics */
+#define PROD_VXL_30          (0x45)	/* VXL-30 Turbo Board */
+
+#define MANUF_HACKER         (0x07db)	/* Test only: no product definitions */
 
-#define PROD_AMIGANET        (1)        /* Hydra Systems Amiganet Board */
 
 struct ExpansionRom {
     /* -First 16 bytes of the expansion ROM */
@@ -83,6 +172,11 @@
     u_char	er_Reserved0e;
     u_char	er_Reserved0f;
 };
+
+/* er_Type board type bits */
+#define ERT_TYPEMASK	0xc0
+#define ERT_ZORROII	0xc0
+#define ERT_ZORROIII	0x80
 
 struct ConfigDev {
     struct Node 	cd_Node;
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/include/asm-m68k/atarihw.h linux-1.2.13pl3/include/asm-m68k/atarihw.h
--- linux-1.2.13pl2/include/asm-m68k/atarihw.h	Thu Aug 10 18:34:47 1995
+++ linux-1.2.13pl3/include/asm-m68k/atarihw.h	Fri Oct 13 19:05:08 1995
@@ -122,9 +122,35 @@
 #define f030_creg ((u_short*)		0xffff82c0)
 #define f030_sreg ((u_short*)		0xffff8260)
 #define f030_mreg ((u_short*)		0xffff820a)
-#define f030_linewidth ((u_short*)      0xffff820f)
-#define f030_hscroll ((u_short*)        0xffff8265)
+#define f030_linewidth ((u_short*)      0xffff820e)
+#define f030_hscroll ((u_char*)        0xffff8265)
 
+#define VIDEL_BAS (0xffff8260)
+struct VIDEL {
+	u_short st_shift;
+	u_short pad1;
+	u_char  xoffset_s;
+	u_char  xoffset;
+	u_short f_shift;
+	u_char  pad2[0x1a];
+	u_short hht;
+	u_short hbb;
+	u_short hbe;
+	u_short hdb;
+	u_short hde;
+	u_short hss;
+	u_char  pad3[0x14];
+	u_short vft;
+	u_short vbb;
+	u_short vbe;
+	u_short vdb;
+	u_short vde;
+	u_short vss;
+	u_char  pad4[0x12];
+	u_short control;
+	u_short mode;
+};
+#define	videl	((*(volatile struct VIDEL *)VIDEL_BAS))
 
 /*
 ** DMA/WD1772 Disk Controller
@@ -264,6 +290,10 @@
  };
 # define scc ((*(volatile struct SCC*)SCC_BAS))
 
+/* The ESCC (Z85230) in an Atari ST. The channels are revered! */
+# define st_escc ((*(volatile struct SCC*)0xfffffa31))
+# define st_escc_dsr ((*(volatile char *)0xfffffa39))
+
 /* TT SCC DMA Controller (same chip as SCSI DMA) */
 
 #define	TT_SCC_DMA_BAS	(0xffff8c01)
@@ -465,7 +495,7 @@
 
 #define	DMASND_CTRL_OFF		0x00
 #define	DMASND_CTRL_ON		0x01
-#define	DMASND_CTRL_REPEAT	0x03
+#define	DMASND_CTRL_REPEAT	0x02
 #define	DMASND_MODE_MONO	0x80
 #define	DMASND_MODE_STEREO	0x00
 #define	DMASND_MODE_6KHZ	0x00
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/include/asm-m68k/bootinfo.h linux-1.2.13pl3/include/asm-m68k/bootinfo.h
--- linux-1.2.13pl2/include/asm-m68k/bootinfo.h	Tue Sep 12 21:18:20 1995
+++ linux-1.2.13pl3/include/asm-m68k/bootinfo.h	Fri Oct 13 19:05:09 1995
@@ -1,5 +1,5 @@
 /*
-** asm/bootinfo.h -- Defintion of the Linux/68K boot information structure
+** asm/bootinfo.h -- Definition of the Linux/68K boot information structure
 **
 ** Copyright 1992 by Greg Harp
 **
@@ -10,7 +10,7 @@
 ** Created 09/29/92 by Greg Harp
 **
 ** 5/2/94 Roman Hodek:
-**   Added bi_atari part of the machine dependant nion bi_un; for now it
+**   Added bi_atari part of the machine dependant union bi_un; for now it
 **	 contains just a model field to distinguish between TT and Falcon.
 */
 
@@ -31,7 +31,17 @@
 struct bi_Amiga {
     int
         model;				/* Amiga Model (3000?) */
-    int
+
+/* ++Geert: The driver for AutoConfig device number i should set bit i of */
+/*          autocon_configured so amiga/zorro.c knows about that. */
+/*          Note that from the bootstrap viewpoint the addition of */
+/*          autocon_configured is backwards compatible with the old bi_Amiga */
+/*          structure (2*sizeof(u_short) == sizeof(int)). */
+
+    unsigned short
+	autocon_configured;		/* Bitmap of configured devices */
+
+    unsigned short
 	num_autocon;			/* # of autoconfig devices found */
 
     struct ConfigDev
@@ -91,6 +101,7 @@
 						   it... but who knows?) */
 		ATARIHW_DECLARE(TT_MFP);	/* 2nd MFP */		      
 		ATARIHW_DECLARE(SCC);		/* Serial Communications Contr. */
+		ATARIHW_DECLARE(ST_ESCC);	/* SCC Z83230 in an ST */
 		ATARIHW_DECLARE(ANALOG_JOY);	/* Paddle Interface for STe
 						   and Falcon */
 		ATARIHW_DECLARE(MICROWIRE);	/* Microwire Interface */
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/include/linux/nfs_fs.h linux-1.2.13pl3/include/linux/nfs_fs.h
--- linux-1.2.13pl2/include/linux/nfs_fs.h	Mon Nov 28 11:28:32 1994
+++ linux-1.2.13pl3/include/linux/nfs_fs.h	Fri Oct 13 19:05:09 1995
@@ -106,6 +106,7 @@
 /* linux/fs/nfs/dir.c */
 
 extern struct inode_operations nfs_dir_inode_operations;
+extern void nfs_kfree_cache(void);
 
 /* linux/fs/nfs/symlink.c */
 
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/include/linux/proc_fs.h linux-1.2.13pl3/include/linux/proc_fs.h
--- linux-1.2.13pl2/include/linux/proc_fs.h	Mon Feb 13 20:49:27 1995
+++ linux-1.2.13pl3/include/linux/proc_fs.h	Fri Oct 13 18:11:49 1995
@@ -30,7 +30,9 @@
 	PROC_KSYMS,
 	PROC_DMA,	
 	PROC_IOPORTS,
-	PROC_PROFILE /* whether enabled or not */
+	PROC_PROFILE, /* whether enabled or not */
+	PROC_HARDWARE,
+	PROC_ZORRO
 };
 
 enum pid_directory_inos {
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/kernel/fork.c linux-1.2.13pl3/kernel/fork.c
--- linux-1.2.13pl2/kernel/fork.c	Wed May 31 22:22:01 1995
+++ linux-1.2.13pl3/kernel/fork.c	Fri Oct 13 19:05:10 1995
@@ -167,6 +167,7 @@
 int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
 {
 	int nr;
+	int error = -ENOMEM;
 	unsigned long new_stack;
 	struct task_struct *p;
 
@@ -175,6 +176,7 @@
 	new_stack = get_free_page(GFP_KERNEL);
 	if (!new_stack)
 		goto bad_fork_free;
+	error = -EAGAIN;
 	nr = find_empty_process();
 	if (nr < 0)
 		goto bad_fork_free;
@@ -207,6 +209,7 @@
 	SET_LINKS(p);
 	nr_tasks++;
 
+	error = -ENOMEM;
 	/* copy all the process information */
 	copy_thread(nr, clone_flags, usp, p, regs);
 	if (copy_mm(clone_flags, p))
@@ -221,7 +224,12 @@
 	p->counter = current->counter >> 1;
 	p->state = TASK_RUNNING;	/* do this last, just in case */
 	return p->pid;
+
 bad_fork_cleanup:
+	if (p->exec_domain && p->exec_domain->use_count)
+		(*p->exec_domain->use_count)--;
+	if (p->binfmt && p->binfmt->use_count)
+		(*p->binfmt->use_count)--;
 	task[nr] = NULL;
 	REMOVE_LINKS(p);
 	nr_tasks--;
@@ -229,5 +237,5 @@
 	free_page(new_stack);
 	free_page((long) p);
 bad_fork:
-	return -EAGAIN;
+	return error;
 }
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/mm/memory.c linux-1.2.13pl3/mm/memory.c
--- linux-1.2.13pl2/mm/memory.c	Fri Aug 18 17:38:35 1995
+++ linux-1.2.13pl3/mm/memory.c	Sat Sep 30 09:55:40 1995
@@ -888,6 +888,7 @@
 		}
 		copy_page(pte_page(from), newpage);
 		*to_table = mk_pte(newpage, to_area->vm_page_prot);
+		invalidate();
 		return 1;
 	}
 /*
@@ -1013,6 +1014,7 @@
 	++vma->vm_task->mm->rss;
 	++vma->vm_task->mm->maj_flt;
 	*page_table = page;
+	invalidate();
 	return;
 }
 
@@ -1113,6 +1115,7 @@
 		return;
 	if (pte_write(*pte)) {
 		*pte = pte_mkdirty(*pte);
+		invalidate();
 		return;
 	}
 	do_wp_page(vma, address, write_access);
diff -ur -x RCS -x asm -x *.ver -x *.[ao] -x .depend -x .version -x .config -x .config.old -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-1.2.13pl2/mm/swap.c linux-1.2.13pl3/mm/swap.c
--- linux-1.2.13pl2/mm/swap.c	Wed Sep 13 07:33:34 1995
+++ linux-1.2.13pl3/mm/swap.c	Sat Sep 30 10:00:18 1995
@@ -300,9 +300,11 @@
 	vma->vm_task->mm->maj_flt++;
 	if (!write_access && add_to_swap_cache(page, entry)) {
 		*page_table = mk_pte(page, vma->vm_page_prot);
+		invalidate();
 		return;
 	}
 	*page_table = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
+	invalidate();
   	swap_free(entry);
   	return;
 }
@@ -333,6 +335,7 @@
 	if (mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED)
 		return 0;
 	if ((pte_dirty(pte) && delete_from_swap_cache(page)) || pte_young(pte))  {
+		invalidate();
 		*page_table = pte_mkold(pte);
 		return 0;
 	}	
@@ -357,6 +360,7 @@
 		if (mem_map[MAP_NR(page)] != 1) {
 			*page_table = pte_mkdirty(pte);
 			printk("Aiee.. duplicated cached swap-cache entry\n");
+			invalidate();
 			return 0;
 		}
 		vma->vm_task->mm->rss--;
@@ -411,6 +415,7 @@
 	if (pmd_bad(*dir)) {
 		printk("swap_out_pmd: bad pmd (%08lx)\n", pmd_val(*dir));
 		pmd_clear(dir);
+		invalidate();
 		return 0;
 	}
 	
@@ -443,6 +448,7 @@
 	if (pgd_bad(*dir)) {
 		printk("swap_out_pgd: bad pgd (%08lx)\n", pgd_val(*dir));
 		pgd_clear(dir);
+		invalidate();
 		return 0;
 	}
 
@@ -856,6 +862,7 @@
 		if (SWP_TYPE(in_swap_cache(page)) != type)
 			return 0;
 		delete_from_swap_cache(page);
+		invalidate();
 		*dir = pte_mkdirty(pte);
 		return 0;
 	}
@@ -866,6 +873,7 @@
 		free_page(page);
 		return 1;
 	}
+	invalidate();
 	*dir = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
 	++vma->vm_task->mm->rss;
 	swap_free(pte_val(pte));
@@ -884,6 +892,7 @@
 	if (pmd_bad(*dir)) {
 		printk("unuse_pmd: bad pmd (%08lx)\n", pmd_val(*dir));
 		pmd_clear(dir);
+		invalidate();
 		return 0;
 	}
 	pte = pte_offset(dir, address);
@@ -913,6 +922,7 @@
 	if (pgd_bad(*dir)) {
 		printk("unuse_pgd: bad pgd (%08lx)\n", pgd_val(*dir));
 		pgd_clear(dir);
+		invalidate();
 		return 0;
 	}
 	pmd = pmd_offset(dir, address);
