[kernel] r7857 - in dists/sid/linux-2.6/debian: . arch/m68k patches patches/series

Christian T. Steigies cts at alioth.debian.org
Sun Nov 19 23:58:29 UTC 2006


Author: cts
Date: Mon Nov 20 00:58:24 2006
New Revision: 7857

Added:
   dists/sid/linux-2.6/debian/patches/m68k-amiga.patch
   dists/sid/linux-2.6/debian/patches/m68k-apollo.patch
   dists/sid/linux-2.6/debian/patches/m68k-atari-ethernet.patch
   dists/sid/linux-2.6/debian/patches/m68k-atari-keyboard.patch
   dists/sid/linux-2.6/debian/patches/m68k-atari-mouse.patch
   dists/sid/linux-2.6/debian/patches/m68k-atari-scsi.patch
   dists/sid/linux-2.6/debian/patches/m68k-atari-serial.patch
   dists/sid/linux-2.6/debian/patches/m68k-atari-video.patch
   dists/sid/linux-2.6/debian/patches/m68k-atari.patch
   dists/sid/linux-2.6/debian/patches/m68k-misc.patch
   dists/sid/linux-2.6/debian/patches/series/6-extra
Modified:
   dists/sid/linux-2.6/debian/arch/m68k/config.atari
   dists/sid/linux-2.6/debian/changelog
Log:
add various atari patches, but do not re-enable building for atari yet


Modified: dists/sid/linux-2.6/debian/arch/m68k/config.atari
==============================================================================
--- dists/sid/linux-2.6/debian/arch/m68k/config.atari	(original)
+++ dists/sid/linux-2.6/debian/arch/m68k/config.atari	Mon Nov 20 00:58:24 2006
@@ -101,3 +101,14 @@
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_ATARI_PARTITION=y
 CONFIG_CRC32=y
+# enable new ethernet drivers
+CONFIG_ATARI_ROM_ISA=y
+CONFIG_ARANYM=y
+CONFIG_NATFEAT=y
+# Atari SCSI driver is buggy
+# CONFIG_ATARI_SCSI is not set
+# enable ethernet
+CONFIG_NET_ETHERNET=y
+CONFIG_ATARILANCE=m
+CONFIG_ATARI_NFETH=m
+CONFIG_ATARI_ETHERNEC=m

Modified: dists/sid/linux-2.6/debian/changelog
==============================================================================
--- dists/sid/linux-2.6/debian/changelog	(original)
+++ dists/sid/linux-2.6/debian/changelog	Mon Nov 20 00:58:24 2006
@@ -79,7 +79,11 @@
   * Added support for TI ez430 development tool ID in ti_usb.
     Thanks to Oleg Verych for providing the patch.
 
- -- maximilian attems <maks at sternwelten.at>  Sun, 19 Nov 2006 23:29:04 +0100
+  [ Christian T. Steigies ]
+  * Added support for Atari EtherNEC, Aranym, video, keyboard, mouse, and serial
+    by Michael Schmitz
+
+ -- Christian T. Steigies <cts at debian.org>  Mon, 20 Nov 2006 00:48:50 +0100
 
 linux-2.6 (2.6.18-5) unstable; urgency=low
 

Added: dists/sid/linux-2.6/debian/patches/m68k-amiga.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/m68k-amiga.patch	Mon Nov 20 00:58:24 2006
@@ -0,0 +1,22 @@
+diff -urN linux-m68k/drivers/char/ioext.h linux-schmitz/drivers/char/ioext.h
+--- linux-m68k/drivers/char/ioext.h	2006-11-19 21:35:33.000000000 +0100
++++ linux-schmitz/drivers/char/ioext.h	2006-11-19 21:37:26.000000000 +0100
+@@ -6,7 +6,6 @@
+ #ifndef _IOEXT_H_
+ #define _IOEXT_H_
+ 
+-#include <linux/config.h>
+ #include <linux/netdevice.h>
+ 
+ #include "16c552.h"
+diff -urN linux-m68k/drivers/char/plip_ioext.c linux-schmitz/drivers/char/plip_ioext.c
+--- linux-m68k/drivers/char/plip_ioext.c	2006-11-19 21:35:33.000000000 +0100
++++ linux-schmitz/drivers/char/plip_ioext.c	2006-11-19 21:37:26.000000000 +0100
+@@ -27,7 +27,6 @@
+ #include <asm/amigaints.h>
+ #include <linux/zorro.h>
+ 
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/fcntl.h>
+ #include <linux/string.h>

Added: dists/sid/linux-2.6/debian/patches/m68k-apollo.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/m68k-apollo.patch	Mon Nov 20 00:58:24 2006
@@ -0,0 +1,54 @@
+diff -urN linux-m68k/arch/m68k/apollo/dma.c linux-schmitz/arch/m68k/apollo/dma.c
+--- linux-m68k/arch/m68k/apollo/dma.c	2006-09-20 05:42:06.000000000 +0200
++++ linux-schmitz/arch/m68k/apollo/dma.c	1970-01-01 01:00:00.000000000 +0100
+@@ -1,50 +0,0 @@
+-#include <linux/types.h>
+-#include <linux/kernel.h>
+-#include <linux/mm.h>
+-#include <linux/kd.h>
+-#include <linux/tty.h>
+-#include <linux/console.h>
+-
+-#include <asm/setup.h>
+-#include <asm/bootinfo.h>
+-#include <asm/system.h>
+-#include <asm/pgtable.h>
+-#include <asm/apollodma.h>
+-#include <asm/io.h>
+-
+-/* note only works for 16 Bit 1 page DMA's */
+-
+-static unsigned short next_free_xlat_entry=0;
+-
+-unsigned short dma_map_page(unsigned long phys_addr,int count,int type) {
+-
+-	unsigned long page_aligned_addr=phys_addr & (~((1<<12)-1));
+-	unsigned short start_map_addr=page_aligned_addr >> 10;
+-	unsigned short free_xlat_entry, *xlat_map_entry;
+-	int i;
+-
+-	free_xlat_entry=next_free_xlat_entry;
+-	for(i=0,xlat_map_entry=addr_xlat_map+(free_xlat_entry<<2);i<8;i++,xlat_map_entry++) {
+-#if 0
+-		printk("phys_addr: %x, page_aligned_addr: %x, start_map_addr: %x\n",phys_addr,page_aligned_addr,start_map_addr+i);
+-#endif
+-		out_be16(xlat_map_entry, start_map_addr+i);
+-	}
+-
+-	next_free_xlat_entry+=2;
+-	if(next_free_xlat_entry>125)
+-		next_free_xlat_entry=0;
+-
+-#if 0
+-	printk("next_free_xlat_entry: %d\n",next_free_xlat_entry);
+-#endif
+-
+-	return free_xlat_entry<<10;
+-}
+-
+-void dma_unmap_page(unsigned short dma_addr) {
+-
+-	return ;
+-
+-}
+-

Added: dists/sid/linux-2.6/debian/patches/m68k-atari-ethernet.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/m68k-atari-ethernet.patch	Mon Nov 20 00:58:24 2006
@@ -0,0 +1,2081 @@
+diff -urN linux-m68k/arch/m68k/Kconfig linux-schmitz/arch/m68k/Kconfig
+--- linux-m68k/arch/m68k/Kconfig	2006-11-19 21:35:33.000000000 +0100
++++ linux-schmitz/arch/m68k/Kconfig	2006-11-19 21:37:26.000000000 +0100
+@@ -132,6 +132,31 @@
+ 	  information about which PCI hardware does work under Linux and which
+ 	  doesn't.
+ 
++config ATARI_ROM_ISA
++	bool "Atari ROM port ISA adapter support"
++	depends on ATARI
++	help
++	  This option enables support for the ROM port ISA adapter used to 
++	  operate ISA cards on Atari. Only 8  bit cards are supported, and
++	  no interrupt lines are connected. 
++	  The only driver currently using this adapter is the EtherNEC
++	  driver for RTL8019AS based NE2000 compatible network cards.
++
++config ARANYM
++	bool "ARAnyM emulator support "
++	depends on ATARI
++	help
++	  This option enables support for the ARAnyM emulator support
++	  features. To use this kernel on ARAnyM, say Y here; otherwise say N.
++
++config NATFEAT
++	bool
++	depends on ARANYM
++	default y
++	help
++	  This option enables support for ARAnyM native features, such as 
++	  access to a disk image as /dev/hda. Useful with the ARANYM option.
++
+ config MAC
+ 	bool "Macintosh support"
+ 	depends on !MMU_SUN3
+diff -urN linux-m68k/arch/m68k/atari/Makefile linux-schmitz/arch/m68k/atari/Makefile
+--- linux-m68k/arch/m68k/atari/Makefile	2006-09-20 05:42:06.000000000 +0200
++++ linux-schmitz/arch/m68k/atari/Makefile	2006-11-19 21:37:26.000000000 +0100
+@@ -3,8 +3,12 @@
+ #
+ 
+ obj-y		:= config.o time.o debug.o ataints.o stdma.o \
+-			atasound.o stram.o atari_ksyms.o
++			atakeyb.o atasound.o stram.o atari_ksyms.o
+ 
+ ifeq ($(CONFIG_PCI),y)
+ obj-$(CONFIG_HADES)	+= hades-pci.o
+ endif
++
++ifeq ($(CONFIG_NATFEAT),y)
++obj-$(CONFIG_NATFEAT)	+= natfeat.o
++endif
+diff -urN linux-m68k/arch/m68k/atari/config.c linux-schmitz/arch/m68k/atari/config.c
+--- linux-m68k/arch/m68k/atari/config.c	2006-09-20 05:42:06.000000000 +0200
++++ linux-schmitz/arch/m68k/atari/config.c	2006-11-19 21:37:26.000000000 +0100
+@@ -32,6 +32,10 @@
+ #include <linux/ioport.h>
+ #include <linux/vt_kern.h>
+ 
++#ifdef CONFIG_NATFEAT
++#include "natfeat.h"
++#endif
++
+ #include <asm/bootinfo.h>
+ #include <asm/setup.h>
+ #include <asm/atarihw.h>
+@@ -207,6 +211,12 @@
+     }
+ }
+ 
++void atari_poweroff(void)
++{
++#ifdef CONFIG_NATFEAT
++    nf_shutdown();
++#endif
++}
+ 
+     /*
+      *  Setup the Atari configuration info
+@@ -218,6 +228,10 @@
+ 
+     memset(&atari_hw_present, 0, sizeof(atari_hw_present));
+ 
++#ifdef CONFIG_NATFEAT
++    nf_init();
++#endif
++
+     atari_debug_init();
+ 
+     ioport_resource.end  = 0xFFFFFFFF;  /* Change size of I/O space from 64KB
+@@ -229,6 +243,8 @@
+     mach_get_hardware_list = atari_get_hardware_list;
+     mach_gettimeoffset   = atari_gettimeoffset;
+     mach_reset           = atari_reset;
++    mach_halt            = atari_poweroff;
++    mach_power_off       = atari_poweroff;
+     mach_max_dma_address = 0xffffff;
+ #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
+     mach_beep          = atari_mksound;
+@@ -614,6 +630,11 @@
+ 
+ static void atari_get_model(char *model)
+ {
++#ifdef CONFIG_NATFEAT
++    if (nf_name1(model, 80)) { // char model[80] defined in kernel/setup.c
++       return;
++    }
++#endif
+     strcpy(model, "Atari ");
+     switch (atari_mch_cookie >> 16) {
+ 	case ATARI_MCH_ST:
+diff -urN linux-m68k/arch/m68k/atari/ethernet_nfapi.h linux-schmitz/arch/m68k/atari/ethernet_nfapi.h
+--- linux-m68k/arch/m68k/atari/ethernet_nfapi.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-schmitz/arch/m68k/atari/ethernet_nfapi.h	2006-11-19 21:37:26.000000000 +0100
+@@ -0,0 +1,56 @@
++/*
++ * ARAnyM ethernet driver - header file.
++ *
++ * Copyright (c) 2002-2004 Standa and Petr of ARAnyM dev team (see AUTHORS)
++ * 
++ * This file is part of the ARAnyM project which builds a new and powerful
++ * TOS/FreeMiNT compatible virtual machine running on almost any hardware.
++ *
++ * ARAnyM is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * ARAnyM is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with ARAnyM; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#ifndef _ARAETHER_NFAPI_H
++#define _ARAETHER_NFAPI_H
++
++/*
++   The code for the FreeMiNT driver was moved to the FreeMiNT CVS:
++   freemint/sys/sockets/xif/nfeth.
++
++   If you edit this file then you would need to synchronize it with the
++   driver in the freemint CVS (nfeth_nfapi.h).
++
++   if you change anything in the enum {} below you have to increase 
++   this ARAETHER_NFAPI_VERSION!
++*/
++#define ARAETHER_NFAPI_VERSION	0x00000005
++
++enum {
++	GET_VERSION = 0,	/* no parameters, return NFAPI_VERSION in d0 */
++	XIF_INTLEVEL,		/* no parameters, return Interrupt Level in d0 */
++	XIF_IRQ,			/* acknowledge interrupt from host */
++	XIF_START,			/* (ethX), called on 'ifup', start receiver thread */
++	XIF_STOP,			/* (ethX), called on 'ifdown', stop the thread */
++	XIF_READLENGTH,		/* (ethX), return size of network data block to read */
++	XIF_READBLOCK,		/* (ethX, buffer, size), read block of network data */
++	XIF_WRITEBLOCK,		/* (ethX, buffer, size), write block of network data */
++	XIF_GET_MAC,		/* (ethX, buffer, size), return MAC HW addr in buffer */
++	XIF_GET_IPHOST,		/* (ethX, buffer, size), return IP address of host */
++	XIF_GET_IPATARI,	/* (ethX, buffer, size), return IP address of atari */
++	XIF_GET_NETMASK		/* (ethX, buffer, size), return IP netmask */
++};
++
++#define ETH(a)	(nfEtherID + a)
++
++#endif /* _ARAETHER_NFAPI_H */
+diff -urN linux-m68k/arch/m68k/atari/natfeat.c linux-schmitz/arch/m68k/atari/natfeat.c
+--- linux-m68k/arch/m68k/atari/natfeat.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-schmitz/arch/m68k/atari/natfeat.c	2006-11-19 21:37:26.000000000 +0100
+@@ -0,0 +1,231 @@
++/*
++ * natfeat.c - ARAnyM hardware support via Native Features (natfeats)
++ *
++ * Copyright (c) 2005 Petr Stehlik of ARAnyM dev team
++ *
++ * This software may be used and distributed according to the terms of
++ * the GNU General Public License (GPL), incorporated herein by reference.
++ */
++
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/string.h> // strncpy()
++#include <linux/kernel.h> // snprintf()
++#include <asm/io.h> // virt_to_phys()
++
++#include "natfeat.h"
++
++#ifdef CONFIG_ATARI_NFETH
++#include "natfeat_ethernet_nfapi.h"
++#endif
++
++#ifndef TRUE
++#define TRUE 1
++#endif
++
++#ifndef FALSE
++#define FALSE 0
++#endif
++
++static unsigned long nf_get_id_instr = 0x73004e75UL;
++static unsigned long nf_call_instr = 0x73014e75UL;
++
++static struct nf_ops _nf_ops = { &nf_get_id_instr, &nf_call_instr }; 
++static struct nf_ops *nf_ops = NULL; 
++
++#define NF_GETID(a)		nf_ops->get_id(virt_to_phys(a))
++
++int detect_native_features(void)
++{
++    int		ret;
++    long	save_sp, save_vbr;
++    static long tmp_vectors[5];
++    static char *nf_version = "NF_VERSION";
++	
++    __asm__ __volatile__
++	(	"movec	%/vbr,%2\n\t"	/* save vbr value            */
++		"movel	#Liierr,%3@(0x10)\n\t" /* set Illegal Insn vec */
++ 		"movec	%3,%/vbr\n\t"	/* set up temporary vectors  */
++		"movel	%/sp,%1\n\t"	/* save sp                   */
++		"moveq	#0,%0\n\t"		/* assume no NatFeats        */
++		"clrl	%/d0\n\t"		/* clear ID value register   */
++		"movel	%4,%/sp@\n\t"
++		"subql	#4,%/sp\n\t"
++		"dc	0x7300\n\t"			/* call NatFeat GetID        */
++		"tstl	%/d0\n\t"		/* check ID value register   */
++		"sne	%0\n\t"			/* if non-zero NatFeats work */
++		"Liierr:\n\t"
++		"movel	%1,%/sp\n\t"	/* restore sp                */
++		"movec	%2,%/vbr"		/* restore vbr               */
++		: "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
++		: "a" (tmp_vectors), "a" (virt_to_phys(nf_version))
++		: "d0"					/* reg d0 used by NatFeats   */
++        );
++
++    return( ret );
++}
++
++struct nf_ops * nf_init(void)
++{
++	if (detect_native_features()) {
++		nf_ops = &_nf_ops;
++		nf_debug("NatFeats found\n");
++		return nf_ops;
++	}
++	
++	return NULL;
++}
++
++/****************/
++/* NF Basic Set */
++int nf_name1(char *buf, int bufsize)
++{
++	if (nf_ops) {
++		static long nfid_name = 0;
++		if (nfid_name == 0) {
++			nfid_name = NF_GETID("NF_NAME");
++		}
++
++		if (nfid_name) {
++			nf_ops->call(nfid_name+1, virt_to_phys(buf), bufsize); // TODO: lock buf to prevent swap out
++			return TRUE;
++		}
++	}
++        
++	return FALSE;
++}
++
++int nf_debug(const char *msg)
++{
++	if (nf_ops) {
++		static long nfid_stderr = 0;
++		if (nfid_stderr == 0) {
++			nfid_stderr = NF_GETID("NF_STDERR");
++		}
++		
++		if (nfid_stderr) {
++			nf_ops->call(nfid_stderr, virt_to_phys(msg)); // TODO: lock msg to prevent swap out
++			return TRUE;
++		}
++	}
++	
++	return FALSE;
++}
++
++int nf_shutdown(void)
++{
++	if (nf_ops) {
++		long shutdown_id = NF_GETID("NF_SHUTDOWN");
++		
++		if (shutdown_id) {
++			nf_ops->call(shutdown_id);
++			return TRUE; /* never returns actually */
++		}
++	}
++
++	return FALSE;
++}
++
++#ifdef CONFIG_ATARI_NFETH
++
++/****************************/
++/* NatFeat Ethernet support */
++static long nfEtherID = 0;
++
++static int is_nf_eth(void)
++{
++	if (nf_ops) {
++		if (nfEtherID == 0) {
++			nfEtherID = NF_GETID("ETHERNET");
++		}
++	}
++	return (nfEtherID != 0);
++}
++
++int nf_ethernet_check_version(char *errmsg, int errmsglen)
++{
++	if (is_nf_eth()) {
++		static unsigned long host_ver = 0;
++		if (host_ver == 0) {
++			host_ver = nf_ops->call(ETH(GET_VERSION));
++		}
++		if (host_ver == ARAETHER_NFAPI_VERSION) {
++			return TRUE;
++		}
++		else {
++			// API version mismatch
++			if (errmsg != NULL) {
++				snprintf(errmsg, errmsglen,
++					"NatFeat Ethernet API: expected %d, got %ld",
++					ARAETHER_NFAPI_VERSION, host_ver);
++			}
++			return FALSE;
++		}
++	}
++	if (errmsg != NULL) {
++		strncpy(errmsg, "NatFeat Ethernet support not found", errmsglen);
++	}
++	return FALSE;
++}
++
++int nf_ethernet_get_irq(void)
++{
++	return is_nf_eth() ? nf_ops->call(ETH(XIF_INTLEVEL)) : 0;
++}
++
++int nf_ethernet_get_hw_addr(int ethX, char *buffer, int bufsize)
++{
++	if (is_nf_eth()) {
++		return nf_ops->call(ETH(XIF_GET_MAC), (unsigned long)ethX, virt_to_phys(buffer), (unsigned long)bufsize); // TODO: lock buffer to prevent swap out
++	}
++	return FALSE;
++}
++
++int nf_ethernet_interrupt(int bit)
++{
++	if (is_nf_eth()) {
++		return nf_ops->call(ETH(XIF_IRQ), (unsigned long)bit);
++	}
++	return 0;
++}
++
++int nf_ethernet_read_packet_len(int ethX)
++{
++	if (is_nf_eth()) {
++		return nf_ops->call(ETH(XIF_READLENGTH), (unsigned long)ethX);
++	}
++	return 0;
++}
++
++void nf_ethernet_read_block(int ethX, char *buffer, int len)
++{
++	if (is_nf_eth()) {
++		nf_ops->call(ETH(XIF_READBLOCK), (unsigned long)ethX, virt_to_phys(buffer), (unsigned long)len); // TODO: lock buffer to prevent swap out
++	}
++}
++
++void nf_ethernet_write_block(int ethX, char *buffer, int len)
++{
++	if (is_nf_eth()) {
++		nf_ops->call(ETH(XIF_WRITEBLOCK), (unsigned long)ethX, virt_to_phys(buffer), (unsigned long)len); // TODO: lock buffer to prevent swap out
++	}
++}
++
++void nf_ethernet_xif_start(int ethX)
++{
++	if (is_nf_eth()) {
++		nf_ops->call(ETH(XIF_START), (unsigned long)ethX);
++	}
++}
++
++void nf_ethernet_xif_stop(int ethX)
++{
++	if (is_nf_eth()) {
++		nf_ops->call(ETH(XIF_STOP), (unsigned long)ethX);
++	}
++}
++#endif // CONFIG_ATARI_NFETH
++
++/*
++vim:ts=4:sw=4:
++*/
+diff -urN linux-m68k/arch/m68k/atari/natfeat.h linux-schmitz/arch/m68k/atari/natfeat.h
+--- linux-m68k/arch/m68k/atari/natfeat.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-schmitz/arch/m68k/atari/natfeat.h	2006-11-19 21:37:26.000000000 +0100
+@@ -0,0 +1,35 @@
++/*
++ * ARAnyM hardware support via Native Features (natfeats)
++ *
++ * Copyright (c) 2005 Petr Stehlik of ARAnyM dev team
++ *
++ * This software may be used and distributed according to the terms of
++ * the GNU General Public License (GPL), incorporated herein by reference.
++ */
++
++#ifndef _natfeat_h
++#define _natfeat_h
++
++struct nf_ops
++{
++	long (*get_id)(const char *);
++	long (*call)(long id, ...);
++	long res[3];
++};
++
++struct nf_ops *nf_init(void);
++
++int nf_name(char *buf, int bufsize);
++int nf_debug(const char *msg);
++int nf_shutdown(void);
++
++int nf_ethernet_check_version(char *errmsg, int errmsglen);
++int nf_ethernet_get_irq(void);
++int nf_ethernet_get_hw_addr(int ethX, char *buffer, int bufsize);
++int nf_ethernet_interrupt(int bit);
++int nf_ethernet_read_packet_len(int ethX);
++void nf_ethernet_read_block(int ethX, char *buffer, int len);
++void nf_ethernet_write_block(int ethX, char *buffer, int len);
++void nf_ethernet_xif_start(int ethX);
++void nf_ethernet_xif_stop(int ethX);
++# endif /* _natfeat_h */
+diff -urN linux-m68k/arch/m68k/atari/natfeat_ethernet_nfapi.h linux-schmitz/arch/m68k/atari/natfeat_ethernet_nfapi.h
+--- linux-m68k/arch/m68k/atari/natfeat_ethernet_nfapi.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-schmitz/arch/m68k/atari/natfeat_ethernet_nfapi.h	2006-11-19 21:37:26.000000000 +0100
+@@ -0,0 +1,56 @@
++/*
++ * ARAnyM ethernet driver - header file.
++ *
++ * Copyright (c) 2002-2004 Standa and Petr of ARAnyM dev team (see AUTHORS)
++ * 
++ * This file is part of the ARAnyM project which builds a new and powerful
++ * TOS/FreeMiNT compatible virtual machine running on almost any hardware.
++ *
++ * ARAnyM is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * ARAnyM is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with ARAnyM; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#ifndef _ARAETHER_NFAPI_H
++#define _ARAETHER_NFAPI_H
++
++/*
++   The code for the FreeMiNT driver was moved to the FreeMiNT CVS:
++   freemint/sys/sockets/xif/nfeth.
++
++   If you edit this file then you would need to synchronize it with the
++   driver in the freemint CVS (nfeth_nfapi.h).
++
++   if you change anything in the enum {} below you have to increase 
++   this ARAETHER_NFAPI_VERSION!
++*/
++#define ARAETHER_NFAPI_VERSION	0x00000005
++
++enum {
++	GET_VERSION = 0,	/* no parameters, return NFAPI_VERSION in d0 */
++	XIF_INTLEVEL,		/* no parameters, return Interrupt Level in d0 */
++	XIF_IRQ,			/* acknowledge interrupt from host */
++	XIF_START,			/* (ethX), called on 'ifup', start receiver thread */
++	XIF_STOP,			/* (ethX), called on 'ifdown', stop the thread */
++	XIF_READLENGTH,		/* (ethX), return size of network data block to read */
++	XIF_READBLOCK,		/* (ethX, buffer, size), read block of network data */
++	XIF_WRITEBLOCK,		/* (ethX, buffer, size), write block of network data */
++	XIF_GET_MAC,		/* (ethX, buffer, size), return MAC HW addr in buffer */
++	XIF_GET_IPHOST,		/* (ethX, buffer, size), return IP address of host */
++	XIF_GET_IPATARI,	/* (ethX, buffer, size), return IP address of atari */
++	XIF_GET_NETMASK		/* (ethX, buffer, size), return IP netmask */
++};
++
++#define ETH(a)	(nfEtherID + a)
++
++#endif /* _ARAETHER_NFAPI_H */
+diff -urN linux-m68k/drivers/net/Kconfig linux-schmitz/drivers/net/Kconfig
+--- linux-m68k/drivers/net/Kconfig	2006-11-19 21:35:33.000000000 +0100
++++ linux-schmitz/drivers/net/Kconfig	2006-11-19 21:37:26.000000000 +0100
+@@ -396,6 +396,22 @@
+ 	  ACSI port ("ACSI node"). The driver works (has to work...) with a
+ 	  polled I/O scheme, so it's rather slow :-(
+ 
++config ATARI_NFETH
++	tristate "Atari NatFeat Ethernet support"
++	depends on NET_ETHERNET && ATARI && NATFEAT
++	help
++	  Say Y to include support for the ARAnyM NatFeat network device
++	  which will emulate a regular ethernet device while presenting an
++	  ethertap device to the host system.
++
++config ATARI_ETHERNEC
++	tristate "Atari EtherNEC Ethernet support"
++	depends on NET_ETHERNET && ATARI && ATARI_ROM_ISA
++	help
++	  Say Y to include support for the EtherNEC network adapter for the
++	  ROM port. The driver works by polling instead of interrupts, so it
++	  is quite slow.
++
+ config SUN3LANCE
+ 	tristate "Sun3/Sun3x on-board LANCE support"
+ 	depends on NET_ETHERNET && (SUN3 || SUN3X)
+diff -urN linux-m68k/drivers/net/Makefile linux-schmitz/drivers/net/Makefile
+--- linux-m68k/drivers/net/Makefile	2006-11-19 21:35:30.000000000 +0100
++++ linux-schmitz/drivers/net/Makefile	2006-11-19 21:37:26.000000000 +0100
+@@ -182,6 +182,8 @@
+ obj-$(CONFIG_ATARILANCE) += atarilance.o
+ obj-$(CONFIG_ATARI_BIONET) += atari_bionet.o
+ obj-$(CONFIG_ATARI_PAMSNET) += atari_pamsnet.o
++obj-$(CONFIG_ATARI_NFETH) += atari_nfeth.o
++obj-$(CONFIG_ATARI_ETHERNEC) += atari_ethernec.o 8390.o
+ obj-$(CONFIG_A2065) += a2065.o
+ obj-$(CONFIG_HYDRA) += hydra.o 8390.o
+ obj-$(CONFIG_ARIADNE) += ariadne.o
+diff -urN linux-m68k/drivers/net/Space.c linux-schmitz/drivers/net/Space.c
+--- linux-m68k/drivers/net/Space.c	2006-09-20 05:42:06.000000000 +0200
++++ linux-schmitz/drivers/net/Space.c	2006-11-19 21:37:26.000000000 +0100
+@@ -74,6 +74,8 @@
+ extern struct net_device *seeq8005_probe(int unit);
+ extern struct net_device *smc_init(int unit);
+ extern struct net_device *atarilance_probe(int unit);
++extern struct net_device *atari_ethernec_probe(int unit);
++extern struct net_device *atari_nfeth_probe(struct net_device *);
+ extern struct net_device *sun3lance_probe(int unit);
+ extern struct net_device *sun3_82586_probe(int unit);
+ extern struct net_device *apne_probe(int unit);
+@@ -261,6 +263,12 @@
+ #ifdef CONFIG_ATARILANCE	/* Lance-based Atari ethernet boards */
+ 	{atarilance_probe, 0},
+ #endif
++#ifdef CONFIG_ATARI_NFETH	/* ARAnyM tun/tap device */
++	{atari_nfeth_probe, 0},
++#endif
++#ifdef CONFIG_ATARI_ETHERNEC	/* NE2000 based ROM port ethernet cards */
++	{atari_ethernec_probe, 0},
++#endif
+ #ifdef CONFIG_SUN3LANCE         /* sun3 onboard Lance chip */
+ 	{sun3lance_probe, 0},
+ #endif
+diff -urN linux-m68k/drivers/net/atari_ethernec.c linux-schmitz/drivers/net/atari_ethernec.c
+--- linux-m68k/drivers/net/atari_ethernec.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-schmitz/drivers/net/atari_ethernec.c	2006-11-19 21:37:26.000000000 +0100
+@@ -0,0 +1,1065 @@
++/* 
++ * atari_ethernec.c: Atari cartridge port ethernet adapter
++ * (C) 2006 Michael Schmitz
++ *
++ * Modified after: 
++ */
++
++/* ne.c: A general non-shared-memory NS8390 ethernet driver for linux. */
++/*
++    Written 1992-94 by Donald Becker.
++
++    Copyright 1993 United States Government as represented by the
++    Director, National Security Agency.
++
++    This software may be used and distributed according to the terms
++    of the GNU General Public License, incorporated herein by reference.
++
++    The author may be reached as becker at scyld.com, or C/O
++    Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403
++
++    This driver should work with many programmed-I/O 8390-based ethernet
++    boards.  Currently it supports the NE1000, NE2000, many clones,
++    and some Cabletron products.
++
++    Changelog:
++
++    Paul Gortmaker	: use ENISR_RDC to monitor Tx PIO uploads, made
++			  sanity checks and bad clone support optional.
++    Paul Gortmaker	: new reset code, reset card after probe at boot.
++    Paul Gortmaker	: multiple card support for module users.
++    Paul Gortmaker	: Support for PCI ne2k clones, similar to lance.c
++    Paul Gortmaker	: Allow users with bad cards to avoid full probe.
++    Paul Gortmaker	: PCI probe changes, more PCI cards supported.
++    rjohnson at analogic.com : Changed init order so an interrupt will only
++    occur after memory is allocated for dev->priv. Deallocated memory
++    last in cleanup_modue()
++    Richard Guenther    : Added support for ISAPnP cards
++    Paul Gortmaker	: Discontinued PCI support - use ne2k-pci.c instead.
++    Hayato Fujiwara	: Add m32r support.
++
++*/
++
++/*
++ * From the driver distribution kit by Thomas Redelberger:
++ * 
++ * Hardware circuit description (see directory ETHERNEC for schematics)
++ *
++ * As there is no reset line on the CP, a resistor and a capacitor are
++ * used to reset the NE card on power up.
++ * 
++ * Reading from the NE card is done by a read cycle on the CP at address
++ * /ROM4 + 512*ISA address as the ISA address lines A0-A4 are connected
++ * to CP A9-A13. /ROM4 going low will start the ISA read cycle, enable
++ * the ISA bus buffers of the NE card and start decoding of the ISA IO
++ * address by the NE card. /ROM4 going high ends the cycle and the
++ * processor latches the data.
++ * 
++ * Because the CP is read only writing to the NE card must be done with
++ * the trick to read from addresses that stand for the data. Dummy reads
++ * at /ROM3 base address + data*2 + ISA address*512 effect this. You
++ * might wonder why everything appears to be shifted up one bit. There is
++ * no CP "A0" address line. There are the signals /UDS and /LDS instead
++ * typical for the 68000 family. The original design which generated an
++ * "A0" worked on an ST and an STE but did not on a Falcon.
++ * 
++ * The falling edge of /ROM3 enables the CP address lines A1-A8 onto the
++ * data bus and starts the ISA write cycle. The rising edge will end the
++ * ISA write cycle and the NE latches the data. The processor will also
++ * see and just read this same data but that is harmless.
++ * Elmar Hilgart reported that the bus buffer IC shall be an TTL F-type
++ * to keep up with the fast cycles on the Falcon.
++ *
++ * Base addresses:
++ * rom4            EQU     $00fa0000       ; ROM4 base address
++ * rom3            EQU     $00fb0000       ; ROM3 base address
++ *
++ */
++
++/* Routines for the NatSemi-based designs (NE[12]000). */
++
++static const char version1[] =
++"ne.c:v1.10 9/23/94 Donald Becker (becker at scyld.com)\n";
++static const char version2[] =
++"atari_ethernec.c 11/10/06 Michael Schmitz (schmitz at debian.org)\n";
++
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/wait.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/isapnp.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/jiffies.h>
++
++#include <asm/system.h>
++#include <asm/atarihw.h>
++#include <asm/atariints.h>
++#include <asm/io.h>
++
++#include "8390.h"
++
++#define DRV_NAME "ethernec"
++
++/* Some defines that people can play with if so inclined. */
++
++/* Do we support clones that don't adhere to 14,15 of the SAprom ? */
++#define SUPPORT_NE_BAD_CLONES
++
++/* Do we perform extra sanity checks on stuff ? */
++/* #define NE_SANITY_CHECK */
++
++/* Do we implement the read before write bugfix ? */
++/* #define NE_RW_BUGFIX */
++
++/* Do we have a non std. amount of memory? (in units of 256 byte pages) */
++/* #define PACKETBUF_MEMSIZE	0x40 */
++
++/* A zero-terminated list of I/O addresses to be probed at boot. */
++#ifndef MODULE
++static unsigned int netcard_portlist[] __initdata = {
++	0x300, 0x280, 0x320, 0x340, 0x360, 0x380, 0
++};
++#endif
++
++static struct isapnp_device_id isapnp_clone_list[] __initdata = {
++	{	ISAPNP_CARD_ID('A','X','E',0x2011),
++		ISAPNP_VENDOR('A','X','E'), ISAPNP_FUNCTION(0x2011),
++		(long) "NetGear EA201" },
++	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
++		ISAPNP_VENDOR('E','D','I'), ISAPNP_FUNCTION(0x0216),
++		(long) "NN NE2000" },
++	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
++		ISAPNP_VENDOR('P','N','P'), ISAPNP_FUNCTION(0x80d6),
++		(long) "Generic PNP" },
++	{ }	/* terminate list */
++};
++
++MODULE_DEVICE_TABLE(isapnp, isapnp_clone_list);
++
++#ifdef SUPPORT_NE_BAD_CLONES
++/* A list of bad clones that we none-the-less recognize. */
++static struct { const char *name8, *name16; unsigned char SAprefix[4];}
++bad_clone_list[] __initdata = {
++    {"DE100", "DE200", {0x00, 0xDE, 0x01,}},
++    {"DE120", "DE220", {0x00, 0x80, 0xc8,}},
++    {"DFI1000", "DFI2000", {'D', 'F', 'I',}}, /* Original, eh?  */
++    {"EtherNext UTP8", "EtherNext UTP16", {0x00, 0x00, 0x79}},
++    {"NE1000","NE2000-invalid", {0x00, 0x00, 0xd8}}, /* Ancient real NE1000. */
++    {"NN1000", "NN2000",  {0x08, 0x03, 0x08}}, /* Outlaw no-name clone. */
++    {"4-DIM8","4-DIM16", {0x00,0x00,0x4d,}},  /* Outlaw 4-Dimension cards. */
++    {"Con-Intl_8", "Con-Intl_16", {0x00, 0x00, 0x24}}, /* Connect Int'nl */
++    {"ET-100","ET-200", {0x00, 0x45, 0x54}}, /* YANG and YA clone */
++    {"COMPEX","COMPEX16",{0x00,0x80,0x48}}, /* Broken ISA Compex cards */
++    {"E-LAN100", "E-LAN200", {0x00, 0x00, 0x5d}}, /* Broken ne1000 clones */
++    {"PCM-4823", "PCM-4823", {0x00, 0xc0, 0x6c}}, /* Broken Advantech MoBo */
++    {"REALTEK", "RTL8019", {0x00, 0x00, 0xe8}}, /* no-name with Realtek chip */
++#if defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938)
++    {"RBHMA4X00-RTL8019", "RBHMA4X00/RTL8019", {0x00, 0x60, 0x0a}},  /* Toshiba built-in */
++#endif
++    {"LCS-8834", "LCS-8836", {0x04, 0x04, 0x37}}, /* ShinyNet (SET) */
++    {NULL,}
++};
++#endif
++
++/* ---- No user-serviceable parts below ---- */
++
++#define NE_BASE	 (dev->base_addr)
++#define NE_CMD	 	0x00
++#define NE_DATAPORT	0x10	/* NatSemi-defined port window offset. */
++#define NE_RESET	0x1f	/* Issue a read to reset, a write to clear. */
++#define NE_IO_EXTENT	0x20
++
++#define NE1SM_START_PG	0x20	/* First page of TX buffer */
++#define NE1SM_STOP_PG 	0x40	/* Last page +1 of RX ring */
++#define NESM_START_PG	0x40	/* First page of TX buffer */
++#define NESM_STOP_PG	0x80	/* Last page +1 of RX ring */
++
++#if defined(CONFIG_PLAT_MAPPI)
++#  define DCR_VAL 0x4b
++#elif defined(CONFIG_PLAT_OAKS32R)  || \
++   defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938) || \
++   defined(CONFIG_ATARI_ETHERNEC)
++#  define DCR_VAL 0x48		/* 8-bit mode */
++#else
++#  define DCR_VAL 0x49
++#endif
++
++#if defined(CONFIG_ATARI_ETHERNEC)
++#  define ETHERNEC_RTL_8019_BASE 0x300
++#  define ETHERNEC_RTL_8019_IRQ IRQ_MFP_TIMD
++#endif
++
++static int ne_probe1(struct net_device *dev, int ioaddr);
++static int ne_probe_isapnp(struct net_device *dev);
++
++static int ne_open(struct net_device *dev);
++static int ne_close(struct net_device *dev);
++
++static void ne_reset_8390(struct net_device *dev);
++static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
++			  int ring_page);
++static void ne_block_input(struct net_device *dev, int count,
++			  struct sk_buff *skb, int ring_offset);
++static void ne_block_output(struct net_device *dev, const int count,
++		const unsigned char *buf, const int start_page);
++
++
++/*
++ * The Atari ROM port has no interrupt line, so we poll the card instead.
++ */
++
++static int use_poll = 0;
++
++/* This is used by cleanup, to prevent the module from being unloaded while
++ * intrpt_routine is still in the task queue
++ */
++static wait_queue_head_t WaitQ;
++
++static struct work_struct tqueue;
++
++static struct {
++	struct work_struct poll_queue;
++	struct timer_list poll_timer;
++	struct net_device *dev;
++} poll_ops;
++
++static struct net_device *poll_dev = NULL;
++
++static void atari_ethernec_int(unsigned long dev_addr)
++{
++	struct net_device *dev  = poll_dev;
++
++        if(!dev) {
++	        /* If cleanup wants us to die */
++                if (waitqueue_active(&WaitQ)) 
++                  wake_up(&WaitQ);               /* Now cleanup_module can return */
++                else
++                  /* Put ourselves back in the task queue */
++                  schedule_delayed_work(&tqueue, 1);
++		return;
++        }
++
++	if (netif_running(dev)) {
++		ei_interrupt(dev->irq, dev, NULL);
++        }
++
++	/* If cleanup wants us to die */
++	if (waitqueue_active(&WaitQ)) 
++	wake_up(&WaitQ);               /* Now cleanup_module can return */
++	else
++	/* Put ourselves back in the task queue */
++	schedule_delayed_work(&tqueue, 0); /* reduced delay from 1 */
++}
++
++#if defined (ETHERNEC_USE_POLL)
++static void atari_ethernec_poll_handler(unsigned long dev_addr)
++{
++	struct net_device *dev  = poll_dev;
++
++        if(!dev || !dev->poll_controller)
++		return;
++
++	if (netif_running(dev)) 
++		dev->poll_controller(dev);
++
++	schedule_work(&poll_ops.poll_queue);
++	mod_timer(&poll_ops.poll_timer, jiffies + HZ/100);
++}
++#endif
++
++static void atari_ethernec_start_poll(struct net_device *dev)
++{
++	poll_dev = dev;
++
++	init_waitqueue_head(&WaitQ);
++
++	INIT_WORK(&tqueue, (void (*)(void *))atari_ethernec_int, dev);
++	schedule_delayed_work(&tqueue, 1);
++#if defined (ETHERNEC_USE_POLL)
++	if ((!poll_ops.poll_queue.func || poll_ops.poll_queue.func == ei_interrupt)) {
++		if (!poll_ops.poll_queue.func)
++			INIT_WORK(&poll_ops.poll_queue, ei_interrupt, dev);
++
++		init_timer(&poll_ops.poll_timer);
++		poll_ops.poll_timer.function = atari_ethernec_poll_handler;
++		poll_ops.poll_timer.expires = jiffies + HZ / 5;
++		poll_ops.poll_timer.data = (unsigned long ) dev;
++		add_timer(&poll_ops.poll_timer);
++	}
++#endif
++}
++
++static void atari_ethernec_stop_poll(struct net_device *dev)
++{
++	poll_dev = NULL;
++
++	if (dev) {
++	        sleep_on(&WaitQ);
++	}
++
++#if defined (ETHERNEC_USE_POLL)
++	if (poll_ops.poll_queue.func == ei_interrupt) {
++		del_timer_sync(&poll_ops.poll_timer);
++	}
++#endif
++}
++
++
++/*  Probe for various non-shared-memory ethercards.
++
++   NEx000-clone boards have a Station Address PROM (SAPROM) in the packet
++   buffer memory space.  NE2000 clones have 0x57,0x57 in bytes 0x0e,0x0f of
++   the SAPROM, while other supposed NE2000 clones must be detected by their
++   SA prefix.
++
++   Reading the SAPROM from a word-wide card with the 8390 set in byte-wide
++   mode results in doubled values, which can be detected and compensated for.
++
++   The probe is also responsible for initializing the card and filling
++   in the 'dev' and 'ei_status' structures.
++
++   We use the minimum memory size for some ethercard product lines, iff we can't
++   distinguish models.  You can increase the packet buffer size by setting
++   PACKETBUF_MEMSIZE.  Reported Cabletron packet buffer locations are:
++	E1010   starts at 0x100 and ends at 0x2000.
++	E1010-x starts at 0x100 and ends at 0x8000. ("-x" means "more memory")
++	E2010	 starts at 0x100 and ends at 0x4000.
++	E2010-x starts at 0x100 and ends at 0xffff.  */
++
++static int __init do_ne_probe(struct net_device *dev)
++{
++	unsigned int base_addr = dev->base_addr;
++	int rv;
++#ifndef MODULE
++	int orig_irq = dev->irq;
++#endif
++
++	SET_MODULE_OWNER(dev);
++
++	/* First check any supplied i/o locations. User knows best. <cough> */
++	if (base_addr > 0x1ff) {	/* Check a single specified location. */
++		rv =ne_probe1(dev, base_addr);
++		if (!rv && use_poll) {
++			/* Seems we have a valid device here; set up polling routine */
++			poll_dev = dev;
++			atari_ethernec_start_poll(dev);
++		}
++		return rv;
++	} else if (base_addr != 0)	/* Don't probe at all. */
++		return -ENXIO;
++
++	/* Then look for any installed ISAPnP clones */
++	if (isapnp_present() && (ne_probe_isapnp(dev) == 0))
++		return 0;
++
++#ifndef MODULE
++	/* Last resort. The semi-risky ISA auto-probe. */
++	for (base_addr = 0; netcard_portlist[base_addr] != 0; base_addr++) {
++		int ioaddr = netcard_portlist[base_addr];
++		dev->irq = orig_irq;
++		rv = ne_probe1(dev, ioaddr);
++		if (rv == 0) {
++			if (use_poll) {
++				poll_dev = dev;
++				atari_ethernec_start_poll(dev);
++			}
++			return 0;
++		}
++	}
++#endif
++
++	return -ENODEV;
++}
++
++#ifndef MODULE
++struct net_device * __init atari_ethernec_probe(int unit)
++{
++	struct net_device *dev = alloc_ei_netdev();
++	int err;
++
++	if (!dev)
++		return ERR_PTR(-ENOMEM);
++
++	sprintf(dev->name, "eth%d", unit);
++	netdev_boot_setup_check(dev);
++
++#ifdef CONFIG_ATARI_ETHERNEC
++	dev->base_addr = ETHERNEC_RTL_8019_BASE;
++	dev->irq = ETHERNEC_RTL_8019_IRQ;
++#endif
++	err = do_ne_probe(dev);
++	if (err)
++		goto out;
++
++	/* Seems we have a valid device here; set up polling routine */
++	return dev;
++out:
++	free_netdev(dev);
++	return ERR_PTR(err);
++}
++#endif
++
++static int __init ne_probe_isapnp(struct net_device *dev)
++{
++	int i;
++
++	for (i = 0; isapnp_clone_list[i].vendor != 0; i++) {
++		struct pnp_dev *idev = NULL;
++
++		while ((idev = pnp_find_dev(NULL,
++					    isapnp_clone_list[i].vendor,
++					    isapnp_clone_list[i].function,
++					    idev))) {
++			/* Avoid already found cards from previous calls */
++			if (pnp_device_attach(idev) < 0)
++				continue;
++			if (pnp_activate_dev(idev) < 0) {
++			      	pnp_device_detach(idev);
++			      	continue;
++			}
++			/* if no io and irq, search for next */
++			if (!pnp_port_valid(idev, 0) || !pnp_irq_valid(idev, 0)) {
++				pnp_device_detach(idev);
++				continue;
++			}
++			/* found it */
++			dev->base_addr = pnp_port_start(idev, 0);
++			dev->irq = pnp_irq(idev, 0);
++			printk(KERN_INFO "atari_ethernec.c: ISAPnP reports %s at i/o %#lx, irq %d.\n",
++				(char *) isapnp_clone_list[i].driver_data,
++				dev->base_addr, dev->irq);
++			if (ne_probe1(dev, dev->base_addr) != 0) {	/* Shouldn't happen. */
++				printk(KERN_ERR "atari_ethernec.c: Probe of ISAPnP card at %#lx failed.\n", dev->base_addr);
++				pnp_device_detach(idev);
++				return -ENXIO;
++			}
++			ei_status.priv = (unsigned long)idev;
++			break;
++		}
++		if (!idev)
++			continue;
++		return 0;
++	}
++
++	return -ENODEV;
++}
++
++static int __init ne_probe1(struct net_device *dev, int ioaddr)
++{
++	int i;
++	unsigned char SA_prom[32];
++	int wordlength = 2;
++	const char *name = NULL;
++	int start_page, stop_page;
++	int neX000, ctron, copam, bad_card;
++	int reg0, ret;
++	static unsigned version_printed;
++
++	if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME))
++		return -EBUSY;
++
++	reg0 = inb_p(ioaddr);
++	if (reg0 == 0xFF) {
++		ret = -ENODEV;
++		goto err_out;
++	}
++
++	/* Do a preliminary verification that we have a 8390. */
++	{
++		int regd;
++		outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD);
++		regd = inb_p(ioaddr + 0x0d);
++		outb_p(0xff, ioaddr + 0x0d);
++		outb_p(E8390_NODMA+E8390_PAGE0, ioaddr + E8390_CMD);
++		inb_p(ioaddr + EN0_COUNTER0); /* Clear the counter by reading. */
++		if (inb_p(ioaddr + EN0_COUNTER0) != 0) {
++			outb_p(reg0, ioaddr);
++			outb_p(regd, ioaddr + 0x0d);	/* Restore the old values. */
++			ret = -ENODEV;
++			goto err_out;
++		}
++	}
++
++	if (ei_debug  &&  version_printed++ == 0)
++		printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
++
++	/* A user with a poor card that fails to ack the reset, or that
++	   does not have a valid 0x57,0x57 signature can still use this
++	   without having to recompile. Specifying an i/o address along
++	   with an otherwise unused dev->mem_end value of "0xBAD" will
++	   cause the driver to skip these parts of the probe. */
++
++	bad_card = ((dev->base_addr != 0) && (dev->mem_end == 0xbad));
++
++	/* Reset card. Who knows what dain-bramaged state it was left in. */
++
++	{
++		unsigned long reset_start_time = jiffies;
++
++		/* DON'T change these to inb_p/outb_p or reset will fail on clones. */
++		outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET);
++
++		while ((inb_p(ioaddr + EN0_ISR) & ENISR_RESET) == 0)
++		if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
++			if (bad_card) {
++				printk(" (warning: no reset ack)");
++				break;
++			} else {
++				// MSch: ARAnyM exits here
++				printk(" not found (no reset ack).\n");
++				ret = -ENODEV;
++				goto err_out;
++			}
++		}
++
++		outb_p(0xff, ioaddr + EN0_ISR);		/* Ack all intr. */
++	}
++
++	/* Read the 16 bytes of station address PROM.
++	   We must first initialize registers, similar to NS8390_init(eifdev, 0).
++	   We can't reliably read the SAPROM address without this.
++	   (I learned the hard way!). */
++	{
++		struct {unsigned char value, offset; } program_seq[] =
++		{
++			{E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
++			{0x48,	EN0_DCFG},	/* Set byte-wide (0x48) access. */
++			{0x00,	EN0_RCNTLO},	/* Clear the count regs. */
++			{0x00,	EN0_RCNTHI},
++			{0x00,	EN0_IMR},	/* Mask completion irq. */
++			{0xFF,	EN0_ISR},
++			{E8390_RXOFF, EN0_RXCR},	/* 0x20  Set to monitor */
++			{E8390_TXOFF, EN0_TXCR},	/* 0x02  and loopback mode. */
++			{32,	EN0_RCNTLO},
++			{0x00,	EN0_RCNTHI},
++			{0x00,	EN0_RSARLO},	/* DMA starting at 0x0000. */
++			{0x00,	EN0_RSARHI},
++			{E8390_RREAD+E8390_START, E8390_CMD},
++		};
++
++		for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
++			outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
++
++	}
++	for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {
++		SA_prom[i] = inb(ioaddr + NE_DATAPORT);
++		SA_prom[i+1] = inb(ioaddr + NE_DATAPORT);
++		if (SA_prom[i] != SA_prom[i+1])
++			wordlength = 1;
++	}
++
++	if (wordlength == 2)
++	{
++		for (i = 0; i < 16; i++)
++			SA_prom[i] = SA_prom[i+i];
++		/* We must set the 8390 for word mode. */
++		outb_p(DCR_VAL, ioaddr + EN0_DCFG);
++		start_page = NESM_START_PG;
++
++		/*
++		 * Realtek RTL8019AS datasheet says that the PSTOP register
++		 * shouldn't exceed 0x60 in 8-bit mode.
++		 * This chip can be identified by reading the signature from
++		 * the  remote byte count registers (otherwise write-only)...
++		 */
++		if ((DCR_VAL & 0x01) == 0 &&		/* 8-bit mode */
++		    inb(ioaddr + EN0_RCNTLO) == 0x50 &&
++		    inb(ioaddr + EN0_RCNTHI) == 0x70)
++			stop_page = 0x60;
++		else
++			stop_page = NESM_STOP_PG;
++	} else {
++		start_page = NE1SM_START_PG;
++		stop_page  = NE1SM_STOP_PG;
++	}
++
++#if  defined(CONFIG_PLAT_MAPPI) || defined(CONFIG_PLAT_OAKS32R)
++	neX000 = ((SA_prom[14] == 0x57  &&  SA_prom[15] == 0x57)
++		|| (SA_prom[14] == 0x42 && SA_prom[15] == 0x42));
++#else
++	neX000 = (SA_prom[14] == 0x57  &&  SA_prom[15] == 0x57);
++#endif
++	ctron =  (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d);
++	copam =  (SA_prom[14] == 0x49 && SA_prom[15] == 0x00);
++
++	/* Set up the rest of the parameters. */
++	if (neX000 || bad_card || copam) {
++		name = (wordlength == 2) ? "NE2000" : "NE1000";
++	}
++	else if (ctron)
++	{
++		name = (wordlength == 2) ? "Ctron-8" : "Ctron-16";
++		start_page = 0x01;
++		stop_page = (wordlength == 2) ? 0x40 : 0x20;
++	}
++	else
++	{
++#ifdef SUPPORT_NE_BAD_CLONES
++		/* Ack!  Well, there might be a *bad* NE*000 clone there.
++		   Check for total bogus addresses. */
++		for (i = 0; bad_clone_list[i].name8; i++)
++		{
++			if (SA_prom[0] == bad_clone_list[i].SAprefix[0] &&
++				SA_prom[1] == bad_clone_list[i].SAprefix[1] &&
++				SA_prom[2] == bad_clone_list[i].SAprefix[2])
++			{
++				if (wordlength == 2)
++				{
++					name = bad_clone_list[i].name16;
++				} else {
++					name = bad_clone_list[i].name8;
++				}
++				break;
++			}
++		}
++		if (bad_clone_list[i].name8 == NULL)
++		{
++			printk(" not found (invalid signature %2.2x %2.2x).\n",
++				SA_prom[14], SA_prom[15]);
++			ret = -ENXIO;
++			goto err_out;
++		}
++#else
++		printk(" not found.\n");
++		ret = -ENXIO;
++		goto err_out;
++#endif
++	}
++
++	if (dev->irq < 2)
++	{
++		unsigned long cookie = probe_irq_on();
++		outb_p(0x50, ioaddr + EN0_IMR);	/* Enable one interrupt. */
++		outb_p(0x00, ioaddr + EN0_RCNTLO);
++		outb_p(0x00, ioaddr + EN0_RCNTHI);
++		outb_p(E8390_RREAD+E8390_START, ioaddr); /* Trigger it... */
++		mdelay(10);		/* wait 10ms for interrupt to propagate */
++		outb_p(0x00, ioaddr + EN0_IMR); 		/* Mask it again. */
++		dev->irq = probe_irq_off(cookie);
++		if (ei_debug > 2)
++			printk(" autoirq is %d\n", dev->irq);
++	} else if (dev->irq == 2)
++		/* Fixup for users that don't know that IRQ 2 is really IRQ 9,
++		   or don't know which one to set. */
++		dev->irq = 9;
++
++	/*
++	 * use timer based polling!
++	 */
++	if (! dev->irq) {
++		printk(" failed to detect IRQ line. Assuming irq %d\n", ETHERNEC_RTL_8019_IRQ);
++		dev->irq = ETHERNEC_RTL_8019_IRQ;
++		/* timer routine set up in atari_ethernec_probe() */
++		if (dev->irq == IRQ_MFP_TIMD) {
++                        /* set Timer D data Register */
++                        mfp.tim_dt_d = 123;	/* 200 Hz */
++                        /* start timer D, div = 1:100 */
++                        mfp.tim_ct_cd = (mfp.tim_ct_cd & 0xf0) | 0x6; 
++                }
++		ret = request_irq(dev->irq, ei_interrupt, 0, name, dev);
++                if (ret) {
++		    printk (" unable to get IRQ %d (errno=%d), polling instead.\n", dev->irq, ret);
++                    use_poll = 1;
++                }
++	} else {
++
++		/* Snarf the interrupt now.  There's no point in waiting since we cannot
++		   share and the board will usually be enabled. */
++		ret = request_irq(dev->irq, ei_interrupt, 0, name, dev);
++		if (ret) {
++			printk (" unable to get IRQ %d (errno=%d).\n", dev->irq, ret);
++			goto err_out;
++		}
++	}
++	dev->base_addr = ioaddr;
++
++#ifdef CONFIG_PLAT_MAPPI
++	outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP,
++		ioaddr + E8390_CMD); /* 0x61 */
++	for (i = 0 ; i < ETHER_ADDR_LEN ; i++) {
++		dev->dev_addr[i] = SA_prom[i]
++			= inb_p(ioaddr + EN1_PHYS_SHIFT(i));
++		printk(" %2.2x", SA_prom[i]);
++	}
++#else
++	for(i = 0; i < ETHER_ADDR_LEN; i++) {
++		printk(" %2.2x", SA_prom[i]);
++		dev->dev_addr[i] = SA_prom[i];
++	}
++#endif
++
++	printk("\n%s: %s found at %#x, using IRQ %d.\n",
++		dev->name, name, ioaddr, dev->irq);
++
++	ei_status.name = name;
++	ei_status.tx_start_page = start_page;
++	ei_status.stop_page = stop_page;
++
++	/* Use 16-bit mode only if this wasn't overridden by DCR_VAL */
++	ei_status.word16 = (wordlength == 2 && (DCR_VAL & 0x01));
++
++	ei_status.rx_start_page = start_page + TX_PAGES;
++#ifdef PACKETBUF_MEMSIZE
++	 /* Allow the packet buffer size to be overridden by know-it-alls. */
++	ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE;
++#endif
++
++	ei_status.reset_8390 = &ne_reset_8390;
++	ei_status.block_input = &ne_block_input;
++	ei_status.block_output = &ne_block_output;
++	ei_status.get_8390_hdr = &ne_get_8390_hdr;
++	ei_status.priv = 0;
++	dev->open = &ne_open;
++	dev->stop = &ne_close;
++#ifdef CONFIG_NET_POLL_CONTROLLER
++	dev->poll_controller = ei_poll;
++#endif
++	NS8390_init(dev, 0);
++
++	ret = register_netdev(dev);
++	if (ret)
++		goto out_irq;
++	return 0;
++
++out_irq:
++	free_irq(dev->irq, dev);
++err_out:
++	release_region(ioaddr, NE_IO_EXTENT);
++	return ret;
++}
++
++static int ne_open(struct net_device *dev)
++{
++	ei_open(dev);
++	return 0;
++}
++
++static int ne_close(struct net_device *dev)
++{
++	if (ei_debug > 1)
++		printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name);
++	ei_close(dev);
++	return 0;
++}
++
++/* Hard reset the card.  This used to pause for the same period that a
++   8390 reset command required, but that shouldn't be necessary. */
++
++static void ne_reset_8390(struct net_device *dev)
++{
++	unsigned long reset_start_time = jiffies;
++
++	if (ei_debug > 1)
++		printk(KERN_DEBUG "resetting the 8390 t=%ld...", jiffies);
++
++	/* DON'T change these to inb_p/outb_p or reset will fail on clones. */
++	outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);
++
++	ei_status.txing = 0;
++	ei_status.dmaing = 0;
++
++	/* This check _should_not_ be necessary, omit eventually. */
++	while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0)
++		if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
++			printk(KERN_WARNING "%s: ne_reset_8390() did not complete.\n", dev->name);
++			break;
++		}
++	outb_p(ENISR_RESET, NE_BASE + EN0_ISR);	/* Ack intr. */
++}
++
++/* Grab the 8390 specific header. Similar to the block_input routine, but
++   we don't need to be concerned with ring wrap as the header will be at
++   the start of a page, so we optimize accordingly. */
++
++static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
++{
++	int nic_base = dev->base_addr;
++
++	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
++
++	if (ei_status.dmaing)
++	{
++		printk(KERN_EMERG "%s: DMAing conflict in ne_get_8390_hdr "
++			"[DMAstat:%d][irqlock:%d].\n",
++			dev->name, ei_status.dmaing, ei_status.irqlock);
++		return;
++	}
++
++	ei_status.dmaing |= 0x01;
++	outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
++	outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
++	outb_p(0, nic_base + EN0_RCNTHI);
++	outb_p(0, nic_base + EN0_RSARLO);		/* On page boundary */
++	outb_p(ring_page, nic_base + EN0_RSARHI);
++	outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
++
++	if (ei_status.word16)
++		insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
++	else
++		insb(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr));
++
++	outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
++	ei_status.dmaing &= ~0x01;
++
++	le16_to_cpus(&hdr->count);
++}
++
++/* Block input and output, similar to the Crynwr packet driver.  If you
++   are porting to a new ethercard, look at the packet driver source for hints.
++   The NEx000 doesn't share the on-board packet memory -- you have to put
++   the packet out through the "remote DMA" dataport using outb. */
++
++static void ne_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
++{
++#ifdef NE_SANITY_CHECK
++	int xfer_count = count;
++#endif
++	int nic_base = dev->base_addr;
++	char *buf = skb->data;
++
++	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
++	if (ei_status.dmaing)
++	{
++		printk(KERN_EMERG "%s: DMAing conflict in ne_block_input "
++			"[DMAstat:%d][irqlock:%d].\n",
++			dev->name, ei_status.dmaing, ei_status.irqlock);
++		return;
++	}
++	ei_status.dmaing |= 0x01;
++	outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
++	outb_p(count & 0xff, nic_base + EN0_RCNTLO);
++	outb_p(count >> 8, nic_base + EN0_RCNTHI);
++	outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
++	outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
++	outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
++	if (ei_status.word16)
++	{
++		insw(NE_BASE + NE_DATAPORT,buf,count>>1);
++		if (count & 0x01)
++		{
++			buf[count-1] = inb(NE_BASE + NE_DATAPORT);
++#ifdef NE_SANITY_CHECK
++			xfer_count++;
++#endif
++		}
++	} else {
++		insb(NE_BASE + NE_DATAPORT, buf, count);
++	}
++
++#ifdef NE_SANITY_CHECK
++	/* This was for the ALPHA version only, but enough people have
++	   been encountering problems so it is still here.  If you see
++	   this message you either 1) have a slightly incompatible clone
++	   or 2) have noise/speed problems with your bus. */
++
++	if (ei_debug > 1)
++	{
++		/* DMA termination address check... */
++		int addr, tries = 20;
++		do {
++			/* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here
++			   -- it's broken for Rx on some cards! */
++			int high = inb_p(nic_base + EN0_RSARHI);
++			int low = inb_p(nic_base + EN0_RSARLO);
++			addr = (high << 8) + low;
++			if (((ring_offset + xfer_count) & 0xff) == low)
++				break;
++		} while (--tries > 0);
++	 	if (tries <= 0)
++			printk(KERN_WARNING "%s: RX transfer address mismatch,"
++				"%#4.4x (expected) vs. %#4.4x (actual).\n",
++				dev->name, ring_offset + xfer_count, addr);
++	}
++#endif
++	outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
++	ei_status.dmaing &= ~0x01;
++}
++
++static void ne_block_output(struct net_device *dev, int count,
++		const unsigned char *buf, const int start_page)
++{
++	int nic_base = NE_BASE;
++	unsigned long dma_start;
++#ifdef NE_SANITY_CHECK
++	int retries = 0;
++#endif
++
++	/* Round the count up for word writes.  Do we need to do this?
++	   What effect will an odd byte count have on the 8390?
++	   I should check someday. */
++
++	if (ei_status.word16 && (count & 0x01))
++		count++;
++
++	/* This *shouldn't* happen. If it does, it's the last thing you'll see */
++	if (ei_status.dmaing)
++	{
++		printk(KERN_EMERG "%s: DMAing conflict in ne_block_output."
++			"[DMAstat:%d][irqlock:%d]\n",
++			dev->name, ei_status.dmaing, ei_status.irqlock);
++		return;
++	}
++	ei_status.dmaing |= 0x01;
++	/* We should already be in page 0, but to be safe... */
++	outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
++
++#ifdef NE_SANITY_CHECK
++retry:
++#endif
++
++#ifdef NE8390_RW_BUGFIX
++	/* Handle the read-before-write bug the same way as the
++	   Crynwr packet driver -- the NatSemi method doesn't work.
++	   Actually this doesn't always work either, but if you have
++	   problems with your NEx000 this is better than nothing! */
++
++	outb_p(0x42, nic_base + EN0_RCNTLO);
++	outb_p(0x00,   nic_base + EN0_RCNTHI);
++	outb_p(0x42, nic_base + EN0_RSARLO);
++	outb_p(0x00, nic_base + EN0_RSARHI);
++	outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
++	/* Make certain that the dummy read has occurred. */
++	udelay(6);
++#endif
++
++	outb_p(ENISR_RDC, nic_base + EN0_ISR);
++
++	/* Now the normal output. */
++	outb_p(count & 0xff, nic_base + EN0_RCNTLO);
++	outb_p(count >> 8,   nic_base + EN0_RCNTHI);
++	outb_p(0x00, nic_base + EN0_RSARLO);
++	outb_p(start_page, nic_base + EN0_RSARHI);
++
++	outb_p(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
++	if (ei_status.word16) {
++		outsw(NE_BASE + NE_DATAPORT, buf, count>>1);
++	} else {
++		outsb(NE_BASE + NE_DATAPORT, buf, count);
++	}
++
++	dma_start = jiffies;
++
++#ifdef NE_SANITY_CHECK
++	/* This was for the ALPHA version only, but enough people have
++	   been encountering problems so it is still here. */
++
++	if (ei_debug > 1)
++	{
++		/* DMA termination address check... */
++		int addr, tries = 20;
++		do {
++			int high = inb_p(nic_base + EN0_RSARHI);
++			int low = inb_p(nic_base + EN0_RSARLO);
++			addr = (high << 8) + low;
++			if ((start_page << 8) + count == addr)
++				break;
++		} while (--tries > 0);
++
++		if (tries <= 0)
++		{
++			printk(KERN_WARNING "%s: Tx packet transfer address mismatch,"
++				"%#4.4x (expected) vs. %#4.4x (actual).\n",
++				dev->name, (start_page << 8) + count, addr);
++			if (retries++ == 0)
++				goto retry;
++		}
++	}
++#endif
++
++	while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0)
++		if (time_after(jiffies, dma_start + 2*HZ/100)) {		/* 20ms */
++			printk(KERN_WARNING "%s: timeout waiting for Tx RDC.\n", dev->name);
++			ne_reset_8390(dev);
++			NS8390_init(dev,1);
++			break;
++		}
++
++	outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
++	ei_status.dmaing &= ~0x01;
++	return;
++}
++
++
++#ifdef MODULE
++#define MAX_NE_CARDS	4	/* Max number of NE cards per module */
++static struct net_device *dev_ne[MAX_NE_CARDS];
++static int io[MAX_NE_CARDS];
++static int irq[MAX_NE_CARDS];
++static int bad[MAX_NE_CARDS];	/* 0xbad = bad sig or no reset ack */
++
++module_param_array(io, int, NULL, 0);
++module_param_array(irq, int, NULL, 0);
++module_param_array(bad, int, NULL, 0);
++module_param(use_poll, int, 0);
++MODULE_PARM_DESC(io, "I/O base address(es),required");
++MODULE_PARM_DESC(irq, "IRQ number(s)");
++MODULE_PARM_DESC(bad, "Accept card(s) with bad signatures");
++MODULE_PARM_DESC(use_poll, "Use timer interrupt to poll driver");
++MODULE_DESCRIPTION("NE1000/NE2000 ISA/PnP Ethernet driver");
++MODULE_LICENSE("GPL");
++
++/* This is set up so that no ISA autoprobe takes place. We can't guarantee
++that the ne2k probe is the last 8390 based probe to take place (as it
++is at boot) and so the probe will get confused by any other 8390 cards.
++ISA device autoprobes on a running machine are not recommended anyway. */
++
++int __init init_module(void)
++{
++	int this_dev, found = 0;
++
++	for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
++		struct net_device *dev = alloc_ei_netdev();
++		if (!dev)
++			break;
++		dev->irq = irq[this_dev];
++		dev->mem_end = bad[this_dev];
++		dev->base_addr = io[this_dev];
++		if (do_ne_probe(dev) == 0) {
++			dev_ne[found++] = dev;
++			continue;
++		}
++		free_netdev(dev);
++		if (found)
++			break;
++		if (io[this_dev] != 0)
++			printk(KERN_WARNING "atari_ethernec.c: No NE*000 card found at i/o = %#x\n", io[this_dev]);
++		else
++			printk(KERN_NOTICE "atari_ethernec.c: You must supply \"io=0xNNN\" value(s) for ISA cards.\n");
++		return -ENXIO;
++	}
++	if (found)
++		return 0;
++	return -ENODEV;
++}
++
++static void cleanup_card(struct net_device *dev)
++{
++	struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv;
++	if (idev)
++		pnp_device_detach(idev);
++	free_irq(dev->irq, dev);
++	release_region(dev->base_addr, NE_IO_EXTENT);
++}
++
++void cleanup_module(void)
++{
++	int this_dev;
++
++	for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
++		struct net_device *dev = dev_ne[this_dev];
++		if (dev) {
++			if (use_poll)
++                        	atari_ethernec_stop_poll(dev);
++			unregister_netdev(dev);
++			cleanup_card(dev);
++			free_netdev(dev);
++		}
++	}
++}
++#endif /* MODULE */
+diff -urN linux-m68k/drivers/net/atari_nfeth.c linux-schmitz/drivers/net/atari_nfeth.c
+--- linux-m68k/drivers/net/atari_nfeth.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-schmitz/drivers/net/atari_nfeth.c	2006-11-19 21:37:26.000000000 +0100
+@@ -0,0 +1,327 @@
++/*
++ * atari_nfeth.c - ARAnyM ethernet card driver for GNU/Linux
++ *
++ * Copyright (c) 2005 Milan Jurik, Petr Stehlik of ARAnyM dev team
++ *
++ * Based on ARAnyM driver for FreeMiNT written by Standa Opichal
++ * 
++ * This software may be used and distributed according to the terms of
++ * the GNU General Public License (GPL), incorporated herein by reference.
++ */
++
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/module.h>
++#include <asm/atariints.h>
++
++#include "../../arch/m68k/atari/natfeat.h"
++
++#define DRV_NAME        "atari_nfeth"
++#define DRV_VERSION     "0.3"
++#define DRV_RELDATE     "10/12/2005"
++
++/* These identify the driver base version and may not be removed. */
++static char version[] __devinitdata =
++KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " S.Opichal, M.Jurik, P.Stehlik\n"
++KERN_INFO "  http://aranym.atari.org/\n";
++
++MODULE_AUTHOR("Milan Jurik");
++MODULE_DESCRIPTION("Atari NFeth driver");
++MODULE_LICENSE("GPL");
++/*
++MODULE_PARM(atari_nfeth_debug, "i");
++MODULE_PARM_DESC(atari_nfeth_debug, "atari_nfeth_debug level (1-2)");
++*/
++
++#undef DEBUG
++
++struct atari_nfeth_private {
++	int ethX;
++	struct net_device_stats	stats;
++	spinlock_t lock;
++};
++
++static inline int getEthX(struct net_device *dev)
++{
++	return ((struct atari_nfeth_private *)netdev_priv(dev))->ethX;
++}
++
++int atari_nfeth_open(struct net_device *dev);
++int atari_nfeth_stop(struct net_device *dev);
++irqreturn_t atari_nfeth_interrupt(int irq, void *dev_id, struct pt_regs *fp);
++int atari_nfeth_xmit(struct sk_buff *skb, struct net_device *dev);
++
++int atari_nfeth_open(struct net_device *dev)
++{
++	nf_ethernet_xif_start(getEthX(dev));
++
++	/* Set IRQ */
++	dev->irq = nf_ethernet_get_irq();
++	if (request_irq(dev->irq, atari_nfeth_interrupt, IRQ_TYPE_PRIO, dev->name, dev)) {
++		printk( DRV_NAME ": request for irq %d failed\n", dev->irq);
++		return( 0 );
++	}
++
++	/* Clean statistics */
++	memset(&(((struct atari_nfeth_private *)netdev_priv(dev))->stats), 0, sizeof(((struct atari_nfeth_private *)(dev->priv))->stats));
++
++	spin_lock_init(&(((struct atari_nfeth_private *)netdev_priv(dev))->lock));
++
++#ifdef DEBUG
++	printk( DRV_NAME ": open");
++#endif
++
++	/* Ready for data */
++	netif_start_queue(dev);
++
++	return 0;
++}
++
++int atari_nfeth_stop(struct net_device *dev)
++{
++	/* No more data */
++	netif_stop_queue(dev);
++
++	/* Release IRQ */
++	free_irq(dev->irq, dev);
++
++	nf_ethernet_xif_stop(getEthX(dev));
++
++	return 0;
++}
++
++/*
++ * Read a packet out of the adapter and pass it to the upper layers
++ */
++static irqreturn_t inline recv_packet (struct net_device *dev)
++{
++	int handled = 0;
++	unsigned short pktlen;
++	struct sk_buff *skb;
++	struct atari_nfeth_private *anp = (struct atari_nfeth_private *)netdev_priv(dev);
++
++	if (dev == NULL) {
++		printk(DRV_NAME " recv_packet(): interrupt for unknown device.\n");
++		return IRQ_NONE;
++	}
++
++	/* read packet length (excluding 32 bit crc) */
++	pktlen = nf_ethernet_read_packet_len(getEthX(dev));
++
++#ifdef DEBUG
++	printk(DRV_NAME ": recv_packet: %i", pktlen);
++#endif
++
++	//if (pktlen < 32)
++	if (!pktlen)
++	{
++#ifdef DEBUG
++		printk(DRV_NAME ": recv_packet: pktlen == 0");
++#endif
++		anp->stats.rx_errors++;
++		return IRQ_RETVAL(handled);
++	}
++
++	skb = dev_alloc_skb(pktlen + 2);
++	if (skb == NULL)
++	{
++#ifdef DEBUG
++		printk(DRV_NAME ": recv_packet: out of mem (buf_alloc failed)");
++#endif
++		anp->stats.rx_dropped++;
++		return IRQ_RETVAL(handled);
++	}
++
++	skb->dev = dev;
++	skb_reserve( skb, 2 );		/* 16 Byte align  */
++	skb_put( skb, pktlen );	/* make room */
++	nf_ethernet_read_block(getEthX(dev), skb->data, pktlen);
++
++	skb->protocol = eth_type_trans(skb, dev);
++	netif_rx(skb);
++	dev->last_rx = jiffies;
++	anp->stats.rx_packets++;
++	anp->stats.rx_bytes += pktlen;
++
++	/* and enqueue packet */
++	handled = 1;
++	return IRQ_RETVAL(handled);
++}
++
++irqreturn_t atari_nfeth_interrupt(int irq, void *dev_id, struct pt_regs *fp)
++{
++	struct net_device *dev = dev_id;
++	struct atari_nfeth_private *anp = (struct atari_nfeth_private *)netdev_priv(dev);
++	int this_dev_irq_bit;
++	int irq_for_eth_bitmask;
++	if (dev == NULL) {
++#ifdef DEBUG
++		printk(DRV_NAME " atari_nfeth_interrupt(): interrupt for unknown device.\n");
++#endif
++		return IRQ_NONE;
++	}
++	spin_lock(&anp->lock);
++	irq_for_eth_bitmask = nf_ethernet_interrupt(0);
++	this_dev_irq_bit = 1 << (anp->ethX);
++	if (this_dev_irq_bit & irq_for_eth_bitmask) {
++		recv_packet(dev);
++		nf_ethernet_interrupt(this_dev_irq_bit);
++	}
++#ifdef DEBUG
++	else {
++		printk(DRV_NAME " atari_nfeth_interrupt(%d): not for me\n", anp->ethX);
++	}
++#endif
++	spin_unlock(&anp->lock);
++}
++
++int atari_nfeth_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++	int len;
++	char *data, shortpkt[ETH_ZLEN];
++	struct atari_nfeth_private *anp = netdev_priv(dev);
++
++	data = skb->data;
++	len = skb->len;
++	if (len < ETH_ZLEN) {
++		memset(shortpkt, 0, ETH_ZLEN);
++		memcpy(shortpkt, data, len);
++		data = shortpkt;
++		len = ETH_ZLEN;
++	}
++
++	dev->trans_start = jiffies;
++	
++#ifdef DEBUG
++	printk( DRV_NAME ": send %d bytes", len);
++#endif
++	nf_ethernet_write_block(getEthX(dev), data, len);
++
++	anp->stats.tx_packets++;
++	anp->stats.tx_bytes += len;
++
++	dev_kfree_skb(skb);
++	return 0;
++}
++
++static void atari_nfeth_tx_timeout(struct net_device *dev)
++{
++	struct atari_nfeth_private *anp = netdev_priv(dev);
++	anp->stats.tx_errors++;
++	netif_wake_queue(dev);
++}
++
++static struct net_device_stats *atari_nfeth_get_stats(struct net_device *dev)
++{
++	struct atari_nfeth_private *anp = netdev_priv(dev);
++	return &(anp->stats);
++}
++
++// probe1() - HW detection
++// probe() - set module owner, found == 1, probe1()
++// init() - probe()
++
++static int __init atari_nfeth_probe1(struct net_device *dev, int ethX)
++{
++	static int did_version = 0;
++	static int did_notinstall = 0;
++	char errmsg[60];
++
++	if ( ! nf_ethernet_check_version(errmsg, sizeof(errmsg)-1) ) {
++		if (did_notinstall++ == 0)
++			printk (DRV_NAME " not installed - %s\n", errmsg);
++                return -ENODEV;
++        }
++
++	/* Get MAC address */
++	if (! nf_ethernet_get_hw_addr(ethX, (unsigned char *)&(dev->dev_addr), ETH_ALEN)) {
++#ifdef DEBUG
++		printk(DRV_NAME " eth%d not installed - not defined\n", ethX);
++#endif
++		return -ENODEV;
++	}
++
++	ether_setup(dev);
++
++	dev->open = &atari_nfeth_open;
++	dev->stop = &atari_nfeth_stop;
++	dev->hard_start_xmit = &atari_nfeth_xmit;
++	dev->tx_timeout = &atari_nfeth_tx_timeout;
++	dev->get_stats = &atari_nfeth_get_stats;
++	dev->flags |= NETIF_F_NO_CSUM;
++
++	//if ((dev->priv = kmalloc(sizeof(struct atari_nfeth_private), GFP_KERNEL)) == NULL)
++	//	return -ENOMEM;
++	((struct atari_nfeth_private *)(dev->priv))->ethX = ethX; /* index of NF NIC */
++
++	if (did_version++ == 0)
++		printk(version);
++
++	return 0;
++}
++
++struct net_device * __init atari_nfeth_probe(int unit)
++{
++        int err;
++	static int found = 0;
++	struct net_device *dev;
++
++	dev = alloc_etherdev(sizeof(struct atari_nfeth_private));
++	if (!dev)
++		return ERR_PTR(-ENOMEM);
++	if (unit >= 0) {
++		sprintf(dev->name, "eth%d", unit);
++		netdev_boot_setup_check(dev);
++	}
++	SET_MODULE_OWNER(dev);
++
++	if (!atari_nfeth_probe1(dev, found++)) {
++		err = register_netdev(dev);
++		if (err == -EIO)  {
++			printk(DRV_NAME ": NatFeat Ethernet not found. Module not loaded.\n");
++		}
++		if (!err)
++			return dev;
++	}
++
++	return ERR_PTR(-ENODEV);
++}
++
++#ifdef MODULE
++static struct net_device * atari_nfeth_dev;
++
++int atari_nfeth_init(void)
++{
++	// int err;
++
++	if (IS_ERR(atari_nfeth_dev = atari_nfeth_probe(0))) {
++		return PTR_ERR((atarilance_dev);
++	}
++
++	// ? atari_nfeth_dev.init = atari_nfeth_probe;
++#if 0
++	if ((err = register_netdev(&atari_nfeth_dev))) {
++		if (err == -EIO)  {
++			printk(DRV_NAME ": NatFeat Ethernet not found. Module not loaded.\n");
++		}
++		return err;
++	}
++#endif
++
++        return 0;
++}
++
++void atari_nfeth_cleanup(void)
++{
++        unregister_netdev(&atari_nfeth_dev);
++        free_netdev(atari_nfeth_dev); // ?
++}
++
++module_init(atari_nfeth_init);
++module_exit(atari_nfeth_cleanup);
++
++#endif /* MODULE */
++
++/*
++vim:ts=4:sw=4:
++*/
+diff -urN linux-m68k/include/asm-m68k/raw_io.h linux-schmitz/include/asm-m68k/raw_io.h
+--- linux-m68k/include/asm-m68k/raw_io.h	2006-09-20 05:42:06.000000000 +0200
++++ linux-schmitz/include/asm-m68k/raw_io.h	2006-11-19 21:37:27.000000000 +0100
+@@ -54,6 +54,46 @@
+ #define raw_outw(val,port) out_be16((port),(val))
+ #define raw_outl(val,port) out_be32((port),(val))
+ 
++/* 
++ * Atari ROM port (cartridge port) ISA adapter, used for the EtherNEC NE2000
++ * network card driver.
++ * The ISA adapter connects address lines A9-A13 to ISA address lines A0-A4, 
++ * and hardwires the rest of the ISA addresses for a base address of 0x300. 
++ *
++ * Data lines D8-D15 are connected to ISA data lines D0-D7 for reading. 
++ * For writes, address lines A1-A8 are latched to ISA data lines D0-D7 
++ * (meaning the bit pattern on A1-A8 can be read back as byte).
++ * 
++ * Reads and writes are byte only. 
++ */
++
++#if defined(CONFIG_ATARI_ROM_ISA)
++#define rom_in_8(addr) \
++    ({ u16 __v = (*(__force volatile u16 *) (addr)); __v >>= 8; __v; })
++#define rom_in_be16(addr) \
++    ({ u16 __v = (*(__force volatile u16 *) (addr)); __v >>= 8; __v; })
++#define rom_in_be32(addr) \
++    ({ u32 __v = (*(__force volatile u32 *) (addr)); __v >>= 8; __v; })
++#define rom_in_le16(addr) \
++    ({ u16 __v = le16_to_cpu(*(__force volatile u16 *) (addr)); __v >>= 8; __v; })
++#define rom_in_le32(addr) \
++    ({ u32 __v = le32_to_cpu(*(__force volatile u32 *) (addr)); __v >>= 8; __v; })
++
++#define rom_out_8(addr,b)     ({u8 __w, __v = (b);            __w = ((*(__force volatile u8 *)  ((addr) + 0x10000 + (__v<<1)))); })
++#define rom_out_be16(addr,w) ({u16 __w, __v = (w);            __w = ((*(__force volatile u16 *) ((addr) + 0x10000 + (__v<<1)))); })
++#define rom_out_be32(addr,l) ({u32 __w, __v = (l);            __w = ((*(__force volatile u32 *) ((addr) + 0x10000 + (__v<<1)))); })
++#define rom_out_le16(addr,w) ({u16 __w, __v = cpu_to_le16(w); __w = ((*(__force volatile u16 *) ((addr) + 0x10000 + (__v<<1)))); })
++#define rom_out_le32(addr,l) ({u32 __w, __v = cpu_to_le32(l); __w = ((*(__force volatile u32 *) ((addr) + 0x10000 + (__v<<1)))); })
++
++#define raw_rom_inb rom_in_8
++#define raw_rom_inw rom_in_be16
++#define raw_rom_inl rom_in_be32
++
++#define raw_rom_outb(val,port) rom_out_8((port),(val))
++#define raw_rom_outw(val,port) rom_out_be16((port),(val))
++#define raw_rom_outl(val,port) rom_out_be32((port),(val))
++#endif /* CONFIG_ATARI_ROM_ISA */
++
+ static inline void raw_insb(volatile u8 __iomem *port, u8 *buf, unsigned int len)
+ {
+ 	unsigned int i;
+@@ -336,6 +376,62 @@
+ 		: "d0", "a0", "a1", "d6");
+ }
+ 
++
++#if defined(CONFIG_ATARI_ROM_ISA)
++static inline void raw_rom_insb(volatile u8 __iomem *port, u8 *buf, unsigned int len)
++{
++	unsigned int i;
++
++        for (i = 0; i < len; i++)
++		*buf++ = rom_in_8(port);
++}
++
++static inline void raw_rom_outsb(volatile u8 __iomem *port, const u8 *buf,
++			     unsigned int len)
++{
++	unsigned int i;
++
++        for (i = 0; i < len; i++)
++		rom_out_8(port, *buf++);
++}
++
++static inline void raw_rom_insw(volatile u16 __iomem *port, u16 *buf,
++				   unsigned int nr)
++{
++    unsigned int i;
++
++    for (i = 0; i < nr; i++)
++	*buf++ = rom_in_be16(port);
++}
++
++static inline void raw_rom_outsw(volatile u16 __iomem *port, const u16 *buf,
++				   unsigned int nr)
++{
++    unsigned int i;
++
++    for (i = 0; i < nr; i++)
++	rom_out_be16(port, *buf++);
++}
++
++static inline void raw_rom_insw_swapw(volatile u16 __iomem *port, u16 *buf,
++				   unsigned int nr)
++{
++    unsigned int i;
++
++    for (i = 0; i < nr; i++)
++	*buf++ = rom_in_le16(port);
++}
++
++static inline void raw_rom_outsw_swapw(volatile u16 __iomem *port, const u16 *buf,
++				   unsigned int nr)
++{
++    unsigned int i;
++
++    for (i = 0; i < nr; i++)
++	rom_out_le16(port, *buf++);
++}
++#endif /* CONFIG_ATARI_ROM_ISA */
++
+ #define __raw_writel raw_outl
+ 
+ #endif /* __KERNEL__ */

Added: dists/sid/linux-2.6/debian/patches/m68k-atari-keyboard.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/m68k-atari-keyboard.patch	Mon Nov 20 00:58:24 2006
@@ -0,0 +1,1059 @@
+diff -urN linux-m68k/arch/m68k/atari/atakeyb.c linux-schmitz/arch/m68k/atari/atakeyb.c
+--- linux-m68k/arch/m68k/atari/atakeyb.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-schmitz/arch/m68k/atari/atakeyb.c	2006-11-19 21:37:26.000000000 +0100
+@@ -0,0 +1,751 @@
++/*
++ * linux/atari/atakeyb.c
++ *
++ * Atari Keyboard driver for 680x0 Linux
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file COPYING in the main directory of this archive
++ * for more details.
++ */
++
++/*
++ * Atari support by Robert de Vries
++ * enhanced by Bjoern Brauel and Roman Hodek
++ */
++
++#include <linux/config.h>
++#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/errno.h>
++#include <linux/keyboard.h>
++#include <linux/delay.h>
++#include <linux/timer.h>
++#include <linux/kd.h>
++#include <linux/random.h>
++#include <linux/init.h>
++#include <linux/kbd_kern.h>
++
++#include <asm/atariints.h>
++#include <asm/atarihw.h>
++#include <asm/atarikb.h>
++#include <asm/atari_joystick.h>
++#include <asm/irq.h>
++
++static void atakeyb_rep( unsigned long ignore );
++extern unsigned int keymap_count;
++
++/* Hook for MIDI serial driver */
++void (*atari_MIDI_interrupt_hook) (void);
++/* Hook for mouse driver */
++void (*atari_mouse_interrupt_hook) (char *);
++/* Hook for keyboard inputdev  driver */
++void (*atari_input_keyboard_interrupt_hook) (unsigned char, char);
++/* Hook for mouse inputdev  driver */
++void (*atari_input_mouse_interrupt_hook) (char *);
++
++/* variables for IKBD self test: */
++
++/* state: 0: off; >0: in progress; >1: 0xf1 received */
++static volatile int ikbd_self_test;
++/* timestamp when last received a char */
++static volatile unsigned long self_test_last_rcv;
++/* bitmap of keys reported as broken */
++static unsigned long broken_keys[128/(sizeof(unsigned long)*8)] = { 0, };
++
++#define BREAK_MASK	(0x80)
++
++/*
++ * ++roman: The following changes were applied manually:
++ *
++ *  - The Alt (= Meta) key works in combination with Shift and
++ *    Control, e.g. Alt+Shift+a sends Meta-A (0xc1), Alt+Control+A sends
++ *    Meta-Ctrl-A (0x81) ...
++ *
++ *  - The parentheses on the keypad send '(' and ')' with all
++ *    modifiers (as would do e.g. keypad '+'), but they cannot be used as
++ *    application keys (i.e. sending Esc O c).
++ *
++ *  - HELP and UNDO are mapped to be F21 and F24, resp, that send the
++ *    codes "\E[M" and "\E[P". (This is better than the old mapping to
++ *    F11 and F12, because these codes are on Shift+F1/2 anyway.) This
++ *    way, applications that allow their own keyboard mappings
++ *    (e.g. tcsh, X Windows) can be configured to use them in the way
++ *    the label suggests (providing help or undoing).
++ *
++ *  - Console switching is done with Alt+Fx (consoles 1..10) and
++ *    Shift+Alt+Fx (consoles 11..20).
++ *
++ *  - The misc. special function implemented in the kernel are mapped
++ *    to the following key combinations:
++ *
++ *      ClrHome          -> Home/Find
++ *      Shift + ClrHome  -> End/Select
++ *      Shift + Up       -> Page Up
++ *      Shift + Down     -> Page Down
++ *      Alt + Help       -> show system status
++ *      Shift + Help     -> show memory info
++ *      Ctrl + Help      -> show registers
++ *      Ctrl + Alt + Del -> Reboot
++ *      Alt + Undo       -> switch to last console
++ *      Shift + Undo     -> send interrupt
++ *      Alt + Insert     -> stop/start output (same as ^S/^Q)
++ *      Alt + Up         -> Scroll back console (if implemented)
++ *      Alt + Down       -> Scroll forward console (if implemented)
++ *      Alt + CapsLock   -> NumLock
++ *
++ * ++Andreas:
++ *
++ *  - Help mapped to K_HELP
++ *  - Undo mapped to K_UNDO (= K_F246)
++ *  - Keypad Left/Right Parenthesis mapped to new K_PPAREN[LR]
++ */
++
++static u_short ataplain_map[NR_KEYS] __initdata = {
++	0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036,
++	0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf009,
++	0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
++	0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73,
++	0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b,
++	0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76,
++	0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf200,
++	0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
++	0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114,
++	0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
++	0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
++	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
++	0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
++	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
++	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
++	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
++};
++
++typedef enum kb_state_t
++{
++    KEYBOARD, AMOUSE, RMOUSE, JOYSTICK, CLOCK, RESYNC
++} KB_STATE_T;
++
++#define	IS_SYNC_CODE(sc)	((sc) >= 0x04 && (sc) <= 0xfb)
++
++typedef struct keyboard_state
++{
++    unsigned char  buf[6];
++    int 	   len;
++    KB_STATE_T	   state;
++} KEYBOARD_STATE;
++
++KEYBOARD_STATE kb_state;
++
++#define	DEFAULT_KEYB_REP_DELAY	(HZ/4)
++#define	DEFAULT_KEYB_REP_RATE	(HZ/25)
++
++/* These could be settable by some ioctl() in future... */
++static unsigned int key_repeat_delay = DEFAULT_KEYB_REP_DELAY;
++static unsigned int key_repeat_rate  = DEFAULT_KEYB_REP_RATE;
++
++static unsigned char rep_scancode;
++static struct timer_list atakeyb_rep_timer = { function: atakeyb_rep };
++
++struct pt_regs *atakbd_pt_regs;
++
++static void atakeyb_rep( unsigned long ignore )
++
++{
++	atakbd_pt_regs = NULL;
++
++	/* Disable keyboard for the time we call handle_scancode(), else a race
++	 * in the keyboard tty queue may happen */
++	atari_disable_irq( IRQ_MFP_ACIA );
++	del_timer( &atakeyb_rep_timer );
++
++	/* A keyboard int may have come in before we disabled the irq, so
++	 * double-check whether rep_scancode is still != 0 */
++	if (rep_scancode) {
++		init_timer(&atakeyb_rep_timer);
++		atakeyb_rep_timer.expires = jiffies + key_repeat_rate;
++		add_timer( &atakeyb_rep_timer );
++
++		//handle_scancode(rep_scancode, 1);
++                if (atari_input_keyboard_interrupt_hook)
++                  atari_input_keyboard_interrupt_hook(rep_scancode, 1);
++	}
++
++	atari_enable_irq( IRQ_MFP_ACIA );
++}
++
++
++/* ++roman: If a keyboard overrun happened, we can't tell in general how much
++ * bytes have been lost and in which state of the packet structure we are now.
++ * This usually causes keyboards bytes to be interpreted as mouse movements
++ * and vice versa, which is very annoying. It seems better to throw away some
++ * bytes (that are usually mouse bytes) than to misinterpret them. Therefor I
++ * introduced the RESYNC state for IKBD data. In this state, the bytes up to
++ * one that really looks like a key event (0x04..0xf2) or the start of a mouse
++ * packet (0xf8..0xfb) are thrown away, but at most 2 bytes. This at least
++ * speeds up the resynchronization of the event structure, even if maybe a
++ * mouse movement is lost. However, nothing is perfect. For bytes 0x01..0x03,
++ * it's really hard to decide whether they're mouse or keyboard bytes. Since
++ * overruns usually occur when moving the Atari mouse rapidly, they're seen as
++ * mouse bytes here. If this is wrong, only a make code of the keyboard gets
++ * lost, which isn't too bad. Loosing a break code would be disastrous,
++ * because then the keyboard repeat strikes...
++ */
++
++static irqreturn_t atari_keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
++{
++  u_char acia_stat;
++  int scancode;
++  int break_flag;
++  
++  /* save frame for register dump */
++  atakbd_pt_regs = fp;
++
++ repeat:
++  if (acia.mid_ctrl & ACIA_IRQ)
++	if (atari_MIDI_interrupt_hook)
++		atari_MIDI_interrupt_hook();
++  acia_stat = acia.key_ctrl;
++  /* check out if the interrupt came from this ACIA */
++  if (!((acia_stat | acia.mid_ctrl) & ACIA_IRQ))
++	return IRQ_HANDLED;
++
++    if (acia_stat & ACIA_OVRN)
++    {
++	/* a very fast typist or a slow system, give a warning */
++	/* ...happens often if interrupts were disabled for too long */
++	printk( KERN_DEBUG "Keyboard overrun\n" );
++	scancode = acia.key_data;
++	/* Turn off autorepeating in case a break code has been lost */
++	del_timer( &atakeyb_rep_timer );
++	rep_scancode = 0;
++	if (ikbd_self_test)
++	    /* During self test, don't do resyncing, just process the code */
++	    goto interpret_scancode;
++	else if (IS_SYNC_CODE(scancode)) {
++	    /* This code seem already to be the start of a new packet or a
++	     * single scancode */
++	    kb_state.state = KEYBOARD;
++	    goto interpret_scancode;
++	}
++	else {
++	    /* Go to RESYNC state and skip this byte */
++	    kb_state.state = RESYNC;
++	    kb_state.len = 1; /* skip max. 1 another byte */
++	    goto repeat;
++	}
++    }
++
++    if (acia_stat & ACIA_RDRF)	/* received a character */
++    {
++	scancode = acia.key_data;	/* get it or reset the ACIA, I'll get it! */
++	tasklet_schedule(&keyboard_tasklet);
++      interpret_scancode:
++	switch (kb_state.state)
++	{
++	  case KEYBOARD:
++	    switch (scancode)
++	    {
++	      case 0xF7:
++		kb_state.state = AMOUSE;
++		kb_state.len = 0;
++		break;
++
++	      case 0xF8:
++	      case 0xF9:
++     	      case 0xFA:
++	      case 0xFB:
++		kb_state.state = RMOUSE;
++	    	kb_state.len = 1;
++		kb_state.buf[0] = scancode;
++		break;
++
++	      case 0xFC:
++		kb_state.state = CLOCK;
++		kb_state.len = 0;
++		break;
++
++	      case 0xFE:
++	      case 0xFF:
++		kb_state.state = JOYSTICK;
++		kb_state.len = 1;
++		kb_state.buf[0] = scancode;
++		break;
++
++	      case 0xF1:
++		/* during self-test, note that 0xf1 received */
++		if (ikbd_self_test) {
++		    ++ikbd_self_test;
++		    self_test_last_rcv = jiffies;
++		    break;
++		}
++		/* FALL THROUGH */
++		
++	      default:
++		break_flag = scancode & BREAK_MASK;
++		scancode &= ~BREAK_MASK;
++		if (ikbd_self_test) {
++		    /* Scancodes sent during the self-test stand for broken
++		     * keys (keys being down). The code *should* be a break
++		     * code, but nevertheless some AT keyboard interfaces send
++		     * make codes instead. Therefore, simply ignore
++		     * break_flag...
++		     * */
++		    int keyval = plain_map[scancode], keytyp;
++		    
++		    set_bit( scancode, broken_keys );
++		    self_test_last_rcv = jiffies;
++		    keyval = plain_map[scancode];
++		    keytyp = KTYP(keyval) - 0xf0;
++		    keyval = KVAL(keyval);
++
++		    printk( KERN_WARNING "Key with scancode %d ", scancode );
++		    if (keytyp == KT_LATIN || keytyp == KT_LETTER) {
++			if (keyval < ' ')
++			    printk( "('^%c') ", keyval + '@' );
++			else
++			    printk( "('%c') ", keyval );
++		    }
++		    printk( "is broken -- will be ignored.\n" );
++		    break;
++		}
++		else if (test_bit( scancode, broken_keys ))
++		    break;
++
++#if 0	// FIXME; hangs at boot
++		if (break_flag) {
++		    del_timer( &atakeyb_rep_timer );
++		    rep_scancode = 0;
++		}
++		else {
++		    del_timer( &atakeyb_rep_timer );
++		    rep_scancode = scancode;
++		    atakeyb_rep_timer.expires = jiffies + key_repeat_delay;
++		    add_timer( &atakeyb_rep_timer );
++		}
++#endif
++
++		// handle_scancode(scancode, !break_flag);
++                if (atari_input_keyboard_interrupt_hook)
++                  atari_input_keyboard_interrupt_hook((unsigned char) scancode, !break_flag);
++		break;
++	    }
++	    break;
++
++	  case AMOUSE:
++	    kb_state.buf[kb_state.len++] = scancode;
++	    if (kb_state.len == 5)
++	    {
++		kb_state.state = KEYBOARD;
++		/* not yet used */
++		/* wake up someone waiting for this */
++	    }
++	    break;	
++
++	  case RMOUSE:
++	    kb_state.buf[kb_state.len++] = scancode;
++	    if (kb_state.len == 3)
++	    {
++		kb_state.state = KEYBOARD;
++		if (atari_mouse_interrupt_hook)
++			atari_mouse_interrupt_hook(kb_state.buf);
++	    }
++	    break;
++
++	  case JOYSTICK:
++	    kb_state.buf[1] = scancode;
++	    kb_state.state = KEYBOARD;
++#ifdef FIXED_ATARI_JOYSTICK
++	    atari_joystick_interrupt(kb_state.buf);
++#endif
++	    break;
++
++	  case CLOCK:
++	    kb_state.buf[kb_state.len++] = scancode;
++	    if (kb_state.len == 6)
++	    {
++		kb_state.state = KEYBOARD;
++		/* wake up someone waiting for this.
++		   But will this ever be used, as Linux keeps its own time.
++		   Perhaps for synchronization purposes? */
++		/* wake_up_interruptible(&clock_wait); */
++	    }
++	    break;
++
++	  case RESYNC:
++	    if (kb_state.len <= 0 || IS_SYNC_CODE(scancode)) {
++		kb_state.state = KEYBOARD;
++		goto interpret_scancode;
++	    }
++	    kb_state.len--;
++	    break;
++	}
++    }
++
++#if 0
++    if (acia_stat & ACIA_CTS)
++	/* cannot happen */;
++#endif
++
++    if (acia_stat & (ACIA_FE | ACIA_PE))
++    {
++	printk("Error in keyboard communication\n");
++    }
++
++    /* handle_scancode() can take a lot of time, so check again if
++	 * some character arrived
++	 */
++    goto repeat;
++}
++
++/*
++ * I write to the keyboard without using interrupts, I poll instead.
++ * This takes for the maximum length string allowed (7) at 7812.5 baud
++ * 8 data 1 start 1 stop bit: 9.0 ms
++ * If this takes too long for normal operation, interrupt driven writing
++ * is the solution. (I made a feeble attempt in that direction but I
++ * kept it simple for now.)
++ */
++void ikbd_write(const char *str, int len)
++{
++    u_char acia_stat;
++
++    if ((len < 1) || (len > 7))
++	panic("ikbd: maximum string length exceeded");
++    while (len)
++    {
++	acia_stat = acia.key_ctrl;
++	if (acia_stat & ACIA_TDRE)
++	{
++	    acia.key_data = *str++;
++	    len--;
++	}
++    }
++}
++
++/* Reset (without touching the clock) */
++void ikbd_reset(void)
++{
++    static const char cmd[2] = { 0x80, 0x01 };
++    
++    ikbd_write(cmd, 2);
++
++    /* if all's well code 0xF1 is returned, else the break codes of
++       all keys making contact */
++}
++
++/* Set mouse button action */
++void ikbd_mouse_button_action(int mode)
++{
++    char cmd[2] = { 0x07, mode };
++
++    ikbd_write(cmd, 2);
++}
++
++/* Set relative mouse position reporting */
++void ikbd_mouse_rel_pos(void)
++{
++    static const char cmd[1] = { 0x08 };
++
++    ikbd_write(cmd, 1);
++}
++
++/* Set absolute mouse position reporting */
++void ikbd_mouse_abs_pos(int xmax, int ymax)
++{
++    char cmd[5] = { 0x09, xmax>>8, xmax&0xFF, ymax>>8, ymax&0xFF };
++
++    ikbd_write(cmd, 5);
++}
++
++/* Set mouse keycode mode */
++void ikbd_mouse_kbd_mode(int dx, int dy)
++{
++    char cmd[3] = { 0x0A, dx, dy };
++
++    ikbd_write(cmd, 3);
++}
++
++/* Set mouse threshold */
++void ikbd_mouse_thresh(int x, int y)
++{
++    char cmd[3] = { 0x0B, x, y };
++
++    ikbd_write(cmd, 3);
++}
++
++/* Set mouse scale */
++void ikbd_mouse_scale(int x, int y)
++{
++    char cmd[3] = { 0x0C, x, y };
++
++    ikbd_write(cmd, 3);
++}
++
++/* Interrogate mouse position */
++void ikbd_mouse_pos_get(int *x, int *y)
++{
++    static const char cmd[1] = { 0x0D };
++
++    ikbd_write(cmd, 1);
++
++    /* wait for returning bytes */
++}
++
++/* Load mouse position */
++void ikbd_mouse_pos_set(int x, int y)
++{
++    char cmd[6] = { 0x0E, 0x00, x>>8, x&0xFF, y>>8, y&0xFF };
++
++    ikbd_write(cmd, 6);
++}
++
++/* Set Y=0 at bottom */
++void ikbd_mouse_y0_bot(void)
++{
++    static const char cmd[1] = { 0x0F };
++
++    ikbd_write(cmd, 1);
++}
++
++/* Set Y=0 at top */
++void ikbd_mouse_y0_top(void)
++{
++    static const char cmd[1] = { 0x10 };
++
++    ikbd_write(cmd, 1);
++}
++
++/* Resume */
++void ikbd_resume(void)
++{
++    static const char cmd[1] = { 0x11 };
++
++    ikbd_write(cmd, 1);
++}
++
++/* Disable mouse */
++void ikbd_mouse_disable(void)
++{
++    static const char cmd[1] = { 0x12 };
++
++    ikbd_write(cmd, 1);
++}
++
++/* Pause output */
++void ikbd_pause(void)
++{
++    static const char cmd[1] = { 0x13 };
++
++    ikbd_write(cmd, 1);
++}
++
++/* Set joystick event reporting */
++void ikbd_joystick_event_on(void)
++{
++    static const char cmd[1] = { 0x14 };
++
++    ikbd_write(cmd, 1);
++}
++
++/* Set joystick interrogation mode */
++void ikbd_joystick_event_off(void)
++{
++    static const char cmd[1] = { 0x15 };
++
++    ikbd_write(cmd, 1);
++}
++
++/* Joystick interrogation */
++void ikbd_joystick_get_state(void)
++{
++    static const char cmd[1] = { 0x16 };
++
++    ikbd_write(cmd, 1);
++}
++
++#if 0
++/* This disables all other ikbd activities !!!! */
++/* Set joystick monitoring */
++void ikbd_joystick_monitor(int rate)
++{
++    static const char cmd[2] = { 0x17, rate };
++
++    ikbd_write(cmd, 2);
++
++    kb_state.state = JOYSTICK_MONITOR;
++}
++#endif
++
++/* some joystick routines not in yet (0x18-0x19) */
++
++/* Disable joysticks */
++void ikbd_joystick_disable(void)
++{
++    static const char cmd[1] = { 0x1A };
++
++    ikbd_write(cmd, 1);
++}
++
++/* Time-of-day clock set */
++void ikbd_clock_set(int year, int month, int day, int hour, int minute, int second)
++{
++    char cmd[7] = { 0x1B, year, month, day, hour, minute, second };
++
++    ikbd_write(cmd, 7);
++}
++
++/* Interrogate time-of-day clock */
++void ikbd_clock_get(int *year, int *month, int *day, int *hour, int *minute, int second)
++{
++    static const char cmd[1] = { 0x1C };
++
++    ikbd_write(cmd, 1);
++}
++
++/* Memory load */
++void ikbd_mem_write(int address, int size, char *data)
++{
++    panic("Attempt to write data into keyboard memory");
++}
++
++/* Memory read */
++void ikbd_mem_read(int address, char data[6])
++{
++    char cmd[3] = { 0x21, address>>8, address&0xFF };
++
++    ikbd_write(cmd, 3);
++
++    /* receive data and put it in data */
++}
++
++/* Controller execute */
++void ikbd_exec(int address)
++{
++    char cmd[3] = { 0x22, address>>8, address&0xFF };
++
++    ikbd_write(cmd, 3);
++}
++
++/* Status inquiries (0x87-0x9A) not yet implemented */
++
++/* Set the state of the caps lock led. */
++void atari_kbd_leds (unsigned int leds)
++{
++    char cmd[6] = {32, 0, 4, 1, 254 + ((leds & 4) != 0), 0};
++    ikbd_write(cmd, 6);
++}
++
++/*
++ * The original code sometimes left the interrupt line of 
++ * the ACIAs low forever. I hope, it is fixed now.
++ *
++ * Martin Rogge, 20 Aug 1995
++ */
++ 
++static int atari_keyb_done = 0;
++
++int __init atari_keyb_init(void)
++{
++
++    if (atari_keyb_done)
++      return 0;
++
++   /* setup key map */
++    memcpy(key_maps[0], ataplain_map, sizeof(plain_map));
++
++    kb_state.state = KEYBOARD;
++    kb_state.len = 0;
++
++    request_irq(IRQ_MFP_ACIA, atari_keyboard_interrupt, IRQ_TYPE_SLOW,
++                "keyboard/mouse/MIDI", atari_keyboard_interrupt);
++
++    atari_turnoff_irq(IRQ_MFP_ACIA);
++    do {
++	/* reset IKBD ACIA */
++	acia.key_ctrl = ACIA_RESET ; // |
++			// (atari_switches & ATARI_SWITCH_IKBD) ? ACIA_RHTID : 0;
++	(void)acia.key_ctrl;
++	(void)acia.key_data;
++
++	/* reset MIDI ACIA */
++	acia.mid_ctrl = ACIA_RESET ; // |
++			// (atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0;
++	(void)acia.mid_ctrl;
++	(void)acia.mid_data;
++
++	/* divide 500kHz by 64 gives 7812.5 baud */
++	/* 8 data no parity 1 start 1 stop bit */
++	/* receive interrupt enabled */
++	/* RTS low (except if switch selected), transmit interrupt disabled */
++	acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RIE) ; // |
++			// ((atari_switches & ATARI_SWITCH_IKBD) ?
++			//  ACIA_RHTID : ACIA_RLTID);
++	   
++	acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S ; // |
++			// (atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0;
++    }
++    /* make sure the interrupt line is up */
++    while ((mfp.par_dt_reg & 0x10) == 0);
++
++    /* enable ACIA Interrupts */ 
++    mfp.active_edge &= ~0x10;
++    atari_turnon_irq(IRQ_MFP_ACIA);
++
++    ikbd_self_test = 1;
++    ikbd_reset();
++    /* wait for a period of inactivity (here: 0.25s), then assume the IKBD's
++     * self-test is finished */
++    self_test_last_rcv = jiffies;
++    while (time_before(jiffies, self_test_last_rcv + HZ/4))
++	barrier();
++    /* if not incremented: no 0xf1 received */
++    if (ikbd_self_test == 1)
++	printk( KERN_ERR "WARNING: keyboard self test failed!\n" );
++    ikbd_self_test = 0;
++    
++    ikbd_mouse_disable();
++    ikbd_joystick_disable();
++
++#ifdef FIXED_ATARI_JOYSTICK
++    atari_joystick_init();
++#endif
++
++    // flag init done
++    atari_keyb_done = 1;
++    return 0;
++}
++
++
++int atari_kbdrate( struct kbd_repeat *k )
++
++{
++	if (k->delay > 0) {
++		/* convert from msec to jiffies */
++		key_repeat_delay = (k->delay * HZ + 500) / 1000;
++		if (key_repeat_delay < 1)
++			key_repeat_delay = 1;
++	}
++	if (k->period > 0) {
++		key_repeat_rate = (k->period * HZ + 500) / 1000;
++		if (key_repeat_rate < 1)
++			key_repeat_rate = 1;
++	}
++
++	k->delay  = key_repeat_delay * 1000 / HZ;
++	k->period = key_repeat_rate  * 1000 / HZ;
++	
++	return( 0 );
++}
++
++int atari_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode)
++{
++#ifdef CONFIG_MAGIC_SYSRQ
++        /* ALT+HELP pressed? */
++        if ((keycode == 98) && ((shift_state & 0xff) == 8))
++                *keycodep = 0xff;
++        else
++#endif
++                *keycodep = keycode;
++        return 1;
++}
++
+diff -urN linux-m68k/drivers/input/keyboard/Kconfig linux-schmitz/drivers/input/keyboard/Kconfig
+--- linux-m68k/drivers/input/keyboard/Kconfig	2006-11-19 21:35:33.000000000 +0100
++++ linux-schmitz/drivers/input/keyboard/Kconfig	2006-11-19 21:37:26.000000000 +0100
+@@ -153,6 +153,16 @@
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called amikbd.
+ 
++config KEYBOARD_ATARI
++	tristate "Atari keyboard"
++	depends on ATARI
++	help
++	  Say Y here if you are running Linux on any Atari and have a keyboard
++	  attached.
++
++	  To compile this driver as a module, choose M here: the
++	  module will be called atakbd.
++
+ config KEYBOARD_HIL_OLD
+ 	tristate "HP HIL keyboard support (simple driver)"
+ 	depends on GSC || HP300
+diff -urN linux-m68k/drivers/input/keyboard/Makefile linux-schmitz/drivers/input/keyboard/Makefile
+--- linux-m68k/drivers/input/keyboard/Makefile	2006-09-20 05:42:06.000000000 +0200
++++ linux-schmitz/drivers/input/keyboard/Makefile	2006-11-19 21:37:26.000000000 +0100
+@@ -9,6 +9,7 @@
+ obj-$(CONFIG_KEYBOARD_LKKBD)		+= lkkbd.o
+ obj-$(CONFIG_KEYBOARD_XTKBD)		+= xtkbd.o
+ obj-$(CONFIG_KEYBOARD_AMIGA)		+= amikbd.o
++obj-$(CONFIG_KEYBOARD_ATARI)		+= atakbd.o
+ obj-$(CONFIG_KEYBOARD_LOCOMO)		+= locomokbd.o
+ obj-$(CONFIG_KEYBOARD_NEWTON)		+= newtonkbd.o
+ obj-$(CONFIG_KEYBOARD_CORGI)		+= corgikbd.o
+diff -urN linux-m68k/drivers/input/keyboard/atakbd.c linux-schmitz/drivers/input/keyboard/atakbd.c
+--- linux-m68k/drivers/input/keyboard/atakbd.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-schmitz/drivers/input/keyboard/atakbd.c	2006-11-19 21:37:26.000000000 +0100
+@@ -0,0 +1,269 @@
++/*
++ *  atakbd.c
++ *
++ *  Copyright (c) 2005 Michael Schmitz
++ *
++ * Based on amikbd.c, which is
++ *
++ *  Copyright (c) 2000-2001 Vojtech Pavlik
++ *
++ *  Based on the work of:
++ *	Hamish Macdonald
++ */
++
++/*
++ * Atari keyboard driver for Linux/m68k
++ *
++ * The low level init and interrupt stuff is handled in arch/mm68k/atari/atakeyb.c
++ * (the keyboard ACIA also handles the mouse and joystick data, and the keyboard 
++ * interrupt is shared with the MIDI ACIA so MIDI data also get handled there). 
++ * This driver only deals with handing key events off to the input layer. 
++ */
++
++/*
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ * Should you need to contact me, the author, you can do so either by
++ * e-mail - mail your message to <vojtech at ucw.cz>, or by paper mail:
++ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/input.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++
++#include <asm/atariints.h>
++#include <asm/atarihw.h>
++#include <asm/atarikb.h>
++#include <asm/irq.h>
++
++MODULE_AUTHOR("Michael Schmitz <schmitz at biophys.uni-duesseldorf.de>");
++MODULE_DESCRIPTION("Atari keyboard driver");
++MODULE_LICENSE("GPL");
++
++/*
++ 0x47: KP_7     71
++ 0x48: KP_8     72
++ 0x49: KP_9     73
++ 0x62: KP_/     98
++ 0x4b: KP_4     75
++ 0x4c: KP_5     76
++ 0x4d: KP_6     77
++ 0x37: KP_*     55
++ 0x4f: KP_1     79
++ 0x50: KP_2     80
++ 0x51: KP_3     81
++ 0x4a: KP_-     74
++ 0x52: KP_0     82
++ 0x53: KP_.     83
++ 0x4e: KP_+     78
++
++ 0x67: Up       103
++ 0x6c: Down     108
++ 0x69: Left     105
++ 0x6a: Right    106
++ */
++                    
++                    
++static unsigned char atakbd_keycode[0x72] = {	// american layout
++	[0]	 = KEY_GRAVE,
++	[1]	 = KEY_ESC,
++	[2]	 = KEY_1,
++	[3]	 = KEY_2,
++	[4]	 = KEY_3,
++	[5]	 = KEY_4,
++	[6]	 = KEY_5,
++	[7]	 = KEY_6,
++	[8]	 = KEY_7,
++	[9]	 = KEY_8,
++	[10]	 = KEY_9,
++	[11]	 = KEY_0,
++	[12]	 = KEY_MINUS,
++	[13]	 = KEY_EQUAL,
++	[14]	 = KEY_BACKSPACE,
++	[15]	 = KEY_TAB,
++	[16]	 = KEY_Q,
++	[17]	 = KEY_W,
++	[18]	 = KEY_E,
++	[19]	 = KEY_R,
++	[20]	 = KEY_T,
++	[21]	 = KEY_Y,
++	[22]	 = KEY_U,
++	[23]	 = KEY_I,
++	[24]	 = KEY_O,
++	[25]	 = KEY_P,
++	[26]	 = KEY_LEFTBRACE,
++	[27]	 = KEY_RIGHTBRACE,
++	[28]	 = KEY_ENTER,
++	[29]	 = KEY_LEFTCTRL,
++	[30]	 = KEY_A,
++	[31]	 = KEY_S,
++	[32]	 = KEY_D,
++	[33]	 = KEY_F,
++	[34]	 = KEY_G,
++	[35]	 = KEY_H,
++	[36]	 = KEY_J,
++	[37]	 = KEY_K,
++	[38]	 = KEY_L,
++	[39]	 = KEY_SEMICOLON,
++	[40]	 = KEY_APOSTROPHE,
++	[41]	 = KEY_BACKSLASH,	// FIXME, '#'
++	[42]	 = KEY_LEFTSHIFT,
++	[43]	 = KEY_GRAVE,		// FIXME: '~'
++	[44]	 = KEY_Z,
++	[45]	 = KEY_X,
++	[46]	 = KEY_C,
++	[47]	 = KEY_V,
++	[48]	 = KEY_B,
++	[49]	 = KEY_N,
++	[50]	 = KEY_M,
++	[51]	 = KEY_COMMA,
++	[52]	 = KEY_DOT,
++	[53]	 = KEY_SLASH,
++	[54]	 = KEY_RIGHTSHIFT,
++	[55]	 = KEY_KPASTERISK,
++	[56]	 = KEY_LEFTALT,
++	[57]	 = KEY_SPACE,
++	[58]	 = KEY_CAPSLOCK,
++	[59]	 = KEY_F1,
++	[60]	 = KEY_F2,
++	[61]	 = KEY_F3,
++	[62]	 = KEY_F4,
++	[63]	 = KEY_F5,
++	[64]	 = KEY_F6,
++	[65]	 = KEY_F7,
++	[66]	 = KEY_F8,
++	[67]	 = KEY_F9,
++	[68]	 = KEY_F10,
++	[69]	 = KEY_ESC,
++	[70]	 = KEY_DELETE,
++	[71]	 = KEY_KP7,
++	[72]	 = KEY_KP8,
++	[73]	 = KEY_KP9,
++	[74]	 = KEY_KPMINUS,
++	[75]	 = KEY_KP4,
++	[76]	 = KEY_KP5,
++	[77]	 = KEY_KP6,
++	[78]	 = KEY_KPPLUS,
++	[79]	 = KEY_KP1,
++	[80]	 = KEY_KP2,
++	[81]	 = KEY_KP3,
++	[82]	 = KEY_KP0,		// FIXME
++	[83]	 = KEY_KPDOT,		// FIXME
++	[90]	 = KEY_KPLEFTPAREN,
++	[91]	 = KEY_KPRIGHTPAREN,
++	[92]	 = KEY_KPSLASH,
++	[93]	 = KEY_KPASTERISK,
++	[94]	 = KEY_KPPLUS,
++	[95]	 = KEY_HELP,
++	[96]	 = KEY_BACKSLASH,	// FIXME: '<'
++	[97]	 = KEY_UNDO,		// FIXME
++	[98]	 = KEY_KPSLASH,		// FIXME
++	[99]	 = KEY_KPLEFTPAREN,
++	[100]	 = KEY_KPRIGHTPAREN,
++	[101]	 = KEY_KPSLASH,
++	[102]	 = KEY_KPASTERISK,
++	[103]	 = KEY_UP,
++	[104]	 = KEY_KP8,
++	[105]	 = KEY_LEFT,
++	[106]	 = KEY_RIGHT,
++	[107]	 = KEY_KP5,
++	[108]	 = KEY_DOWN,
++	[109]	 = KEY_KP1,
++	[110]	 = KEY_KP2,
++	[111]	 = KEY_KP3,
++	[112]	 = KEY_KP0,
++	[113]	 = KEY_KPDOT
++};
++
++static struct input_dev *atakbd_dev;
++
++static void atakbd_interrupt(unsigned char scancode, char down)
++{
++
++	if (scancode < 0x72) {		/* scancodes < 0xf2 are keys */
++
++		// report raw events here? 
++
++		scancode = atakbd_keycode[scancode];
++		input_regs(atakbd_dev, atakbd_pt_regs);
++
++		if (scancode == KEY_CAPSLOCK) {	/* CapsLock is a toggle switch key on Amiga */
++			input_report_key(atakbd_dev, scancode, 1);
++			input_report_key(atakbd_dev, scancode, 0);
++			input_sync(atakbd_dev);
++		} else {
++			input_report_key(atakbd_dev, scancode, down);
++			input_sync(atakbd_dev);
++		}
++	} else				/* scancodes >= 0xf2 are mouse data, most likely */
++		printk(KERN_INFO "atakbd: unhandled scancode %x\n", scancode);
++
++	return;
++}
++
++static int __init atakbd_init(void)
++{
++	int i;
++
++	if (!ATARIHW_PRESENT(ST_MFP))
++		return -EIO;
++
++	// TODO: request_mem_region if not done in arch code
++
++	if (!(atakbd_dev = input_allocate_device()))
++		return -ENOMEM;
++
++	// need to init core driver if not already done so
++	if (atari_keyb_init())
++		return -ENODEV;
++
++	atakbd_dev->name = "Atari Keyboard";
++	atakbd_dev->phys = "atakbd/input0";
++	atakbd_dev->id.bustype = BUS_ATARI;
++	atakbd_dev->id.vendor = 0x0001;
++	atakbd_dev->id.product = 0x0001;
++	atakbd_dev->id.version = 0x0100;
++
++	atakbd_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
++	atakbd_dev->keycode = atakbd_keycode;
++	atakbd_dev->keycodesize = sizeof(unsigned char);
++	atakbd_dev->keycodemax = ARRAY_SIZE(atakbd_keycode);
++
++	for (i = 0; i < 0x72; i++)
++		if (atakbd_keycode[i])
++			set_bit(atakbd_keycode[i], atakbd_dev->keybit);
++
++	// TODO: populate key_maps
++
++	input_register_device(atakbd_dev);
++
++	atari_input_keyboard_interrupt_hook = atakbd_interrupt;
++
++	printk(KERN_INFO "input: %s at IKBD ACIA\n", atakbd_dev->name);
++
++	return 0;
++}
++
++static void __exit atakbd_exit(void)
++{
++	atari_input_keyboard_interrupt_hook = NULL;
++	input_unregister_device(atakbd_dev);
++}
++
++module_init(atakbd_init);
++module_exit(atakbd_exit);

Added: dists/sid/linux-2.6/debian/patches/m68k-atari-mouse.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/m68k-atari-mouse.patch	Mon Nov 20 00:58:24 2006
@@ -0,0 +1,201 @@
+diff -urN linux-m68k/drivers/input/mouse/Kconfig linux-schmitz/drivers/input/mouse/Kconfig
+--- linux-m68k/drivers/input/mouse/Kconfig	2006-11-19 21:35:33.000000000 +0100
++++ linux-schmitz/drivers/input/mouse/Kconfig	2006-11-19 21:37:26.000000000 +0100
+@@ -96,6 +96,16 @@
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called amimouse.
+ 
++config MOUSE_ATARI
++	tristate "Atari mouse"
++	depends on ATARI
++	help
++	  Say Y here if you have an Atari and want its native mouse
++	  supported by the kernel.
++
++	  To compile this driver as a module, choose M here: the
++	  module will be called atarimouse.
++
+ config MOUSE_RISCPC
+ 	tristate "Acorn RiscPC mouse"
+ 	depends on ARCH_ACORN
+diff -urN linux-m68k/drivers/input/mouse/Makefile linux-schmitz/drivers/input/mouse/Makefile
+--- linux-m68k/drivers/input/mouse/Makefile	2006-09-20 05:42:06.000000000 +0200
++++ linux-schmitz/drivers/input/mouse/Makefile	2006-11-19 21:37:26.000000000 +0100
+@@ -5,6 +5,7 @@
+ # Each configuration option enables a list of files.
+ 
+ obj-$(CONFIG_MOUSE_AMIGA)	+= amimouse.o
++obj-$(CONFIG_MOUSE_ATARI)	+= atarimouse.o
+ obj-$(CONFIG_MOUSE_RISCPC)	+= rpcmouse.o
+ obj-$(CONFIG_MOUSE_INPORT)	+= inport.o
+ obj-$(CONFIG_MOUSE_LOGIBM)	+= logibm.o
+diff -urN linux-m68k/drivers/input/mouse/atarimouse.c linux-schmitz/drivers/input/mouse/atarimouse.c
+--- linux-m68k/drivers/input/mouse/atarimouse.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-schmitz/drivers/input/mouse/atarimouse.c	2006-11-19 21:37:26.000000000 +0100
+@@ -0,0 +1,166 @@
++/*
++ *  Atari mouse driver for Linux/m68k
++ *
++ *  Copyright (c) 2005 Michael Schmitz
++ *
++ *  Based on:
++ *  Amiga mouse driver for Linux/m68k
++ *
++ *  Copyright (c) 2000-2002 Vojtech Pavlik
++ *
++ */
++/*
++ * The low level init and interrupt stuff is handled in arch/mm68k/atari/atakeyb.c
++ * (the keyboard ACIA also handles the mouse and joystick data, and the keyboard 
++ * interrupt is shared with the MIDI ACIA so MIDI data also get handled there). 
++ * This driver only deals with handing key events off to the input layer. 
++ *
++ * Largely based on the old:
++ *
++ * Atari Mouse Driver for Linux
++ * by Robert de Vries (robert at and.nl) 19Jul93
++ *
++ * 16 Nov 1994 Andreas Schwab
++ * Compatibility with busmouse
++ * Support for three button mouse (shamelessly stolen from MiNT)
++ * third button wired to one of the joystick directions on joystick 1
++ *
++ * 1996/02/11 Andreas Schwab
++ * Module support
++ * Allow multiple open's
++ *
++ * Converted to use new generic busmouse code.  5 Apr 1998
++ *   Russell King <rmk at arm.uk.linux.org>
++ */
++
++
++/*
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published by
++ * the Free Software Foundation
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/input.h>
++#include <linux/interrupt.h>
++
++#include <asm/irq.h>
++#include <asm/setup.h>
++#include <asm/system.h>
++#include <asm/uaccess.h>
++#include <asm/atarihw.h>
++#include <asm/atarikb.h>
++#include <asm/atariints.h>
++
++MODULE_AUTHOR("Michael Schmitz <schmitz at biophys.uni-duesseldorf.de>");
++MODULE_DESCRIPTION("Atari mouse driver");
++MODULE_LICENSE("GPL");
++
++static int mouse_threshold[2] = {2,2};
++#ifdef __MODULE__
++MODULE_PARM(mouse_threshold, "2i");
++#endif
++#ifdef FIXED_ATARI_JOYSTICK
++extern int atari_mouse_buttons;
++#endif
++static int atamouse_used = 0;
++static int atamouse_lastx, atamouse_lasty;
++
++static struct input_dev *atamouse_dev;
++
++static void atamouse_interrupt(char *buf)
++{
++	int buttons;
++	int nx, ny, dx, dy;
++
++/*	ikbd_mouse_disable(); */
++
++	buttons = ((buf[0] & 1)
++	       | ((buf[0] & 2) << 1)
++#ifdef FIXED_ATARI_JOYSTICK
++	       | (atari_mouse_buttons & 2));
++	atari_mouse_buttons = buttons;
++#else
++                );
++#endif
++/*	ikbd_mouse_rel_pos(); */
++
++        /* only relative events get here */
++	dx =  buf[1];
++	dy = -buf[2];
++
++	input_regs(atamouse_dev, atakbd_pt_regs);
++
++	input_report_rel(atamouse_dev, REL_X, dx);
++	input_report_rel(atamouse_dev, REL_Y, dy);
++
++	input_report_key(atamouse_dev, BTN_LEFT,   buttons & 0x1);
++	input_report_key(atamouse_dev, BTN_MIDDLE, buttons & 0x2);
++	input_report_key(atamouse_dev, BTN_RIGHT,  buttons & 0x4);
++
++	input_sync(atamouse_dev);
++
++	return;
++}
++
++static int atamouse_open(struct input_dev *dev)
++{
++        if (atamouse_used++)
++                return 0;
++
++#ifdef FIXED_ATARI_JOYSTICK
++	atari_mouse_buttons = 0;
++#endif
++	ikbd_mouse_y0_top ();
++	ikbd_mouse_thresh (mouse_threshold[0], mouse_threshold[1]);
++	ikbd_mouse_rel_pos();
++	atari_input_mouse_interrupt_hook = atamouse_interrupt;
++	return 0;
++}
++
++static void atamouse_close(struct input_dev *dev)
++{
++        if (!--atamouse_used) {
++	        ikbd_mouse_disable();
++                atari_mouse_interrupt_hook = NULL;
++        }
++}
++
++static int __init atamouse_init(void)
++{
++	if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP))
++		return -ENODEV;
++
++	if (!(atamouse_dev = input_allocate_device()))
++		return -ENOMEM;
++
++        if (!(atari_keyb_init()))
++                return -ENODEV;
++
++	atamouse_dev->name = "Atari mouse";
++	atamouse_dev->phys = "atamouse/input0";
++	atamouse_dev->id.bustype = BUS_ATARI;
++	atamouse_dev->id.vendor = 0x0001;
++	atamouse_dev->id.product = 0x0002;
++	atamouse_dev->id.version = 0x0100;
++
++	atamouse_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
++	atamouse_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
++	atamouse_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
++	atamouse_dev->open = atamouse_open;
++	atamouse_dev->close = atamouse_close;
++
++	input_register_device(atamouse_dev);
++
++        printk(KERN_INFO "input: %s at keyboard ACIA\n", atamouse_dev->name);
++	return 0;
++}
++
++static void __exit atamouse_exit(void)
++{
++        input_unregister_device(atamouse_dev);
++}
++
++module_init(atamouse_init);
++module_exit(atamouse_exit);

Added: dists/sid/linux-2.6/debian/patches/m68k-atari-scsi.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/m68k-atari-scsi.patch	Mon Nov 20 00:58:24 2006
@@ -0,0 +1,215 @@
+diff -urN linux-m68k/drivers/scsi/Kconfig linux-schmitz/drivers/scsi/Kconfig
+--- linux-m68k/drivers/scsi/Kconfig	2006-11-19 21:35:33.000000000 +0100
++++ linux-schmitz/drivers/scsi/Kconfig	2006-11-19 21:37:26.000000000 +0100
+@@ -1713,7 +1713,7 @@
+ 
+ config ATARI_SCSI
+ 	tristate "Atari native SCSI support"
+-	depends on ATARI && SCSI && BROKEN
++	depends on ATARI && SCSI
+ 	select SCSI_SPI_ATTRS
+ 	---help---
+ 	  If you have an Atari with built-in NCR5380 SCSI controller (TT,
+diff -urN linux-m68k/drivers/scsi/atari_NCR5380.c linux-schmitz/drivers/scsi/atari_NCR5380.c
+--- linux-m68k/drivers/scsi/atari_NCR5380.c	2006-09-20 05:42:06.000000000 +0200
++++ linux-schmitz/drivers/scsi/atari_NCR5380.c	2006-11-19 21:37:26.000000000 +0100
+@@ -716,7 +716,7 @@
+ 	printk("NCR5380_print_status: no memory for print buffer\n");
+ 	return;
+     }
+-    len = NCR5380_proc_info(pr_bfr, &start, 0, PAGE_SIZE, HOSTNO, 0);
++    len = NCR5380_proc_info(instance, pr_bfr, &start, 0, PAGE_SIZE, 0);
+     pr_bfr[len] = 0;
+     printk("\n%s\n", pr_bfr);
+     free_page((unsigned long) pr_bfr);
+@@ -878,6 +878,46 @@
+ }
+ 
+ /* 
++ * our own old-style timeout update
++ */
++/*
++ * The strategy is to cause the timer code to call scsi_times_out()
++ * when the soonest timeout is pending.
++ * The arguments are used when we are queueing a new command, because
++ * we do not want to subtract the time used from this time, but when we
++ * set the timer, we want to take this value into account.
++ */
++
++int atari_scsi_update_timeout(Scsi_Cmnd * SCset, int timeout)
++{
++    int rtn;
++
++    /*
++     * We are using the new error handling code to actually register/deregister
++     * timers for timeout.
++     */
++
++    if (!timer_pending(&SCset->eh_timeout)) {
++	rtn = 0;
++    } else {
++	rtn = SCset->eh_timeout.expires - jiffies;
++    }
++
++    if (timeout == 0) {
++        del_timer(&SCset->eh_timeout);
++        SCset->eh_timeout.data = (unsigned long) NULL;
++        SCset->eh_timeout.expires = 0;
++    } else {
++        if (SCset->eh_timeout.data != (unsigned long) NULL) 
++            del_timer(&SCset->eh_timeout);
++        SCset->eh_timeout.data = (unsigned long) SCset;
++        SCset->eh_timeout.expires = jiffies + timeout;
++        add_timer(&SCset->eh_timeout);
++    }
++    return rtn;
++}
++
++/* 
+  * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, 
+  *	void (*done)(Scsi_Cmnd *)) 
+  *
+@@ -902,7 +942,7 @@
+     Scsi_Cmnd *tmp;
+     int oldto;
+     unsigned long flags;
+-    extern int update_timeout(Scsi_Cmnd * SCset, int timeout);
++    // extern int update_timeout(Scsi_Cmnd * SCset, int timeout);
+ 
+ #if (NDEBUG & NDEBUG_NO_WRITE)
+     switch (cmd->cmnd[0]) {
+@@ -956,6 +996,7 @@
+ 
+     cmd->result = 0;
+ 
++    // moved local_irq_save() from here
+ 
+     /* 
+      * Insert the cmd into the issue queue. Note that REQUEST SENSE 
+@@ -964,7 +1005,6 @@
+      * sense data is only guaranteed to be valid while the condition exists.
+      */
+ 
+-    local_irq_save(flags);
+     /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA.
+      * Otherwise a running NCR5380_main may steal the lock.
+      * Lock before actually inserting due to fairness reasons explained in
+@@ -977,11 +1017,15 @@
+      * because also a timer int can trigger an abort or reset, which would
+      * alter queues and touch the lock.
+      */
++#if 1
+     if (!IS_A_TT()) {
+-	oldto = update_timeout(cmd, 0);
++	oldto = atari_scsi_update_timeout(cmd, 0);
+ 	falcon_get_lock();
+-	update_timeout(cmd, oldto);
++	atari_scsi_update_timeout(cmd, oldto);
+     }
++#endif
++    // moved local_irq_save() here for now
++    local_irq_save(flags);
+     if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+ 	LIST(cmd, hostdata->issue_queue);
+ 	NEXT(cmd) = hostdata->issue_queue;
+@@ -1435,7 +1479,7 @@
+     local_irq_restore(flags);
+ 
+     /* Wait for arbitration logic to complete */
+-#if NCR_TIMEOUT
++#if defined(NCR_TIMEOUT)
+     {
+       unsigned long timeout = jiffies + 2*NCR_TIMEOUT;
+ 
+diff -urN linux-m68k/drivers/scsi/atari_scsi.c linux-schmitz/drivers/scsi/atari_scsi.c
+--- linux-m68k/drivers/scsi/atari_scsi.c	2006-09-20 05:42:06.000000000 +0200
++++ linux-schmitz/drivers/scsi/atari_scsi.c	2006-11-19 21:37:26.000000000 +0100
+@@ -558,11 +558,11 @@
+ 
+ 	local_irq_save(flags);
+ 
+-	while( !in_interrupt() && falcon_got_lock && stdma_others_waiting() )
++	while( !in_irq() && falcon_got_lock && stdma_others_waiting() )
+ 		sleep_on( &falcon_fairness_wait );
+ 
+ 	while (!falcon_got_lock) {
+-		if (in_interrupt())
++		if (in_irq())
+ 			panic( "Falcon SCSI hasn't ST-DMA lock in interrupt" );
+ 		if (!falcon_trying_lock) {
+ 			falcon_trying_lock = 1;
+@@ -764,7 +764,6 @@
+ 	return( 1 );
+ }
+ 
+-#ifdef MODULE
+ int atari_scsi_release (struct Scsi_Host *sh)
+ {
+ 	if (IS_A_TT())
+@@ -773,7 +772,6 @@
+ 		atari_stram_free (atari_dma_buffer);
+ 	return 1;
+ }
+-#endif
+ 
+ void __init atari_scsi_setup(char *str, int *ints)
+ {
+diff -urN linux-m68k/drivers/scsi/atari_scsi.h linux-schmitz/drivers/scsi/atari_scsi.h
+--- linux-m68k/drivers/scsi/atari_scsi.h	2006-09-20 05:42:06.000000000 +0200
++++ linux-schmitz/drivers/scsi/atari_scsi.h	2006-11-19 21:37:26.000000000 +0100
+@@ -21,11 +21,7 @@
+ int atari_scsi_detect (struct scsi_host_template *);
+ const char *atari_scsi_info (struct Scsi_Host *);
+ int atari_scsi_reset (Scsi_Cmnd *, unsigned int);
+-#ifdef MODULE
+ int atari_scsi_release (struct Scsi_Host *);
+-#else
+-#define atari_scsi_release NULL
+-#endif
+ 
+ /* The values for CMD_PER_LUN and CAN_QUEUE are somehow arbitrary. Higher
+  * values should work, too; try it! (but cmd_per_lun costs memory!) */
+@@ -43,7 +39,9 @@
+ 
+ #define ATARI_FALCON_CAN_QUEUE		8
+ #define ATARI_FALCON_CMD_PER_LUN	1
+-#define ATARI_FALCON_SG_TABLESIZE	SG_NONE
++/*  Set to 1 in order to shut up warning message in bio code
++ */
++#define ATARI_FALCON_SG_TABLESIZE	1	// SG_NONE
+ 
+ #define	DEFAULT_USE_TAGGED_QUEUING	0
+ 
+@@ -63,6 +61,32 @@
+ #define	NCR5380_dma_xfer_len(i,cmd,phase) \
+ 	atari_dma_xfer_len(cmd->SCp.this_residual,cmd,((phase) & SR_IO) ? 0 : 1)
+ 
++/* former generic SCSI error handling stuff */
++
++#define SCSI_ABORT_SNOOZE 0
++#define SCSI_ABORT_SUCCESS 1
++#define SCSI_ABORT_PENDING 2
++#define SCSI_ABORT_BUSY 3
++#define SCSI_ABORT_NOT_RUNNING 4
++#define SCSI_ABORT_ERROR 5
++
++#define SCSI_RESET_SNOOZE 0
++#define SCSI_RESET_PUNT 1
++#define SCSI_RESET_SUCCESS 2
++#define SCSI_RESET_PENDING 3
++#define SCSI_RESET_WAKEUP 4
++#define SCSI_RESET_NOT_RUNNING 5
++#define SCSI_RESET_ERROR 6
++
++#define SCSI_RESET_SYNCHRONOUS		0x01
++#define SCSI_RESET_ASYNCHRONOUS		0x02
++#define SCSI_RESET_SUGGEST_BUS_RESET	0x04
++#define SCSI_RESET_SUGGEST_HOST_RESET	0x08
++
++#define SCSI_RESET_BUS_RESET 0x100
++#define SCSI_RESET_HOST_RESET 0x200
++#define SCSI_RESET_ACTION   0xff
++
+ /* Debugging printk definitions:
+  *
+  *  ARB  -> arbitration

Added: dists/sid/linux-2.6/debian/patches/m68k-atari-serial.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/m68k-atari-serial.patch	Mon Nov 20 00:58:24 2006
@@ -0,0 +1,1747 @@
+diff -urN linux-m68k/drivers/char/Makefile linux-schmitz/drivers/char/Makefile
+--- linux-m68k/drivers/char/Makefile	2006-11-19 21:35:29.000000000 +0100
++++ linux-schmitz/drivers/char/Makefile	2006-11-19 21:37:26.000000000 +0100
+@@ -30,6 +30,7 @@
+ obj-$(CONFIG_MOXA_INTELLIO)	+= moxa.o
+ obj-$(CONFIG_SIBYTE_SB1250_DUART)	+= sb1250_duart.o
+ obj-$(CONFIG_A2232)		+= ser_a2232.o generic_serial.o
++obj-$(CONFIG_ATARI_SCC)		+= atari_scc.o generic_serial.o
+ obj-$(CONFIG_ATARI_DSP56K)	+= dsp56k.o
+ obj-$(CONFIG_MOXA_SMARTIO)	+= mxser.o
+ obj-$(CONFIG_COMPUTONE)		+= ip2/
+diff -urN linux-m68k/drivers/char/atari_scc.c linux-schmitz/drivers/char/atari_scc.c
+--- linux-m68k/drivers/char/atari_scc.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-schmitz/drivers/char/atari_scc.c	2006-11-19 21:37:26.000000000 +0100
+@@ -0,0 +1,1732 @@
++/*
++ * drivers/char/atari_scc.c: Atari TT/Falcon Am8530 SCC serial ports implementation.
++ * 
++ * Copyright 2005 Michael Schmitz
++ *
++ * Based on:
++ *   drivers/char/vme_scc.c: MVME147, MVME162, BVME6000 SCC serial ports
++ *   implementation.
++ *   Copyright 1999 Richard Hirst <richard at sleepie.demon.co.uk>
++ *
++ * which, in turn, was
++ *
++ * Based on atari_SCC.c which was
++ *   Copyright 1994-95 Roman Hodek <Roman.Hodek at informatik.uni-erlangen.de>
++ *   Partially based on PC-Linux serial.c by Linus Torvalds and Theodore Ts'o
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file COPYING in the main directory of this archive
++ * for more details.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/config.h>
++#include <linux/kdev_t.h>
++#include <asm/io.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/ioport.h>
++#include <linux/interrupt.h>
++#include <linux/errno.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/mm.h>
++#include <linux/serial.h>
++#include <linux/fcntl.h>
++#include <linux/major.h>
++#include <linux/delay.h>
++#include <linux/slab.h>
++#include <linux/miscdevice.h>
++#include <linux/console.h>
++#include <linux/init.h>
++#include <asm/setup.h>
++#include <asm/uaccess.h>
++#include <asm/bootinfo.h>
++
++#include <asm/atarihw.h>
++#include <asm/atariints.h>
++
++#include <linux/generic_serial.h>
++#include "scc.h"
++
++#define CONFIG_TT_SCC     1
++#define CONFIG_FALCON_SCC 1
++
++#define CHANNEL_A	0
++#define CHANNEL_B	1
++
++#define SCC_MINOR_BASE	64
++
++/* Shadows for all SCC write registers */
++static unsigned char scc_shadow[2][16];
++
++/* Location to access for SCC register access delay */
++static volatile unsigned char *scc_del = NULL;
++
++/* To keep track of STATUS_REG state for detection of Ext/Status int source */
++static unsigned char scc_last_status_reg[2];
++
++/***************************** Prototypes *****************************/
++
++/* Function prototypes */
++static void scc_disable_tx_interrupts(void * ptr);
++static void scc_enable_tx_interrupts(void * ptr);
++static void scc_disable_rx_interrupts(void * ptr);
++static void scc_enable_rx_interrupts(void * ptr);
++static int  scc_get_CD(void * ptr);
++static void scc_shutdown_port(void * ptr);
++static int scc_set_real_termios(void  *ptr);
++static void scc_hungup(void  *ptr);
++static void scc_close(void  *ptr);
++static int scc_chars_in_buffer(void * ptr);
++static int scc_open(struct tty_struct * tty, struct file * filp);
++static int scc_ioctl(struct tty_struct * tty, struct file * filp,
++                     unsigned int cmd, unsigned long arg);
++static void scc_throttle(struct tty_struct *tty);
++static void scc_unthrottle(struct tty_struct *tty);
++static irqreturn_t scc_tx_int(int irq, void *data, struct pt_regs *fp);
++static irqreturn_t scc_rx_int(int irq, void *data, struct pt_regs *fp);
++static irqreturn_t scc_stat_int(int irq, void *data, struct pt_regs *fp);
++static irqreturn_t scc_spcond_int(int irq, void *data, struct pt_regs *fp);
++static void scc_setsignals(struct scc_port *port, int dtr, int rts);
++static void scc_break_ctl(struct tty_struct *tty, int break_state);
++
++static struct tty_driver *scc_driver;
++
++struct scc_port scc_ports[2];
++
++int scc_initialized = 0;
++
++/*
++ * Flags to indicate one of the serial ports has already been initialized by the 
++ * serial debug driver. We may want to hold off reinitializing ... 
++ */
++
++/* Flag that Modem1 port is already initialized and used */
++extern int atari_SCC_init_done;
++/* Can be set somewhere, if a SCC master reset has already be done and should
++ * not be repeated; used by kgdb */
++extern int atari_SCC_reset_done;
++
++/*---------------------------------------------------------------------------
++ * Interface from generic_serial.c back here
++ *--------------------------------------------------------------------------*/
++
++static struct real_driver scc_real_driver = {
++        scc_disable_tx_interrupts,
++        scc_enable_tx_interrupts,
++        scc_disable_rx_interrupts,
++        scc_enable_rx_interrupts,
++        scc_get_CD,
++        scc_shutdown_port,
++        scc_set_real_termios,
++        scc_chars_in_buffer,
++        scc_close,
++        scc_hungup,
++        NULL
++};
++
++static struct tty_operations scc_ops = {
++	.open	= scc_open,
++	.close = gs_close,
++	.write = gs_write,
++	.put_char = gs_put_char,
++	.flush_chars = gs_flush_chars,
++	.write_room = gs_write_room,
++	.chars_in_buffer = gs_chars_in_buffer,
++	.flush_buffer = gs_flush_buffer,
++	.ioctl = scc_ioctl,
++	.throttle = scc_throttle,
++	.unthrottle = scc_unthrottle,
++	.set_termios = gs_set_termios,
++	.stop = gs_stop,
++	.start = gs_start,
++	.hangup = gs_hangup,
++	.break_ctl = scc_break_ctl,
++};
++
++static unsigned SCC_clocks[2][2] = {
++	  /* RTxC */			/* TRxC */
++	{ SCC_BAUD_BASE_PCLK4,	SCC_BAUD_BASE_NONE },	/* Channel A */
++	{ SCC_BAUD_BASE_TIMC,	SCC_BAUD_BASE_BCLK }	/* Channel B */
++};
++
++/* BRG values for the standard speeds and the various clock sources */
++
++typedef struct {
++	unsigned	clksrc;		/* clock source to use or -1 for not possible */
++	unsigned	div;		/* divisor: 1, 2 and 4 correspond to
++					 * direct 1:16, 1:32 and 1:64 modes,
++					 * divisors >= 4 yield a BRG value of
++					 * div/2-2 (in 1:16 mode)
++					 */
++} BAUD_ENTRY;
++
++/* A pointer for each channel to the current baud table */
++static BAUD_ENTRY *scc_baud_table[2];
++
++/* Baud table format:
++ *
++ * Each entry consists of the clock source (CLK_RTxC, CLK_TRxC or
++ * CLK_PCLK) and a divisor. The following rules apply to the divisor:
++ *
++ *   - CLK_RTxC: 1 or even (1, 2 and 4 are the direct modes, > 4 use
++ *               the BRG)
++ *
++ *   - CLK_TRxC: 1, 2 or 4 (no BRG, only direct modes possible)
++ *
++ *   - CLK_PCLK: >= 4 and even (no direct modes, only BRG)
++ *
++ */
++
++/* This table is used if RTxC = 3.672 MHz. This is the case for TT's
++ * channel A and for both channels on the Mega STE/Falcon. (TRxC is unused)
++ */
++
++static BAUD_ENTRY bdtab_norm[20] = {
++	/* B0      */ { 0, 0 },
++	/* B50     */ { CLK_RTxC, 4590 },
++	/* B75     */ { CLK_RTxC, 3060 },
++	/* B110    */ { CLK_PCLK, 4576 },
++	/* B134    */ { CLK_PCLK, 3756 },
++	/* B150    */ { CLK_RTxC, 1530 },
++	/* B200    */ { CLK_PCLK, 2516 },
++	/* B300    */ { CLK_PCLK, 1678 },
++	/* B600    */ { CLK_PCLK, 838 },
++	/* B1200   */ { CLK_PCLK, 420 },
++	/* B1800   */ { CLK_PCLK, 280 },
++	/* B2400   */ { CLK_PCLK, 210 },
++	/* B4800   */ { CLK_RTxC, 48 },
++	/* B9600   */ { CLK_RTxC, 24 },
++	/* B19200  */ { CLK_RTxC, 12 },
++	/* B38400  */ { CLK_RTxC, 6 },   /* #15 spd_extra */
++	/* B57600  */ { CLK_RTxC, 4 },   /* #16 spd_hi */
++	/* B115200 */ { CLK_RTxC, 2 },   /* #17 spd_vhi */
++	/* B230400 */ { CLK_RTxC, 1 },   /* #18 spd_shi */
++	/* B460800 */ { 0, 0 }           /* #19 spd_warp: Impossible */
++};
++
++/* This is a special table for the TT channel B with 307.2 kHz at RTxC
++ * and 2.4576 MHz at TRxC
++ */
++static BAUD_ENTRY bdtab_TTChB[20] = {
++	/* B0      */ { 0, 0 },
++	/* B50     */ { CLK_RTxC, 384 },
++	/* B75     */ { CLK_RTxC, 256 },
++	/* B110    */ { CLK_PCLK, 4576 },
++	/* B134    */ { CLK_PCLK, 3756 },
++	/* B150    */ { CLK_RTxC, 128 },
++	/* B200    */ { CLK_RTxC, 96 },
++	/* B300    */ { CLK_RTxC, 64 },
++	/* B600    */ { CLK_RTxC, 32 },
++	/* B1200   */ { CLK_RTxC, 16 },
++	/* B1800   */ { CLK_PCLK, 280 },
++	/* B2400   */ { CLK_RTxC, 8 },
++	/* B4800   */ { CLK_RTxC, 4 },
++	/* B9600   */ { CLK_RTxC, 2 },
++	/* B19200  */ { CLK_RTxC, 1 },
++	/* B38400  */ { CLK_TRxC, 4 },
++	/* B57600  */ { CLK_TRxC, 2 }, /* 57600 is not possible, use 76800 instead */
++	/* B115200 */ { CLK_TRxC, 1 }, /* 115200 is not possible, use 153600 instead */
++	/* B230400 */ { 0, 0 },        /* #18 spd_shi: Impossible  */
++	/* B460800 */ { 0, 0 }         /* #19 spd_warp: Impossible */
++};
++
++
++/**
++ *	tty_flip_buffer_flush	-	terminal
++ *	@tty: tty to flush
++ *
++ *	Queue a flush of the terminal flip buffers to the line discipline. This
++ *	function may also be called from IRQ context if tty->low_latency is set.
++ *
++ *	In the event of the queue being busy for flipping the work will be
++ *	held off and retried later.
++ *
++ *	Locking: tty buffer lock. Driver locks in low latency mode.
++ */
++
++void tty_flip_buffer_flush(struct tty_struct *tty)
++{
++	unsigned long flags;
++	spin_lock_irqsave(&tty->buf.lock, flags);
++	if (tty->buf.tail != NULL)
++		tty->buf.tail->commit = tty->buf.tail->used;
++	spin_unlock_irqrestore(&tty->buf.lock, flags);
++
++	if (tty->low_latency)
++		schedule_work(&tty->buf.work);
++	else
++		schedule_delayed_work(&tty->buf.work, 1);
++}
++
++/*----------------------------------------------------------------------------
++ * atari_scc_init() and support functions
++ *---------------------------------------------------------------------------*/
++
++static int scc_init_drivers(void)
++{
++	int error;
++
++	scc_driver = alloc_tty_driver(2);
++	if (!scc_driver)
++		return -ENOMEM;
++	scc_driver->owner = THIS_MODULE;
++	scc_driver->driver_name = "scc";
++	scc_driver->name = "ttyS";
++	// scc_driver->devfs_name = "tts/";
++	scc_driver->major = TTY_MAJOR;
++	scc_driver->minor_start = SCC_MINOR_BASE;
++	scc_driver->type = TTY_DRIVER_TYPE_SERIAL;
++	scc_driver->subtype = SERIAL_TYPE_NORMAL;
++	scc_driver->init_termios = tty_std_termios;
++	scc_driver->init_termios.c_cflag =
++	  B9600 | CS8 | CREAD | HUPCL | CLOCAL;
++	scc_driver->flags = TTY_DRIVER_REAL_RAW;
++
++	tty_set_operations(scc_driver, &scc_ops);
++
++	if ((error = tty_register_driver(scc_driver))) {
++		printk(KERN_ERR "scc: Couldn't register scc driver, error = %d\n",
++		       error);
++		put_tty_driver(scc_driver);
++		return 1;
++	}
++
++	return 0;
++}
++
++
++/* ports[] array is indexed by line no (i.e. [0] for ttyS0, [1] for ttyS1).
++ */
++
++static void scc_init_portstructs(void)
++{
++	struct scc_port *port;
++	int i;
++
++	for (i = 0; i < 2; i++) {
++		port = scc_ports + i;
++		port->gs.magic = SCC_MAGIC;
++		port->gs.close_delay = HZ/2;
++		port->gs.closing_wait = 30 * HZ;
++		port->gs.rd = &scc_real_driver;
++#ifdef NEW_WRITE_LOCKING
++		port->gs.port_write_sem = MUTEX;
++#endif
++		init_waitqueue_head(&port->gs.open_wait);
++		init_waitqueue_head(&port->gs.close_wait);
++	}
++}
++
++
++#ifdef CONFIG_TT_SCC
++static int atari_tt_scc_init(void)
++{
++	struct scc_port *port;
++
++	printk(KERN_INFO "SCC: Atari TT Serial Driver\n");
++	/* FIXME channel A may be switchable between modem and LAN port */
++	/* Init channel A */
++	if (atari_SCC_init_done)
++		printk(KERN_INFO "SCC: already initialized, expect trouble!\n");
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: init channel A\n");
++#endif
++	port = &scc_ports[0];
++	port->channel = CHANNEL_A;
++	port->ctrlp = (volatile unsigned char *)&scc.cha_a_ctrl;
++	port->datap = port->ctrlp + 1;
++	port->port_a = &scc_ports[0];
++	port->port_b = &scc_ports[1];
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: request channel A irqs, port = %p\n", port);
++#endif
++	request_irq(IRQ_SCCA_TX, scc_tx_int, IRQ_TYPE_PRIO,
++		            "SCC-A TX", port);
++	request_irq(IRQ_SCCA_STAT, scc_stat_int, IRQ_TYPE_PRIO,
++		            "SCC-A status", port);
++	request_irq(IRQ_SCCA_RX, scc_rx_int, IRQ_TYPE_PRIO,
++		            "SCC-A RX", port);
++	request_irq(IRQ_SCCA_SPCOND, scc_spcond_int, IRQ_TYPE_PRIO,
++		            "SCC-A special cond", port);
++	{
++		SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++		printk(KERN_INFO "SCC: read SCC status\n");
++#endif
++		/* on the first access, read status register to reset internal pointers */
++		SCCread(STATUS_REG);
++#ifdef DEBUG
++		printk(KERN_INFO "SCC: reset SCC\n");
++#endif
++		/* FIXME: master reset, once only */
++		SCCwrite(MASTER_INT_CTRL, MIC_HARD_RESET);
++		udelay(40);
++
++		/* disable interrupts for this channel */
++		SCCwrite(INT_AND_DMA_REG, 0);
++		/* Set the interrupt vector ; 0x60 for all Atari models */
++		SCCwrite(INT_VECTOR_REG, 0x60);
++		/* Interrupt parameters: vector includes status, status low */
++		SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT);
++		SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB);
++
++		/* disable interrupts for this channel */
++		SCCwrite(INT_AND_DMA_REG, 0);
++	}
++
++	if (!atari_SCC_init_done) {
++	/* Init channel B */
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: init channel B\n");
++#endif
++	port = &scc_ports[1];
++	port->channel = CHANNEL_B;
++	port->ctrlp = (volatile unsigned char *)&scc.cha_b_ctrl;
++	port->datap = port->ctrlp + 1;
++	port->port_a = &scc_ports[0];
++	port->port_b = &scc_ports[1];
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: request channel B irqs, port = %p\n", port);
++#endif
++	request_irq(IRQ_SCCB_TX, scc_tx_int, IRQ_TYPE_PRIO,
++		            "SCC-B TX", port);
++	request_irq(IRQ_SCCB_STAT, scc_stat_int, IRQ_TYPE_PRIO,
++		            "SCC-B status", port);
++	request_irq(IRQ_SCCB_RX, scc_rx_int, IRQ_TYPE_PRIO,
++		            "SCC-B RX", port);
++	request_irq(IRQ_SCCB_SPCOND, scc_spcond_int, IRQ_TYPE_PRIO,
++		            "SCC-B special cond", port);
++	{
++		SCC_ACCESS_INIT(port);
++
++		/* disable interrupts for this channel */
++		SCCwrite(INT_AND_DMA_REG, 0);
++	}
++/* not implemented yet */
++#if 0
++	request_irq(IRQ_TT_MFP_RI, scc_ri_int, IRQ_TYPE_SLOW,
++		     "TT-MFP ring indicator (modem 2)", port);
++#endif
++
++	}
++
++	/* once only: initalize MFP timer C for RTxC */
++	tt_mfp.tim_ct_cd = (tt_mfp.tim_ct_cd & ~0x70) | 0x10;
++	tt_mfp.tim_dt_c = 1;
++	atari_turnoff_irq(IRQ_TT_MFP_TIMC);
++
++	/* set baud tables */
++	scc_baud_table[CHANNEL_A] = bdtab_norm;
++	scc_baud_table[CHANNEL_B] = bdtab_TTChB;
++
++	/* Initialise the tty driver structures and register */
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: scc_init_portstructs()\n");
++#endif
++	scc_init_portstructs();
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: scc_init_drivers()\n");
++#endif
++	scc_init_drivers();
++
++	return 0;
++}
++#endif
++
++
++#ifdef CONFIG_FALCON_SCC
++static int atari_falcon_scc_init(void)
++{
++	struct scc_port *port;
++
++	printk(KERN_INFO "SCC: Atari Falcon Serial Driver\n");
++	if (atari_SCC_init_done)
++		printk(KERN_INFO "SCC: already initialized, expect trouble!\n");
++
++	/* Init channel A */
++	port = &scc_ports[0];
++	port->channel = CHANNEL_A;
++	port->ctrlp = (volatile unsigned char *)&scc.cha_a_ctrl;
++	port->datap = port->ctrlp + 2;
++	port->port_a = &scc_ports[0];
++	port->port_b = &scc_ports[1];
++	request_irq(IRQ_SCCA_TX, scc_tx_int, IRQ_TYPE_PRIO,
++		            "SCC-A TX", port);
++	request_irq(IRQ_SCCA_STAT, scc_stat_int, IRQ_TYPE_PRIO,
++		            "SCC-A status", port);
++	request_irq(IRQ_SCCA_RX, scc_rx_int, IRQ_TYPE_PRIO,
++		            "SCC-A RX", port);
++	request_irq(IRQ_SCCA_SPCOND, scc_spcond_int, IRQ_TYPE_PRIO,
++		            "SCC-A special cond", port);
++	{
++		SCC_ACCESS_INIT(port);
++
++		/* on the first access, read status register to reset internal pointers */
++		SCCread(STATUS_REG);
++
++		/* FIXME: master reset, once only */
++		SCCwrite(MASTER_INT_CTRL, MIC_HARD_RESET);
++		udelay(40);
++
++		/* disable interrupts for this channel */
++		SCCwrite(INT_AND_DMA_REG, 0);
++		/* Set the interrupt vector */
++		SCCwrite(INT_VECTOR_REG, 0x60);
++		/* Interrupt parameters: vector includes status, status low */
++		SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT);
++		SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB);
++	}
++
++	/* conditionalize if port in use by console ?? */
++	/* Init channel B */
++	port = &scc_ports[1];
++	port->channel = CHANNEL_B;
++	port->ctrlp = (volatile unsigned char *)&scc.cha_b_ctrl;
++	port->datap = port->ctrlp + 2;
++	port->port_a = &scc_ports[0];
++	port->port_b = &scc_ports[1];
++	request_irq(IRQ_SCCB_TX, scc_tx_int, IRQ_TYPE_PRIO,
++		            "SCC-B TX", port);
++	request_irq(IRQ_SCCB_STAT, scc_stat_int, IRQ_TYPE_PRIO,
++		            "SCC-B status", port);
++	request_irq(IRQ_SCCB_RX, scc_rx_int, IRQ_TYPE_PRIO,
++		            "SCC-B RX", port);
++	request_irq(IRQ_SCCB_SPCOND, scc_spcond_int, IRQ_TYPE_PRIO,
++		            "SCC-B special cond", port);
++
++	{
++		SCC_ACCESS_INIT(port);	/* Either channel will do */
++
++		/* disable interrupts for this channel */
++		SCCwrite(INT_AND_DMA_REG, 0);
++	}
++
++	/* set baud tables */
++	scc_baud_table[CHANNEL_A] = bdtab_norm;
++	scc_baud_table[CHANNEL_B] = bdtab_norm;
++
++	/* Initialise the tty driver structures and register */
++	scc_init_portstructs();
++	scc_init_drivers();
++
++	return 0;
++}
++#endif
++
++
++#ifdef CONFIG_ST_SCC
++static int atari_st_scc_init(void)
++{
++	struct scc_port *port;
++
++	int escc = ATARIHW_PRESENT(ST_ESCC);
++
++	printk(KERN_INFO "SCC: Atari MegaST/E Serial Driver\n");
++	/* FIXME: ports reversed logic */
++	/* Init channel A */
++	port = &scc_ports[1];
++	port->channel = CHANNEL_A;
++	port->ctrlp = (volatile unsigned char *)(escc ? &st_escc.cha_a_ctrl : &scc.cha_a_ctrl);
++	port->datap = port->ctrlp + 4;
++	port->port_a = &scc_ports[1];
++	port->port_b = &scc_ports[0];
++	request_irq(IRQ_SCCA_TX, scc_tx_int, IRQ_TYPE_PRIO,
++		            "SCC-A TX", port);
++	request_irq(IRQ_SCCA_STAT, scc_stat_int, IRQ_TYPE_PRIO,
++		            "SCC-A status", port);
++	request_irq(IRQ_SCCA_RX, scc_rx_int, IRQ_TYPE_PRIO,
++		            "SCC-A RX", port);
++	request_irq(SCCA_SPCOND, scc_spcond_int, IRQ_TYPE_PRIO,
++		            "SCC-A special cond", port);
++	{
++		SCC_ACCESS_INIT(port);
++
++		/* on the first access, read status register to reset internal pointers */
++		SCCread(STATUS_REG);
++
++		/* FIXME: master reset, once only */
++		SCCwrite(MASTER_INT_CTRL, MIC_HARD_RESET);
++		udelay(40);
++
++		/* disable interrupts for this channel */
++		SCCwrite(INT_AND_DMA_REG, 0);
++		/* Set the interrupt vector */
++		SCCwrite(INT_VECTOR_REG, BVME_IRQ_SCC_BASE);
++		/* Interrupt parameters: vector includes status, status low */
++		SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT);
++		SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB);
++	}
++
++	/* Init channel B */
++	port = &scc_ports[0];
++	port->channel = CHANNEL_B;
++	port->ctrlp = (volatile unsigned char *)(escc ? &st_escc.cha_b_ctrl : &scc.cha_b_ctrl);
++	port->datap = port->ctrlp + 4;
++	port->port_a = &scc_ports[0];
++	port->port_b = &scc_ports[1];
++	request_irq(IRQ_SCCB_TX, scc_tx_int, IRQ_TYPE_PRIO,
++		            "SCC-B TX", port);
++	request_irq(IRQ_SCCB_STAT, scc_stat_int, IRQ_TYPE_PRIO,
++		            "SCC-B status", port);
++	request_irq(IRQ_SCCB_RX, scc_rx_int, IRQ_TYPE_PRIO,
++		            "SCC-B RX", port);
++	request_irq(IRQ_SCCB_SPCOND, scc_spcond_int, IRQ_TYPE_PRIO,
++		            "SCC-B special cond", port);
++
++	{
++		SCC_ACCESS_INIT(port);	/* Either channel will do */
++
++		/* disable interrupts for this channel */
++		SCCwrite(INT_AND_DMA_REG, 0);
++	}
++
++	/* set baud tables */
++	scc_baud_table[CHANNEL_A] = bdtab_norm;
++	scc_baud_table[CHANNEL_B] = bdtab_norm;
++
++	/* Initialise the tty driver structures and register */
++	scc_init_portstructs();
++	scc_init_drivers();
++
++	return 0;
++}
++#endif
++
++
++int atari_scc_init(void)
++{
++	int res = -ENODEV;
++	static int called = 0;
++
++	if (called)
++		return res;
++	called = 1;
++
++        if (!(ATARIHW_PRESENT(SCC) || ATARIHW_PRESENT(ST_ESCC)))
++                        return( -ENODEV );
++	
++	scc_del = &mfp.par_dt_reg;
++
++#ifdef CONFIG_TT_SCC
++	if (MACH_IS_TT)
++		res = atari_tt_scc_init();
++#endif
++#ifdef CONFIG_FALCON_SCC
++	if (MACH_IS_FALCON)
++		res = atari_falcon_scc_init();
++#endif
++#ifdef CONFIG_ST_SCC
++	if (MACH_IS_ST)
++		res = atari_st_scc_init();
++#endif
++	return res;
++}
++
++void atari_scc_cleanup(void)
++{
++	struct scc_port *port;
++
++	tty_unregister_driver(scc_driver);
++	port = &scc_ports[0];
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: free channel A irqs, port = %p\n", port);
++#endif
++	free_irq(IRQ_SCCA_TX, port);
++	free_irq(IRQ_SCCA_STAT, port);
++	free_irq(IRQ_SCCA_RX, port);
++	free_irq(IRQ_SCCA_SPCOND, port);
++
++	port = &scc_ports[1];
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: free channel A irqs, port = %p\n", port);
++#endif
++	free_irq(IRQ_SCCB_TX, port);
++	free_irq(IRQ_SCCB_STAT, port);
++	free_irq(IRQ_SCCB_RX, port);
++	free_irq(IRQ_SCCB_SPCOND, port);
++
++}
++
++module_init(atari_scc_init);
++module_exit(atari_scc_cleanup);
++
++/*---------------------------------------------------------------------------
++ * Interrupt handlers
++ *--------------------------------------------------------------------------*/
++
++static irqreturn_t scc_rx_int(int irq, void *data, struct pt_regs *fp)
++{
++	unsigned char	ch;
++	struct scc_port *port = data;
++	struct tty_struct *tty = port->gs.tty;
++	SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: rx_int ...\n");
++#endif
++	ch = SCCread_NB(RX_DATA_REG);
++	if (!tty) {
++		printk(KERN_WARNING "scc_rx_int with NULL tty!\n");
++		SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
++		return IRQ_HANDLED;
++	}
++   	tty_insert_flip_char(tty, ch, 0);
++
++	/* Check if another character is already ready; in that case, the
++	 * spcond_int() function must be used, because this character may have an
++	 * error condition that isn't signalled by the interrupt vector used!
++	 */
++	if (SCCread(INT_PENDING_REG) &
++	    (port->channel == CHANNEL_A ? IPR_A_RX : IPR_B_RX)) {
++		scc_spcond_int (irq, data, fp);
++		return IRQ_HANDLED;
++	}
++
++	SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
++
++	tty_flip_buffer_flush(tty);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: rx_int done\n");
++#endif
++	return IRQ_HANDLED;
++}
++
++
++static irqreturn_t scc_spcond_int(int irq, void *data, struct pt_regs *fp)
++{
++	struct scc_port *port = data;
++	struct tty_struct *tty = port->gs.tty;
++	unsigned char	stat, ch, err;
++	int		int_pending_mask = port->channel == CHANNEL_A ?
++			                   IPR_A_RX : IPR_B_RX;
++	SCC_ACCESS_INIT(port);
++#ifdef DEBUG	
++	printk(KERN_INFO "SCC: spcond_int ...\n");
++#endif
++	if (!tty) {
++		printk(KERN_WARNING "scc_spcond_int with NULL tty!\n");
++		SCCwrite(COMMAND_REG, CR_ERROR_RESET);
++		SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
++		return IRQ_HANDLED;
++	}
++	do {
++		stat = SCCread(SPCOND_STATUS_REG);
++		ch = SCCread_NB(RX_DATA_REG);
++
++		if (stat & SCSR_RX_OVERRUN)
++			err = TTY_OVERRUN;
++		else if (stat & SCSR_PARITY_ERR)
++			err = TTY_PARITY;
++		else if (stat & SCSR_CRC_FRAME_ERR)
++			err = TTY_FRAME;
++		else
++			err = 0;
++
++	    	tty_insert_flip_char(tty, ch, err);
++
++		/* ++TeSche: *All* errors have to be cleared manually,
++		 * else the condition persists for the next chars
++		 */
++		if (err)
++		  SCCwrite(COMMAND_REG, CR_ERROR_RESET);
++
++	} while(SCCread(INT_PENDING_REG) & int_pending_mask);
++
++	SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
++
++	tty_flip_buffer_flush(tty);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: spcond_int done\n");
++#endif
++	return IRQ_HANDLED;
++}
++
++/* not implemented yet */
++#if 0
++static void scc_ri_int(int irq, void *data, struct pt_regs *fp)
++{
++	struct scc_port *port = data;
++	/* update input line counter */
++	port->icount.rng++;
++	wake_up_interruptible(&port->delta_msr_wait);
++}
++#endif
++
++static irqreturn_t scc_tx_int(int irq, void *data, struct pt_regs *fp)
++{
++	struct scc_port *port = data;
++	SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: tx_int irq %d port %p ...\n", irq, data);
++#endif
++	if (!port->gs.tty) {
++		printk(KERN_WARNING "scc_tx_int with NULL tty!\n");
++		SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0);
++		SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET);
++		SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
++		return IRQ_HANDLED;
++	}
++	while ((SCCread_NB(STATUS_REG) & SR_TX_BUF_EMPTY)) {
++		if (port->x_char) {
++#ifdef DEBUG
++			printk(KERN_INFO "SCC: tx_int writing char %c\n", port->x_char);
++#endif
++			SCCwrite(TX_DATA_REG, port->x_char);
++			port->x_char = 0;
++		}
++		else if ((port->gs.xmit_cnt <= 0) || port->gs.tty->stopped ||
++				port->gs.tty->hw_stopped) {
++#ifdef DEBUG
++			printk(KERN_INFO "SCC: nothing to do!\n");
++#endif
++			break;
++		} else {
++#ifdef DEBUG
++			printk(KERN_INFO "SCC: tx_int writing buf %c\n", port->gs.xmit_buf[port->gs.xmit_tail]);
++#endif
++			SCCwrite(TX_DATA_REG, port->gs.xmit_buf[port->gs.xmit_tail++]);
++			port->gs.xmit_tail = port->gs.xmit_tail & (SERIAL_XMIT_SIZE-1);
++			if (--port->gs.xmit_cnt <= 0)
++				break;
++		}
++	}
++	if ((port->gs.xmit_cnt <= 0) || port->gs.tty->stopped ||
++			port->gs.tty->hw_stopped) {
++#ifdef DEBUG
++		printk(KERN_INFO "SCC: nothing to do, disabling int\n");
++#endif
++		/* disable tx interrupts */
++		SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0);
++		SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET);   /* disable tx_int on next tx underrun? */
++		port->gs.flags &= ~GS_TX_INTEN;
++	}
++	if (port->gs.tty && port->gs.xmit_cnt <= port->gs.wakeup_chars) {
++#ifdef DEBUG
++		printk(KERN_INFO "SCC: waking up tty!\n");
++#endif
++		tty_wakeup(port->gs.tty);
++	}
++
++	SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: tx_int done\n");
++#endif
++	return IRQ_HANDLED;
++}
++
++
++static irqreturn_t scc_stat_int(int irq, void *data, struct pt_regs *fp)
++{
++	struct scc_port *port = data;
++	unsigned channel = port->channel;
++	unsigned char	last_sr, sr, changed;
++	SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: stat_int ...\n");
++#endif
++	last_sr = scc_last_status_reg[channel];
++	sr = scc_last_status_reg[channel] = SCCread_NB(STATUS_REG);
++	changed = last_sr ^ sr;
++
++	if (changed & SR_DCD) {
++		port->c_dcd = !!(sr & SR_DCD);
++		if (!(port->gs.flags & ASYNC_CHECK_CD))
++			;	/* Don't report DCD changes */
++		else if (port->c_dcd) {
++			/* Are we blocking in open?*/
++			wake_up_interruptible(&port->gs.open_wait);
++		}
++		else {
++			if (port->gs.tty)
++				tty_hangup (port->gs.tty);
++		}
++	}
++
++	// FIXME: CTS and DSR status changes? 
++
++	SCCwrite(COMMAND_REG, CR_EXTSTAT_RESET);
++	SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: stat_int done\n");
++#endif
++	return IRQ_HANDLED;
++}
++
++
++/*---------------------------------------------------------------------------
++ * generic_serial.c callback funtions
++ *--------------------------------------------------------------------------*/
++
++static void scc_disable_tx_interrupts(void *ptr)
++{
++	struct scc_port *port = ptr;
++	unsigned long	flags;
++	SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: disable_tx_int ...\n");
++#endif
++	local_irq_save(flags);
++	SCCmod(INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0);
++	port->gs.flags &= ~GS_TX_INTEN;
++	local_irq_restore(flags);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: disable_tx_int done!\n");
++#endif
++}
++
++
++static void scc_enable_tx_interrupts(void *ptr)
++{
++	struct scc_port *port = ptr;
++	unsigned long	flags;
++	SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: enable_tx_int ...\n");
++#endif
++	local_irq_save(flags);
++	SCCmod(INT_AND_DMA_REG, 0xff, IDR_TX_INT_ENAB);
++	/* restart the transmitter */
++	scc_tx_int (0, port, 0);
++	local_irq_restore(flags);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: enable_tx_int done!\n");
++#endif
++}
++
++
++static void scc_disable_rx_interrupts(void *ptr)
++{
++	struct scc_port *port = ptr;
++	unsigned long	flags;
++	SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: disable_rx_int ...\n");
++#endif
++	local_irq_save(flags);
++	SCCmod(INT_AND_DMA_REG,
++	    ~(IDR_RX_INT_MASK|IDR_PARERR_AS_SPCOND|IDR_EXTSTAT_INT_ENAB), 0);
++	local_irq_restore(flags);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: disable_rx_int done!\n");
++#endif
++}
++
++
++static void scc_enable_rx_interrupts(void *ptr)
++{
++	struct scc_port *port = ptr;
++	unsigned long	flags;
++	SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: enable_rx_int ...\n");
++#endif
++	local_irq_save(flags);
++	SCCmod(INT_AND_DMA_REG, 0xff,
++		IDR_EXTSTAT_INT_ENAB|IDR_PARERR_AS_SPCOND|IDR_RX_INT_ALL);
++	local_irq_restore(flags);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: enable_rx_int done!\n");
++#endif
++}
++
++
++static int scc_get_CD(void *ptr)
++{
++	struct scc_port *port = ptr;
++	unsigned channel = port->channel;
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: get_CD!\n");
++#endif
++	return !!(scc_last_status_reg[channel] & SR_DCD);
++}
++
++
++static void scc_shutdown_port(void *ptr)
++{
++	struct scc_port *port = ptr;
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: shutdown_port ...\n");
++#endif
++	port->gs.flags &= ~ GS_ACTIVE;
++	if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL) {
++		scc_setsignals (port, 0, 0);
++	}
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: shutdown_port done!\n");
++#endif
++}
++
++
++static int scc_set_real_termios (void *ptr)
++{
++	/* the SCC has char sizes 5,7,6,8 in that order! */
++	static int chsize_map[4] = { 0, 2, 1, 3 };
++	unsigned cflag, baud, baudbits, baudidx, brgmode, clkmode, clksrc, div, chsize, channel, brgval = 0;
++	unsigned long flags;
++	struct scc_port *port = ptr;
++	SCC_ACCESS_INIT(port);
++
++	if (!port->gs.tty || !port->gs.tty->termios) return 0;
++
++	channel = port->channel;
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: termios for channel %p\n", channel);
++#endif
++	cflag  = port->gs.tty->termios->c_cflag;
++	baud = port->gs.baud;
++	baudbits = cflag & CBAUD;
++	chsize = (cflag & CSIZE) >> 4;
++
++	if (baud == 0) {
++		/* speed == 0 -> drop DTR */
++		local_irq_save(flags);
++		SCCmod(TX_CTRL_REG, ~TCR_DTR, 0);
++		local_irq_restore(flags);
++		return 0;
++	}
++	else if ((MACH_IS_TT && (baud < 50 || baud > 115200)) ||
++		 (MACH_IS_FALCON && (baud < 50 || baud > 230400))) {
++		printk(KERN_NOTICE "SCC: Bad speed requested, %d\n", baud);
++		return 0;
++	}
++
++	if (cflag & CLOCAL)
++		port->gs.flags &= ~ASYNC_CHECK_CD;
++	else
++		port->gs.flags |= ASYNC_CHECK_CD;
++
++	// calculate brgval for Atari; enable direct modes! 
++
++	/* convert baud rate from gs.baud to table index, set custom divisor eventually */
++
++	div     = 0;
++	clksrc  = 0;
++	baudidx = 0;
++
++	switch (baud) {
++	case 50:
++	  baudidx = 1; 
++	  break;
++	case 75:
++	  baudidx = 2; 
++	  break;
++	case 110:
++	  baudidx = 3; 
++	  break;
++	case 134:
++	  baudidx = 4; 
++	  break;
++	case 150:
++	  baudidx = 5; 
++	  break;
++	case 200:
++	  baudidx = 6; 
++	  break;
++	case 300:
++	  baudidx = 7; 
++	  break;
++	case 600:
++	  baudidx = 8; 
++	  break;
++	case 1200:
++	  baudidx = 9; 
++	  break;
++	case 1800:
++	  baudidx = 10; 
++	  break;
++	case 2400:
++	  baudidx = 11; 
++	  break;
++	case 4800:
++	  baudidx = 12; 
++	  break;
++	case 9600:
++	  baudidx = 13; 
++	  break;
++	case 19200:
++	  baudidx = 14; 
++	  break;
++	case 38400:
++	  baudidx = 15; 
++	  break;
++	case 57600:
++	  baudidx = 16; 
++	  port->gs.tty->low_latency = 1;
++	  break;
++	case 115200:
++	  baudidx = 17; 
++	  port->gs.tty->low_latency = 1;
++	  break;
++	case 230400:
++	  baudidx = 18; 
++	  port->gs.tty->low_latency = 1;
++	  break;
++	default:
++	  baudidx = 15;
++	}
++
++	/* do we have a custom divisor ?? */
++	if (!div) {
++		if (baudidx > 19) baudidx = 19;
++		clksrc = scc_baud_table[channel][baudidx].clksrc;
++		div = scc_baud_table[channel][baudidx].div;
++		if(!div)
++		{
++			printk(" SCC_change_speed: divisor = 0 !!!");
++			return 0;
++		}
++	}
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: termios baud %d baudbits %d baudidx %d \n clksrc %d div %d\n",
++		baud, baudbits, baudidx, clksrc, div);
++#endif
++	/* compute the SCC's clock source, clock mode, BRG mode and BRG
++	 * value from clksrc and div
++	 */
++	if (div <= 4) {
++		clkmode = (div == 1 ? A1CR_CLKMODE_x16 :
++			   div == 2 ? A1CR_CLKMODE_x32 :
++				      A1CR_CLKMODE_x64);
++		clksrc  = (clksrc == CLK_RTxC
++			   ? CCR_TXCLK_RTxC | CCR_RXCLK_RTxC
++			   : CCR_TXCLK_TRxC | CCR_RXCLK_TRxC);
++		brgmode = 0; /* off */
++		brgval  = 0;
++	}
++	else {
++		brgval  = div/2 - 2;
++		brgmode = (DCR_BRG_ENAB |
++			   (clksrc == CLK_PCLK ? DCR_BRG_USE_PCLK : 0));
++		clkmode = A1CR_CLKMODE_x16;
++		clksrc  = CCR_TXCLK_BRG | CCR_RXCLK_BRG;
++	}
++
++	//printk(KERN_INFO "SCC: termios baud %d baudbits %d baudidx %d \n clksrc %d clkmode %d div %d brgval %d brgmode %d\n",
++	//	baud, baudbits, baudidx, clksrc, clkmode, div, brgval, brgmode);
++
++	/* Now we have all parameters and can go to set them: */
++	local_irq_save(flags);
++
++#ifdef DEBUG
++	printk( "  brgval=%d brgmode=%02x clkmode=%02x clksrc=%02x\n",
++			brgval, brgmode, clkmode, clksrc );
++#endif
++	/* receiver's character size */
++	SCCmod( RX_CTRL_REG, ~RCR_CHSIZE_MASK, chsize_map[chsize] << 6 );
++#ifdef DEBUG
++	printk( "  RX_CTRL_REG <- %02x\n", SCCread( RX_CTRL_REG ) );
++#endif
++
++	// clock mode changes depending on baud rate
++	/* parity and stop bits (both, Tx and Rx) and clock mode */
++	SCCmod (AUX1_CTRL_REG,
++		~(A1CR_PARITY_MASK | A1CR_MODE_MASK | A1CR_CLKMODE_MASK),
++		((cflag & PARENB
++		  ? (cflag & PARODD ? A1CR_PARITY_ODD : A1CR_PARITY_EVEN)
++		  : A1CR_PARITY_NONE)
++		 | (cflag & CSTOPB ? A1CR_MODE_ASYNC_2 : A1CR_MODE_ASYNC_1)
++		 | clkmode));
++
++#ifdef DEBUG
++	printk( "  AUX1_CTRL_REG <- %02x\n", SCCread( AUX1_CTRL_REG ) );
++#endif
++	/* sender's character size, set DTR for valid baud rate */
++	SCCmod(TX_CTRL_REG, ~TCR_CHSIZE_MASK, chsize_map[chsize] << 5 | TCR_DTR);
++#ifdef DEBUG
++	printk( "  TX_CTRL_REG <- %02x\n", SCCread( TX_CTRL_REG ) );
++#endif
++
++	// clock sources change for TT !!
++	/* clock sources never change */
++	/* clock sources */
++	SCCmod( CLK_CTRL_REG, ~(CCR_TXCLK_MASK | CCR_RXCLK_MASK), clksrc );
++#ifdef DEBUG
++	printk( "  CLK_CTRL_REG <- %02x\n", SCCread( CLK_CTRL_REG ) );
++#endif
++
++	/* disable BRG before changing the value */
++	SCCmod(DPLL_CTRL_REG, ~DCR_BRG_ENAB, 0);
++	/* BRG value */
++	SCCwrite(TIMER_LOW_REG, brgval & 0xff);
++	SCCwrite(TIMER_HIGH_REG, (brgval >> 8) & 0xff);
++	/* BRG enable, and clock source never changes */
++	//SCCmod(DPLL_CTRL_REG, 0xff, DCR_BRG_ENAB);
++	SCCmod(DPLL_CTRL_REG, ~(DCR_BRG_ENAB | DCR_BRG_USE_PCLK), brgmode);
++#ifdef DEBUG
++	printk( "  TIMER_LOW_REG <- %02x\n", SCCread( TIMER_LOW_REG ) );
++	printk( "  TIMER_HIGH_REG <- %02x\n", SCCread( TIMER_HIGH_REG ) );
++#endif
++#ifdef DEBUG
++	printk( "  DPLL_CTRL_REG <- %02x\n", SCCread( DPLL_CTRL_REG ) );
++#endif
++
++	local_irq_restore(flags);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: done termios for channel %d\n", channel);
++#endif
++	return 0;
++}
++
++
++static int scc_chars_in_buffer (void *ptr)
++{
++	struct scc_port *port = ptr;
++#ifdef DEBUG
++	int rv;
++#endif
++	SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++	rv = (SCCread (SPCOND_STATUS_REG) & SCSR_ALL_SENT) ? 0  : 1;
++	printk(KERN_INFO "SCC: chars_in_buffer: %d\n", rv);
++	return rv;
++#else
++	return (SCCread (SPCOND_STATUS_REG) & SCSR_ALL_SENT) ? 0  : 1;
++#endif
++}
++
++
++/* Comment taken from sx.c (2.4.0):
++   I haven't the foggiest why the decrement use count has to happen
++   here. The whole linux serial drivers stuff needs to be redesigned.
++   My guess is that this is a hack to minimize the impact of a bug
++   elsewhere. Thinking about it some more. (try it sometime) Try
++   running minicom on a serial port that is driven by a modularized
++   driver. Have the modem hangup. Then remove the driver module. Then
++   exit minicom.  I expect an "oops".  -- REW */
++
++static void scc_hungup(void *ptr)
++{
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: hungup ...\n");
++#endif
++	scc_disable_tx_interrupts(ptr);
++	scc_disable_rx_interrupts(ptr);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: hungup done\n");
++#endif
++}
++
++
++static void scc_close(void *ptr)
++{
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: close ...\n");
++#endif
++	scc_disable_tx_interrupts(ptr);
++	scc_disable_rx_interrupts(ptr);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: close done\n");
++#endif
++}
++
++
++/*---------------------------------------------------------------------------
++ * Internal support functions
++ *--------------------------------------------------------------------------*/
++
++static void scc_setsignals(struct scc_port *port, int dtr, int rts)
++{
++	unsigned long flags;
++	unsigned char t;
++	SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: setsignals dtr %d rts %d...\n", dtr, rts);
++#endif
++	local_irq_save(flags);
++	t = SCCread(TX_CTRL_REG);
++	if (dtr >= 0) t = dtr? (t | TCR_DTR): (t & ~TCR_DTR);
++	if (rts >= 0) t = rts? (t | TCR_RTS): (t & ~TCR_RTS);
++	SCCwrite(TX_CTRL_REG, t);
++	local_irq_restore(flags);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: setsignals done\n");
++#endif
++}
++
++
++static void scc_send_xchar(struct tty_struct *tty, char ch)
++{
++	struct scc_port *port = (struct scc_port *)tty->driver_data;
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: send_xchar ...\n");
++#endif
++	port->x_char = ch;
++	if (ch)
++		scc_enable_tx_interrupts(port);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: send_xchar done\n");
++#endif
++}
++
++
++/*---------------------------------------------------------------------------
++ * Driver entrypoints referenced from above
++ *--------------------------------------------------------------------------*/
++
++static int scc_open (struct tty_struct * tty, struct file * filp)
++{
++	int line = tty->index;
++	int retval;
++	struct scc_port *port = &scc_ports[line];
++	int i, channel = port->channel;
++	unsigned long	flags;
++
++	if (atari_SCC_init_done && line == 1)
++		return -ENODEV;
++
++	SCC_ACCESS_INIT(port);
++
++	static const struct {
++		unsigned reg, val;
++	} scc_init_tab[] = {
++		/* no parity, 1 stop bit, async, 1:16 */
++		{ AUX1_CTRL_REG, A1CR_PARITY_NONE|A1CR_MODE_ASYNC_1|A1CR_CLKMODE_x64 },
++		/* parity error is special cond, ints disabled, no DMA */
++		{ INT_AND_DMA_REG, IDR_PARERR_AS_SPCOND | IDR_RX_INT_DISAB },
++		/* Rx 8 bits/char, no auto enable, Rx off */
++		{ RX_CTRL_REG, RCR_CHSIZE_8 },
++		/* DTR off, Tx 8 bits/char, RTS off, Tx off */
++		{ TX_CTRL_REG, TCR_CHSIZE_8 },
++		/* special features off */
++		{ AUX2_CTRL_REG, 0 },
++		/* RTxC is XTAL, TRxC is input, both clocks = RTxC */
++		{ CLK_CTRL_REG, CCR_TRxCOUT_XTAL | CCR_TXCLK_RTxC | CCR_RXCLK_RTxC },
++		{ DPLL_CTRL_REG, 0 },
++		/* Start Rx */
++		{ RX_CTRL_REG, RCR_RX_ENAB | RCR_CHSIZE_8 },
++		/* Start Tx */
++		{ TX_CTRL_REG, TCR_TX_ENAB | TCR_RTS | TCR_DTR | TCR_CHSIZE_8 },
++		/* Ext/Stat ints: CTS, DCD, SYNC (DSR) */
++		{ INT_CTRL_REG, ICR_ENAB_DCD_INT | ICR_ENAB_CTS_INT | ICR_ENAB_SYNC_INT },
++		/* Reset Ext/Stat ints */
++		{ COMMAND_REG, CR_EXTSTAT_RESET },
++		/* ...again */
++		{ COMMAND_REG, CR_EXTSTAT_RESET },
++		/* Rx int always, TX int off, Ext/Stat int on */
++		{ INT_AND_DMA_REG, IDR_EXTSTAT_INT_ENAB |
++		  IDR_PARERR_AS_SPCOND | IDR_RX_INT_ALL }
++	};
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: open port ...\n");
++#endif
++	if (!(port->gs.flags & ASYNC_INITIALIZED)) {
++#ifdef DEBUG
++		printk(KERN_INFO "SCC: init port ...\n");
++#endif
++		local_irq_save(flags);
++
++		SCCmod( MASTER_INT_CTRL, 0x3f,
++			channel == 0 ? MIC_CH_A_RESET : MIC_CH_B_RESET );
++		udelay(40); /* extra delay after a reset */
++
++	       	for (i=0; i<sizeof(scc_init_tab)/sizeof(*scc_init_tab); ++i)
++		       	SCCwrite(scc_init_tab[i].reg, scc_init_tab[i].val);
++
++
++		/* remember status register for detection of DCD and CTS changes */
++		scc_last_status_reg[channel] = SCCread(STATUS_REG);
++
++		port->c_dcd = 0;	/* Prevent initial 1->0 interrupt */
++		scc_setsignals (port, 1,1);
++		local_irq_restore(flags);
++#ifdef DEBUG
++		printk(KERN_INFO "SCC: init port done!\n");
++#endif
++	}
++
++	tty->driver_data = port;
++	port->gs.tty = tty;
++	port->gs.count++;
++#ifdef DEBUG
++	printk(KERN_WARNING "SCC: gs init port ...\n");
++#endif
++	retval = gs_init_port(&port->gs);
++	if (retval) {
++		port->gs.count--;
++		return retval;
++	}
++#ifdef DEBUG
++	printk(KERN_WARNING "SCC: gs init port done!\n");
++#endif
++	port->gs.flags |= GS_ACTIVE;
++
++#ifdef DEBUG
++	printk(KERN_WARNING "SCC: gs wait ready ...\n");
++#endif
++	retval = gs_block_til_ready(port, filp);
++#ifdef DEBUG
++	printk(KERN_WARNING "SCC: gs wait ready done!\n");
++#endif
++	if (retval) {
++		port->gs.count--;
++		return retval;
++	}
++
++	port->c_dcd = scc_get_CD (port);
++
++#ifdef DEBUG
++	printk(KERN_WARNING "SCC: enable rx ints ...\n");
++#endif
++	scc_enable_rx_interrupts(port);
++#ifdef DEBUG
++	printk(KERN_WARNING "SCC: enable rx ints done!\n");
++
++	printk(KERN_INFO "SCC: open port done!\n");
++#endif
++	return 0;
++}
++
++
++static void scc_throttle (struct tty_struct * tty)
++{
++	struct scc_port *port = (struct scc_port *)tty->driver_data;
++	unsigned long	flags;
++	SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: throttle ...\n");
++#endif
++	if (tty->termios->c_cflag & CRTSCTS) {
++		local_irq_save(flags);
++		SCCmod(TX_CTRL_REG, ~TCR_RTS, 0);
++		local_irq_restore(flags);
++	}
++	if (I_IXOFF(tty))
++		scc_send_xchar(tty, STOP_CHAR(tty));
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: throttle done!\n");
++#endif
++}
++
++
++static void scc_unthrottle (struct tty_struct * tty)
++{
++	struct scc_port *port = (struct scc_port *)tty->driver_data;
++	unsigned long	flags;
++	SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: unthrottle ...\n");
++#endif
++	if (tty->termios->c_cflag & CRTSCTS) {
++		local_irq_save(flags);
++		SCCmod(TX_CTRL_REG, 0xff, TCR_RTS);
++		local_irq_restore(flags);
++	}
++	if (I_IXOFF(tty))
++		scc_send_xchar(tty, START_CHAR(tty));
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: unthrottle done!\n");
++#endif
++}
++
++
++static int scc_ioctl(struct tty_struct *tty, struct file *file,
++		     unsigned int cmd, unsigned long arg)
++{
++	struct scc_port *port = (struct scc_port *) tty->driver_data;
++	int retval;
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: ioctl! cmd %d, arg %p \n", cmd, arg);
++#endif
++	//if (serial_paranoia_check(info, tty->device, "zs_ioctl"))
++	//	return -ENODEV;
++
++	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
++	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
++	    (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
++		if (tty->flags & (1 << TTY_IO_ERROR))
++		    return -EIO;
++	}
++
++	switch (cmd) {
++		case TCSBRK:	/* SVID version: non-zero arg --> no break */
++#ifdef DEBUG
++			printk(KERN_INFO "SCC: ioctl TCSBRK\n");
++#endif
++			retval = tty_check_change(tty);
++			if (retval)
++				return retval;
++			tty_wait_until_sent(tty, 0);
++			//if (!arg)
++			//	send_break(info, HZ/4);	/* 1/4 second */
++			return 0;
++		case TCSBRKP:	/* support for POSIX tcsendbreak() */
++#ifdef DEBUG
++			printk(KERN_INFO "SCC: ioctl TCSBRKP\n");
++#endif
++			retval = tty_check_change(tty);
++			if (retval)
++				return retval;
++			tty_wait_until_sent(tty, 0);
++			//send_break(info, arg ? arg*(HZ/10) : HZ/4);
++			return 0;
++		case TIOCGSOFTCAR:
++#ifdef DEBUG
++			printk(KERN_INFO "SCC: ioctl TIOCGSOFTCAR\n");
++#endif
++			if (put_user(C_CLOCAL(tty) ? 1 : 0,
++				     (unsigned long *) arg))
++				return -EFAULT;
++			return 0;
++		case TIOCSSOFTCAR:
++#ifdef DEBUG
++			printk(KERN_INFO "SCC: ioctl TIOCSSOFTCAR\n");
++#endif
++			if (get_user(arg, (unsigned long *) arg))
++				return -EFAULT;
++			tty->termios->c_cflag =
++				((tty->termios->c_cflag & ~CLOCAL) |
++				 (arg ? CLOCAL : 0));
++			return 0;
++		case TIOCMGET:
++#ifdef DEBUG
++			printk(KERN_INFO "SCC: ioctl TIOCMGET\n");
++#endif
++			//return get_modem_info(info, (unsigned int *) arg);
++			return 0;
++		case TIOCMBIS:
++		case TIOCMBIC:
++		case TIOCMSET:
++#ifdef DEBUG
++			printk(KERN_INFO "SCC: ioctl TIOCMSET\n");
++#endif
++			//return set_modem_info(info, cmd, (unsigned int *) arg);
++			return 0;
++		case TIOCGSERIAL:
++#ifdef DEBUG
++			printk(KERN_INFO "SCC: ioctl TIOCGSERIAL\n");
++#endif
++			return 0;
++			//return get_serial_info(info,
++			//		       (struct serial_struct *) arg);
++		case TIOCSSERIAL:
++#ifdef DEBUG
++			printk(KERN_INFO "SCC: ioctl TIOCSSERIAL\n");
++#endif
++			return 0;
++			//return set_serial_info(info,
++			//		       (struct serial_struct *) arg);
++		case TIOCSERGETLSR: /* Get line status register */
++#ifdef DEBUG
++			printk(KERN_INFO "SCC: ioctl TIOCSERGETLSR\n");
++#endif
++			return 0;
++			//return get_lsr_info(info, (unsigned int *) arg);
++
++		case TIOCSERGSTRUCT:
++#ifdef DEBUG
++			printk(KERN_INFO "SCC: ioctl TIOCSERGSTRUCT\n");
++#endif
++			return 0;
++			if (copy_to_user((struct scc_port *) arg,
++				    port, sizeof(struct scc_port)))
++				return -EFAULT;
++			return 0;
++
++		default:
++#ifdef DEBUG
++			printk(KERN_INFO "SCC: ioctl default\n");
++#endif
++			return -ENOIOCTLCMD;
++		}
++	return 0;
++
++	return -ENOIOCTLCMD;
++}
++
++
++static void scc_break_ctl(struct tty_struct *tty, int break_state)
++{
++	struct scc_port *port = (struct scc_port *)tty->driver_data;
++	unsigned long	flags;
++	SCC_ACCESS_INIT(port);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: break ctl ...\n");
++#endif
++	local_irq_save(flags);
++	SCCmod(TX_CTRL_REG, ~TCR_SEND_BREAK, 
++			break_state ? TCR_SEND_BREAK : 0);
++	local_irq_restore(flags);
++#ifdef DEBUG
++	printk(KERN_INFO "SCC: break ctl done!\n");
++#endif
++}
++
++
++/*---------------------------------------------------------------------------
++ * Serial console stuff...
++ *--------------------------------------------------------------------------*/
++#if 1
++#define scc_delay() \
++    do {			\
++	__asm__ __volatile__ ( "tstb %0" : : "g" (*scc_del) : "cc" );\
++    } while (0)
++
++#define SCC_WRITE(reg,val)				\
++    do {						\
++	scc.cha_b_ctrl = (reg);				\
++	scc_delay();					\
++	scc.cha_b_ctrl = (val);				\
++	scc_delay();					\
++    } while(0)
++
++/* loops_per_jiffy isn't initialized yet, so we can't use udelay(). This does a
++ * delay of ~ 60us. */
++#define LONG_DELAY()				\
++    do {					\
++	int i;					\
++	for( i = 100; i > 0; --i )		\
++	    scc_delay();				\
++    } while(0)
++
++static void atari_init_scc_port( int cflag )
++{
++    extern int atari_SCC_reset_done;
++    static int clksrc_table[9] =
++	/* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */
++	{ 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 };
++    static int brgsrc_table[9] =
++	/* reg 14: 0 = RTxC, 2 = PCLK */
++	{ 2, 2, 2, 2, 2, 2, 0, 2, 2 };
++    static int clkmode_table[9] =
++	/* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */
++	{ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 };
++    static int div_table[9] =
++	/* reg12 (BRG low) */
++	{ 208, 138, 103, 50, 24, 11, 1, 0, 0 };
++
++    int baud = cflag & CBAUD;
++    int clksrc, clkmode, div, reg3, reg5;
++
++    scc_del = &mfp.par_dt_reg;
++
++    if (cflag & CBAUDEX)
++	baud += B38400;
++    if (baud < B1200 || baud > B38400+2)
++	baud = B9600; /* use default 9600bps for non-implemented rates */
++    baud -= B1200; /* tables starts at 1200bps */
++
++    clksrc  = clksrc_table[baud];
++    clkmode = clkmode_table[baud];
++    div     = div_table[baud];
++    if (ATARIHW_PRESENT(TT_MFP) && baud >= 6) {
++	/* special treatment for TT, where rates >= 38400 are done via TRxC */
++	clksrc = 0x28; /* TRxC */
++	clkmode = baud == 6 ? 0xc0 :
++		  baud == 7 ? 0x80 : /* really 76800bps */
++			      0x40;  /* really 153600bps */
++	div = 0;
++    }
++
++    reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40;
++    reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */;
++
++    (void)scc.cha_b_ctrl;	/* reset reg pointer */
++    SCC_WRITE( 9, 0xc0 );	/* reset */
++    LONG_DELAY();		/* extra delay after WR9 access */
++    SCC_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
++		  0x04 /* 1 stopbit */ |
++		  clkmode );
++    SCC_WRITE( 3, reg3 );
++    SCC_WRITE( 5, reg5 );
++    SCC_WRITE( 9, 0 );		/* no interrupts */
++    LONG_DELAY();		/* extra delay after WR9 access */
++    SCC_WRITE( 10, 0 );		/* NRZ mode */
++    SCC_WRITE( 11, clksrc );	/* main clock source */
++    SCC_WRITE( 12, div );	/* BRG value */
++    SCC_WRITE( 13, 0 );		/* BRG high byte */
++    SCC_WRITE( 14, brgsrc_table[baud] );
++    SCC_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) );
++    SCC_WRITE( 3, reg3 | 1 );
++    SCC_WRITE( 5, reg5 | 8 );
++
++    atari_SCC_reset_done = 1;
++    atari_SCC_init_done = 1;
++}
++
++static void scc_ch_write (char ch)
++{
++	volatile char *p = NULL;
++	
++	if (MACH_IS_TT || MACH_IS_FALCON)
++		p = (volatile char *)&scc.cha_b_ctrl;
++
++	if (MACH_IS_ST)
++		p = (volatile char *)&scc.cha_b_ctrl;
++
++	if (MACH_IS_STE)
++		p = (volatile char *)&st_escc.cha_b_ctrl;
++
++	do {
++		scc_delay();
++	}
++	while (!(*p & 4));
++	// scc_delay();
++	// *p = 8;
++	scc_delay();
++	*(p+1) = ch;
++}
++
++/* The console must be locked when we get here. */
++
++static void scc_console_write (struct console *co, const char *str, unsigned count)
++{
++	unsigned long	flags;
++
++	//printk("scc_console_write: %s\n", str);
++	local_irq_save(flags);
++
++	while (count--)
++	{
++		if (*str == '\n')
++			scc_ch_write ('\r');
++		scc_ch_write (*str++);
++	}
++	local_irq_restore(flags);
++	//printk("scc_console_write done!\n");
++}
++
++static struct tty_driver *scc_console_device(struct console *c, int *index)
++{
++	*index = c->index;
++	return scc_driver;
++}
++
++
++static int __init scc_console_setup(struct console *co, char *options)
++{
++	printk("scc_console_setup: initializing SCC port B\n");
++	atari_init_scc_port(B9600|CS8);
++	printk("scc_console_setup: done!\n");
++	return 0;
++}
++
++
++static struct console sercons = {
++	.name		= "ttyS",
++	.write		= scc_console_write,
++	.device		= scc_console_device,
++	.setup		= scc_console_setup,
++	.flags		= CON_PRINTBUFFER,
++	.index		= -1,
++};
++
++
++static int __init vme_scc_console_init(void)
++{
++	if (MACH_IS_TT ||
++		MACH_IS_ST ||
++		MACH_IS_FALCON)
++		register_console(&sercons);
++	return 0;
++}
++
++console_initcall(vme_scc_console_init);
++#endif
++
++/***************************** End of Functions *********************/
++
++MODULE_AUTHOR("Michael Schmitz");
++MODULE_DESCRIPTION("Atari Amd8350 SCC serial driver");
++MODULE_LICENSE("GPL");

Added: dists/sid/linux-2.6/debian/patches/m68k-atari-video.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/m68k-atari-video.patch	Mon Nov 20 00:58:24 2006
@@ -0,0 +1,3978 @@
+diff -urN linux-m68k/drivers/video/Kconfig linux-schmitz/drivers/video/Kconfig
+--- linux-m68k/drivers/video/Kconfig	2006-09-20 05:42:06.000000000 +0200
++++ linux-schmitz/drivers/video/Kconfig	2006-11-19 21:37:27.000000000 +0100
+@@ -404,7 +404,10 @@
+ 
+ config FB_ATARI
+ 	bool "Atari native chipset support"
+-	depends on (FB = y) && ATARI && BROKEN
++	depends on (FB = y) && ATARI
++	select FB_CFB_FILLRECT
++	select FB_CFB_COPYAREA
++	select FB_CFB_IMAGEBLIT
+ 	help
+ 	  This is the frame buffer device driver for the builtin graphics
+ 	  chipset found in Ataris.
+diff -urN linux-m68k/drivers/video/Makefile linux-schmitz/drivers/video/Makefile
+--- linux-m68k/drivers/video/Makefile	2006-09-20 05:42:06.000000000 +0200
++++ linux-schmitz/drivers/video/Makefile	2006-11-19 21:37:27.000000000 +0100
+@@ -64,7 +64,8 @@
+ obj-$(CONFIG_FB_LEO)              += leo.o sbuslib.o
+ obj-$(CONFIG_FB_SGIVW)            += sgivwfb.o
+ obj-$(CONFIG_FB_ACORN)            += acornfb.o
+-obj-$(CONFIG_FB_ATARI)            += atafb.o
++obj-$(CONFIG_FB_ATARI)            += atafb.o c2p.o atafb_mfb.o \
++						atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o
+ obj-$(CONFIG_FB_MAC)              += macfb.o
+ obj-$(CONFIG_FB_HGA)              += hgafb.o
+ obj-$(CONFIG_FB_IGA)              += igafb.o
+diff -urN linux-m68k/drivers/video/atafb.c linux-schmitz/drivers/video/atafb.c
+--- linux-m68k/drivers/video/atafb.c	2006-09-20 05:42:06.000000000 +0200
++++ linux-schmitz/drivers/video/atafb.c	2006-11-19 21:37:27.000000000 +0100
+@@ -53,6 +53,7 @@
+ #include <linux/errno.h>
+ #include <linux/string.h>
+ #include <linux/mm.h>
++#include <linux/tty.h>
+ #include <linux/slab.h>
+ #include <linux/delay.h>
+ #include <linux/init.h>
+@@ -71,14 +72,11 @@
+ #include <linux/fb.h>
+ #include <asm/atarikb.h>
+ 
+-#include <video/fbcon.h>
+-#include <video/fbcon-cfb8.h>
+-#include <video/fbcon-cfb16.h>
+-#include <video/fbcon-iplan2p2.h>
+-#include <video/fbcon-iplan2p4.h>
+-#include <video/fbcon-iplan2p8.h>
+-#include <video/fbcon-mfb.h>
+-
++#include "c2p.h"	// FIXME: rewrite for iplan2p
++#include "atafb_mfb.h"
++#include "atafb_iplan2p2.h"
++#include "atafb_iplan2p4.h"
++#include "atafb_iplan2p8.h"
+ 
+ #define SWITCH_ACIA 0x01		/* modes for switch on OverScan */
+ #define SWITCH_SND6 0x40
+@@ -88,6 +86,27 @@
+ 
+ #define up(x, r) (((x) + (r) - 1) & ~((r)-1))
+ 
++	/*
++	 * Interface to the world
++	 */
++
++static int atafb_check_var(struct fb_var_screeninfo *var,
++			   struct fb_info *info);
++static int atafb_set_par(struct fb_info *info);
++static int atafb_setcolreg(unsigned regno, unsigned red, unsigned green,
++			   unsigned blue, unsigned transp,
++			   struct fb_info *info);
++static int atafb_blank(int blank, struct fb_info *info);
++static int atafb_pan_display(struct fb_var_screeninfo *var,
++			     struct fb_info *info);
++static void atafb_fillrect(struct fb_info *info,
++			   const struct fb_fillrect *rect);
++static void atafb_copyarea(struct fb_info *info,
++			   const struct fb_copyarea *region);
++static void atafb_imageblit(struct fb_info *info,
++			    const struct fb_image *image);
++static int atafb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg);
++
+ 
+ static int default_par=0;	/* default resolution (0=none) */
+ 
+@@ -101,9 +120,15 @@
+ static int sttt_xres_virtual=640,sttt_yres_virtual=400;
+ static int ovsc_offset=0, ovsc_addlen=0;
+ 
++	/*
++	 * Hardware parameters for current mode
++	 */
++
+ static struct atafb_par {
+ 	void *screen_base;
+ 	int yres_virtual;
++	u_long next_line;
++	u_long next_plane;
+ #if defined ATAFB_TT || defined ATAFB_STE
+ 	union {
+ 		struct {
+@@ -136,6 +161,8 @@
+ 	} hw;
+ } current_par;
+ 
++struct fb_var_screeninfo current_var;
++
+ /* Don't calculate an own resolution, and thus don't change the one found when
+  * booting (currently used for the Falcon to keep settings for internal video
+  * hardware extensions (e.g. ScreenBlaster)  */
+@@ -164,7 +191,13 @@
+ #define VMO_PREMASK		0x0c
+ #endif
+ 
+-static struct fb_info fb_info;
++static struct fb_info fb_info = {
++    .fix = {
++        .id             = "Atari ",
++	.visual         = FB_VISUAL_PSEUDOCOLOR,
++	.accel          = FB_ACCEL_NONE
++    }
++};
+ 
+ static void *screen_base;	/* base address of screen */
+ static void *real_screen_base;	/* (only for Overscan) */
+@@ -175,8 +208,6 @@
+ 
+ static int mono_moni=0;
+ 
+-static struct display disp;
+-
+ 
+ #ifdef ATAFB_EXT
+ /* external video handling */
+@@ -250,6 +281,75 @@
+ extern int fontwidth_8x16;
+ extern unsigned char fontdata_8x16[];
+ 
++/* 
++ * struct fb_ops {
++ *	* open/release and usage marking 
++ *	struct module *owner;
++ *	int (*fb_open)(struct fb_info *info, int user);
++ *	int (*fb_release)(struct fb_info *info, int user);
++ *
++ *	* For framebuffers with strange non linear layouts or that do not
++ *	* work with normal memory mapped access
++ *	ssize_t (*fb_read)(struct file *file, char __user *buf, size_t count, loff_t *ppos);
++ *	ssize_t (*fb_write)(struct file *file, const char __user *buf, size_t count, loff_t *ppos);
++ *
++ *	* checks var and eventually tweaks it to something supported,
++ *	* DOES NOT MODIFY PAR *
++ *	int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
++ *
++ *	* set the video mode according to info->var *
++ *	int (*fb_set_par)(struct fb_info *info);
++ *
++ *	* set color register *
++ *	int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
++ *			    unsigned blue, unsigned transp, struct fb_info *info);
++ *
++ *	* set color registers in batch *
++ *	int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);
++ *
++ *	* blank display *
++ *	int (*fb_blank)(int blank, struct fb_info *info);
++ *
++ *	* pan display *
++ *	int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);
++ *
++ *	*** The meat of the drawing engine ***
++ *	* Draws a rectangle *
++ *	void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
++ *	* Copy data from area to another *
++ *	void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
++ *	* Draws a image to the display *
++ *	void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
++ *
++ *	* Draws cursor *
++ *	int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);
++ *
++ *	* Rotates the display *
++ *	void (*fb_rotate)(struct fb_info *info, int angle);
++ *
++ *	* wait for blit idle, optional *
++ *	int (*fb_sync)(struct fb_info *info);
++ *
++ *	* perform fb specific ioctl (optional) *
++ *	int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
++ *			unsigned long arg);
++ *
++ *	* Handle 32bit compat ioctl (optional) *
++ *	int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,
++ *			unsigned long arg);
++ *
++ *	* perform fb specific mmap *
++ *	int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
++ *
++ *	* save current hardware state *
++ *	void (*fb_save_state)(struct fb_info *info);
++ *
++ *	* restore saved state *
++ *	void (*fb_restore_state)(struct fb_info *info);
++ * } ;
++ */
++
++
+ /* ++roman: This structure abstracts from the underlying hardware (ST(e),
+  * TT, or Falcon.
+  *
+@@ -263,6 +363,7 @@
+  *                    struct atafb_par *par )
+  *   This function should fill in the 'fix' structure based on the
+  *   values in the 'par' structure.
++ * !!! Obsolete, perhaps !!!
+  *   
+  * int (*decode_var)( struct fb_var_screeninfo *var,
+  *                    struct atafb_par *par )
+@@ -279,6 +380,7 @@
+  *   
+  * void (*get_par)( struct atafb_par *par )
+  *   Fill the hardware's 'par' structure.
++ *   !!! Used only by detect() !!!
+  *   
+  * void (*set_par)( struct atafb_par *par )
+  *   Set the hardware according to 'par'.
+@@ -417,6 +519,124 @@
+ 
+ static int num_atafb_predefined=ARRAY_SIZE(atafb_predefined);
+ 
++	/*
++	 * Tags used to indicate a specific Pixel Clock
++	 *
++	 * tag is the shift value to get the timings in 35 ns units
++	 */
++
++enum { TAG_SHRES, TAG_HIRES, TAG_LORES };
++
++
++static struct fb_videomode atafb_modedb[] __initdata = {
++
++    /*
++     *  Atari Video Modes
++     *
++     *  If you change these, make sure to update DEFMODE_* as well!
++     */
++
++    {
++	/* 640x200, 15 kHz, 60 Hz (NTSC) */
++	"ntsc", 60, 640, 200, TAG_HIRES, 106, 86, 44, 16, 76, 2,
++	FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
++    }, {
++	/* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */
++	"ntsc-lace", 60, 640, 400, TAG_HIRES, 106, 86, 88, 33, 76, 4,
++	FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
++    }, {
++	/* 640x256, 15 kHz, 50 Hz (PAL) */
++	"pal", 50, 640, 256, TAG_HIRES, 106, 86, 40, 14, 76, 2,
++	FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
++    }, {
++	/* 640x512, 15 kHz, 50 Hz interlaced (PAL) */
++	"pal-lace", 50, 640, 512, TAG_HIRES, 106, 86, 80, 29, 76, 4,
++	FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
++    }, {
++	/* 640x480, 29 kHz, 57 Hz */
++	"multiscan", 57, 640, 480, TAG_SHRES, 96, 112, 29, 8, 72, 8,
++	0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
++    }, {
++	/* 640x960, 29 kHz, 57 Hz interlaced */
++	"multiscan-lace", 57, 640, 960, TAG_SHRES, 96, 112, 58, 16, 72, 16,
++	0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
++    }, {
++	/* 640x200, 15 kHz, 72 Hz */
++	"euro36", 72, 640, 200, TAG_HIRES, 92, 124, 6, 6, 52, 5,
++	0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
++    }, {
++	/* 640x400, 15 kHz, 72 Hz interlaced */
++	"euro36-lace", 72, 640, 400, TAG_HIRES, 92, 124, 12, 12, 52, 10,
++	0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
++    }, {
++	/* 640x400, 29 kHz, 68 Hz */
++	"euro72", 68, 640, 400, TAG_SHRES, 164, 92, 9, 9, 80, 8,
++	0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
++    }, {
++	/* 640x800, 29 kHz, 68 Hz interlaced */
++	"euro72-lace", 68, 640, 800, TAG_SHRES, 164, 92, 18, 18, 80, 16,
++	0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
++    }, {
++	/* 800x300, 23 kHz, 70 Hz */
++	"super72", 70, 800, 300, TAG_SHRES, 212, 140, 10, 11, 80, 7,
++	0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
++    }, {
++	/* 800x600, 23 kHz, 70 Hz interlaced */
++	"super72-lace", 70, 800, 600, TAG_SHRES, 212, 140, 20, 22, 80, 14,
++	0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
++    }, {
++	/* 640x200, 27 kHz, 57 Hz doublescan */
++	"dblntsc", 57, 640, 200, TAG_SHRES, 196, 124, 18, 17, 80, 4,
++	0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP
++    }, {
++	/* 640x400, 27 kHz, 57 Hz */
++	"dblntsc-ff", 57, 640, 400, TAG_SHRES, 196, 124, 36, 35, 80, 7,
++	0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
++    }, {
++	/* 640x800, 27 kHz, 57 Hz interlaced */
++	"dblntsc-lace", 57, 640, 800, TAG_SHRES, 196, 124, 72, 70, 80, 14,
++	0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
++    }, {
++	/* 640x256, 27 kHz, 47 Hz doublescan */
++	"dblpal", 47, 640, 256, TAG_SHRES, 196, 124, 14, 13, 80, 4,
++	0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP
++    }, {
++	/* 640x512, 27 kHz, 47 Hz */
++	"dblpal-ff", 47, 640, 512, TAG_SHRES, 196, 124, 28, 27, 80, 7,
++	0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
++    }, {
++	/* 640x1024, 27 kHz, 47 Hz interlaced */
++	"dblpal-lace", 47, 640, 1024, TAG_SHRES, 196, 124, 56, 54, 80, 14,
++	0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
++    },
++
++    /*
++     *  VGA Video Modes
++     */
++
++    {
++	/* 640x480, 31 kHz, 60 Hz (VGA) */
++	"vga", 60, 640, 480, TAG_SHRES, 64, 96, 30, 9, 112, 2,
++	0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
++    }, {
++	/* 640x400, 31 kHz, 70 Hz (VGA) */
++	"vga70", 70, 640, 400, TAG_SHRES, 64, 96, 35, 12, 112, 2,
++	FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
++    },
++
++};
++
++#define NUM_TOTAL_MODES  ARRAY_SIZE(atafb_modedb)
++
++static char *mode_option __initdata = NULL;
++
++ /* default modes */
++
++#define DEFMODE_TT	    2	/* "pal" for PAL OCS/ECS */
++#define DEFMODE_F30	    0	/* "ntsc" for NTSC OCS/ECS */
++#define DEFMODE_STE   	    3	/* "pal-lace" for flicker fixed PAL (A3000) */
++#define DEFMODE_EXT  	    1	/* "ntsc-lace" for flicker fixed NTSC (A3000) */
++
+ 
+ static int
+ get_video_mode(char *vname)
+@@ -1290,6 +1510,15 @@
+ 	par->screen_base = screen_base + var->yoffset * linelen;
+ 	par->hw.falcon.xoffset = 0;
+ 
++	// FIXME!!! sort of works, no crash
++	//par->next_line  = linelen;
++	//par->next_plane = yres_virtual * linelen;
++	par->next_line  = linelen;
++	par->next_plane = 2;
++	// crashes
++	//par->next_plane = linelen;
++	//par->next_line  = yres_virtual * linelen;
++
+ 	return 0;
+ }
+ 
+@@ -1372,6 +1601,8 @@
+ 	else {
+ 		var->red.offset=0;
+ 		var->red.length = hw->ste_mode ? 4 : 6;
++		if (var->red.length > var->bits_per_pixel)
++			var->red.length = var->bits_per_pixel;
+ 		var->red.msb_right=0;
+ 		var->grayscale=0;
+ 		var->blue=var->green=var->red;
+@@ -1583,10 +1814,12 @@
+ 
+ 
+ static int falcon_pan_display( struct fb_var_screeninfo *var,
+-							   struct atafb_par *par )
++			       struct fb_info *info )
+ {
++	struct atafb_par *par=(struct atafb_par *)info->par;
++
+ 	int xoffset;
+-	int bpp = fb_display[fb_info.currcon].var.bits_per_pixel;
++	int bpp = info->var.bits_per_pixel;
+ 
+ 	if (bpp == 1)
+ 		var->xoffset = up(var->xoffset, 32);
+@@ -1597,13 +1830,13 @@
+ 		var->xoffset = up(var->xoffset, 2);
+ 	}
+ 	par->hw.falcon.line_offset = bpp *
+-	       	(fb_display[fb_info.currcon].var.xres_virtual - fb_display[fb_info.currcon].var.xres) / 16;
++	       	(info->var.xres_virtual - info->var.xres) / 16;
+ 	if (par->hw.falcon.xoffset)
+ 		par->hw.falcon.line_offset -= bpp;
+ 	xoffset = var->xoffset - par->hw.falcon.xoffset;
+ 
+ 	par->screen_base = screen_base +
+-	        (var->yoffset * fb_display[fb_info.currcon].var.xres_virtual + xoffset) * bpp / 8;
++	        (var->yoffset * info->var.xres_virtual + xoffset) * bpp / 8;
+ 	if (fbhw->set_screen_base)
+ 		fbhw->set_screen_base (par->screen_base);
+ 	else
+@@ -2294,15 +2527,17 @@
+ 
+ 
+ static int pan_display( struct fb_var_screeninfo *var,
+-                        struct atafb_par *par )
++                        struct fb_info *info )
+ {
++	struct atafb_par *par=(struct atafb_par *)info->par;
++
+ 	if (!fbhw->set_screen_base ||
+ 		(!ATARIHW_PRESENT(EXTD_SHIFTER) && var->xoffset))
+ 		return -EINVAL;
+ 	var->xoffset = up(var->xoffset, 16);
+ 	par->screen_base = screen_base +
+-	        (var->yoffset * fb_display[fb_info.currcon].var.xres_virtual + var->xoffset)
+-	        * fb_display[fb_info.currcon].var.bits_per_pixel / 8;
++	        (var->yoffset * info->var.xres_virtual + var->xoffset)
++	        * info->var.bits_per_pixel / 8;
+ 	fbhw->set_screen_base (par->screen_base);
+ 	return 0;
+ }
+@@ -2344,7 +2579,7 @@
+ 
+ 
+ 
+-static void atafb_get_par( struct atafb_par *par )
++static void ata_get_par( struct atafb_par *par )
+ {
+ 	if (current_par_valid) {
+ 		*par=current_par;
+@@ -2354,7 +2589,7 @@
+ }
+ 
+ 
+-static void atafb_set_par( struct atafb_par *par )
++static void ata_set_par( struct atafb_par *par )
+ {
+ 	fbhw->set_par(par);
+ 	current_par=*par;
+@@ -2371,10 +2606,10 @@
+ /* used for hardware scrolling */
+ 
+ static int
+-fb_update_var(int con, struct fb_info *info)
++fb_update_var(struct fb_info *info)
+ {
+-	int off=fb_display[con].var.yoffset*fb_display[con].var.xres_virtual*
+-			fb_display[con].var.bits_per_pixel>>3;
++	int off=info->var.yoffset*info->var.xres_virtual*
++			info->var.bits_per_pixel>>3;
+ 
+ 	current_par.screen_base=screen_base + off;
+ 
+@@ -2392,106 +2627,82 @@
+ 		return err;
+ 	activate=var->activate;
+ 	if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive)
+-		atafb_set_par(&par);
++		ata_set_par(&par);
+ 	fbhw->encode_var(var, &par);
+ 	var->activate=activate;
+ 	return 0;
+ }
+ 
+ static int
+-atafb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
++atafb_get_fix(struct fb_fix_screeninfo *fix, struct fb_info *info)
+ {
+ 	struct atafb_par par;
+-	if (con == -1)
+-		atafb_get_par(&par);
+-	else {
+ 	  int err;
+-		if ((err=fbhw->decode_var(&fb_display[con].var,&par)))
++	// Get fix directly from hw (case con == -1 before) ?? 
++	if ((err=fbhw->decode_var(&info->var,&par)))
+ 		  return err;
+-	}
+ 	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+ 	return fbhw->encode_fix(fix, &par);
+ }
+ 	
+ static int
+-atafb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
++atafb_get_var(struct fb_var_screeninfo *var, struct fb_info *info)
+ {
+ 	struct atafb_par par;
+-	if (con == -1) {
+-		atafb_get_par(&par);
++
++	ata_get_par(&par);
+ 		fbhw->encode_var(var, &par);
+-	}
+-	else
+-		*var=fb_display[con].var;
++
+ 	return 0;
+ }
+ 
++// No longer called by fbcon!
++// Still called by set_var internally
++
+ static void
+-atafb_set_disp(int con, struct fb_info *info)
++atafb_set_disp(struct fb_info *info)
+ {
+-	struct fb_fix_screeninfo fix;
+-	struct fb_var_screeninfo var;
+-	struct display *display;
++	atafb_get_var(&info->var, info);
++	atafb_get_fix(&info->fix, info);
+ 
+-	if (con >= 0)
+-		display = &fb_display[con];
+-	else
+-		display = &disp;	/* used during initialization */
++	info->screen_base = (void *)info->fix.smem_start;
+ 
+-	atafb_get_fix(&fix, con, info);
+-	atafb_get_var(&var, con, info);
+-	if (con == -1)
+-		con=0;
+-	info->screen_base = (void *)fix.smem_start;
+-	display->visual = fix.visual;
+-	display->type = fix.type;
+-	display->type_aux = fix.type_aux;
+-	display->ypanstep = fix.ypanstep;
+-	display->ywrapstep = fix.ywrapstep;
+-	display->line_length = fix.line_length;
+-	if (fix.visual != FB_VISUAL_PSEUDOCOLOR &&
+-		fix.visual != FB_VISUAL_DIRECTCOLOR)
+-		display->can_soft_blank = 0;
+-	else
+-		display->can_soft_blank = 1;
+-	display->inverse =
+-	    (fix.visual == FB_VISUAL_MONO01 ? !inverse : inverse);
+-	switch (fix.type) {
++	switch (info->fix.type) {
+ 	    case FB_TYPE_INTERLEAVED_PLANES:
+-		switch (var.bits_per_pixel) {
++		switch (info->var.bits_per_pixel) {
+ #ifdef FBCON_HAS_IPLAN2P2
+ 		    case 2:
+-			display->dispsw = &fbcon_iplan2p2;
++			// display->dispsw = &fbcon_iplan2p2;
+ 			break;
+ #endif
+ #ifdef FBCON_HAS_IPLAN2P4
+ 		    case 4:
+-			display->dispsw = &fbcon_iplan2p4;
++			// display->dispsw = &fbcon_iplan2p4;
+ 			break;
+ #endif
+ #ifdef FBCON_HAS_IPLAN2P8
+ 		    case 8:
+-			display->dispsw = &fbcon_iplan2p8;
++			// display->dispsw = &fbcon_iplan2p8;
+ 			break;
+ #endif
+ 		}
+ 		break;
+ 	    case FB_TYPE_PACKED_PIXELS:
+-		switch (var.bits_per_pixel) {
++		switch (info->var.bits_per_pixel) {
+ #ifdef FBCON_HAS_MFB
+ 		    case 1:
+-			display->dispsw = &fbcon_mfb;
++			// display->dispsw = &fbcon_mfb;
+ 			break;
+ #endif
+ #ifdef FBCON_HAS_CFB8
+ 		    case 8:
+-			display->dispsw = &fbcon_cfb8;
++			// display->dispsw = &fbcon_cfb8;
+ 			break;
+ #endif
+ #ifdef FBCON_HAS_CFB16
+ 		    case 16:
+-			display->dispsw = &fbcon_cfb16;
+-			display->dispsw_data = fbcon_cfb16_cmap;
++			// display->dispsw = &fbcon_cfb16;
++			// display->dispsw_data = fbcon_cfb16_cmap;
+ 			break;
+ #endif
+ 		}
+@@ -2504,71 +2715,881 @@
+ {
+ 	int err,oldxres,oldyres,oldbpp,oldxres_virtual,
+ 	    oldyres_virtual,oldyoffset;
+-	if ((err=do_fb_set_var(var, con==info->currcon)))
++	if ((err=do_fb_set_var(var, 1)))
+ 		return err;
+ 	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+-		oldxres=fb_display[con].var.xres;
+-		oldyres=fb_display[con].var.yres;
+-		oldxres_virtual=fb_display[con].var.xres_virtual;
+-		oldyres_virtual=fb_display[con].var.yres_virtual;
+-		oldbpp=fb_display[con].var.bits_per_pixel;
+-		oldyoffset=fb_display[con].var.yoffset;
+-		fb_display[con].var=*var;
++		oldxres=info->var.xres;
++		oldyres=info->var.yres;
++		oldxres_virtual=info->var.xres_virtual;
++		oldyres_virtual=info->var.yres_virtual;
++		oldbpp=info->var.bits_per_pixel;
++		oldyoffset=info->var.yoffset;
++		info->var=*var;
+ 		if (oldxres != var->xres || oldyres != var->yres 
+ 		    || oldxres_virtual != var->xres_virtual
+ 		    || oldyres_virtual != var->yres_virtual
+ 		    || oldbpp != var->bits_per_pixel
+ 		    || oldyoffset != var->yoffset) {
+-			atafb_set_disp(con, info);
+-			(*fb_info.changevar)(con);
+-			fb_alloc_cmap(&fb_display[con].cmap, 0, 0);
+-			do_install_cmap(con, info);
++			atafb_set_disp(info);
+ 		}
+ 	}
+ 	var->activate=0;
+ 	return 0;
+ }
+ 
+-
+-
+-static int
+-atafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
++static int atafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
++                           u_int transp, struct fb_info *info)
+ {
+-	if (con == info->currcon) /* current console ? */
+-		return fb_get_cmap(cmap, kspc, fbhw->getcolreg, info);
+-	else
+-		if (fb_display[con].cmap.len) /* non default colormap ? */
+-			fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
+-		else
+-			fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
+-				     cmap, kspc ? 0 : 2);
+-	return 0;
++        red >>= 8;
++	green >>= 8;
++	blue >>= 8;                        
++	return info->fbops->fb_setcolreg(regno, red, green, blue, transp, info);
+ }
+ 
+ static int
+-atafb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info)
++atafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+ {
+ 	int xoffset = var->xoffset;
+ 	int yoffset = var->yoffset;
+ 	int err;
+ 
+-	if (   xoffset < 0 || xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual
+-	    || yoffset < 0 || yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
++        if (var->vmode & FB_VMODE_YWRAP) {
++		if (var->yoffset < 0 ||
++		    var->yoffset >= info->var.yres_virtual || var->xoffset)
+ 		return -EINVAL;
++	} else {                                           
++		if (var->xoffset+info->var.xres > info->var.xres_virtual ||
++		    var->yoffset+info->var.yres > info->var.yres_virtual)
++		return -EINVAL;
++	}
+ 
+-	if (con == info->currcon) {
+ 		if (fbhw->pan_display) {
+-			if ((err = fbhw->pan_display(var, &current_par)))
++		if ((err = fbhw->pan_display(var, info)))
+ 				return err;
+ 		}
+ 		else
+ 			return -EINVAL;
+-	}
+-	fb_display[con].var.xoffset = var->xoffset;
+-	fb_display[con].var.yoffset = var->yoffset;
++
++	info->var.xoffset = var->xoffset;
++	info->var.yoffset = var->yoffset;
++
++	if (var->vmode & FB_VMODE_YWRAP)
++        	info->var.vmode |= FB_VMODE_YWRAP;
++        else
++                info->var.vmode &= ~FB_VMODE_YWRAP;
++                
+ 	return 0;
+ }
+ 
++#if BITS_PER_LONG == 32
++#define BYTES_PER_LONG	4
++#define SHIFT_PER_LONG	5
++#elif BITS_PER_LONG == 64
++#define BYTES_PER_LONG	8
++#define SHIFT_PER_LONG	6
++#else
++#define Please update me
++#endif
++
++
++    /*
++     *  Compose two values, using a bitmask as decision value
++     *  This is equivalent to (a & mask) | (b & ~mask)
++     */
++
++static inline unsigned long comp(unsigned long a, unsigned long b,
++				 unsigned long mask)
++{
++	return ((a ^ b) & mask) ^ b;
++}
++
++
++static inline unsigned long xor(unsigned long a, unsigned long b,
++				unsigned long mask)
++{
++	return (a & mask) ^ b;
++}
++
++
++    /*
++     *  Unaligned forward bit copy using 32-bit or 64-bit memory accesses
++     */
++
++static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src,
++		   int src_idx, u32 n)
++{
++	unsigned long first, last;
++	int shift = dst_idx-src_idx, left, right;
++	unsigned long d0, d1;
++	int m;
++
++	if (!n)
++		return;
++
++	shift = dst_idx-src_idx;
++	first = ~0UL >> dst_idx;
++	last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
++
++	if (!shift) {
++		// Same alignment for source and dest
++
++		if (dst_idx+n <= BITS_PER_LONG) {
++			// Single word
++			if (last)
++				first &= last;
++			*dst = comp(*src, *dst, first);
++		} else {
++			// Multiple destination words
++			// Leading bits
++			if (first) {
++				*dst = comp(*src, *dst, first);
++				dst++;
++				src++;
++				n -= BITS_PER_LONG-dst_idx;
++			}
++
++			// Main chunk
++			n /= BITS_PER_LONG;
++			while (n >= 8) {
++				*dst++ = *src++;
++				*dst++ = *src++;
++				*dst++ = *src++;
++				*dst++ = *src++;
++				*dst++ = *src++;
++				*dst++ = *src++;
++				*dst++ = *src++;
++				*dst++ = *src++;
++				n -= 8;
++			}
++			while (n--)
++				*dst++ = *src++;
++
++			// Trailing bits
++			if (last)
++				*dst = comp(*src, *dst, last);
++		}
++	} else {
++		// Different alignment for source and dest
++
++		right = shift & (BITS_PER_LONG-1);
++		left = -shift & (BITS_PER_LONG-1);
++
++		if (dst_idx+n <= BITS_PER_LONG) {
++			// Single destination word
++			if (last)
++				first &= last;
++			if (shift > 0) {
++				// Single source word
++				*dst = comp(*src >> right, *dst, first);
++			} else if (src_idx+n <= BITS_PER_LONG) {
++				// Single source word
++				*dst = comp(*src << left, *dst, first);
++			} else {
++				// 2 source words
++				d0 = *src++;
++				d1 = *src;
++				*dst = comp(d0 << left | d1 >> right, *dst,
++					    first);
++			}
++		} else {
++			// Multiple destination words
++			d0 = *src++;
++			// Leading bits
++			if (shift > 0) {
++				// Single source word
++				*dst = comp(d0 >> right, *dst, first);
++				dst++;
++				n -= BITS_PER_LONG-dst_idx;
++			} else {
++				// 2 source words
++				d1 = *src++;
++				*dst = comp(d0 << left | d1 >> right, *dst,
++					    first);
++				d0 = d1;
++				dst++;
++				n -= BITS_PER_LONG-dst_idx;
++			}
++
++			// Main chunk
++			m = n % BITS_PER_LONG;
++			n /= BITS_PER_LONG;
++			while (n >= 4) {
++				d1 = *src++;
++				*dst++ = d0 << left | d1 >> right;
++				d0 = d1;
++				d1 = *src++;
++				*dst++ = d0 << left | d1 >> right;
++				d0 = d1;
++				d1 = *src++;
++				*dst++ = d0 << left | d1 >> right;
++				d0 = d1;
++				d1 = *src++;
++				*dst++ = d0 << left | d1 >> right;
++				d0 = d1;
++				n -= 4;
++			}
++			while (n--) {
++				d1 = *src++;
++				*dst++ = d0 << left | d1 >> right;
++				d0 = d1;
++			}
++
++			// Trailing bits
++			if (last) {
++				if (m <= right) {
++					// Single source word
++					*dst = comp(d0 << left, *dst, last);
++				} else {
++					// 2 source words
++					d1 = *src;
++					*dst = comp(d0 << left | d1 >> right,
++						    *dst, last);
++				}
++			}
++		}
++	}
++}
++
++
++    /*
++     *  Unaligned reverse bit copy using 32-bit or 64-bit memory accesses
++     */
++
++static void bitcpy_rev(unsigned long *dst, int dst_idx,
++		       const unsigned long *src, int src_idx, u32 n)
++{
++	unsigned long first, last;
++	int shift = dst_idx-src_idx, left, right;
++	unsigned long d0, d1;
++	int m;
++
++	if (!n)
++		return;
++
++	dst += (n-1)/BITS_PER_LONG;
++	src += (n-1)/BITS_PER_LONG;
++	if ((n-1) % BITS_PER_LONG) {
++		dst_idx += (n-1) % BITS_PER_LONG;
++		dst += dst_idx >> SHIFT_PER_LONG;
++		dst_idx &= BITS_PER_LONG-1;
++		src_idx += (n-1) % BITS_PER_LONG;
++		src += src_idx >> SHIFT_PER_LONG;
++		src_idx &= BITS_PER_LONG-1;
++	}
++
++	shift = dst_idx-src_idx;
++	first = ~0UL << (BITS_PER_LONG-1-dst_idx);
++	last = ~(~0UL << (BITS_PER_LONG-1-((dst_idx-n) % BITS_PER_LONG)));
++
++	if (!shift) {
++		// Same alignment for source and dest
++
++		if ((unsigned long)dst_idx+1 >= n) {
++			// Single word
++			if (last)
++				first &= last;
++			*dst = comp(*src, *dst, first);
++		} else {
++			// Multiple destination words
++			// Leading bits
++			if (first) {
++				*dst = comp(*src, *dst, first);
++				dst--;
++				src--;
++				n -= dst_idx+1;
++			}
++
++			// Main chunk
++			n /= BITS_PER_LONG;
++			while (n >= 8) {
++				*dst-- = *src--;
++				*dst-- = *src--;
++				*dst-- = *src--;
++				*dst-- = *src--;
++				*dst-- = *src--;
++				*dst-- = *src--;
++				*dst-- = *src--;
++				*dst-- = *src--;
++				n -= 8;
++			}
++			while (n--)
++				*dst-- = *src--;
++
++			// Trailing bits
++			if (last)
++				*dst = comp(*src, *dst, last);
++		}
++	} else {
++		// Different alignment for source and dest
++
++		right = shift & (BITS_PER_LONG-1);
++		left = -shift & (BITS_PER_LONG-1);
++
++		if ((unsigned long)dst_idx+1 >= n) {
++			// Single destination word
++			if (last)
++				first &= last;
++			if (shift < 0) {
++				// Single source word
++				*dst = comp(*src << left, *dst, first);
++			} else if (1+(unsigned long)src_idx >= n) {
++				// Single source word
++				*dst = comp(*src >> right, *dst, first);
++			} else {
++				// 2 source words
++				d0 = *src--;
++				d1 = *src;
++				*dst = comp(d0 >> right | d1 << left, *dst,
++					    first);
++			}
++		} else {
++			// Multiple destination words
++			d0 = *src--;
++			// Leading bits
++			if (shift < 0) {
++				// Single source word
++				*dst = comp(d0 << left, *dst, first);
++				dst--;
++				n -= dst_idx+1;
++			} else {
++				// 2 source words
++				d1 = *src--;
++				*dst = comp(d0 >> right | d1 << left, *dst,
++					    first);
++				d0 = d1;
++				dst--;
++				n -= dst_idx+1;
++			}
++
++			// Main chunk
++			m = n % BITS_PER_LONG;
++			n /= BITS_PER_LONG;
++			while (n >= 4) {
++				d1 = *src--;
++				*dst-- = d0 >> right | d1 << left;
++				d0 = d1;
++				d1 = *src--;
++				*dst-- = d0 >> right | d1 << left;
++				d0 = d1;
++				d1 = *src--;
++				*dst-- = d0 >> right | d1 << left;
++				d0 = d1;
++				d1 = *src--;
++				*dst-- = d0 >> right | d1 << left;
++				d0 = d1;
++				n -= 4;
++			}
++			while (n--) {
++				d1 = *src--;
++				*dst-- = d0 >> right | d1 << left;
++				d0 = d1;
++			}
++
++			// Trailing bits
++			if (last) {
++				if (m <= left) {
++					// Single source word
++					*dst = comp(d0 >> right, *dst, last);
++				} else {
++					// 2 source words
++					d1 = *src;
++					*dst = comp(d0 >> right | d1 << left,
++						    *dst, last);
++				}
++			}
++		}
++	}
++}
++
++
++    /*
++     *  Unaligned forward inverting bit copy using 32-bit or 64-bit memory
++     *  accesses
++     */
++
++static void bitcpy_not(unsigned long *dst, int dst_idx,
++		       const unsigned long *src, int src_idx, u32 n)
++{
++	unsigned long first, last;
++	int shift = dst_idx-src_idx, left, right;
++	unsigned long d0, d1;
++	int m;
++
++	if (!n)
++		return;
++
++	shift = dst_idx-src_idx;
++	first = ~0UL >> dst_idx;
++	last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
++
++	if (!shift) {
++		// Same alignment for source and dest
++
++		if (dst_idx+n <= BITS_PER_LONG) {
++			// Single word
++			if (last)
++				first &= last;
++			*dst = comp(~*src, *dst, first);
++		} else {
++			// Multiple destination words
++			// Leading bits
++			if (first) {
++				*dst = comp(~*src, *dst, first);
++				dst++;
++				src++;
++				n -= BITS_PER_LONG-dst_idx;
++			}
++
++			// Main chunk
++			n /= BITS_PER_LONG;
++			while (n >= 8) {
++				*dst++ = ~*src++;
++				*dst++ = ~*src++;
++				*dst++ = ~*src++;
++				*dst++ = ~*src++;
++				*dst++ = ~*src++;
++				*dst++ = ~*src++;
++				*dst++ = ~*src++;
++				*dst++ = ~*src++;
++				n -= 8;
++			}
++			while (n--)
++				*dst++ = ~*src++;
++
++			// Trailing bits
++			if (last)
++				*dst = comp(~*src, *dst, last);
++		}
++	} else {
++		// Different alignment for source and dest
++
++		right = shift & (BITS_PER_LONG-1);
++		left = -shift & (BITS_PER_LONG-1);
++
++		if (dst_idx+n <= BITS_PER_LONG) {
++			// Single destination word
++			if (last)
++				first &= last;
++			if (shift > 0) {
++				// Single source word
++				*dst = comp(~*src >> right, *dst, first);
++			} else if (src_idx+n <= BITS_PER_LONG) {
++				// Single source word
++				*dst = comp(~*src << left, *dst, first);
++			} else {
++				// 2 source words
++				d0 = ~*src++;
++				d1 = ~*src;
++				*dst = comp(d0 << left | d1 >> right, *dst,
++					    first);
++			}
++		} else {
++			// Multiple destination words
++			d0 = ~*src++;
++			// Leading bits
++			if (shift > 0) {
++				// Single source word
++				*dst = comp(d0 >> right, *dst, first);
++				dst++;
++				n -= BITS_PER_LONG-dst_idx;
++			} else {
++				// 2 source words
++				d1 = ~*src++;
++				*dst = comp(d0 << left | d1 >> right, *dst,
++					    first);
++				d0 = d1;
++				dst++;
++				n -= BITS_PER_LONG-dst_idx;
++			}
++
++			// Main chunk
++			m = n % BITS_PER_LONG;
++			n /= BITS_PER_LONG;
++			while (n >= 4) {
++				d1 = ~*src++;
++				*dst++ = d0 << left | d1 >> right;
++				d0 = d1;
++				d1 = ~*src++;
++				*dst++ = d0 << left | d1 >> right;
++				d0 = d1;
++				d1 = ~*src++;
++				*dst++ = d0 << left | d1 >> right;
++				d0 = d1;
++				d1 = ~*src++;
++				*dst++ = d0 << left | d1 >> right;
++				d0 = d1;
++				n -= 4;
++			}
++			while (n--) {
++				d1 = ~*src++;
++				*dst++ = d0 << left | d1 >> right;
++				d0 = d1;
++			}
++
++			// Trailing bits
++			if (last) {
++				if (m <= right) {
++					// Single source word
++					*dst = comp(d0 << left, *dst, last);
++				} else {
++					// 2 source words
++					d1 = ~*src;
++					*dst = comp(d0 << left | d1 >> right,
++						    *dst, last);
++				}
++			}
++		}
++	}
++}
++
++
++    /*
++     *  Unaligned 32-bit pattern fill using 32/64-bit memory accesses
++     */
++
++static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
++{
++	unsigned long val = pat;
++	unsigned long first, last;
++
++	if (!n)
++		return;
++
++#if BITS_PER_LONG == 64
++	val |= val << 32;
++#endif
++
++	first = ~0UL >> dst_idx;
++	last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
++
++	if (dst_idx+n <= BITS_PER_LONG) {
++		// Single word
++		if (last)
++			first &= last;
++		*dst = comp(val, *dst, first);
++	} else {
++		// Multiple destination words
++		// Leading bits
++		if (first) {
++			*dst = comp(val, *dst, first);
++			dst++;
++			n -= BITS_PER_LONG-dst_idx;
++		}
++
++		// Main chunk
++		n /= BITS_PER_LONG;
++		while (n >= 8) {
++			*dst++ = val;
++			*dst++ = val;
++			*dst++ = val;
++			*dst++ = val;
++			*dst++ = val;
++			*dst++ = val;
++			*dst++ = val;
++			*dst++ = val;
++			n -= 8;
++		}
++		while (n--)
++			*dst++ = val;
++
++		// Trailing bits
++		if (last)
++			*dst = comp(val, *dst, last);
++	}
++}
++
++
++    /*
++     *  Unaligned 32-bit pattern xor using 32/64-bit memory accesses
++     */
++
++static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
++{
++	unsigned long val = pat;
++	unsigned long first, last;
++
++	if (!n)
++		return;
++
++#if BITS_PER_LONG == 64
++	val |= val << 32;
++#endif
++
++	first = ~0UL >> dst_idx;
++	last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
++
++	if (dst_idx+n <= BITS_PER_LONG) {
++		// Single word
++		if (last)
++			first &= last;
++		*dst = xor(val, *dst, first);
++	} else {
++		// Multiple destination words
++		// Leading bits
++		if (first) {
++			*dst = xor(val, *dst, first);
++			dst++;
++			n -= BITS_PER_LONG-dst_idx;
++		}
++
++		// Main chunk
++		n /= BITS_PER_LONG;
++		while (n >= 4) {
++			*dst++ ^= val;
++			*dst++ ^= val;
++			*dst++ ^= val;
++			*dst++ ^= val;
++			n -= 4;
++		}
++		while (n--)
++			*dst++ ^= val;
++
++		// Trailing bits
++		if (last)
++			*dst = xor(val, *dst, last);
++	}
++}
++
++static inline void fill_one_line(int bpp, unsigned long next_plane,
++				 unsigned long *dst, int dst_idx, u32 n,
++				 u32 color)
++{
++	while (1) {
++		dst += dst_idx >> SHIFT_PER_LONG;
++		dst_idx &= (BITS_PER_LONG-1);
++		bitfill32(dst, dst_idx, color & 1 ? ~0 : 0, n);
++		if (!--bpp)
++			break;
++		color >>= 1;
++		dst_idx += next_plane*8;
++	}
++}
++
++static inline void xor_one_line(int bpp, unsigned long next_plane,
++				unsigned long *dst, int dst_idx, u32 n,
++				u32 color)
++{
++	while (color) {
++		dst += dst_idx >> SHIFT_PER_LONG;
++		dst_idx &= (BITS_PER_LONG-1);
++		bitxor32(dst, dst_idx, color & 1 ? ~0 : 0, n);
++		if (!--bpp)
++			break;
++		color >>= 1;
++		dst_idx += next_plane*8;
++	}
++}
++
++
++static void atafb_fillrect(struct fb_info *info,
++			   const struct fb_fillrect *rect)
++{
++	struct atafb_par *par = (struct atafb_par *)info->par;
++	int dst_idx, x2, y2;
++	unsigned long *dst;
++	u32 width, height;
++
++	if (!rect->width || !rect->height)
++		return;
++
++	/*
++	 * We could use hardware clipping but on many cards you get around
++	 * hardware clipping by writing to framebuffer directly.
++	 * */
++	x2 = rect->dx + rect->width;
++	y2 = rect->dy + rect->height;
++	x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
++	y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
++	width = x2 - rect->dx;
++	height = y2 - rect->dy;
++
++	if (info->var.bits_per_pixel == 1)
++		atafb_mfb_fillrect(info, par->next_line, rect->color, 
++				rect->dy, rect->dx, height, width);
++	else if (info->var.bits_per_pixel == 2)
++		atafb_iplan2p2_fillrect(info, par->next_line, rect->color, 
++				rect->dy, rect->dx, height, width);
++	else if (info->var.bits_per_pixel == 4)
++		atafb_iplan2p4_fillrect(info, par->next_line, rect->color, 
++				rect->dy, rect->dx, height, width);
++	else 
++		atafb_iplan2p8_fillrect(info, par->next_line, rect->color, 
++				rect->dy, rect->dx, height, width);
++
++	return;
++}
++
++static inline void copy_one_line(int bpp, unsigned long next_plane,
++				 unsigned long *dst, int dst_idx,
++				 unsigned long *src, int src_idx, u32 n)
++{
++	while (1) {
++		dst += dst_idx >> SHIFT_PER_LONG;
++		dst_idx &= (BITS_PER_LONG-1);
++		src += src_idx >> SHIFT_PER_LONG;
++		src_idx &= (BITS_PER_LONG-1);
++		bitcpy(dst, dst_idx, src, src_idx, n);
++		if (!--bpp)
++			break;
++		dst_idx += next_plane*8;
++		src_idx += next_plane*8;
++	}
++}
++
++static inline void copy_one_line_rev(int bpp, unsigned long next_plane,
++				     unsigned long *dst, int dst_idx,
++				     unsigned long *src, int src_idx, u32 n)
++{
++	while (1) {
++		dst += dst_idx >> SHIFT_PER_LONG;
++		dst_idx &= (BITS_PER_LONG-1);
++		src += src_idx >> SHIFT_PER_LONG;
++		src_idx &= (BITS_PER_LONG-1);
++		bitcpy_rev(dst, dst_idx, src, src_idx, n);
++		if (!--bpp)
++			break;
++		dst_idx += next_plane*8;
++		src_idx += next_plane*8;
++	}
++}
++
++
++static void atafb_copyarea(struct fb_info *info,
++			   const struct fb_copyarea *area)
++{
++	struct atafb_par *par = (struct atafb_par *)info->par;
++	int x2, y2;
++	u32 dx, dy, sx, sy, width, height;
++	unsigned long *dst, *src;
++	int dst_idx, src_idx;
++	int rev_copy = 0;
++
++	/* clip the destination */
++	x2 = area->dx + area->width;
++	y2 = area->dy + area->height;
++	dx = area->dx > 0 ? area->dx : 0;
++	dy = area->dy > 0 ? area->dy : 0;
++	x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
++	y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
++	width = x2 - dx;
++	height = y2 - dy;
++
++	/* update sx,sy */
++	sx = area->sx + (dx - area->dx);
++	sy = area->sy + (dy - area->dy);
++
++	/* the source must be completely inside the virtual screen */
++	if (sx < 0 || sy < 0 || (sx + width) > info->var.xres_virtual ||
++	    (sy + height) > info->var.yres_virtual)
++		return;
++
++	if (dy > sy || (dy == sy && dx > sx)) {
++		dy += height;
++		sy += height;
++		rev_copy = 1;
++	}
++
++	if (info->var.bits_per_pixel == 1)
++		atafb_mfb_copyarea(info, par->next_line, sy, sx, dy, dx, height, width);
++	else if (info->var.bits_per_pixel == 2)
++		atafb_iplan2p2_copyarea(info, par->next_line, sy, sx, dy, dx, height, width);
++	else if (info->var.bits_per_pixel == 4)
++		atafb_iplan2p4_copyarea(info, par->next_line, sy, sx, dy, dx, height, width);
++	else
++		atafb_iplan2p8_copyarea(info, par->next_line, sy, sx, dy, dx, height, width);
++
++	return;
++}
++
++
++static inline void expand_one_line(int bpp, unsigned long next_plane,
++				   unsigned long *dst, int dst_idx, u32 n,
++				   const u8 *data, u32 bgcolor, u32 fgcolor)
++{
++    const unsigned long *src;
++    int src_idx;
++
++    while (1) {
++	dst += dst_idx >> SHIFT_PER_LONG;
++	dst_idx &= (BITS_PER_LONG-1);
++	if ((bgcolor ^ fgcolor) & 1) {
++	    src = (unsigned long *)((unsigned long)data & ~(BYTES_PER_LONG-1));
++	    src_idx = ((unsigned long)data & (BYTES_PER_LONG-1))*8;
++	    if (fgcolor & 1)
++		bitcpy(dst, dst_idx, src, src_idx, n);
++	    else
++		bitcpy_not(dst, dst_idx, src, src_idx, n);
++	    /* set or clear */
++	} else
++	    bitfill32(dst, dst_idx, fgcolor & 1 ? ~0 : 0, n);
++	if (!--bpp)
++	    break;
++	bgcolor >>= 1;
++	fgcolor >>= 1;
++	dst_idx += next_plane*8;
++    }
++}
++
++
++static void atafb_imageblit(struct fb_info *info, const struct fb_image *image)
++{
++	struct atafb_par *par = (struct atafb_par *)info->par;
++	int x2, y2;
++	unsigned long *dst;
++	int dst_idx;
++	const char *src;
++	u32 dx, dy, width, height, pitch;
++
++	/*
++	 * We could use hardware clipping but on many cards you get around
++	 * hardware clipping by writing to framebuffer directly like we are
++	 * doing here.
++	 */
++	x2 = image->dx + image->width;
++	y2 = image->dy + image->height;
++	dx = image->dx;
++	dy = image->dy;
++	x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
++	y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
++	width  = x2 - dx;
++	height = y2 - dy;
++
++	if (image->depth == 1) {
++		// used for font data
++		dst = (unsigned long *)
++			((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1));
++		dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8;
++		dst_idx += dy*par->next_line*8+dx;
++		src = image->data;
++		pitch = (image->width+7)/8;
++		while (height--) {
++
++		    if (info->var.bits_per_pixel == 1)
++			atafb_mfb_linefill(info, par->next_line, 
++					dy, dx, width, src, 
++					image->bg_color, image->fg_color);
++		    else if (info->var.bits_per_pixel == 2)
++			atafb_iplan2p2_linefill(info, par->next_line, 
++					dy, dx, width, src, 
++					image->bg_color, image->fg_color);
++		    else if (info->var.bits_per_pixel == 4)
++			atafb_iplan2p4_linefill(info, par->next_line, 
++					dy, dx, width, src, 
++					image->bg_color, image->fg_color);
++		    else
++			atafb_iplan2p8_linefill(info, par->next_line, 
++					dy, dx, width, src, 
++					image->bg_color, image->fg_color);
++			dy++;
++			src += pitch;
++		}
++	} else {
++		// only used for logo
++		c2p(info->screen_base, image->data, dx, dy, width, height,
++		    par->next_line, par->next_plane, image->width,
++		    info->var.bits_per_pixel);
++	}
++}
+ static int
+ atafb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
+ {
+@@ -2585,7 +3606,7 @@
+ 		if (copy_from_user((void *)&current_par, (void *)arg,
+ 				   sizeof(struct atafb_par)))
+ 			return -EFAULT;
+-		atafb_set_par(&current_par);
++		ata_set_par(&current_par);
+ 		return 0;
+ #endif
+ 	}
+@@ -2614,22 +3635,65 @@
+ 		cmap.transp=NULL;
+ 		cmap.start=0;
+ 		cmap.len=16;
+-		fb_set_cmap(&cmap, 1, info);
++		fb_set_cmap(&cmap, info);
+ 	}
++#if 0
+ 	else
+-		do_install_cmap(info->currcon, info);
++		do_install_cmap(info);
++#endif
++	return 0;
++}
++
++	/*
++	 * New fbcon interface ... 
++	 */
++
++	 /* check var by decoding var into hw par, rounding if necessary, 
++	  * then encoding hw par back into new, validated var */
++static int atafb_check_var(struct fb_var_screeninfo *var,
++			   struct fb_info *info)
++{
++	int err;
++	struct atafb_par par;
++
++	/* Validate wanted screen parameters */
++	if ((err = fbhw->decode_var(var, &par)))
++		return err;
++
++	/* Encode (possibly rounded) screen parameters */
++	fbhw->encode_var(var, &par);
++	return 0;
++}
++
++	/* actually set hw par by decoding var, then setting hardware from 
++	 * hw par just decoded */
++static int atafb_set_par(struct fb_info *info)
++{
++	struct atafb_par *par = (struct atafb_par *)info->par;
++
++	/* Decode wanted screen parameters */
++	fbhw->decode_var(&info->var, par);
++	fbhw->encode_fix(&info->fix, par);
++
++	/* Set new videomode */
++	ata_set_par(par);
++
+ 	return 0;
+ }
+ 
++
++
++
+ static struct fb_ops atafb_ops = {
+ 	.owner =	THIS_MODULE,
+-	.fb_get_fix =	atafb_get_fix,
+-	.fb_get_var =	atafb_get_var,
+-	.fb_set_var =	atafb_set_var,
+-	.fb_get_cmap =	atafb_get_cmap,
+-	.fb_set_cmap =	gen_set_cmap,
+-	.fb_pan_display =atafb_pan_display,
++	.fb_check_var	= atafb_check_var,
++	.fb_set_par	= atafb_set_par,
++	.fb_setcolreg	= atafb_setcolreg,
+ 	.fb_blank =	atafb_blank,
++	.fb_pan_display	= atafb_pan_display,
++	.fb_fillrect	= atafb_fillrect,
++	.fb_copyarea	= atafb_copyarea,
++	.fb_imageblit	= atafb_imageblit,
+ 	.fb_ioctl =	atafb_ioctl,
+ };
+ 
+@@ -2674,17 +3738,19 @@
+ 		default_mem_req=min_mem;
+ }
+ 
++// Obsolete
+ static int
+ atafb_switch(int con, struct fb_info *info)
+ {
++#if 0
+ 	/* Do we have to save the colormap ? */
+-	if (fb_display[info->currcon].cmap.len)
+-		fb_get_cmap(&fb_display[info->currcon].cmap, 1, fbhw->getcolreg,
++	if (info->cmap.len)
++		fb_get_cmap(info->cmap, 1, fbhw->getcolreg,
+ 			    info);
+-	do_fb_set_var(&fb_display[con].var,1);
+-	info->currcon=con;
++#endif
++	do_fb_set_var(&info->var,1);
+ 	/* Install new colormap */
+-	do_install_cmap(con, info);
++	// do_install_cmap(info);
+ 	return 0;
+ }
+ 
+@@ -2692,40 +3758,59 @@
+ {
+ 	int pad;
+ 	int detected_mode;
++	unsigned int defmode;
+ 	unsigned long mem_req;
+ 
++#ifndef MODULE
++	char *option = NULL;
++
++	if (fb_get_options("atafb", &option)) {
++		return -ENODEV;
++	}
++	atafb_setup(option);
++#endif
++	printk("atafb_init: start\n");
++
+ 	if (!MACH_IS_ATARI)
+ 	        return -ENXIO;
+ 
+ 	do {
+ #ifdef ATAFB_EXT
+ 		if (external_addr) {
++			printk("atafb_init: initializing external hw\n");
+ 			fbhw = &ext_switch;
+ 			atafb_ops.fb_setcolreg = &ext_setcolreg;
++			defmode = DEFMODE_EXT;
+ 			break;
+ 		}
+ #endif
+ #ifdef ATAFB_TT
+ 		if (ATARIHW_PRESENT(TT_SHIFTER)) {
++			printk("atafb_init: initializing TT hw\n");
+ 			fbhw = &tt_switch;
+ 			atafb_ops.fb_setcolreg = &tt_setcolreg;
++			defmode = DEFMODE_TT;
+ 			break;
+ 		}
+ #endif
+ #ifdef ATAFB_FALCON
+ 		if (ATARIHW_PRESENT(VIDEL_SHIFTER)) {
++			printk("atafb_init: initializing Falcon hw\n");
+ 			fbhw = &falcon_switch;
+ 			atafb_ops.fb_setcolreg = &falcon_setcolreg;
+ 			request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO,
+ 			            "framebuffer/modeswitch", falcon_vbl_switcher);
++			defmode = DEFMODE_F30;
+ 			break;
+ 		}
+ #endif
+ #ifdef ATAFB_STE
+ 		if (ATARIHW_PRESENT(STND_SHIFTER) ||
+ 		    ATARIHW_PRESENT(EXTD_SHIFTER)) {
++			printk("atafb_init: initializing ST/E hw\n");
+ 			fbhw = &st_switch;
+ 			atafb_ops.fb_setcolreg = &stste_setcolreg;
++			defmode = DEFMODE_STE;
+ 			break;
+ 		}
+ 		fbhw = &st_switch;
+@@ -2770,6 +3855,8 @@
+ 			kernel_set_cachemode(screen_base, screen_len,
+ 					     IOMAP_WRITETHROUGH);
+ 		}
++		printk("atafb: screen_base %p real_screen_base %p screen_len %ld\n",
++			screen_base, real_screen_base, screen_len);
+ #ifdef ATAFB_EXT
+ 	}
+ 	else {
+@@ -2789,32 +3876,46 @@
+ 	}
+ #endif /* ATAFB_EXT */
+ 
+-	strcpy(fb_info.modename, "Atari Builtin ");
+-	fb_info.changevar = NULL;
++//	strcpy(fb_info.mode->name, "Atari Builtin ");
+ 	fb_info.fbops = &atafb_ops;
+-	fb_info.disp = &disp;
+-	fb_info.currcon = -1;
+-	fb_info.switch_con = &atafb_switch;
+-	fb_info.updatevar = &fb_update_var;
+-	fb_info.flags = FBINFO_FLAG_DEFAULT;
++	// try to set default (detected; requested) var
+ 	do_fb_set_var(&atafb_predefined[default_par-1], 1);
+-	strcat(fb_info.modename, fb_var_names[default_par-1][0]);
+-
+-	atafb_get_var(&disp.var, -1, &fb_info);
+-	atafb_set_disp(-1, &fb_info);
+-	do_install_cmap(0, &fb_info);
++	// reads hw state into current par, which may not be sane yet
++	ata_get_par(&current_par);
++	fb_info.par = &current_par;
++	// tries to read from HW which may not be initialized yet
++	// so set sane var first, then call atafb_set_par
++	atafb_get_var(&current_var, &fb_info);
++	fb_info.var = current_var;
++	fb_info.flags = FBINFO_FLAG_DEFAULT;
+ 
+-	if (register_framebuffer(&fb_info) < 0)
++	if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, atafb_modedb,
++			  NUM_TOTAL_MODES, &atafb_modedb[defmode], 
++			  current_var.bits_per_pixel)) {
+ 		return -EINVAL;
++	}
++
++// 	strcat(fb_info.mode->name, fb_var_names[default_par-1][0]);
++
++	atafb_set_disp(&fb_info);
++
++	fb_alloc_cmap(&(fb_info.cmap), 1<<fb_info.var.bits_per_pixel, 0);
+ 
+ 	printk("Determined %dx%d, depth %d\n",
+-	       disp.var.xres, disp.var.yres, disp.var.bits_per_pixel);
+-	if ((disp.var.xres != disp.var.xres_virtual) ||
+-	    (disp.var.yres != disp.var.yres_virtual))
++	       fb_info.var.xres, fb_info.var.yres, fb_info.var.bits_per_pixel);
++	if ((current_var.xres != current_var.xres_virtual) ||
++	    (current_var.yres != current_var.yres_virtual))
+ 	   printk("   virtual %dx%d\n",
+-			  disp.var.xres_virtual, disp.var.yres_virtual);
+-	printk("fb%d: %s frame buffer device, using %dK of video memory\n",
+-	       fb_info.node, fb_info.modename, screen_len>>10);
++			  current_var.xres_virtual, current_var.yres_virtual);
++
++	if (register_framebuffer(&fb_info) < 0)
++		return -EINVAL;
++
++	// FIXME: mode needs setting!
++	//printk("fb%d: %s frame buffer device, using %dK of video memory\n",
++	//       fb_info.node, fb_info.mode->name, screen_len>>10);
++	printk("fb%d: frame buffer device, using %dK of video memory\n",
++	       fb_info.node, screen_len>>10);
+ 
+ 	/* TODO: This driver cannot be unloaded yet */
+ 	return 0;
+@@ -3038,19 +4139,16 @@
+     char *this_opt;
+     int temp;
+ 
+-    fb_info.fontname[0] = '\0';
+-
+     if (!options || !*options)
+ 		return 0;
+     
+     while ((this_opt = strsep(&options, ",")) != NULL) {	 
+ 	if (!*this_opt) continue;
+-	if ((temp=get_video_mode(this_opt)))
++	if ((temp=get_video_mode(this_opt))) {
+ 		default_par=temp;
+-	else if (! strcmp(this_opt, "inverse"))
++		mode_option = this_opt;
++	} else if (! strcmp(this_opt, "inverse"))
+ 		inverse=1;
+-	else if (!strncmp(this_opt, "font:", 5))
+-	   strcpy(fb_info.fontname, this_opt+5);
+ 	else if (! strncmp(this_opt, "hwscroll_",9)) {
+ 		hwscroll=simple_strtoul(this_opt+9, NULL, 10);
+ 		if (hwscroll < 0)
+@@ -3086,11 +4184,14 @@
+     return 0;
+ }
+ 
++module_init(atafb_init);
++
+ #ifdef MODULE
+ MODULE_LICENSE("GPL");
+ 
+-int init_module(void)
++int cleanup_module(void)
+ {
+-	return atafb_init();
++	unregister_framebuffer(&fb_info);
++	return atafb_deinit();
+ }
+ #endif /* MODULE */
+diff -urN linux-m68k/drivers/video/atafb_iplan2p2.c linux-schmitz/drivers/video/atafb_iplan2p2.c
+--- linux-m68k/drivers/video/atafb_iplan2p2.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-schmitz/drivers/video/atafb_iplan2p2.c	2006-11-19 21:37:27.000000000 +0100
+@@ -0,0 +1,353 @@
++/*
++ *  linux/drivers/video/iplan2p2.c -- Low level frame buffer operations for
++ *				      interleaved bitplanes à la Atari (2
++ *				      planes, 2 bytes interleave)
++ *
++ *	Created 5 Apr 1997 by Geert Uytterhoeven
++ *
++ *  This file is subject to the terms and conditions of the GNU General Public
++ *  License.  See the file COPYING in the main directory of this archive for
++ *  more details.
++ */
++
++#include <linux/module.h>
++#include <linux/tty.h>
++#include <linux/console.h>
++#include <linux/string.h>
++#include <linux/fb.h>
++
++#include <asm/byteorder.h>
++
++#ifdef __mc68000__
++#include <asm/setup.h>
++#endif
++
++#include "console/fbcon.h"
++#include "atafb_utils.h"
++#include "atafb_iplan2p2.h"
++
++
++    /*
++     *  Interleaved bitplanes à la Atari (2 planes, 2 bytes interleave)
++     */
++
++/* Increment/decrement 2 plane addresses */
++
++#define	INC_2P(p)	do { if (!((long)(++(p)) & 1)) (p) += 2; } while(0)
++#define	DEC_2P(p)	do { if ((long)(--(p)) & 1) (p) -= 2; } while(0)
++
++    /*  Convert a standard 4 bit color to our 2 bit color assignment:
++     *  If at least two RGB channels are active, the low bit is turned on;
++     *  The intensity bit (b3) is shifted into b1.
++     */
++
++static const u8 color_2p[] = { 0, 0, 0, 1, 0, 1, 1, 1, 2, 2, 2, 3, 2, 3, 3, 3 };
++#define	COLOR_2P(c)	color_2p[c]
++
++/* Perform the m68k movepw operation.  */
++static inline void movepw(u8 *d, u16 val)
++{
++#if defined __mc68000__ && !defined CPU_M68060_ONLY
++    asm volatile ("movepw %1,%0@(0)" : : "a" (d), "d" (val));
++#else
++    d[0] = (val >> 16) & 0xff;
++    d[2] = val & 0xff;
++#endif
++}
++
++/* Sets the bytes in the visible column at d, height h, to the value
++ * val for a 2 plane screen. The bits of the color in 'color' are
++ * moved (8 times) to the respective bytes. This means:
++ *
++ * for(h times; d += bpr)
++ *   *d     = (color & 1) ? 0xff : 0;
++ *   *(d+2) = (color & 2) ? 0xff : 0;
++ */
++
++static __inline__ void memclear_2p_col(void *d, size_t h, u16 val, int bpr)
++{
++    u8 *dd = d;
++    do {
++	movepw(dd, val);
++	dd += bpr;
++    } while (--h);
++}
++
++/* Sets a 2 plane region from 'd', length 'count' bytes, to the color
++ * in val1. 'd' has to be an even address and count must be divisible
++ * by 8, because only whole words and all planes are accessed. I.e.:
++ *
++ * for(count/4 times)
++ *   *d     = *(d+1) = (color & 1) ? 0xff : 0;
++ *   *(d+2) = *(d+3) = (color & 2) ? 0xff : 0;
++ */
++
++static __inline__ void memset_even_2p(void *d, size_t count, u32 val)
++{
++    u32 *dd = d;
++
++    count /= 4;
++    while (count--)
++	*dd++ = val;
++}
++
++/* Copies a 2 plane column from 's', height 'h', to 'd'. */
++
++static __inline__ void memmove_2p_col (void *d, void *s, int h, int bpr)
++{
++    u8 *dd = d, *ss = s;
++
++    while (h--) {
++	dd[0] = ss[0];
++	dd[2] = ss[2];
++	dd += bpr;
++	ss += bpr;
++    }
++}
++
++
++/* This expands a 2 bit color into a short for movepw (2 plane) operations. */
++
++static const u16 two2byte[] = {
++    0x0000, 0xff00, 0x00ff, 0xffff
++};
++
++static __inline__ u16 expand2w(u8 c)
++{
++    return two2byte[c];
++}
++
++
++/* This expands a 2 bit color into one long for a movel operation
++ * (2 planes).
++ */
++
++static const u32 two2word[] = {
++#ifndef __LITTLE_ENDIAN
++    0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
++#else
++    0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
++#endif
++};
++
++static __inline__ u32 expand2l(u8 c)
++{
++    return two2word[c];
++}
++
++
++/* This duplicates a byte 2 times into a short. */
++
++static __inline__ u16 dup2w(u8 c)
++{
++    u16 rv;
++
++    rv = c;
++    rv |= c << 8;
++    return rv;
++}
++
++
++void atafb_iplan2p2_copyarea(struct fb_info *info, u_long next_line,
++                             int sy, int sx, int dy, int dx,
++			     int height, int width)
++{
++    /*  bmove() has to distinguish two major cases: If both, source and
++     *  destination, start at even addresses or both are at odd
++     *  addresses, just the first odd and last even column (if present)
++     *  require special treatment (memmove_col()). The rest between
++     *  then can be copied by normal operations, because all adjacent
++     *  bytes are affected and are to be stored in the same order.
++     *    The pathological case is when the move should go from an odd
++     *  address to an even or vice versa. Since the bytes in the plane
++     *  words must be assembled in new order, it seems wisest to make
++     *  all movements by memmove_col().
++     */
++
++     if (sx == 0 && dx == 0 && width * 2 == next_line) {
++	/*  Special (but often used) case: Moving whole lines can be
++	 *  done with memmove()
++	 */
++        fb_memmove((u8 *)info->screen_base + dy * next_line,
++                   (u8 *)info->screen_base + sy * next_line,
++                    next_line * height);
++     } else {
++	int rows, cols;
++	u8 *src;
++	u8 *dst;
++	int bytes = next_line;
++	int linesize;
++	u_int colsize;
++	u_int upwards = (dy < sy) || (dy == sy && dx < sx);
++
++        linesize = bytes;
++        colsize = height;
++	if ((sx & 1) == (dx & 1)) {
++	    /* odd->odd or even->even */
++
++	    if (upwards) {
++		src = (u8 *)info->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
++		dst = (u8 *)info->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
++		if (sx & 1) {
++		    memmove_2p_col(dst, src, colsize, bytes);
++		    src += 3;
++		    dst += 3;
++		    --width;
++		}
++		if (width > 1) {
++		    for(rows = colsize; rows > 0; --rows) {
++			fb_memmove (dst, src, (width >> 1) * 4);
++			src += bytes;
++			dst += bytes;
++		    }
++		}
++
++		if (width & 1) {
++		    src -= colsize * bytes;
++		    dst -= colsize * bytes;
++		    memmove_2p_col(dst + (width>>1)*4, src + (width>>1)*4,
++		    colsize, bytes);
++		}
++	    } else {
++		if (!((sx+width-1) & 1)) {
++		    src = (u8 *)info->screen_base + sy * linesize + ((sx+width-1)>>1)*4;
++		    dst = (u8 *)info->screen_base + dy * linesize + ((dx+width-1)>>1)*4;
++		    memmove_2p_col(dst, src, colsize, bytes);
++		    --width;
++		}
++		src = (u8 *)info->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
++		dst = (u8 *)info->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
++		if (width > 1) {
++		    src += colsize * bytes + (sx & 1)*3;
++		    dst += colsize * bytes + (sx & 1)*3;
++		    for(rows = colsize; rows > 0; --rows) {
++			src -= bytes;
++			dst -= bytes;
++			fb_memmove (dst, src, (width>>1)*4);
++		    }
++		}
++		if (width & 1)
++		    memmove_2p_col(dst-3, src-3, colsize, bytes);
++	    }
++	} else {
++	/* odd->even or even->odd */
++
++	    if (upwards) {
++		src = (u8 *)info->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
++		dst = (u8 *)info->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
++		for(cols = width; cols > 0; --cols) {
++		    memmove_2p_col(dst, src, colsize, bytes);
++		    INC_2P(src);
++		    INC_2P(dst);
++		}
++	    } else {
++		sx += width-1;
++		dx += width-1;
++		src = (u8 *)info->screen_base + sy * linesize + (sx>>1)*4 + (sx & 1);
++		dst = (u8 *)info->screen_base + dy * linesize + (dx>>1)*4 + (dx & 1);
++		for(cols = width; cols > 0; --cols) {
++		    memmove_2p_col(dst, src, colsize, bytes);
++		    DEC_2P(src);
++		    DEC_2P(dst);
++		}
++	    }
++	}
++    }
++}
++
++void atafb_iplan2p2_fillrect(struct fb_info *info, u_long next_line, u32 color, 
++                             int sy, int sx, int height, int width)
++{
++    u32 offset;
++    u8 *start;
++    int rows;
++    int bytes = next_line;
++    int lines;
++    u32 size;
++    u32 cval;
++    u16 pcval;
++
++    cval = expand2l(color);
++
++    lines = height;
++
++    if (sx == 0 && width * 2 == bytes) {
++        offset = (sy * bytes);
++	size    = lines * bytes;
++	memset_even_2p((u8 *)info->screen_base + offset, size, cval);
++    } else {
++        offset = sy * bytes + (sx>>1)*4 + (sx & 1);
++	start = (u8 *) info->screen_base + offset;
++	pcval = expand2w(color);
++
++	/* Clears are split if the region starts at an odd column or
++	* end at an even column. These extra columns are spread
++	* across the interleaved planes. All in between can be
++	* cleared by normal fb_memclear_small(), because both bytes of
++	* the single plane words are affected.
++	*/
++
++	if (sx & 1) {
++	    memclear_2p_col(start, lines, pcval, bytes);
++	    start += 3;
++	    width--;
++	}
++	if (width & 1) {
++	    memclear_2p_col(start + (width>>1)*4, lines, pcval, bytes);
++	    width--;
++	}
++	if (width)
++	    for(rows = lines; rows-- ; start += bytes)
++		memset_even_2p(start, width*2, cval);
++	}
++}
++
++void atafb_iplan2p2_linefill(struct fb_info *info, u_long next_line,
++                             int dy, int dx, u32 width,
++                             const u8 *data, u32 bgcolor, u32 fgcolor)
++{
++    u8 *dest;
++    u8 *cdat;
++    int rows;
++    int bytes = next_line;
++    u16 eorx, fgx, bgx, fdx;
++
++    // source data
++    cdat = data;
++
++    // advance from odd to even (dx>>3) by 3: 0 1 4 5 .... 
++    // dest = (p->screen_base + yy * p->next_line + (xx>>1)*4 + (xx & 1));
++    dest = (u8*) info->screen_base + dy * bytes + (dx>>4)*4 + ((dx>>3)&1);
++
++    fgx = expand2w(fgcolor);
++    bgx = expand2w(bgcolor);
++    eorx = fgx ^ bgx;
++
++      for(rows = width/8; rows-- ;) {
++	fdx = dup2w(*cdat++);
++	movepw(dest, (fdx & eorx) ^ bgx);
++	INC_2P(dest);
++      }
++    
++}
++
++#ifdef MODULE
++MODULE_LICENSE("GPL");
++
++int init_module(void)
++{
++    return 0;
++}
++
++void cleanup_module(void)
++{}
++#endif /* MODULE */
++
++
++    /*
++     *  Visible symbols for modules
++     */
++
++EXPORT_SYMBOL(atafb_iplan2p2_copyarea);
++EXPORT_SYMBOL(atafb_iplan2p2_fillrect);
++EXPORT_SYMBOL(atafb_iplan2p2_linefill);
+diff -urN linux-m68k/drivers/video/atafb_iplan2p2.h linux-schmitz/drivers/video/atafb_iplan2p2.h
+--- linux-m68k/drivers/video/atafb_iplan2p2.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-schmitz/drivers/video/atafb_iplan2p2.h	2006-11-19 21:37:27.000000000 +0100
+@@ -0,0 +1,27 @@
++/*
++ *  FBcon low-level driver for Atari interleaved bitplanes (8 planes) (iplan2p8)
++ */
++
++#ifndef _VIDEO_FBCON_IPLAN2P2_H
++#define _VIDEO_FBCON_IPLAN2P2_H
++
++#ifdef MODULE
++#if defined(CONFIG_FBCON_IPLAN2P2) || defined(CONFIG_FBCON_IPLAN2P2_MODULE)
++#define FBCON_HAS_IPLAN2P2
++#endif
++#else
++#if defined(CONFIG_FBCON_IPLAN2P2)
++#define FBCON_HAS_IPLAN2P2
++#endif
++#endif
++
++extern void atafb_iplan2p2_copyarea(struct fb_info *info, u_long next_line, int sy, int sx, int dy,
++				    int dx, int height, int width);
++extern void atafb_iplan2p2_fillrect(struct fb_info *info, u_long next_line, u32 color,
++				    int sy, int sx, int height, int width);
++extern void atafb_iplan2p2_linefill(struct fb_info *info, u_long next_line,
++                                    int dy, int dx, u32 width,
++                                    const u8 *data, u32 bgcolor, u32 fgcolor);
++
++
++#endif /* _VIDEO_FBCON_IPLAN2P8_H */
+diff -urN linux-m68k/drivers/video/atafb_iplan2p4.c linux-schmitz/drivers/video/atafb_iplan2p4.c
+--- linux-m68k/drivers/video/atafb_iplan2p4.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-schmitz/drivers/video/atafb_iplan2p4.c	2006-11-19 21:37:27.000000000 +0100
+@@ -0,0 +1,361 @@
++/*
++ *  linux/drivers/video/iplan2p4.c -- Low level frame buffer operations for
++ *				      interleaved bitplanes à la Atari (8
++ *				      planes, 2 bytes interleave)
++ *
++ *	Created 5 Apr 1997 by Geert Uytterhoeven
++ *
++ *  This file is subject to the terms and conditions of the GNU General Public
++ *  License.  See the file COPYING in the main directory of this archive for
++ *  more details.
++ */
++
++#include <linux/module.h>
++#include <linux/tty.h>
++#include <linux/console.h>
++#include <linux/string.h>
++#include <linux/fb.h>
++
++#include <asm/byteorder.h>
++
++#ifdef __mc68000__
++#include <asm/setup.h>
++#endif
++
++#include "console/fbcon.h"
++#include "atafb_utils.h"
++#include "atafb_iplan2p4.h"
++
++
++    /*
++     *  Interleaved bitplanes à la Atari (4 planes, 2 bytes interleave)
++     */
++
++/* Increment/decrement 4 plane addresses */
++
++#define	INC_4P(p)	do { if (!((long)(++(p)) & 1)) (p) += 6; } while(0)
++#define	DEC_4P(p)	do { if ((long)(--(p)) & 1) (p) -= 6; } while(0)
++
++/* Perform the m68k movepl operation.  */
++static inline void movepl(u8 *d, u32 val)
++{
++#if defined __mc68000__ && !defined CPU_M68060_ONLY
++    asm volatile ("movepl %1,%0@(0)"
++		  : : "a" (d), "d" (val));
++#else
++    d[0] = (val >> 24) & 0xff;
++    d[2] = (val >> 16) & 0xff;
++    d[4] = (val >> 8) & 0xff;
++    d[6] = val & 0xff;
++#endif
++}
++
++/* Sets the bytes in the visible column at d, height h, to the value
++ * val for a 4 plane screen. The bits of the color in 'color' are
++ * moved (8 times) to the respective bytes. This means:
++ *
++ * for(h times; d += bpr)
++ *   *d     = (color & 1) ? 0xff : 0;
++ *   *(d+2) = (color & 2) ? 0xff : 0;
++ *   *(d+4) = (color & 4) ? 0xff : 0;
++ *   *(d+6) = (color & 8) ? 0xff : 0;
++ */
++
++static __inline__ void memclear_4p_col(void *d, size_t h, u32 val, int bpr)
++{
++    u8 *dd = d;
++    do {
++	movepl(dd, val);
++	dd += bpr;
++    } while (--h);
++}
++
++/* Sets a 4 plane region from 'd', length 'count' bytes, to the color
++ * in val1/val2. 'd' has to be an even address and count must be divisible
++ * by 8, because only whole words and all planes are accessed. I.e.:
++ *
++ * for(count/8 times)
++ *   *d     = *(d+1) = (color & 1) ? 0xff : 0;
++ *   *(d+2) = *(d+3) = (color & 2) ? 0xff : 0;
++ *   *(d+4) = *(d+5) = (color & 4) ? 0xff : 0;
++ *   *(d+6) = *(d+7) = (color & 8) ? 0xff : 0;
++ */
++
++static __inline__ void memset_even_4p(void *d, size_t count, u32 val1,
++                                      u32 val2)
++{
++    u32 *dd = d;
++
++    count /= 8;
++    while (count--) {
++	*dd++ = val1;
++	*dd++ = val2;
++    }
++}
++
++/* Copies a 4 plane column from 's', height 'h', to 'd'. */
++
++static __inline__ void memmove_4p_col (void *d, void *s, int h, int bpr)
++{
++    u8 *dd = d, *ss = s;
++
++    while (h--) {
++	dd[0] = ss[0];
++	dd[2] = ss[2];
++	dd[4] = ss[4];
++	dd[6] = ss[6];
++	dd += bpr;
++	ss += bpr;
++    }
++}
++
++
++/* This expands a 4 bit color into a long for movepl (4 plane) operations. */
++
++static const u32 four2byte[] = {
++    0x00000000, 0xff000000, 0x00ff0000, 0xffff0000,
++    0x0000ff00, 0xff00ff00, 0x00ffff00, 0xffffff00,
++    0x000000ff, 0xff0000ff, 0x00ff00ff, 0xffff00ff,
++    0x0000ffff, 0xff00ffff, 0x00ffffff, 0xffffffff
++};
++
++static __inline__ u32 expand4l(u8 c)
++{
++    return four2byte[c];
++}
++
++
++/* This expands a 4 bit color into two longs for two movel operations
++ * (4 planes).
++ */
++static const u32 two2word[] = {
++#ifndef __LITTLE_ENDIAN
++    0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff,
++#else
++    0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff,
++#endif
++};
++
++static __inline__ void expand4dl(u8 c, u32 *ret1, u32 *ret2)
++{
++    *ret1 = two2word[c & 3];
++    *ret2 = two2word[c >> 2];
++}
++
++
++/* This duplicates a byte 4 times into a long. */
++
++static __inline__ u32 dup4l(u8 c)
++{
++    u32 rv;
++
++    rv = c;
++    rv |= rv << 8;
++    rv |= rv << 16;
++    return rv;
++}
++
++
++void atafb_iplan2p4_copyarea(struct fb_info *info, u_long next_line,
++                             int sy, int sx, int dy, int dx,
++			     int height, int width)
++{
++    /*  bmove() has to distinguish two major cases: If both, source and
++     *  destination, start at even addresses or both are at odd
++     *  addresses, just the first odd and last even column (if present)
++     *  require special treatment (memmove_col()). The rest between
++     *  then can be copied by normal operations, because all adjacent
++     *  bytes are affected and are to be stored in the same order.
++     *    The pathological case is when the move should go from an odd
++     *  address to an even or vice versa. Since the bytes in the plane
++     *  words must be assembled in new order, it seems wisest to make
++     *  all movements by memmove_col().
++     */
++
++     if (sx == 0 && dx == 0 && width * 4 == next_line) {
++	/*  Special (but often used) case: Moving whole lines can be
++	 *  done with memmove()
++	 */
++        fb_memmove((u8 *)info->screen_base + dy * next_line,
++                   (u8 *)info->screen_base + sy * next_line,
++                    next_line * height);
++     } else {
++	int rows, cols;
++	u8 *src;
++	u8 *dst;
++	int bytes = next_line;
++	int linesize;
++	u_int colsize;
++	u_int upwards = (dy < sy) || (dy == sy && dx < sx);
++
++        linesize = bytes;
++        colsize = height;
++	if ((sx & 1) == (dx & 1)) {
++	    /* odd->odd or even->even */
++
++	    if (upwards) {
++		src = (u8 *)info->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1);
++		dst = (u8 *)info->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1);
++		if (sx & 1) {
++		    memmove_4p_col(dst, src, colsize, bytes);
++		    src += 7;
++		    dst += 7;
++		    --width;
++		}
++		if (width > 1) {
++		    for(rows = colsize; rows > 0; --rows) {
++			fast_memmove (dst, src, (width >> 1) * 8);
++			src += bytes;
++			dst += bytes;
++		    }
++		}
++
++		if (width & 1) {
++		    src -= colsize * bytes;
++		    dst -= colsize * bytes;
++		    memmove_4p_col(dst + (width>>1)*8, src + (width>>1)*8,
++		    colsize, bytes);
++		}
++	    } else {
++		if (!((sx+width-1) & 1)) {
++		    src = (u8 *)info->screen_base + sy * linesize + ((sx+width-1)>>1)*8;
++		    dst = (u8 *)info->screen_base + dy * linesize + ((dx+width-1)>>1)*8;
++		    memmove_4p_col(dst, src, colsize, bytes);
++		    --width;
++		}
++		src = (u8 *)info->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1);
++		dst = (u8 *)info->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1);
++		if (width > 1) {
++		    src += colsize * bytes + (sx & 1)*7;
++		    dst += colsize * bytes + (sx & 1)*7;
++		    for(rows = colsize; rows > 0; --rows) {
++			src -= bytes;
++			dst -= bytes;
++			fb_memmove (dst, src, (width>>1)*8);
++		    }
++		}
++		if (width & 1)
++		    memmove_4p_col(dst-7, src-7, colsize, bytes);
++	    }
++	} else {
++	/* odd->even or even->odd */
++
++	    if (upwards) {
++		src = (u8 *)info->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1);
++		dst = (u8 *)info->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1);
++		for(cols = width; cols > 0; --cols) {
++		    memmove_4p_col(dst, src, colsize, bytes);
++		    INC_4P(src);
++		    INC_4P(dst);
++		}
++	    } else {
++		sx += width-1;
++		dx += width-1;
++		src = (u8 *)info->screen_base + sy * linesize + (sx>>1)*8 + (sx & 1);
++		dst = (u8 *)info->screen_base + dy * linesize + (dx>>1)*8 + (dx & 1);
++		for(cols = width; cols > 0; --cols) {
++		    memmove_4p_col(dst, src, colsize, bytes);
++		    DEC_4P(src);
++		    DEC_4P(dst);
++		}
++	    }
++	}
++    }
++}
++
++void atafb_iplan2p4_fillrect(struct fb_info *info, u_long next_line, u32 color, 
++                             int sy, int sx, int height, int width)
++{
++    u32 offset;
++    u8 *start;
++    int rows;
++    int bytes = next_line;
++    int lines;
++    u32 size;
++    u32 cval1, cval2, pcval;
++
++    expand4dl(color, &cval1, &cval2);
++
++    lines = height;
++
++    if (sx == 0 && width * 4 == bytes) {
++        offset = (sy * bytes);
++	size    = lines * bytes;
++	memset_even_4p((u8 *)info->screen_base + offset, size, cval1, cval2);
++    } else {
++        offset = sy * bytes + (sx>>1)*8 + (sx & 1);
++	start = (u8 *) info->screen_base + offset;
++	pcval = expand4l(color);
++
++	/* Clears are split if the region starts at an odd column or
++	* end at an even column. These extra columns are spread
++	* across the interleaved planes. All in between can be
++	* cleared by normal fb_memclear_small(), because both bytes of
++	* the single plane words are affected.
++	*/
++
++	if (sx & 1) {
++	    memclear_4p_col(start, lines, pcval, bytes);
++	    start += 7;
++	    width--;
++	}
++	if (width & 1) {
++	    memclear_4p_col(start + (width>>1)*8, lines, pcval, bytes);
++	    width--;
++	}
++	if (width)
++	    for(rows = lines; rows-- ; start += bytes)
++		memset_even_4p(start, width*4, cval1, cval2);
++	}
++}
++
++void atafb_iplan2p4_linefill(struct fb_info *info, u_long next_line,
++                             int dy, int dx, u32 width,
++                             const u8 *data, u32 bgcolor, u32 fgcolor)
++{
++    u8 *dest;
++    u8 *cdat;
++    int rows;
++    int bytes = next_line;
++    u32 eorx, fgx, bgx, fdx;
++
++    // source data
++    cdat = data;
++
++    // advance from odd to even dx by 7: 0 1 8 9 ...
++    // dest = (p->screen_base + yy * bytes + (xx>>1)*8 + (xx & 1));
++
++    dest = (u8*) info->screen_base + dy * bytes + (dx>>4)*8 + ((dx>>3)&1);
++
++    fgx = expand4l(fgcolor);
++    bgx = expand4l(bgcolor);
++    eorx = fgx ^ bgx;
++
++      for(rows = width/8; rows-- ;) {
++	fdx = dup4l(*cdat++);
++	movepl(dest, (fdx & eorx) ^ bgx);
++	INC_4P(dest);
++      }
++    
++}
++
++#ifdef MODULE
++MODULE_LICENSE("GPL");
++
++int init_module(void)
++{
++    return 0;
++}
++
++void cleanup_module(void)
++{}
++#endif /* MODULE */
++
++
++    /*
++     *  Visible symbols for modules
++     */
++
++EXPORT_SYMBOL(atafb_iplan2p4_copyarea);
++EXPORT_SYMBOL(atafb_iplan2p4_fillrect);
++EXPORT_SYMBOL(atafb_iplan2p4_linefill);
+diff -urN linux-m68k/drivers/video/atafb_iplan2p4.h linux-schmitz/drivers/video/atafb_iplan2p4.h
+--- linux-m68k/drivers/video/atafb_iplan2p4.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-schmitz/drivers/video/atafb_iplan2p4.h	2006-11-19 21:37:27.000000000 +0100
+@@ -0,0 +1,27 @@
++/*
++ *  FBcon low-level driver for Atari interleaved bitplanes (8 planes) (iplan2p8)
++ */
++
++#ifndef _VIDEO_FBCON_IPLAN2P4_H
++#define _VIDEO_FBCON_IPLAN2P4_H
++
++#ifdef MODULE
++#if defined(CONFIG_FBCON_IPLAN2P4) || defined(CONFIG_FBCON_IPLAN2P4_MODULE)
++#define FBCON_HAS_IPLAN2P4
++#endif
++#else
++#if defined(CONFIG_FBCON_IPLAN2P4)
++#define FBCON_HAS_IPLAN2P4
++#endif
++#endif
++
++extern void atafb_iplan2p4_copyarea(struct fb_info *info, u_long next_line, int sy, int sx, int dy,
++				    int dx, int height, int width);
++extern void atafb_iplan2p4_fillrect(struct fb_info *info, u_long next_line, u32 color,
++				    int sy, int sx, int height, int width);
++extern void atafb_iplan2p4_linefill(struct fb_info *info, u_long next_line,
++                                    int dy, int dx, u32 width,
++                                    const u8 *data, u32 bgcolor, u32 fgcolor);
++
++
++#endif /* _VIDEO_FBCON_IPLAN2P4_H */
+diff -urN linux-m68k/drivers/video/atafb_iplan2p8.c linux-schmitz/drivers/video/atafb_iplan2p8.c
+--- linux-m68k/drivers/video/atafb_iplan2p8.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-schmitz/drivers/video/atafb_iplan2p8.c	2006-11-19 21:37:27.000000000 +0100
+@@ -0,0 +1,396 @@
++/*
++ *  linux/drivers/video/iplan2p8.c -- Low level frame buffer operations for
++ *				      interleaved bitplanes à la Atari (8
++ *				      planes, 2 bytes interleave)
++ *
++ *	Created 5 Apr 1997 by Geert Uytterhoeven
++ *
++ *  This file is subject to the terms and conditions of the GNU General Public
++ *  License.  See the file COPYING in the main directory of this archive for
++ *  more details.
++ */
++
++#include <linux/module.h>
++#include <linux/tty.h>
++#include <linux/console.h>
++#include <linux/string.h>
++#include <linux/fb.h>
++
++#include <asm/byteorder.h>
++
++#ifdef __mc68000__
++#include <asm/setup.h>
++#endif
++
++#include "console/fbcon.h"
++#include "atafb_utils.h"
++#include "atafb_iplan2p8.h"
++
++
++    /*
++     *  Interleaved bitplanes à la Atari (8 planes, 2 bytes interleave)
++     *
++     *  In 8 plane mode, 256 colors would be possible, but only the first
++     *  16 are used by the console code (the upper 4 bits are
++     *  background/unused). For that, the following functions mask off the
++     *  higher 4 bits of each color.
++     */
++
++/* Increment/decrement 8 plane addresses */
++
++#define	INC_8P(p)	do { if (!((long)(++(p)) & 1)) (p) += 14; } while(0)
++#define	DEC_8P(p)	do { if ((long)(--(p)) & 1) (p) -= 12; } while(0)
++
++/* Perform the m68k movepl operation extended to 64 bits.  */
++static inline void movepl2(u8 *d, u32 val1, u32 val2)
++{
++#if defined __mc68000__ && !defined CPU_M68060_ONLY
++    asm volatile ("movepl %1,%0@(0); movepl %2,%0@(8)"
++		  : : "a" (d), "d" (val1), "d" (val2));
++#else
++    d[0] = (val1 >> 24) & 0xff;
++    d[2] = (val1 >> 16) & 0xff;
++    d[4] = (val1 >> 8) & 0xff;
++    d[6] = val1 & 0xff;
++    d[8] = (val2 >> 24) & 0xff;
++    d[10] = (val2 >> 16) & 0xff;
++    d[12] = (val2 >> 8) & 0xff;
++    d[14] = val2 & 0xff;
++#endif
++}
++
++/* Sets the bytes in the visible column at d, height h, to the value
++ * val1,val2 for a 8 plane screen. The bits of the color in 'color' are
++ * moved (8 times) to the respective bytes. This means:
++ *
++ * for(h times; d += bpr)
++ *   *d      = (color & 1) ? 0xff : 0;
++ *   *(d+2)  = (color & 2) ? 0xff : 0;
++ *   *(d+4)  = (color & 4) ? 0xff : 0;
++ *   *(d+6)  = (color & 8) ? 0xff : 0;
++ *   *(d+8)  = (color & 16) ? 0xff : 0;
++ *   *(d+10) = (color & 32) ? 0xff : 0;
++ *   *(d+12) = (color & 64) ? 0xff : 0;
++ *   *(d+14) = (color & 128) ? 0xff : 0;
++ */
++
++static __inline__ void memclear_8p_col(void *d, size_t h, u32 val1,
++                                       u32 val2, int bpr)
++{
++    u8 *dd = d;
++    do {
++	movepl2(dd, val1, val2);
++	dd += bpr;
++    } while (--h);
++}
++
++/* Sets a 8 plane region from 'd', length 'count' bytes, to the color
++ * val1..val4. 'd' has to be an even address and count must be divisible
++ * by 16, because only whole words and all planes are accessed. I.e.:
++ *
++ * for(count/16 times)
++ *   *d      = *(d+1)  = (color & 1) ? 0xff : 0;
++ *   *(d+2)  = *(d+3)  = (color & 2) ? 0xff : 0;
++ *   *(d+4)  = *(d+5)  = (color & 4) ? 0xff : 0;
++ *   *(d+6)  = *(d+7)  = (color & 8) ? 0xff : 0;
++ *   *(d+8)  = *(d+9)  = (color & 16) ? 0xff : 0;
++ *   *(d+10) = *(d+11) = (color & 32) ? 0xff : 0;
++ *   *(d+12) = *(d+13) = (color & 64) ? 0xff : 0;
++ *   *(d+14) = *(d+15) = (color & 128) ? 0xff : 0;
++ */
++
++static __inline__ void memset_even_8p(void *d, size_t count, u32 val1,
++                                      u32 val2, u32 val3, u32 val4)
++{
++    u32 *dd = d;
++
++    count /= 16;
++    while (count--) {
++	*dd++ = val1;
++	*dd++ = val2;
++	*dd++ = val3;
++	*dd++ = val4;
++    }
++}
++
++/* Copies a 8 plane column from 's', height 'h', to 'd'. */
++
++static __inline__ void memmove_8p_col (void *d, void *s, int h, int bpr)
++{
++    u8 *dd = d, *ss = s;
++
++    while (h--) {
++	dd[0] = ss[0];
++	dd[2] = ss[2];
++	dd[4] = ss[4];
++	dd[6] = ss[6];
++	dd[8] = ss[8];
++	dd[10] = ss[10];
++	dd[12] = ss[12];
++	dd[14] = ss[14];
++	dd += bpr;
++	ss += bpr;
++    }
++}
++
++
++/* This expands a 8 bit color into two longs for two movepl (8 plane)
++ * operations.
++ */
++
++static const u32 four2long[] =
++{
++    0x00000000, 0xff000000, 0x00ff0000, 0xffff0000,
++    0x0000ff00, 0xff00ff00, 0x00ffff00, 0xffffff00,
++    0x000000ff, 0xff0000ff, 0x00ff00ff, 0xffff00ff,
++    0x0000ffff, 0xff00ffff, 0x00ffffff, 0xffffffff,
++};
++
++static __inline__ void expand8dl(u8 c, u32 *ret1, u32 *ret2)
++{
++    *ret1 = four2long[c & 15];
++    *ret2 = four2long[c >> 4];
++}
++
++
++/* This expands a 8 bit color into four longs for four movel operations
++ * (8 planes).
++ */
++
++static const u32 two2word[] =
++{
++#ifndef __LITTLE_ENDIAN
++    0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
++#else
++    0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
++#endif
++};
++
++static inline void expand8ql(u8 c, u32 *rv1, u32 *rv2, u32 *rv3, u32 *rv4)
++{
++    *rv1 = two2word[c & 4];
++    *rv2 = two2word[(c >> 2) & 4];
++    *rv3 = two2word[(c >> 4) & 4];
++    *rv4 = two2word[c >> 6];
++}
++
++
++/* This duplicates a byte 4 times into a long. */
++
++static __inline__ u32 dup4l(u8 c)
++{
++    u32 rv;
++
++    rv = c;
++    rv |= rv << 8;
++    rv |= rv << 16;
++    return rv;
++}
++
++
++void atafb_iplan2p8_copyarea(struct fb_info *info, u_long next_line,
++                             int sy, int sx, int dy, int dx,
++			     int height, int width)
++{
++    /*  bmove() has to distinguish two major cases: If both, source and
++     *  destination, start at even addresses or both are at odd
++     *  addresses, just the first odd and last even column (if present)
++     *  require special treatment (memmove_col()). The rest between
++     *  then can be copied by normal operations, because all adjacent
++     *  bytes are affected and are to be stored in the same order.
++     *    The pathological case is when the move should go from an odd
++     *  address to an even or vice versa. Since the bytes in the plane
++     *  words must be assembled in new order, it seems wisest to make
++     *  all movements by memmove_col().
++     */
++
++     printk("copyarea: dx %d dy %d sx %d sy %d\n", dx, dy, sy, sy);
++
++     if (sx == 0 && dx == 0 && width * 8 == next_line) {
++	/*  Special (but often used) case: Moving whole lines can be
++	 *  done with memmove()
++	 */
++	fast_memmove((u8 *)info->screen_base + dy * next_line,
++                     (u8 *)info->screen_base + sy * next_line,
++                      next_line * height);
++     } else {
++	int rows, cols;
++	u8 *src;
++	u8 *dst;
++	int bytes = next_line;
++	int linesize;
++	u_int colsize;
++	u_int upwards = (dy < sy) || (dy == sy && dx < sx);
++
++        linesize = bytes;
++        colsize = height;
++	if ((sx & 1) == (dx & 1)) {
++	    /* odd->odd or even->even */
++
++	    if (upwards) {
++		src = (u8 *)info->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1);
++		dst = (u8 *)info->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1);
++		if (sx & 1) {
++		    memmove_8p_col(dst, src, colsize, bytes);
++		    src += 15;
++		    dst += 15;
++		    --width;
++		}
++		if (width > 1) {
++		    for(rows = colsize; rows > 0; --rows) {
++			fast_memmove (dst, src, (width >> 1) * 16);
++			src += bytes;
++			dst += bytes;
++		    }
++		}
++
++		if (width & 1) {
++		    src -= colsize * bytes;
++		    dst -= colsize * bytes;
++		    memmove_8p_col(dst + (width>>1)*16, src + (width>>1)*16,
++		    colsize, bytes);
++		}
++	    } else {
++		if (!((sx+width-1) & 1)) {
++		    src = (u8 *)info->screen_base + sy * linesize + ((sx+width-1)>>1)*16;
++		    dst = (u8 *)info->screen_base + dy * linesize + ((dx+width-1)>>1)*16;
++		    memmove_8p_col(dst, src, colsize, bytes);
++		    --width;
++		}
++		src = (u8 *)info->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1);
++		dst = (u8 *)info->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1);
++		if (width > 1) {
++		    src += colsize * bytes + (sx & 1)*15;
++		    dst += colsize * bytes + (sx & 1)*15;
++		    for(rows = colsize; rows > 0; --rows) {
++			src -= bytes;
++			dst -= bytes;
++			fast_memmove (dst, src, (width>>1)*16);
++		    }
++		}
++		if (width & 1)
++		    memmove_8p_col(dst-15, src-15, colsize, bytes);
++	    }
++	} else {
++	/* odd->even or even->odd */
++
++	    if (upwards) {
++		src = (u8 *)info->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1);
++		dst = (u8 *)info->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1);
++		for(cols = width; cols > 0; --cols) {
++		    memmove_8p_col(dst, src, colsize, bytes);
++		    INC_8P(src);
++		    INC_8P(dst);
++		}
++	    } else {
++		sx += width-1;
++		dx += width-1;
++		src = (u8 *)info->screen_base + sy * linesize + (sx>>1)*16 + (sx & 1);
++		dst = (u8 *)info->screen_base + dy * linesize + (dx>>1)*16 + (dx & 1);
++		for(cols = width; cols > 0; --cols) {
++		    memmove_8p_col(dst, src, colsize, bytes);
++		    DEC_8P(src);
++		    DEC_8P(dst);
++		}
++	    }
++	}
++    }
++}
++
++void atafb_iplan2p8_fillrect(struct fb_info *info, u_long next_line, u32 color, 
++                             int sy, int sx, int height, int width)
++{
++    u32 offset;
++    u8 *start;
++    int rows;
++    int bytes = next_line;
++    int lines;
++    u32 size;
++    u32 cval1, cval2, cval3, cval4, pcval1, pcval2;
++
++    expand8ql(color, &cval1, &cval2, &cval3, &cval4);
++
++    lines = height;
++
++    if (sx == 0 && width * 8 == bytes) {
++        offset = (sy * bytes);
++	size    = lines * bytes;
++	memset_even_8p((u8 *)info->screen_base + offset, size, cval1, cval2, cval3, cval4);
++    } else {
++        offset = sy * bytes + (sx>>1)*2 + (sx & 1);
++	start = (u8 *) info->screen_base + offset;
++	expand8dl(color, &pcval1, &pcval2);
++
++	/* Clears are split if the region starts at an odd column or
++	* end at an even column. These extra columns are spread
++	* across the interleaved planes. All in between can be
++	* cleared by normal fb_memclear_small(), because both bytes of
++	* the single plane words are affected.
++	*/
++
++	if (sx & 1) {
++	    memclear_8p_col(start, lines, pcval1, pcval2, bytes);
++	    start += 7;
++	    width--;
++	}
++	if (width & 1) {
++	    memclear_8p_col(start + (width>>1)*2, lines, pcval1,
++	    pcval2, bytes);
++	    width--;
++	}
++	if (width)
++	    for(rows = lines; rows-- ; start += bytes)
++		memset_even_8p(start, width, cval1, cval2, cval3, cval4);
++	}
++}
++
++void atafb_iplan2p8_linefill(struct fb_info *info, u_long next_line,
++                             int dy, int dx, u32 width,
++                             const u8 *data, u32 bgcolor, u32 fgcolor)
++{
++    u8 *dest;
++    u8 *cdat;
++    int rows;
++    int bytes = next_line;
++    u32 eorx1, eorx2, fgx1, fgx2, bgx1, bgx2, fdx;
++
++    // source data
++    cdat = data;
++
++    // advance from odd to even (dx>>3) by 16
++    // dest = (p->screen_base + yy * bytes + (xx>>1)*16 + (xx & 1));
++
++
++    dest = (u8*) info->screen_base + dy * bytes + (dx>>4)*16 + ((dx>>3)&1);
++
++    expand8dl(fgcolor, &fgx1, &fgx2);
++    expand8dl(bgcolor, &bgx1, &bgx2);
++    eorx1 = fgx1 ^ bgx1; eorx2  = fgx2 ^ bgx2;
++
++      for(rows = width/8; rows-- ;) {
++	fdx = dup4l(*cdat++);
++	movepl2(dest, (fdx & eorx1) ^ bgx1, (fdx & eorx2) ^ bgx2);
++	INC_8P(dest);
++      }
++}
++
++#ifdef MODULE
++MODULE_LICENSE("GPL");
++
++int init_module(void)
++{
++    return 0;
++}
++
++void cleanup_module(void)
++{}
++#endif /* MODULE */
++
++
++    /*
++     *  Visible symbols for modules
++     */
++
++EXPORT_SYMBOL(atafb_iplan2p8_copyarea);
++EXPORT_SYMBOL(atafb_iplan2p8_fillrect);
++EXPORT_SYMBOL(atafb_iplan2p8_linefill);
+diff -urN linux-m68k/drivers/video/atafb_iplan2p8.h linux-schmitz/drivers/video/atafb_iplan2p8.h
+--- linux-m68k/drivers/video/atafb_iplan2p8.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-schmitz/drivers/video/atafb_iplan2p8.h	2006-11-19 21:37:27.000000000 +0100
+@@ -0,0 +1,27 @@
++/*
++ *  FBcon low-level driver for Atari interleaved bitplanes (8 planes) (iplan2p8)
++ */
++
++#ifndef _VIDEO_FBCON_IPLAN2P8_H
++#define _VIDEO_FBCON_IPLAN2P8_H
++
++#ifdef MODULE
++#if defined(CONFIG_FBCON_IPLAN2P8) || defined(CONFIG_FBCON_IPLAN2P8_MODULE)
++#define FBCON_HAS_IPLAN2P8
++#endif
++#else
++#if defined(CONFIG_FBCON_IPLAN2P8)
++#define FBCON_HAS_IPLAN2P8
++#endif
++#endif
++
++extern void atafb_iplan2p8_copyarea(struct fb_info *info, u_long next_line, int sy, int sx, int dy,
++				    int dx, int height, int width);
++extern void atafb_iplan2p8_fillrect(struct fb_info *info, u_long next_line, u32 color,
++				    int sy, int sx, int height, int width);
++extern void atafb_iplan2p8_linefill(struct fb_info *info, u_long next_line,
++                                    int dy, int dx, u32 width,
++                                    const u8 *data, u32 bgcolor, u32 fgcolor);
++
++
++#endif /* _VIDEO_FBCON_IPLAN2P8_H */
+diff -urN linux-m68k/drivers/video/atafb_mfb.c linux-schmitz/drivers/video/atafb_mfb.c
+--- linux-m68k/drivers/video/atafb_mfb.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-schmitz/drivers/video/atafb_mfb.c	2006-11-19 21:37:27.000000000 +0100
+@@ -0,0 +1,115 @@
++/*
++ *  linux/drivers/video/mfb.c -- Low level frame buffer operations for
++ *				 monochrome
++ *
++ *	Created 5 Apr 1997 by Geert Uytterhoeven
++ *
++ *  This file is subject to the terms and conditions of the GNU General Public
++ *  License.  See the file COPYING in the main directory of this archive for
++ *  more details.
++ */
++
++#include <linux/module.h>
++#include <linux/tty.h>
++#include <linux/console.h>
++#include <linux/string.h>
++#include <linux/fb.h>
++
++#include "console/fbcon.h"
++#include "atafb_utils.h"
++#include "atafb_mfb.h"
++
++
++    /*
++     *  Monochrome
++     */
++
++void atafb_mfb_copyarea(struct fb_info *info, u_long next_line, 
++                        int sy, int sx, int dy, int dx,
++                        int height, int width)
++{
++    u8 *src, *dest;
++    u_int rows;
++
++    if (sx == 0 && dx == 0 && width == next_line) {
++	src = (u8 *)info->screen_base+sy*(width>>3);
++	dest = (u8 *)info->screen_base+dy*(width>>3);
++	fb_memmove(dest, src, height*(width>>3));
++    } else if (dy <= sy) {
++	src = (u8 *)info->screen_base+sy*next_line+(sx>>3);
++	dest = (u8 *)info->screen_base+dy*next_line+(dx>>3);
++	for (rows = height; rows--;) {
++	    fb_memmove(dest, src, (width>>3));
++	    src += next_line;
++	    dest += next_line;
++	}
++    } else {
++	src = (u8 *)info->screen_base+((sy+height)-1)*next_line+(sx>>3);
++	dest = (u8 *)info->screen_base+((dy+height)-1)*next_line+(dx>>3);
++	for (rows = height; rows--;) {
++	    fb_memmove(dest, src, (width>>3));
++	    src -= next_line;
++	    dest -= next_line;
++	}
++    }
++}
++
++void atafb_mfb_fillrect(struct fb_info *info, u_long next_line, u32 color, 
++                        int sy, int sx,
++                        int height, int width)
++{
++    u8 *dest;
++    u_int rows;
++
++    dest = (u8 *)info->screen_base+sy*next_line+(sx>>3);
++
++    if (sx == 0 && width == next_line) {
++	if (color)
++	    fb_memset255(dest, height*(width>>3));
++	else
++	    fb_memclear(dest, height*(width>>3));
++    } else
++	for (rows = height; rows--; dest += next_line)
++	    if (color)
++		fb_memset255(dest, (width>>3));
++	    else
++		fb_memclear_small(dest, (width>>3));
++}
++
++void atafb_mfb_linefill(struct fb_info *info, u_long next_line,
++                        int dy, int dx, u32 width,
++                        const u8 *data, u32 bgcolor, u32 fgcolor)
++{
++    u8 *dest, *cdat;
++    u_int rows;
++    u8 d;
++
++    dest = (u8*) info->screen_base+dy*next_line+(dx>>3) + (dx & 1);
++    cdat = data;
++
++    for (rows = width/8; rows--; /* check margins */ ) {
++        // use fast_memmove or fb_memmove
++	*dest++ = *cdat++;
++    }
++}
++
++#ifdef MODULE
++MODULE_LICENSE("GPL");
++
++int init_module(void)
++{
++    return 0;
++}
++
++void cleanup_module(void)
++{}
++#endif /* MODULE */
++
++
++    /*
++     *  Visible symbols for modules
++     */
++
++EXPORT_SYMBOL(atafb_mfb_copyarea);
++EXPORT_SYMBOL(atafb_mfb_fillrect);
++EXPORT_SYMBOL(atafb_mfb_linefill);
+diff -urN linux-m68k/drivers/video/atafb_mfb.h linux-schmitz/drivers/video/atafb_mfb.h
+--- linux-m68k/drivers/video/atafb_mfb.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-schmitz/drivers/video/atafb_mfb.h	2006-11-19 21:37:27.000000000 +0100
+@@ -0,0 +1,26 @@
++/*
++ *  FBcon low-level driver for Monochrome (mfb)
++ */
++
++#ifndef _VIDEO_FBCON_MFB_H
++#define _VIDEO_FBCON_MFB_H
++
++#ifdef MODULE
++#if defined(CONFIG_FBCON_MFB) || defined(CONFIG_FBCON_MFB_MODULE)
++#define FBCON_HAS_MFB
++#endif
++#else
++#if defined(CONFIG_FBCON_MFB)
++#define FBCON_HAS_MFB
++#endif
++#endif
++
++extern void atafb_mfb_copyarea(struct fb_info *info, u_long next_line, int sy, int sx, int dy,
++			       int dx, int height, int width);
++extern void atafb_mfb_fillrect(struct fb_info *info, u_long next_line, u32 color,
++			       int sy, int sx, int height, int width);
++extern void atafb_mfb_linefill(struct fb_info *info, u_long next_line,
++                               int dy, int dx, u32 width,
++                               const u8 *data, u32 bgcolor, u32 fgcolor);
++
++#endif /* _VIDEO_FBCON_MFB_H */
+diff -urN linux-m68k/drivers/video/atafb_utils.h linux-schmitz/drivers/video/atafb_utils.h
+--- linux-m68k/drivers/video/atafb_utils.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-schmitz/drivers/video/atafb_utils.h	2006-11-19 21:37:27.000000000 +0100
+@@ -0,0 +1,570 @@
++#ifndef _VIDEO_ATAFB_UTILS_H
++#define _VIDEO_ATAFB_UTILS_H
++
++/* ================================================================= */
++/*                      Utility Assembler Functions                  */
++/* ================================================================= */
++
++
++#if defined(__mc68000__)
++
++/* ====================================================================== */
++
++/* Those of a delicate disposition might like to skip the next couple of
++ * pages.
++ *
++ * These functions are drop in replacements for memmove and
++ * memset(_, 0, _). However their five instances add at least a kilobyte
++ * to the object file. You have been warned.
++ *
++ * Not a great fan of assembler for the sake of it, but I think
++ * that these routines are at least 10 times faster than their C
++ * equivalents for large blits, and that's important to the lowest level of
++ * a graphics driver. Question is whether some scheme with the blitter
++ * would be faster. I suspect not for simple text system - not much
++ * asynchrony.
++ *
++ * Code is very simple, just gruesome expansion. Basic strategy is to
++ * increase data moved/cleared at each step to 16 bytes to reduce
++ * instruction per data move overhead. movem might be faster still
++ * For more than 15 bytes, we try to align the write direction on a
++ * longword boundary to get maximum speed. This is even more gruesome.
++ * Unaligned read/write used requires 68020+ - think this is a problem?
++ *
++ * Sorry!
++ */
++
++
++/* ++roman: I've optimized Robert's original versions in some minor
++ * aspects, e.g. moveq instead of movel, let gcc choose the registers,
++ * use movem in some places...
++ * For other modes than 1 plane, lots of more such assembler functions
++ * were needed (e.g. the ones using movep or expanding color values).
++ */
++
++/* ++andreas: more optimizations:
++   subl #65536,d0 replaced by clrw d0; subql #1,d0 for dbcc
++   addal is faster than addaw
++   movep is rather expensive compared to ordinary move's
++   some functions rewritten in C for clarity, no speed loss */
++
++static __inline__ void *fb_memclear_small(void *s, size_t count)
++{
++   if (!count)
++      return(0);
++
++   __asm__ __volatile__(
++         "lsrl   #1,%1 ; jcc 1f ; moveb %2,%0 at -\n\t"
++      "1: lsrl   #1,%1 ; jcc 1f ; movew %2,%0 at -\n\t"
++      "1: lsrl   #1,%1 ; jcc 1f ; movel %2,%0 at -\n\t"
++      "1: lsrl   #1,%1 ; jcc 1f ; movel %2,%0 at - ; movel %2,%0 at -\n\t"
++      "1:"
++         : "=a" (s), "=d" (count)
++         : "d" (0), "0" ((char *)s+count), "1" (count)
++   );
++   __asm__ __volatile__(
++         "subql  #1,%1 ; jcs 3f\n\t"
++	 "movel %2,%%d4; movel %2,%%d5; movel %2,%%d6\n\t"
++      "2: moveml %2/%%d4/%%d5/%%d6,%0 at -\n\t"
++         "dbra %1,2b\n\t"
++      "3:"
++         : "=a" (s), "=d" (count)
++         : "d" (0), "0" (s), "1" (count)
++	 : "d4", "d5", "d6"
++  );
++
++   return(0);
++}
++
++
++static __inline__ void *fb_memclear(void *s, size_t count)
++{
++   if (!count)
++      return(0);
++
++   if (count < 16) {
++      __asm__ __volatile__(
++            "lsrl   #1,%1 ; jcc 1f ; clrb %0 at +\n\t"
++         "1: lsrl   #1,%1 ; jcc 1f ; clrw %0 at +\n\t"
++         "1: lsrl   #1,%1 ; jcc 1f ; clrl %0 at +\n\t"
++         "1: lsrl   #1,%1 ; jcc 1f ; clrl %0 at + ; clrl %0 at +\n\t"
++         "1:"
++            : "=a" (s), "=d" (count)
++            : "0" (s), "1" (count)
++     );
++   } else {
++      long tmp;
++      __asm__ __volatile__(
++            "movel %1,%2\n\t"
++            "lsrl   #1,%2 ; jcc 1f ; clrb %0 at + ; subqw #1,%1\n\t"
++            "lsrl   #1,%2 ; jcs 2f\n\t"  /* %0 increased=>bit 2 switched*/
++            "clrw   %0 at +  ; subqw  #2,%1 ; jra 2f\n\t"
++         "1: lsrl   #1,%2 ; jcc 2f\n\t"
++            "clrw   %0 at +  ; subqw  #2,%1\n\t"
++         "2: movew %1,%2; lsrl #2,%1 ; jeq 6f\n\t"
++            "lsrl   #1,%1 ; jcc 3f ; clrl %0 at +\n\t"
++         "3: lsrl   #1,%1 ; jcc 4f ; clrl %0 at + ; clrl %0 at +\n\t"
++         "4: subql  #1,%1 ; jcs 6f\n\t"
++         "5: clrl %0 at +; clrl %0 at + ; clrl %0 at + ; clrl %0 at +\n\t"
++            "dbra %1,5b   ; clrw %1; subql #1,%1; jcc 5b\n\t"
++         "6: movew %2,%1; btst #1,%1 ; jeq 7f ; clrw %0 at +\n\t"
++         "7:            ; btst #0,%1 ; jeq 8f ; clrb %0 at +\n\t"
++         "8:"
++            : "=a" (s), "=d" (count), "=d" (tmp)
++            : "0" (s), "1" (count)
++     );
++   }
++
++   return(0);
++}
++
++
++static __inline__ void *fb_memset255(void *s, size_t count)
++{
++   if (!count)
++      return(0);
++
++   __asm__ __volatile__(
++         "lsrl   #1,%1 ; jcc 1f ; moveb %2,%0 at -\n\t"
++      "1: lsrl   #1,%1 ; jcc 1f ; movew %2,%0 at -\n\t"
++      "1: lsrl   #1,%1 ; jcc 1f ; movel %2,%0 at -\n\t"
++      "1: lsrl   #1,%1 ; jcc 1f ; movel %2,%0 at - ; movel %2,%0 at -\n\t"
++      "1:"
++         : "=a" (s), "=d" (count)
++         : "d" (-1), "0" ((char *)s+count), "1" (count)
++   );
++   __asm__ __volatile__(
++         "subql  #1,%1 ; jcs 3f\n\t"
++	 "movel %2,%%d4; movel %2,%%d5; movel %2,%%d6\n\t"
++      "2: moveml %2/%%d4/%%d5/%%d6,%0 at -\n\t"
++         "dbra %1,2b\n\t"
++      "3:"
++         : "=a" (s), "=d" (count)
++         : "d" (-1), "0" (s), "1" (count)
++	 : "d4", "d5", "d6"
++  );
++
++   return(0);
++}
++
++
++static __inline__ void *fb_memmove(void *d, const void *s, size_t count)
++{
++   if (d < s) {
++      if (count < 16) {
++         __asm__ __volatile__(
++               "lsrl   #1,%2 ; jcc 1f ; moveb %1 at +,%0 at +\n\t"
++            "1: lsrl   #1,%2 ; jcc 1f ; movew %1 at +,%0 at +\n\t"
++            "1: lsrl   #1,%2 ; jcc 1f ; movel %1 at +,%0 at +\n\t"
++            "1: lsrl   #1,%2 ; jcc 1f ; movel %1 at +,%0 at + ; movel %1 at +,%0 at +\n\t"
++            "1:"
++               : "=a" (d), "=a" (s), "=d" (count)
++               : "0" (d), "1" (s), "2" (count)
++        );
++      } else {
++         long tmp;
++         __asm__ __volatile__(
++               "movel  %0,%3\n\t"
++               "lsrl   #1,%3 ; jcc 1f ; moveb %1 at +,%0 at + ; subqw #1,%2\n\t"
++               "lsrl   #1,%3 ; jcs 2f\n\t"  /* %0 increased=>bit 2 switched*/
++               "movew  %1 at +,%0 at +  ; subqw  #2,%2 ; jra 2f\n\t"
++            "1: lsrl   #1,%3 ; jcc 2f\n\t"
++               "movew  %1 at +,%0 at +  ; subqw  #2,%2\n\t"
++            "2: movew  %2,%-; lsrl #2,%2 ; jeq 6f\n\t"
++               "lsrl   #1,%2 ; jcc 3f ; movel %1 at +,%0 at +\n\t"
++            "3: lsrl   #1,%2 ; jcc 4f ; movel %1 at +,%0 at + ; movel %1 at +,%0 at +\n\t"
++            "4: subql  #1,%2 ; jcs 6f\n\t"
++            "5: movel  %1 at +,%0 at +;movel %1 at +,%0 at +\n\t"
++               "movel  %1 at +,%0 at +;movel %1 at +,%0 at +\n\t"
++               "dbra   %2,5b ; clrw %2; subql #1,%2; jcc 5b\n\t"
++            "6: movew  %+,%2; btst #1,%2 ; jeq 7f ; movew %1 at +,%0 at +\n\t"
++            "7:              ; btst #0,%2 ; jeq 8f ; moveb %1 at +,%0 at +\n\t"
++            "8:"
++               : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp)
++               : "0" (d), "1" (s), "2" (count)
++        );
++      }
++   } else {
++      if (count < 16) {
++         __asm__ __volatile__(
++               "lsrl   #1,%2 ; jcc 1f ; moveb %1 at -,%0 at -\n\t"
++            "1: lsrl   #1,%2 ; jcc 1f ; movew %1 at -,%0 at -\n\t"
++            "1: lsrl   #1,%2 ; jcc 1f ; movel %1 at -,%0 at -\n\t"
++            "1: lsrl   #1,%2 ; jcc 1f ; movel %1 at -,%0 at - ; movel %1 at -,%0 at -\n\t"
++            "1:"
++               : "=a" (d), "=a" (s), "=d" (count)
++               : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count)
++        );
++      } else {
++         long tmp;
++         __asm__ __volatile__(
++               "movel %0,%3\n\t"
++               "lsrl   #1,%3 ; jcc 1f ; moveb %1 at -,%0 at - ; subqw #1,%2\n\t"
++               "lsrl   #1,%3 ; jcs 2f\n\t"  /* %0 increased=>bit 2 switched*/
++               "movew  %1 at -,%0 at -  ; subqw  #2,%2 ; jra 2f\n\t"
++            "1: lsrl   #1,%3 ; jcc 2f\n\t"
++               "movew  %1 at -,%0 at -  ; subqw  #2,%2\n\t"
++            "2: movew %2,%-; lsrl #2,%2 ; jeq 6f\n\t"
++               "lsrl   #1,%2 ; jcc 3f ; movel %1 at -,%0 at -\n\t"
++            "3: lsrl   #1,%2 ; jcc 4f ; movel %1 at -,%0 at - ; movel %1 at -,%0 at -\n\t"
++            "4: subql  #1,%2 ; jcs 6f\n\t"
++            "5: movel %1 at -,%0 at -;movel %1 at -,%0 at -\n\t"
++               "movel %1 at -,%0 at -;movel %1 at -,%0 at -\n\t"
++               "dbra %2,5b ; clrw %2; subql #1,%2; jcc 5b\n\t"
++            "6: movew %+,%2; btst #1,%2 ; jeq 7f ; movew %1 at -,%0 at -\n\t"
++            "7:              ; btst #0,%2 ; jeq 8f ; moveb %1 at -,%0 at -\n\t"
++            "8:"
++               : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp)
++               : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count)
++        );
++      }
++   }
++
++   return(0);
++}
++
++
++/* ++andreas: Simple and fast version of memmove, assumes size is
++   divisible by 16, suitable for moving the whole screen bitplane */
++static __inline__ void fast_memmove(char *dst, const char *src, size_t size)
++{
++  if (!size)
++    return;
++  if (dst < src)
++    __asm__ __volatile__
++      ("1:"
++       "  moveml %0 at +,%/d0/%/d1/%/a0/%/a1\n"
++       "  moveml %/d0/%/d1/%/a0/%/a1,%1@\n"
++       "  addql #8,%1; addql #8,%1\n"
++       "  dbra %2,1b\n"
++       "  clrw %2; subql #1,%2\n"
++       "  jcc 1b"
++       : "=a" (src), "=a" (dst), "=d" (size)
++       : "0" (src), "1" (dst), "2" (size / 16 - 1)
++       : "d0", "d1", "a0", "a1", "memory");
++  else
++    __asm__ __volatile__
++      ("1:"
++       "  subql #8,%0; subql #8,%0\n"
++       "  moveml %0@,%/d0/%/d1/%/a0/%/a1\n"
++       "  moveml %/d0/%/d1/%/a0/%/a1,%1 at -\n"
++       "  dbra %2,1b\n"
++       "  clrw %2; subql #1,%2\n"
++       "  jcc 1b"
++       : "=a" (src), "=a" (dst), "=d" (size)
++       : "0" (src + size), "1" (dst + size), "2" (size / 16 - 1)
++       : "d0", "d1", "a0", "a1", "memory");
++}
++
++#elif defined(CONFIG_SUN4)
++
++/* You may think that I'm crazy and that I should use generic
++   routines.  No, I'm not: sun4's framebuffer crashes if we std
++   into it, so we cannot use memset.  */
++
++static __inline__ void *sun4_memset(void *s, char val, size_t count)
++{
++    int i;
++    for(i=0; i<count;i++)
++        ((char *) s) [i] = val;
++    return s;
++}
++
++static __inline__ void *fb_memset255(void *s, size_t count)
++{
++    return sun4_memset(s, 255, count);
++}
++
++static __inline__ void *fb_memclear(void *s, size_t count)
++{
++    return sun4_memset(s, 0, count);
++}
++
++static __inline__ void *fb_memclear_small(void *s, size_t count)
++{
++    return sun4_memset(s, 0, count);
++}
++
++/* To be honest, this is slow_memmove :). But sun4 is crappy, so what we can do. */
++static __inline__ void fast_memmove(void *d, const void *s, size_t count)
++{
++    int i;
++    if (d<s) {
++	for (i=0; i<count; i++)
++	    ((char *) d)[i] = ((char *) s)[i];
++    } else
++	for (i=0; i<count; i++)
++	    ((char *) d)[count-i-1] = ((char *) s)[count-i-1];
++}
++
++static __inline__ void *fb_memmove(char *dst, const char *src, size_t size)
++{
++    fast_memmove(dst, src, size);
++    return dst;
++}
++
++#else
++
++static __inline__ void *fb_memclear_small(void *s, size_t count)
++{
++    char *xs = (char *) s;
++
++    while (count--)
++	fb_writeb(0, xs++);
++
++    return s;
++}
++
++static __inline__ void *fb_memclear(void *s, size_t count)
++{
++    unsigned long xs = (unsigned long) s;
++
++    if (count < 8)
++	goto rest;
++
++    if (xs & 1) {
++	fb_writeb(0, xs++);
++	count--;
++    }
++    if (xs & 2) {
++	fb_writew(0, xs);
++	xs += 2;
++	count -= 2;
++    }
++    while (count > 3) {
++	fb_writel(0, xs);
++	xs += 4;
++	count -= 4;
++    }
++rest:
++    while (count--)
++	fb_writeb(0, xs++);
++
++    return s;
++}
++
++static __inline__ void *fb_memset255(void *s, size_t count)
++{
++    unsigned long xs = (unsigned long) s;
++
++    if (count < 8)
++	goto rest;
++
++    if (xs & 1) {
++	fb_writeb(0xff, xs++);
++	count--;
++    }
++    if (xs & 2) {
++	fb_writew(0xffff, xs);
++	xs += 2;
++	count -= 2;
++    }
++    while (count > 3) {
++	fb_writel(0xffffffff, xs);
++	xs += 4;
++	count -= 4;
++    }
++rest:
++    while (count--)
++	fb_writeb(0xff, xs++);
++
++    return s;
++}
++
++#if defined(__i386__)
++
++static __inline__ void fast_memmove(void *d, const void *s, size_t count)
++{
++  int d0, d1, d2, d3;
++    if (d < s) {
++__asm__ __volatile__ (
++	"cld\n\t"
++	"shrl $1,%%ecx\n\t"
++	"jnc 1f\n\t"
++	"movsb\n"
++	"1:\tshrl $1,%%ecx\n\t"
++	"jnc 2f\n\t"
++	"movsw\n"
++	"2:\trep\n\t"
++	"movsl"
++	: "=&c" (d0), "=&D" (d1), "=&S" (d2)
++	:"0"(count),"1"((long)d),"2"((long)s)
++	:"memory");
++    } else {
++__asm__ __volatile__ (
++	"std\n\t"
++	"shrl $1,%%ecx\n\t"
++	"jnc 1f\n\t"
++	"movb 3(%%esi),%%al\n\t"
++	"movb %%al,3(%%edi)\n\t"
++	"decl %%esi\n\t"
++	"decl %%edi\n"
++	"1:\tshrl $1,%%ecx\n\t"
++	"jnc 2f\n\t"
++	"movw 2(%%esi),%%ax\n\t"
++	"movw %%ax,2(%%edi)\n\t"
++	"decl %%esi\n\t"
++	"decl %%edi\n\t"
++	"decl %%esi\n\t"
++	"decl %%edi\n"
++	"2:\trep\n\t"
++	"movsl\n\t"
++	"cld"
++	: "=&c" (d0), "=&D" (d1), "=&S" (d2), "=&a" (d3)
++	:"0"(count),"1"(count-4+(long)d),"2"(count-4+(long)s)
++	:"memory");
++    }
++}
++
++static __inline__ void *fb_memmove(char *dst, const char *src, size_t size)
++{
++    fast_memmove(dst, src, size);
++    return dst;
++}
++
++#else /* !__i386__ */
++
++    /*
++     *  Anyone who'd like to write asm functions for other CPUs?
++     *   (Why are these functions better than those from include/asm/string.h?)
++     */
++
++static __inline__ void *fb_memmove(void *d, const void *s, size_t count)
++{
++    unsigned long dst, src;
++
++    if (d < s) {
++	dst = (unsigned long) d;
++	src = (unsigned long) s;
++
++	if ((count < 8) || ((dst ^ src) & 3))
++	    goto restup;
++
++	if (dst & 1) {
++	    fb_writeb(fb_readb(src++), dst++);
++	    count--;
++	}
++	if (dst & 2) {
++	    fb_writew(fb_readw(src), dst);
++	    src += 2;
++	    dst += 2;
++	    count -= 2;
++	}
++	while (count > 3) {
++	    fb_writel(fb_readl(src), dst);
++	    src += 4;
++	    dst += 4;
++	    count -= 4;
++	}
++
++    restup:
++	while (count--)
++	    fb_writeb(fb_readb(src++), dst++);
++    } else {
++	dst = (unsigned long) d + count;
++	src = (unsigned long) s + count;
++
++	if ((count < 8) || ((dst ^ src) & 3))
++	    goto restdown;
++
++	if (dst & 1) {
++	    src--;
++	    dst--;
++	    count--;
++	    fb_writeb(fb_readb(src), dst);
++	}
++	if (dst & 2) {
++	    src -= 2;
++	    dst -= 2;
++	    count -= 2;
++	    fb_writew(fb_readw(src), dst);
++	}
++	while (count > 3) {
++	    src -= 4;
++	    dst -= 4;
++	    count -= 4;
++	    fb_writel(fb_readl(src), dst);
++	}
++
++    restdown:
++	while (count--) {
++	    src--;
++	    dst--;
++	    fb_writeb(fb_readb(src), dst);
++	}
++    }
++
++    return d;
++}
++
++static __inline__ void fast_memmove(char *d, const char *s, size_t count)
++{
++    unsigned long dst, src;
++
++    if (d < s) {
++	dst = (unsigned long) d;
++	src = (unsigned long) s;
++
++	if ((count < 8) || ((dst ^ src) & 3))
++	    goto restup;
++
++	if (dst & 1) {
++	    fb_writeb(fb_readb(src++), dst++);
++	    count--;
++	}
++	if (dst & 2) {
++	    fb_writew(fb_readw(src), dst);
++	    src += 2;
++	    dst += 2;
++	    count -= 2;
++	}
++	while (count > 3) {
++	    fb_writel(fb_readl(src), dst);
++	    src += 4;
++	    dst += 4;
++	    count -= 4;
++	}
++
++    restup:
++	while (count--)
++	    fb_writeb(fb_readb(src++), dst++);
++    } else {
++	dst = (unsigned long) d + count;
++	src = (unsigned long) s + count;
++
++	if ((count < 8) || ((dst ^ src) & 3))
++	    goto restdown;
++
++	if (dst & 1) {
++	    src--;
++	    dst--;
++	    count--;
++	    fb_writeb(fb_readb(src), dst);
++	}
++	if (dst & 2) {
++	    src -= 2;
++	    dst -= 2;
++	    count -= 2;
++	    fb_writew(fb_readw(src), dst);
++	}
++	while (count > 3) {
++	    src -= 4;
++	    dst -= 4;
++	    count -= 4;
++	    fb_writel(fb_readl(src), dst);
++	}
++
++    restdown:
++	while (count--) {
++	    src--;
++	    dst--;
++	    fb_writeb(fb_readb(src), dst);
++	}
++    }
++}
++
++#endif /* !__i386__ */
++
++#endif /* !__mc68000__ */
++
++#endif /* _VIDEO_ATAFB_UTILS_H */
+diff -urN linux-m68k/fs/fat/inode.c linux-schmitz/fs/fat/inode.c
+--- linux-m68k/fs/fat/inode.c	2006-11-19 21:35:33.000000000 +0100
++++ linux-schmitz/fs/fat/inode.c	2006-11-19 21:37:27.000000000 +0100
+@@ -11,7 +11,6 @@
+  */
+ 
+ #include <linux/module.h>
+-#include <linux/config.h>
+ #include <linux/init.h>
+ #include <linux/time.h>
+ #include <linux/slab.h>
+@@ -1358,8 +1357,8 @@
+ 	total_clusters = (total_sectors - sbi->data_start) / sbi->sec_per_clus;
+ 
+ 	if (!sbi->options.atari) {
+-		if (sbi->fat_bits != 32)
+-			sbi->fat_bits = (total_clusters > MAX_FAT12) ? 16 : 12;
++	if (sbi->fat_bits != 32)
++		sbi->fat_bits = (total_clusters > MAX_FAT12) ? 16 : 12;
+ 	} else {
+ 		int sectors;
+ 		/* Atari GEMDOS partitions always have 16-bit fat */
+diff -urN linux-m68k/include/asm-m68k/atarikb.h linux-schmitz/include/asm-m68k/atarikb.h
+--- linux-m68k/include/asm-m68k/atarikb.h	2006-09-20 05:42:06.000000000 +0200
++++ linux-schmitz/include/asm-m68k/atarikb.h	2006-11-19 21:37:27.000000000 +0100
+@@ -36,5 +36,11 @@
+ extern void (*atari_MIDI_interrupt_hook) (void);
+ /* Hook for mouse driver */
+ extern void (*atari_mouse_interrupt_hook) (char *);
++/* Hook for keyboard inputdev  driver */
++extern void (*atari_input_keyboard_interrupt_hook) (unsigned char, char);
++/* Hook for mouse inputdev  driver */
++extern void (*atari_input_mouse_interrupt_hook) (char *);
++
++extern struct pt_regs *atakbd_pt_regs;
+ 
+ #endif /* _LINUX_ATARIKB_H */
+diff -urN linux-m68k/include/asm-m68k/ide.h linux-schmitz/include/asm-m68k/ide.h
+--- linux-m68k/include/asm-m68k/ide.h	2006-09-20 05:42:06.000000000 +0200
++++ linux-schmitz/include/asm-m68k/ide.h	2006-11-19 21:37:27.000000000 +0100
+@@ -108,13 +108,19 @@
+ #ifdef CONFIG_BLK_DEV_FALCON_IDE
+ #define IDE_ARCH_LOCK
+ 
++/* MSch 20061021: even without avoiding registering the IDE interrupt on top 
++ * of stdma_irq, I still get locking bug warnings suggesting mutiple instances 
++ * of ide_do_request are running. The warning is printed now only if the status 
++ * of falconide_intr_lock and stdma_islocked() conflict! */
++
+ extern int falconide_intr_lock;
+ 
+ static __inline__ void ide_release_lock (void)
+ {
+ 	if (MACH_IS_ATARI) {
+-		if (falconide_intr_lock == 0) {
++		if (falconide_intr_lock == 0 && stdma_islocked()) {
+ 			printk("ide_release_lock: bug\n");
++			stdma_debug();
+ 			return;
+ 		}
+ 		falconide_intr_lock = 0;
+diff -urN linux-m68k/include/asm-m68k/io.h linux-schmitz/include/asm-m68k/io.h
+--- linux-m68k/include/asm-m68k/io.h	2006-11-19 21:35:33.000000000 +0100
++++ linux-schmitz/include/asm-m68k/io.h	2006-11-19 21:37:27.000000000 +0100
+@@ -82,9 +82,22 @@
+ #endif
+ #endif /* AMIGA_PCMCIA */
+ 
++#ifdef CONFIG_ATARI_ROM_ISA
+ 
++#define enec_isa_read_base  0xfffa0000
++#define enec_isa_write_base 0xfffb0000
+ 
+-#ifdef CONFIG_ISA
++#define ENEC_ISA_IO_B(ioaddr) (enec_isa_read_base+((((unsigned long)(ioaddr))&0x1F)<<9))
++#define ENEC_ISA_IO_W(ioaddr) (enec_isa_read_base+((((unsigned long)(ioaddr))&0x1F)<<9))
++#define ENEC_ISA_MEM_B(madr)  (enec_isa_read_base+((((unsigned long)(madr))&0x1F)<<9))
++#define ENEC_ISA_MEM_W(madr)  (enec_isa_read_base+((((unsigned long)(madr))&0x1F)<<9))
++
++#define MULTI_ISA 0
++#endif /* ATARI */
++
++
++
++#if defined(CONFIG_ISA) || defined(CONFIG_ATARI_ROM_ISA)
+ 
+ #if MULTI_ISA == 0
+ #undef MULTI_ISA
+@@ -93,6 +106,7 @@
+ #define Q40_ISA (1)
+ #define GG2_ISA (2)
+ #define AG_ISA  (3)
++#define ENEC_ISA (4)
+ 
+ #if defined(CONFIG_Q40) && !defined(MULTI_ISA)
+ #define ISA_TYPE Q40_ISA
+@@ -106,6 +120,10 @@
+ #define ISA_TYPE GG2_ISA
+ #define ISA_SEX  0
+ #endif
++#if defined(CONFIG_ATARI_ROM_ISA) && !defined(MULTI_ISA)
++#define ISA_TYPE ENEC_ISA
++#define ISA_SEX  0
++#endif
+ 
+ #ifdef MULTI_ISA
+ extern int isa_type;
+@@ -133,6 +151,9 @@
+ #ifdef CONFIG_AMIGA_PCMCIA
+     case AG_ISA: return (u8 __iomem *)AG_ISA_IO_B(addr);
+ #endif
++#ifdef CONFIG_ATARI_ROM_ISA
++    case ENEC_ISA: return (u8 __iomem *)ENEC_ISA_IO_B(addr);
++#endif
+     default: return NULL; /* avoid warnings, just in case */
+     }
+ }
+@@ -149,6 +170,9 @@
+ #ifdef CONFIG_AMIGA_PCMCIA
+     case AG_ISA: return (u16 __iomem *)AG_ISA_IO_W(addr);
+ #endif
++#ifdef CONFIG_ATARI_ROM_ISA
++    case ENEC_ISA: return (u16 __iomem *)ENEC_ISA_IO_W(addr);
++#endif
+     default: return NULL; /* avoid warnings, just in case */
+     }
+ }
+@@ -165,6 +189,9 @@
+ #ifdef CONFIG_AMIGA_PCMCIA
+     case AG_ISA: return (u8 __iomem *)addr;
+ #endif
++#ifdef CONFIG_ATARI_ROM_ISA
++    case ENEC_ISA: return (u8 __iomem *)ENEC_ISA_MEM_B(addr);
++#endif
+     default: return NULL; /* avoid warnings, just in case */
+     }
+ }
+@@ -181,6 +208,9 @@
+ #ifdef CONFIG_AMIGA_PCMCIA
+     case AG_ISA: return (u16 __iomem *)addr;
+ #endif
++#ifdef CONFIG_ATARI_ROM_ISA
++    case ENEC_ISA: return (u16 __iomem *)ENEC_ISA_MEM_W(addr);
++#endif
+     default: return NULL; /* avoid warnings, just in case */
+     }
+ }
+@@ -200,6 +230,19 @@
+ 	(ISA_SEX ? out_be16(isa_mtw((unsigned long)(p)),(val))	\
+ 		 : out_le16(isa_mtw((unsigned long)(p)),(val)))
+ 
++#if defined(CONFIG_ATARI_ROM_ISA)
++#define isa_rom_inb(port)      rom_in_8(isa_itb(port))
++#define isa_rom_inw(port)      (ISA_SEX ? rom_in_be16(isa_itw(port)) : rom_in_le16(isa_itw(port)))
++
++#define isa_rom_outb(val,port) rom_out_8(isa_itb(port),(val))
++#define isa_rom_outw(val,port) (ISA_SEX ? rom_out_be16(isa_itw(port),(val)) : rom_out_le16(isa_itw(port),(val)))
++
++#define isa_rom_writeb(val,p)  rom_out_8(isa_mtb((unsigned long)(p)),(val))
++#define isa_rom_writew(val,p)  \
++	(ISA_SEX ? rom_out_be16(isa_mtw((unsigned long)(p)),(val))	\
++		 : rom_out_le16(isa_mtw((unsigned long)(p)),(val)))
++#endif
++
+ static inline void isa_delay(void)
+ {
+   switch(ISA_TYPE)
+@@ -213,6 +256,9 @@
+ #ifdef CONFIG_AMIGA_PCMCIA
+     case AG_ISA: break;
+ #endif
++#ifdef CONFIG_ATARI_ROM_ISA
++    case ENEC_ISA: break;
++#endif
+     default: break; /* avoid warnings */
+     }
+ }
+@@ -234,10 +280,33 @@
+ #define isa_outsw(port, buf, nr)    \
+        (ISA_SEX ? raw_outsw(isa_itw(port), (u16 *)(buf), (nr)) :  \
+                   raw_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr)))
++
++#if defined(CONFIG_ATARI_ROM_ISA)
++#define isa_rom_inb_p(p)      ({u8 v=isa_rom_inb(p);isa_delay();v;})
++#define isa_rom_inw_p(p)      ({u16 v=isa_rom_inw(p);isa_delay();v;})
++#define isa_rom_inl_p(p)      ({u32 v=isa_rom_inl(p);isa_delay();v;})
++#define isa_rom_outb_p(v,p)   ({isa_rom_outb((v),(p));isa_delay();})
++#define isa_rom_outw_p(v,p)   ({isa_rom_outw((v),(p));isa_delay();})
++#define isa_rom_outl_p(v,p)   ({isa_rom_outl((v),(p));isa_delay();})
++
++#define isa_rom_insb(port, buf, nr) raw_rom_insb(isa_itb(port), (u8 *)(buf), (nr))
++
++#define isa_rom_insw(port, buf, nr)     \
++       (ISA_SEX ? raw_rom_insw(isa_itw(port), (u16 *)(buf), (nr)) :    \
++                  raw_rom_insw_swapw(isa_itw(port), (u16 *)(buf), (nr)))
++
++#define isa_rom_outsb(port, buf, nr) raw_rom_outsb(isa_itb(port), (u8 *)(buf), (nr))
++
++#define isa_rom_outsw(port, buf, nr)    \
++       (ISA_SEX ? raw_rom_outsw(isa_itw(port), (u16 *)(buf), (nr)) :  \
++                  raw_rom_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr)))
++
++#endif
++
+ #endif  /* CONFIG_ISA */
+ 
+ 
+-#if defined(CONFIG_ISA) && !defined(CONFIG_PCI)
++#if defined(CONFIG_ISA) && !defined(CONFIG_PCI) && !defined(CONFIG_ATARI_ROM_ISA)
+ #define inb     isa_inb
+ #define inb_p   isa_inb_p
+ #define outb    isa_outb
+@@ -306,7 +375,34 @@
+ #endif
+ #endif /* CONFIG_PCI */
+ 
+-#if !defined(CONFIG_ISA) && !defined(CONFIG_PCI) && defined(CONFIG_HP300)
++#if defined(CONFIG_ATARI_ROM_ISA)
++/*
++ * kernel with both ROM port ISA and IDE compiled in, those have
++ * conflicting defs for in/out. Simply consider port < 1024
++ * ROM port ISA and everything else regular ISA for IDE. read,write not defined
++ * in this case
++ */
++#define inb(port) ((port)<1024 ? isa_rom_inb(port) : in_8(port))
++#define inb_p(port) ((port)<1024 ? isa_rom_inb_p(port) : in_8(port))
++#define inw(port) ((port)<1024 ? isa_rom_inw(port) : in_le16(port))
++#define inw_p(port) ((port)<1024 ? isa_rom_inw_p(port) : in_le16(port))
++#define inl(port) ((port)<1024 ? isa_rom_inl(port) : in_le32(port))
++#define inl_p(port) ((port)<1024 ? isa_rom_inl_p(port) : in_le32(port))
++
++#define outb(val,port) ((port)<1024 ? isa_rom_outb((val),(port)) : out_8((port),(val)))
++#define outb_p(val,port) ((port)<1024 ? isa_rom_outb_p((val),(port)) : out_8((port),(val)))
++#define outw(val,port) ((port)<1024 ? isa_rom_outw((val),(port)) : out_le16((port),(val)))
++#define outw_p(val,port) ((port)<1024 ? isa_rom_outw_p((val),(port)) : out_le16((port),(val)))
++#define outl(val,port) ((port)<1024 ? isa_rom_outl((val),(port)) : out_le32((port),(val)))
++#define outl_p(val,port) ((port)<1024 ? isa_rom_outl_p((val),(port)) : out_le32((port),(val)))
++
++#define insb    isa_rom_insb
++#define insw    isa_rom_insw
++#define outsb   isa_rom_outsb
++#define outsw   isa_rom_outsw
++#endif
++
++#if !defined(CONFIG_ISA) && !defined(CONFIG_PCI) && !defined(CONFIG_ATARI_ROM_ISA) && defined(CONFIG_HP300)
+ /*
+  * We need to define dummy functions otherwise drivers/serial/8250.c doesn't link
+  */

Added: dists/sid/linux-2.6/debian/patches/m68k-atari.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/m68k-atari.patch	Mon Nov 20 00:58:24 2006
@@ -0,0 +1,115 @@
+diff -urN linux-m68k/arch/m68k/atari/stdma.c linux-schmitz/arch/m68k/atari/stdma.c
+--- linux-m68k/arch/m68k/atari/stdma.c	2006-09-20 05:42:06.000000000 +0200
++++ linux-schmitz/arch/m68k/atari/stdma.c	2006-11-19 21:37:26.000000000 +0100
+@@ -48,7 +48,7 @@
+ static void *stdma_isr_data;			/* data passed to isr */
+ static DECLARE_WAIT_QUEUE_HEAD(stdma_wait);	/* wait queue for ST-DMA */
+ 
+-
++static unsigned long stdma_locked_from, stdma_released_from;
+ 
+ 
+ /***************************** Prototypes *****************************/
+@@ -90,6 +90,9 @@
+ 	stdma_locked   = 1;
+ 	stdma_isr      = handler;
+ 	stdma_isr_data = data;
++
++	stdma_locked_from =  __builtin_return_address(0);
++
+ 	local_irq_restore(flags);
+ }
+ 
+@@ -114,6 +117,7 @@
+ 	stdma_locked   = 0;
+ 	stdma_isr      = NULL;
+ 	stdma_isr_data = NULL;
++	stdma_released_from =  __builtin_return_address(0);
+ 	wake_up(&stdma_wait);
+ 
+ 	local_irq_restore(flags);
+@@ -159,6 +163,29 @@
+ 
+ 
+ /*
++ * Function: int stdma_debug( void )
++ *
++ * Purpose: Report current ST-DMA locking status.
++ * Note: Returned status is only valid if ints are disabled while calling and
++ *       as long as they remain disabled.
++ *       If called with ints enabled, status can change only from locked to
++ *       unlocked, because ints may not lock the ST-DMA.
++ *
++ * Inputs: none
++ *
++ * Returns: none
++ *
++ */
++
++void stdma_debug(void)
++{
++        printk("stdma_debug at %p: status %d, locked from %p unlocked from %p\n",
++                __builtin_return_address(0), stdma_locked, stdma_locked_from, 
++                stdma_released_from);
++	return;
++}
++
++/*
+  * Function: void stdma_init( void )
+  *
+  * Purpose: Initialize the ST-DMA chip access controlling.
+@@ -175,7 +202,9 @@
+ void __init stdma_init(void)
+ {
+ 	stdma_isr = NULL;
+-	request_irq(IRQ_MFP_FDC, stdma_int, IRQ_TYPE_SLOW,
++	stdma_locked_from = NULL;
++	stdma_released_from = NULL;
++	request_irq(IRQ_MFP_FDC, stdma_int, IRQ_TYPE_SLOW /* | SA_SHIRQ */,
+ 	            "ST-DMA: floppy/ACSI/IDE/Falcon-SCSI", stdma_int);
+ }
+ 
+diff -urN linux-m68k/arch/m68k/atari/time.c linux-schmitz/arch/m68k/atari/time.c
+--- linux-m68k/arch/m68k/atari/time.c	2006-11-19 21:35:33.000000000 +0100
++++ linux-schmitz/arch/m68k/atari/time.c	2006-11-19 21:37:26.000000000 +0100
+@@ -217,7 +217,7 @@
+ 	if (in_atomic() || irqs_disabled())
+ 	    mdelay(1);
+ 	else
+-	    schedule_timeout_interruptible(HWCLK_POLL_INTERVAL);
++        schedule_timeout_interruptible(HWCLK_POLL_INTERVAL);
+     }
+ 
+     local_irq_save(flags);
+diff -urN linux-m68k/arch/m68k/kernel/entry.S linux-schmitz/arch/m68k/kernel/entry.S
+--- linux-m68k/arch/m68k/kernel/entry.S	2006-11-19 21:35:33.000000000 +0100
++++ linux-schmitz/arch/m68k/kernel/entry.S	2006-11-19 21:37:26.000000000 +0100
+@@ -711,4 +711,28 @@
+ 	.long sys_inotify_init
+ 	.long sys_inotify_add_watch	/* 285 */
+ 	.long sys_inotify_rm_watch
++	.long sys_migrate_pages
++	.long sys_openat
++	.long sys_mkdirat
++	.long sys_mknodat		/* 290 */
++	.long sys_fchownat
++	.long sys_futimesat
++	.long sys_fstatat64
++	.long sys_unlinkat
++	.long sys_renameat		/* 295 */
++	.long sys_linkat
++	.long sys_symlinkat
++	.long sys_readlinkat
++	.long sys_fchmodat
++	.long sys_faccessat		/* 300 */
++	.long sys_ni_syscall		/* Reserved for pselect6 */
++	.long sys_ni_syscall		/* Reserved for ppoll */
++	.long sys_unshare
++	.long sys_set_robust_list
++	.long sys_get_robust_list	/* 305 */
++	.long sys_splice
++	.long sys_sync_file_range
++	.long sys_tee
++	.long sys_vmsplice
++	.long sys_move_pages		/* 310 */
+ 

Added: dists/sid/linux-2.6/debian/patches/m68k-misc.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/m68k-misc.patch	Mon Nov 20 00:58:24 2006
@@ -0,0 +1,136 @@
+diff -urN linux-m68k/arch/m68k/Makefile linux-schmitz/arch/m68k/Makefile
+--- linux-m68k/arch/m68k/Makefile	2006-11-19 21:35:33.000000000 +0100
++++ linux-schmitz/arch/m68k/Makefile	2006-11-19 21:37:26.000000000 +0100
+@@ -22,7 +22,7 @@
+ LDFLAGS_MODULE += -T $(srctree)/arch/m68k/kernel/module.lds
+ ifneq ($(COMPILE_ARCH),$(ARCH))
+ 	# prefix for cross-compiling binaries
+-	CROSS_COMPILE = m68k-linux-
++	CROSS_COMPILE = m68k-linux-gnu-
+ endif
+ 
+ ifdef CONFIG_SUN3
+diff -urN linux-m68k/arch/m68k/kernel/vmlinux-std.lds linux-schmitz/arch/m68k/kernel/vmlinux-std.lds
+--- linux-m68k/arch/m68k/kernel/vmlinux-std.lds	2006-11-19 21:35:33.000000000 +0100
++++ linux-schmitz/arch/m68k/kernel/vmlinux-std.lds	2006-09-20 05:42:06.000000000 +0200
+@@ -66,11 +66,6 @@
+   __con_initcall_start = .;
+   .con_initcall.init : { *(.con_initcall.init) }
+   __con_initcall_end = .;
+-  .m68k_fixup : {
+-	__start_fixup = .;
+-	*(.m68k_fixup)
+-	__stop_fixup = .;
+-  }
+   SECURITY_INIT
+   . = ALIGN(8192);
+   __initramfs_start = .;
+diff -urN linux-m68k/arch/m68k/kernel/vmlinux-sun3.lds linux-schmitz/arch/m68k/kernel/vmlinux-sun3.lds
+--- linux-m68k/arch/m68k/kernel/vmlinux-sun3.lds	2006-11-19 21:35:33.000000000 +0100
++++ linux-schmitz/arch/m68k/kernel/vmlinux-sun3.lds	2006-09-20 05:42:06.000000000 +0200
+@@ -8,7 +8,7 @@
+ jiffies = jiffies_64 + 4;
+ SECTIONS
+ {
+-  . = 0xE002000;
++  . = 0xE004000;
+   _text = .;			/* Text and read-only data */
+   .text : {
+ 	*(.head)
+@@ -60,11 +60,6 @@
+ 	__con_initcall_start = .;
+ 	.con_initcall.init : { *(.con_initcall.init) }
+ 	__con_initcall_end = .;
+-	.m68k_fixup : {
+-		__start_fixup = .;
+-		*(.m68k_fixup)
+-		__stop_fixup = .;
+-	}
+ 	SECURITY_INIT
+ 	. = ALIGN(8192);
+ 	__initramfs_start = .;
+diff -urN linux-m68k/arch/m68k/mm/motorola.c linux-schmitz/arch/m68k/mm/motorola.c
+--- linux-m68k/arch/m68k/mm/motorola.c	2006-11-19 21:35:33.000000000 +0100
++++ linux-schmitz/arch/m68k/mm/motorola.c	2006-11-19 21:37:26.000000000 +0100
+@@ -47,7 +47,6 @@
+ #define INIT_MAPPED_SIZE	(4UL<<20)
+ 
+ extern unsigned long availmem;
+-extern struct mem_info m68k_ramdisk;
+ 
+ static pte_t * __init kernel_page_table(void)
+ {
+@@ -211,11 +210,7 @@
+ 	int i;
+ 
+ #ifdef DEBUG
+-	{
+-		extern unsigned long availmem;
+-		printk ("start of paging_init (%p, %lx)\n",
+-			kernel_pg_dir, availmem);
+-	}
++	printk ("start of paging_init (%p, %lx)\n", kernel_pg_dir, availmem);
+ #endif
+ 
+ 	/* Fix the cache mode in the page descriptors for the 680[46]0.  */
+diff -urN linux-m68k/include/asm-m68k/unistd.h linux-schmitz/include/asm-m68k/unistd.h
+--- linux-m68k/include/asm-m68k/unistd.h	2006-11-19 21:35:33.000000000 +0100
++++ linux-schmitz/include/asm-m68k/unistd.h	2006-11-19 21:37:27.000000000 +0100
+@@ -289,10 +289,34 @@
+ #define __NR_inotify_init	284
+ #define __NR_inotify_add_watch	285
+ #define __NR_inotify_rm_watch	286
++#define __NR_migrate_pages	287
++#define __NR_openat		288
++#define __NR_mkdirat		289
++#define __NR_mknodat		290
++#define __NR_fchownat		291
++#define __NR_futimesat		292
++#define __NR_fstatat64		293
++#define __NR_unlinkat		294
++#define __NR_renameat		295
++#define __NR_linkat		296
++#define __NR_symlinkat		297
++#define __NR_readlinkat		298
++#define __NR_fchmodat		299
++#define __NR_faccessat		300
++#define __NR_pselect6		301
++#define __NR_ppoll		302
++#define __NR_unshare		303
++#define __NR_set_robust_list	304
++#define __NR_get_robust_list	305
++#define __NR_splice		306
++#define __NR_sync_file_range	307
++#define __NR_tee		308
++#define __NR_vmsplice		309
++#define __NR_move_pages		310
+ 
+ #ifdef __KERNEL__
+ 
+-#define NR_syscalls		287
++#define NR_syscalls		311
+ 
+ /* user-visible error numbers are in the range -1 - -124: see
+    <asm-m68k/errno.h> */
+diff -urN linux-m68k/include/linux/input.h linux-schmitz/include/linux/input.h
+--- linux-m68k/include/linux/input.h	2006-09-20 05:42:06.000000000 +0200
++++ linux-schmitz/include/linux/input.h	2006-11-19 21:37:27.000000000 +0100
+@@ -657,6 +657,7 @@
+ #define BUS_I2C			0x18
+ #define BUS_HOST		0x19
+ #define BUS_GSC			0x1A
++#define BUS_ATARI		0x1B
+ 
+ /*
+  * Values describing the status of an effect
+diff -urN linux-m68k/scripts/mod/modpost.c linux-schmitz/scripts/mod/modpost.c
+--- linux-m68k/scripts/mod/modpost.c	2006-11-19 21:35:33.000000000 +0100
++++ linux-schmitz/scripts/mod/modpost.c	2006-09-20 05:42:06.000000000 +0200
+@@ -1181,7 +1181,6 @@
+ 		buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
+ 			      " .exit = cleanup_module,\n"
+ 			      "#endif\n");
+-	buf_printf(b, " .arch = MODULE_ARCH_INIT,\n");
+ 	buf_printf(b, "};\n");
+ }
+ 

Added: dists/sid/linux-2.6/debian/patches/series/6-extra
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/series/6-extra	Mon Nov 20 00:58:24 2006
@@ -0,0 +1,10 @@
++ m68k-misc.patch m68k
++ m68k-amiga.patch m68k
++ m68k-atari.patch m68k
++ m68k-atari-ethernet.patch m68k
++ m68k-atari-keyboard.patch m68k
++ m68k-atari-mouse.patch m68k
++ m68k-atari-scsi.patch m68k
++ m68k-atari-serial.patch m68k
++ m68k-atari-video.patch m68k
++ m68k-apollo.patch m68k



More information about the Kernel-svn-changes mailing list