diff options
61 files changed, 33551 insertions, 0 deletions
diff --git a/debian/patches/bugfix/m68k/130-adbraw.diff b/debian/patches/bugfix/m68k/130-adbraw.diff new file mode 100644 index 000000000000..2cabbd468cfe --- /dev/null +++ b/debian/patches/bugfix/m68k/130-adbraw.diff @@ -0,0 +1,44 @@ +To: linus, alan +Cc: lkml +Subject: [PATCH] ADB raw packets + +From: Linux/m68k legacy + +ADB: add support for raw packets + +--- + drivers/macintosh/adb.c | 8 +++++--- + include/linux/adb.h | 1 + + 2 files changed, 6 insertions(+), 3 deletions(-) + +--- linux-m68k-2.6.21.orig/drivers/macintosh/adb.c ++++ linux-m68k-2.6.21/drivers/macintosh/adb.c +@@ -478,13 +478,15 @@ adb_request(struct adb_request *req, voi + use_sreq = 1; + } else + use_sreq = 0; +- req->nbytes = nbytes+1; ++ i = (flags & ADBREQ_RAW) ? 0 : 1; ++ req->nbytes = nbytes+i; + req->done = done; + req->reply_expected = flags & ADBREQ_REPLY; + req->data[0] = ADB_PACKET; + va_start(list, nbytes); +- for (i = 0; i < nbytes; ++i) +- req->data[i+1] = va_arg(list, int); ++ while (i < req->nbytes) { ++ req->data[i++] = va_arg(list, int); ++ } + va_end(list); + + if (flags & ADBREQ_NOSEND) +--- linux-m68k-2.6.21.orig/include/linux/adb.h ++++ linux-m68k-2.6.21/include/linux/adb.h +@@ -76,6 +76,7 @@ struct adb_driver { + #define ADBREQ_REPLY 1 /* expect reply */ + #define ADBREQ_SYNC 2 /* poll until done */ + #define ADBREQ_NOSEND 4 /* build the request, but don't send it */ ++#define ADBREQ_RAW 8 /* send raw packet (don't prepend ADB_PACKET) */ + + /* Messages sent thru the client_list notifier. You should NOT stop + the operation, at least not with this version */ diff --git a/debian/patches/bugfix/m68k/133-arch.diff b/debian/patches/bugfix/m68k/133-arch.diff new file mode 100644 index 000000000000..2ef342af65dd --- /dev/null +++ b/debian/patches/bugfix/m68k/133-arch.diff @@ -0,0 +1,28 @@ +Subject: [PATCH] Local m68k changes + +Local m68k changes, _NEVER_ to be submitted upstream: + - Force ARCH to be m68k + - Append `-m68k' to EXTRAVERSION + +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> for m68k CVS only + +--- + Makefile | 2 +- + localversion.m68k | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +--- linux-m68k-2.6.21.orig/Makefile ++++ linux-m68k-2.6.21/Makefile +@@ -182,7 +182,7 @@ SUBARCH := $(shell uname -m | sed -e s/i + # Default value for CROSS_COMPILE is not to prefix executables + # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile + +-ARCH ?= $(SUBARCH) ++ARCH ?= m68k + CROSS_COMPILE ?= + + # Architecture as present in compile.h +--- /dev/null ++++ linux-m68k-2.6.21/localversion.m68k +@@ -0,0 +1 @@ ++-m68k diff --git a/debian/patches/bugfix/m68k/134-atari-fat.diff b/debian/patches/bugfix/m68k/134-atari-fat.diff new file mode 100644 index 000000000000..5ce087b90d85 --- /dev/null +++ b/debian/patches/bugfix/m68k/134-atari-fat.diff @@ -0,0 +1,102 @@ +To: linus, alan +Cc: lkml +Subject: [PATCH] Atari FAT updates + +From: Linux/m68k legacy + +Add support for the Atari-variant of the FAT filesystem + +--- + fs/fat/inode.c | 46 +++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 43 insertions(+), 3 deletions(-) + +--- linux-m68k-2.6.21.orig/fs/fat/inode.c ++++ linux-m68k-2.6.21/fs/fat/inode.c +@@ -17,6 +17,7 @@ + #include <linux/smp_lock.h> + #include <linux/seq_file.h> + #include <linux/msdos_fs.h> ++#include <linux/major.h> + #include <linux/pagemap.h> + #include <linux/mpage.h> + #include <linux/buffer_head.h> +@@ -852,7 +853,7 @@ enum { + Opt_check_n, Opt_check_r, Opt_check_s, Opt_uid, Opt_gid, + Opt_umask, Opt_dmask, Opt_fmask, Opt_codepage, Opt_nocase, + Opt_quiet, Opt_showexec, Opt_debug, Opt_immutable, +- Opt_dots, Opt_nodots, ++ Opt_dots, Opt_nodots, Opt_atari_no, Opt_atari_yes, + Opt_charset, Opt_shortname_lower, Opt_shortname_win95, + Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, + Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, +@@ -877,6 +878,9 @@ static match_table_t fat_tokens = { + {Opt_showexec, "showexec"}, + {Opt_debug, "debug"}, + {Opt_immutable, "sys_immutable"}, ++ {Opt_atari_yes, "atari=yes"}, ++ {Opt_atari_yes, "atari"}, ++ {Opt_atari_no, "atari=no"}, + {Opt_obsolate, "conv=binary"}, + {Opt_obsolate, "conv=text"}, + {Opt_obsolate, "conv=auto"}, +@@ -952,6 +956,13 @@ static int parse_options(char *options, + opts->utf8 = opts->unicode_xlate = 0; + opts->numtail = 1; + opts->nocase = 0; ++ opts->atari = 0; ++ ++#ifdef CONFIG_ATARI ++ if(MACH_IS_ATARI) ++ /* make Atari GEMDOS format the default if machine is an Atari */ ++ opts->atari = 1; ++#endif + *debug = 0; + + if (!options) +@@ -1000,6 +1011,12 @@ static int parse_options(char *options, + case Opt_immutable: + opts->sys_immutable = 1; + break; ++ case Opt_atari_yes: ++ opts->atari = 1; ++ break; ++ case Opt_atari_no: ++ opts->atari = 0; ++ break; + case Opt_uid: + if (match_int(&args[0], &option)) + return 0; +@@ -1336,8 +1353,31 @@ int fat_fill_super(struct super_block *s + + total_clusters = (total_sectors - sbi->data_start) / sbi->sec_per_clus; + +- if (sbi->fat_bits != 32) +- sbi->fat_bits = (total_clusters > MAX_FAT12) ? 16 : 12; ++ if (!sbi->options.atari) { ++ if (sbi->fat_bits != 32) ++ sbi->fat_bits = (total_clusters > MAX_FAT12) ? 16 : 12; ++ } else { ++ int sectors; ++ /* Atari GEMDOS partitions always have 16-bit fat */ ++ if (sbi->fat_bits != 32) ++ sbi->fat_bits = 16; ++ /* If more clusters than fat entries in 16-bit fat, we assume ++ * it's a real MSDOS partition with 12-bit fat. ++ */ ++ if (sbi->fat_bits != 32 && total_clusters+2 > sbi-> ++ fat_length*SECTOR_SIZE*8/sbi->fat_bits) ++ sbi->fat_bits = 12; ++ /* if it's a floppy disk --> 12bit fat */ ++ if (sbi->fat_bits != 32 && MAJOR(sb->s_dev) == FLOPPY_MAJOR) ++ sbi->fat_bits = 12; ++ /* if it's a ramdisk or loopback device and has one of the usual ++ * floppy sizes -> 12bit FAT */ ++ sectors = total_sectors + sbi->data_start; ++ if (sbi->fat_bits != 32 && (MAJOR(sb->s_dev) == RAMDISK_MAJOR || ++ MAJOR(sb->s_dev) == LOOP_MAJOR) && ++ (sectors == 720 || sectors == 1440 || sectors == 2880)) ++ sbi->fat_bits = 12; ++ } + + /* check that FAT table does not overflow */ + fat_clusters = sbi->fat_length * sb->s_blocksize * 8 / sbi->fat_bits; diff --git a/debian/patches/bugfix/m68k/141-ide.diff b/debian/patches/bugfix/m68k/141-ide.diff new file mode 100644 index 000000000000..b4537dc693a3 --- /dev/null +++ b/debian/patches/bugfix/m68k/141-ide.diff @@ -0,0 +1,38 @@ +To: linus, alan +Cc: lkml +Subject: [PATCH] M68k IDE updates + +From: Linux/m68k legacy + +M68k IDE updates: Add m68k-isms to the generic ide_fix_driveid() + +--- + drivers/ide/ide-iops.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +--- linux-m68k-2.6.21.orig/drivers/ide/ide-iops.c ++++ linux-m68k-2.6.21/drivers/ide/ide-iops.c +@@ -313,6 +313,23 @@ void ide_fix_driveid (struct hd_driveid + int i; + u16 *stringcast; + ++#ifdef __mc68000__ ++ if (!MACH_IS_AMIGA && !MACH_IS_MAC && !MACH_IS_Q40 && !MACH_IS_ATARI) ++ return; ++ ++#ifdef M68K_IDE_SWAPW ++ if (M68K_IDE_SWAPW) { /* fix bus byteorder first */ ++ u_char *p = (u_char *)id; ++ u_char t; ++ for (i = 0; i < 512; i += 2) { ++ t = p[i]; ++ p[i] = p[i+1]; ++ p[i+1] = t; ++ } ++ } ++#endif ++#endif /* __mc68000__ */ ++ + id->config = __le16_to_cpu(id->config); + id->cyls = __le16_to_cpu(id->cyls); + id->reserved2 = __le16_to_cpu(id->reserved2); diff --git a/debian/patches/bugfix/m68k/143-ioext.diff b/debian/patches/bugfix/m68k/143-ioext.diff new file mode 100644 index 000000000000..01c02d095522 --- /dev/null +++ b/debian/patches/bugfix/m68k/143-ioext.diff @@ -0,0 +1,1352 @@ +To: linus, alan +Cc: lkml +Subject: [PATCH] Amiga GVP I/O Extender PLIP + +From: Linux/m68k legacy + +Add a PLIP driver for the Amiga GVP I/O Extender's parallel port + +--- + drivers/char/16c552.h | 165 +++++++ + drivers/char/ioext.h | 107 ++++ + drivers/char/plip_ioext.c | 1057 ++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 1329 insertions(+) + +--- /dev/null ++++ linux-m68k-2.6.21/drivers/char/16c552.h +@@ -0,0 +1,165 @@ ++/* ++ * Definitions for the 16c552 DACE ++ * (dual-asynchronous-communications-element) used on the GVP ++ * IO-Extender. ++ * ++ * Basically this is two 16c550 uarts's and a parallel port, which is ++ * why the serial definitions should be valid for the 16c550 uart ++ * aswell. ++ * ++ * Data was taken from National Semiconductors duart 16c552 ++ * data-sheets and the Texas Instruments DACE 16c552 data-sheets (the ++ * NS version of the chip is _non_ standard and their data-sheets did ++ * cost me several wasted hours of work). ++ * ++ * This file is (C) 1995 Jes Sorensen (jds@kom.auc.dk) ++ * ++ * Moved from drivers/char/ to include/linux/, because it's useful ++ * on more than just the one card. I'm using it on the hp300 DCA ++ * serial driver, for example. ++ * -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 05/1998 ++ */ ++ ++#ifndef _16C552_H_ ++#define _16C552_H_ ++ ++/* Serial stuff */ ++ ++struct uart_16c550 { ++ volatile u_char skip0; ++ volatile u_char RBR; ++ volatile u_char skip1; ++ volatile u_char IER; ++ volatile u_char skip2; ++ volatile u_char IIR; ++ volatile u_char skip3; ++ volatile u_char LCR; ++ volatile u_char skip4; ++ volatile u_char MCR; ++ volatile u_char skip5; ++ volatile u_char LSR; ++ volatile u_char skip6; ++ volatile u_char MSR; ++ volatile u_char skip7; ++ volatile u_char SCR; ++}; ++ ++#define THR RBR ++#define FCR IIR ++#define DLL RBR ++#define DLM IER ++#define AFR IIR ++ ++/* ++ * Bit-defines for the various registers. ++ */ ++ ++ ++/* IER */ ++ ++#define ERDAI (1<<0) ++#define ETHREI (1<<1) ++#define ELSI (1<<2) ++#define EMSI (1<<3) ++ ++/* IIR - Interrupt Ident. Register */ ++ ++#define IRQ_PEND (1<<0) /* NOTE: IRQ_PEND=0 implies irq pending */ ++#define IRQ_ID1 (1<<1) ++#define IRQ_ID2 (1<<2) ++#define IRQ_ID3 (1<<3) ++#define FIFO_ENA0 (1<<6) /* Both these are set when FCR(1<<0)=1 */ ++#define FIFO_ENA1 (1<<7) ++ ++#define IRQ_RLS (IRQ_ID1 | IRQ_ID2) ++#define IRQ_RDA (IRQ_ID2) ++#define IRQ_CTI (IRQ_ID2 | IRQ_ID3) ++#define IRQ_THRE (IRQ_ID1) ++#define IRQ_MS 0 ++ ++/* FCR - FIFO Control Register */ ++ ++#define FIFO_ENA (1<<0) ++#define RCVR_FIFO_RES (1<<1) ++#define XMIT_FIFO_RES (1<<2) ++#define DMA_MODE_SEL (1<<3) ++#define RCVR_TRIG_LSB (1<<6) ++#define RCVR_TRIG_MSB (1<<7) ++ ++#define FIFO_TRIG_1 0x00 ++#define FIFO_TRIG_4 RCVR_TRIG_LSB ++#define FIFO_TRIG_8 RCVR_TRIG_MSB ++#define FIFO_TRIG_14 RCVR_TRIG_LSB|RCVR_TRIG_MSB ++ ++/* LCR - Line Control Register */ ++ ++#define WLS0 (1<<0) ++#define WLS1 (1<<1) ++#define STB (1<<2) ++#define PEN (1<<3) ++#define EPS (1<<4) ++#define STICK_PARITY (1<<5) ++#define SET_BREAK (1<<6) ++#define DLAB (1<<7) ++ ++#define data_5bit 0x00 ++#define data_6bit 0x01 ++#define data_7bit 0x02 ++#define data_8bit 0x03 ++ ++ ++/* MCR - Modem Control Register */ ++ ++#define DTR (1<<0) ++#define RTS (1<<1) ++#define OUT1 (1<<2) ++#define OUT2 (1<<3) ++#define LOOP (1<<4) ++ ++/* LSR - Line Status Register */ ++ ++#define DR (1<<0) ++#define OE (1<<1) ++#define PE (1<<2) ++#define FE (1<<3) ++#define BI (1<<4) ++#define THRE (1<<5) ++#define TEMT (1<<6) ++#define RCVR_FIFO_ERR (1<<7) ++ ++/* MSR - Modem Status Register */ ++ ++#define DCTS (1<<0) ++#define DDSR (1<<1) ++#define TERI (1<<2) ++#define DDCD (1<<3) ++#define CTS (1<<4) ++#define DSR (1<<5) ++#define RING_I (1<<6) ++#define DCD (1<<7) ++ ++/* AFR - Alternate Function Register */ ++ ++#define CONCUR_WRITE (1<<0) ++#define BAUDOUT (1<<1) ++#define RXRDY (1<<2) ++ ++/* Parallel stuff */ ++ ++/* ++ * Unfortunately National Semiconductors did not supply the ++ * specifications for the parallel port in the chip :-( ++ * TI succed though, so here they are :-) ++ * ++ * Defines for the bits can be found by including <linux/lp.h> ++ */ ++struct IOEXT_par { ++ volatile u_char skip0; ++ volatile u_char DATA; ++ volatile u_char skip1; ++ volatile u_char STATUS; ++ volatile u_char skip2; ++ volatile u_char CTRL; ++}; ++ ++#endif +--- /dev/null ++++ linux-m68k-2.6.21/drivers/char/ioext.h +@@ -0,0 +1,107 @@ ++/* ++ * Shared data structure for GVP IO-Extender support. ++ * ++ * Merge of ioext.h and ser_ioext.h ++ */ ++#ifndef _IOEXT_H_ ++#define _IOEXT_H_ ++ ++#include <linux/netdevice.h> ++ ++#include "16c552.h" ++ ++#define MAX_IOEXT 5 /* ++ * The maximum number of io-extenders is 5, as you ++ * can't have more than 5 ZII boards in any Amiga. ++ */ ++ ++#define UART_CLK 7372800 ++ ++#define IOEXT_BAUD_BASE (UART_CLK / 16) ++ ++#define IOEXT_MAX_LINES 2 ++ ++#define IOEXT_PAR_PLIP 0x0001 ++#define IOEXT_PAR_LP 0x0002 ++ ++ ++/* ++ * Macros for the serial driver. ++ */ ++#define curruart(info) ((struct uart_16c550 *)(info->port)) ++ ++#define ser_DTRon(info) curruart(info)->MCR |= DTR ++#define ser_RTSon(info) curruart(info)->MCR |= RTS ++#define ser_DTRoff(info) curruart(info)->MCR &= ~DTR ++#define ser_RTSoff(info) curruart(info)->MCR &= ~RTS ++ ++ ++/* ++ * CNTR defines (copied from the GVP SCSI-driver file gvp11.h ++ */ ++#define GVP_BUSY (1<<0) ++#define GVP_IRQ_PEND (1<<1) ++#define GVP_IRQ_ENA (1<<3) ++#define GVP_DIR_WRITE (1<<4) ++ ++ ++/* ++ * CTRL defines ++ */ ++#define PORT0_MIDI (1<<0) /* CLR = DRIVERS SET = MIDI */ ++#define PORT1_MIDI (1<<1) /* CLR = DRIVERS SET = MIDI */ ++#define PORT0_DRIVER (1<<2) /* CLR = RS232, SET = MIDI */ ++#define PORT1_DRIVER (1<<3) /* CLR = RS232, SET = MIDI */ ++#define IRQ_SEL (1<<4) /* CLR = INT2, SET = INT6 */ ++#define ROM_BANK_SEL (1<<5) /* CLR = LOW 32K, SET = HIGH 32K */ ++#define PORT0_CTRL (1<<6) /* CLR = RTSx or RXRDYx, SET = RTSx ONLY */ ++#define PORT1_CTRL (1<<7) /* CLR = RTSx or RXRDYx, SET = RTSx ONLY */ ++ ++ ++/* ++ * This is the struct describing the registers on the IO-Extender. ++ * NOTE: The board uses a dual uart (16c552), which should be equal to ++ * two 16c550 uarts. ++ */ ++typedef struct { ++ char gap0[0x41]; ++ volatile unsigned char CNTR; /* GVP DMAC CNTR (status register) */ ++ char gap1[0x11e]; ++ struct uart_16c550 uart0; /* The first uart */ ++ char gap2[0xf0]; ++ struct uart_16c550 uart1; /* The second uart */ ++ char gap3[0xf0]; ++ struct IOEXT_par par; /* The parallel port */ ++ char gap4[0xfb]; ++ volatile unsigned char CTRL; /* The control-register on the board */ ++} IOEXT_struct; ++ ++ ++typedef struct { ++ int num_uarts; ++ int line[IOEXT_MAX_LINES]; ++ volatile struct uart_16c550 *uart[IOEXT_MAX_LINES]; ++ IOEXT_struct *board; ++ int spurious_count; ++ unsigned char par_use; /* IOEXT_PAR_xxx */ ++#if defined(CONFIG_GVPIOEXT_PLIP) || defined(CONFIG_GVPIOEXT_PLIP_MODULE) ++ struct nt_device *dev; ++#endif ++#if defined(CONFIG_GVPIOEXT_LP) || defined(CONFIG_GVPIOEXT_LP_MODULE) ++ struct lp_struct *lp_table; ++ int lp_dev; ++ int lp_interrupt; ++#endif ++} IOExtInfoType; ++ ++/* Number of detected boards. */ ++extern int ioext_num; ++extern IOExtInfoType ioext_info[MAX_IOEXT]; ++ ++void ioext_plip_interrupt(struct net_device *dev, int *spurious_count); ++void ioext_lp_interrupt(int dev, int *spurious_count); ++ ++extern struct net_device ioext_dev_plip[3]; ++extern struct lp_struct ioext_lp_table[1]; ++ ++#endif +--- /dev/null ++++ linux-m68k-2.6.21/drivers/char/plip_ioext.c +@@ -0,0 +1,1057 @@ ++/* ++ * plip_ioext: A parallel port "network" driver for GVP IO-Extender. ++ * ++ * Authors: See drivers/net/plip.c ++ * IO-Extender version by Steve Bennett, <msteveb@ozemail.com.au> ++ * ++ * This driver is for use with a 5-bit cable (LapLink (R) cable). ++ */ ++ ++static const char *version = "NET3 PLIP version 2.2/m68k"; ++ ++#define __NO_VERSION__ ++ ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/sched.h> ++#include <linux/errno.h> ++#include <linux/interrupt.h> ++#include <linux/slab.h> ++#include <linux/termios.h> ++#include <linux/tty.h> ++#include <linux/serial.h> ++ ++#include <asm/setup.h> ++#include <asm/irq.h> ++#include <asm/amigahw.h> ++#include <asm/amigaints.h> ++#include <linux/zorro.h> ++ ++#include <linux/kernel.h> ++#include <linux/fcntl.h> ++#include <linux/string.h> ++#include <linux/ptrace.h> ++#include <linux/if_ether.h> ++ ++#include <asm/system.h> ++ ++#include <linux/in.h> ++#include <linux/delay.h> ++/*#include <linux/lp_m68k.h>*/ ++ ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/inetdevice.h> ++#include <linux/skbuff.h> ++#include <linux/if_plip.h> ++ ++#include <linux/tqueue.h> ++#include <linux/ioport.h> ++#include <linux/bitops.h> ++#include <asm/byteorder.h> ++ ++#include "ioext.h" ++ ++#define DEBUG 0 ++ ++/* Map 'struct device *' to our control structure */ ++#define PLIP_DEV(DEV) (&ioext_info[(DEV)->irq]) ++ ++/************************************************************************ ++** ++** PLIP definitions ++** ++************************************************************************* ++*/ ++ ++/* Use 0 for production, 1 for verification, >2 for debug */ ++#ifndef NET_DEBUG ++#define NET_DEBUG 2 ++#endif ++static unsigned int net_debug = NET_DEBUG; ++ ++/* In micro second */ ++#define PLIP_DELAY_UNIT 1 ++ ++/* Connection time out = PLIP_TRIGGER_WAIT * PLIP_DELAY_UNIT usec */ ++#define PLIP_TRIGGER_WAIT 500 ++ ++/* Nibble time out = PLIP_NIBBLE_WAIT * PLIP_DELAY_UNIT usec */ ++#define PLIP_NIBBLE_WAIT 3000 ++ ++#define PAR_DATA(dev) ((dev)->base_addr+0) ++#define PAR_STATUS(dev) ((dev)->base_addr+2) ++#define PAR_CONTROL(dev) ((dev)->base_addr+4) ++ ++static void enable_par_irq(struct device *dev, int on); ++static int plip_init(struct device *dev); ++ ++/* Bottom halfs */ ++static void plip_kick_bh(struct device *dev); ++static void plip_bh(struct device *dev); ++ ++/* Functions for DEV methods */ ++static int plip_rebuild_header(struct sk_buff *skb); ++static int plip_tx_packet(struct sk_buff *skb, struct device *dev); ++static int plip_open(struct device *dev); ++static int plip_close(struct device *dev); ++static struct enet_statistics *plip_get_stats(struct device *dev); ++static int plip_config(struct device *dev, struct ifmap *map); ++static int plip_ioctl(struct device *dev, struct ifreq *ifr, int cmd); ++ ++enum plip_connection_state { ++ PLIP_CN_NONE=0, ++ PLIP_CN_RECEIVE, ++ PLIP_CN_SEND, ++ PLIP_CN_CLOSING, ++ PLIP_CN_ERROR ++}; ++ ++enum plip_packet_state { ++ PLIP_PK_DONE=0, ++ PLIP_PK_TRIGGER, ++ PLIP_PK_LENGTH_LSB, ++ PLIP_PK_LENGTH_MSB, ++ PLIP_PK_DATA, ++ PLIP_PK_CHECKSUM ++}; ++ ++enum plip_nibble_state { ++ PLIP_NB_BEGIN, ++ PLIP_NB_1, ++ PLIP_NB_2, ++}; ++ ++struct plip_local { ++ enum plip_packet_state state; ++ enum plip_nibble_state nibble; ++ union { ++ struct { ++#if defined(__LITTLE_ENDIAN) ++ unsigned char lsb; ++ unsigned char msb; ++#elif defined(__BIG_ENDIAN) ++ unsigned char msb; ++ unsigned char lsb; ++#else ++#error "Please fix the endianness defines in <asm/byteorder.h>" ++#endif ++ } b; ++ unsigned short h; ++ } length; ++ unsigned short byte; ++ unsigned char checksum; ++ unsigned char data; ++ struct sk_buff *skb; ++}; ++ ++struct net_local { ++ struct enet_statistics enet_stats; ++ struct tq_struct immediate; ++ struct tq_struct deferred; ++ struct plip_local snd_data; ++ struct plip_local rcv_data; ++ unsigned long trigger; ++ unsigned long nibble; ++ enum plip_connection_state connection; ++ unsigned short timeout_count; ++ char is_deferred; ++ int (*orig_rebuild_header)(struct sk_buff *skb); ++}; ++ ++struct device ioext_dev_plip[] = { ++ { ++ "plip0", ++ 0, 0, 0, 0, /* memory */ ++ 0, 0, /* base, irq */ ++ 0, 0, 0, NULL, plip_init ++ }, ++ { ++ "plip1", ++ 0, 0, 0, 0, /* memory */ ++ 0, 0, /* base, irq */ ++ 0, 0, 0, NULL, plip_init ++ }, ++ { ++ "plip2", ++ 0, 0, 0, 0, /* memory */ ++ 0, 0, /* base, irq */ ++ 0, 0, 0, NULL, plip_init ++ } ++}; ++ ++/* ++ * Check for and handle an interrupt for this PLIP device. ++ * ++ */ ++void ioext_plip_interrupt(struct device *dev, int *spurious_count) ++{ ++ struct net_local *nl; ++ struct plip_local *rcv; ++ unsigned char c0; ++ unsigned long flags; ++ ++ nl = (struct net_local *)dev->priv; ++ rcv = &nl->rcv_data; ++ ++ c0 = z_readb(PAR_STATUS(dev)); ++ ++ if (dev->interrupt) { ++ return; ++ } ++ ++ if ((c0 & 0xf8) != 0xc0) { ++ /* Not for us */ ++ ++*spurious_count; ++ return; ++ } ++ ++ *spurious_count = 0; ++ dev->interrupt = 1; ++ ++ local_irq_save(flags); ++ ++ switch (nl->connection) { ++ case PLIP_CN_CLOSING: ++ dev->tbusy = 0; ++ case PLIP_CN_NONE: ++ case PLIP_CN_SEND: ++ dev->last_rx = jiffies; ++ rcv->state = PLIP_PK_TRIGGER; ++ nl->connection = PLIP_CN_RECEIVE; ++ nl->timeout_count = 0; ++ queue_task(&nl->immediate, &tq_immediate); ++ mark_bh(IMMEDIATE_BH); ++ local_irq_restore(flags); ++#if 0 ++ printk("%s: receive irq in SEND/NONE/CLOSING (%d) ok\n", ++ dev->name, nl->connection); ++#endif ++ break; ++ ++ case PLIP_CN_RECEIVE: ++ local_irq_restore(flags); ++ printk("%s: receive interrupt when receiving packet\n", ++ dev->name); ++ break; ++ ++ case PLIP_CN_ERROR: ++ local_irq_restore(flags); ++ printk("%s: receive interrupt in error state\n", dev->name); ++ break; ++ } ++} ++ ++ ++/* Bottom half handler for the delayed request. ++ This routine is kicked by do_timer(). ++ Request `plip_bh' to be invoked. */ ++static void ++plip_kick_bh(struct device *dev) ++{ ++ struct net_local *nl = (struct net_local *)dev->priv; ++ ++ if (nl->is_deferred) { ++ queue_task(&nl->immediate, &tq_immediate); ++ mark_bh(IMMEDIATE_BH); ++ } ++} ++ ++/* Forward declarations of internal routines */ ++static int plip_none(struct device *, struct net_local *, ++ struct plip_local *, struct plip_local *); ++static int plip_receive_packet(struct device *, struct net_local *, ++ struct plip_local *, struct plip_local *); ++static int plip_send_packet(struct device *, struct net_local *, ++ struct plip_local *, struct plip_local *); ++static int plip_connection_close(struct device *, struct net_local *, ++ struct plip_local *, struct plip_local *); ++static int plip_error(struct device *, struct net_local *, ++ struct plip_local *, struct plip_local *); ++static int plip_bh_timeout_error(struct device *dev, struct net_local *nl, ++ struct plip_local *snd, ++ struct plip_local *rcv, ++ int error); ++ ++#define OK 0 ++#define TIMEOUT 1 ++#define ERROR 2 ++ ++typedef int (*plip_func)(struct device *dev, struct net_local *nl, ++ struct plip_local *snd, struct plip_local *rcv); ++ ++static plip_func connection_state_table[] = ++{ ++ plip_none, ++ plip_receive_packet, ++ plip_send_packet, ++ plip_connection_close, ++ plip_error ++}; ++ ++/* ++** enable_par_irq() ++** ++** Enable or disable parallel irq for 'dev' according to 'on'. ++** ++** It is NOT possible to disable only the parallel irq. ++** So we disable the board interrupt instead. This means that ++** during reception of a PLIP packet, no serial interrupts can ++** happen. Sorry. ++*/ ++static void enable_par_irq(struct device *dev, int on) ++{ ++ if (on) { ++ PLIP_DEV(dev)->board->CNTR |= GVP_IRQ_ENA; ++ } ++ else { ++ PLIP_DEV(dev)->board->CNTR &= ~GVP_IRQ_ENA; ++ } ++} ++ ++/* Bottom half handler of PLIP. */ ++static void ++plip_bh(struct device *dev) ++{ ++ struct net_local *nl = (struct net_local *)dev->priv; ++ struct plip_local *snd = &nl->snd_data; ++ struct plip_local *rcv = &nl->rcv_data; ++ plip_func f; ++ int r; ++ ++ nl->is_deferred = 0; ++ f = connection_state_table[nl->connection]; ++ if ((r = (*f)(dev, nl, snd, rcv)) != OK ++ && (r = plip_bh_timeout_error(dev, nl, snd, rcv, r)) != OK) { ++ nl->is_deferred = 1; ++ queue_task(&nl->deferred, &tq_timer); ++ } ++} ++ ++static int ++plip_bh_timeout_error(struct device *dev, struct net_local *nl, ++ struct plip_local *snd, struct plip_local *rcv, ++ int error) ++{ ++ unsigned char c0; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ if (nl->connection == PLIP_CN_SEND) { ++ ++ if (error != ERROR) { /* Timeout */ ++ nl->timeout_count++; ++ if ((snd->state == PLIP_PK_TRIGGER ++ && nl->timeout_count <= 10) ++ || nl->timeout_count <= 3) { ++ local_irq_restore(flags); ++ /* Try again later */ ++ return TIMEOUT; ++ } ++ c0 = z_readb(PAR_STATUS(dev)); ++ printk(KERN_INFO "%s: transmit timeout(%d,%02x)\n", ++ dev->name, snd->state, c0); ++ } ++ nl->enet_stats.tx_errors++; ++ nl->enet_stats.tx_aborted_errors++; ++ } else if (nl->connection == PLIP_CN_RECEIVE) { ++ if (rcv->state == PLIP_PK_TRIGGER) { ++ /* Transmission was interrupted. */ ++ local_irq_restore(flags); ++ return OK; ++ } ++ if (error != ERROR) { /* Timeout */ ++ if (++nl->timeout_count <= 3) { ++ local_irq_restore(flags); ++ /* Try again later */ ++ return TIMEOUT; ++ } ++ c0 = z_readb(PAR_STATUS(dev)); ++ printk(KERN_INFO "%s: receive timeout(%d,%02x)\n", ++ dev->name, rcv->state, c0); ++ } ++ nl->enet_stats.rx_dropped++; ++ } ++ rcv->state = PLIP_PK_DONE; ++ if (rcv->skb) { ++ kfree_skb(rcv->skb); ++ rcv->skb = NULL; ++ } ++ snd->state = PLIP_PK_DONE; ++ if (snd->skb) { ++ dev_kfree_skb(snd->skb); ++ snd->skb = NULL; ++ } ++ enable_par_irq(dev, 0); ++ dev->tbusy = 1; ++ nl->connection = PLIP_CN_ERROR; ++ z_writeb(0x00, PAR_DATA(dev)); ++ local_irq_restore(flags); ++ ++ return TIMEOUT; ++} ++ ++static int ++plip_none(struct device *dev, struct net_local *nl, ++ struct plip_local *snd, struct plip_local *rcv) ++{ ++ return OK; ++} ++ ++/* PLIP_RECEIVE --- receive a byte(two nibbles) ++ Returns OK on success, TIMEOUT on timeout */ ++inline static int ++plip_receive(struct device *dev, unsigned short nibble_timeout, ++ enum plip_nibble_state *ns_p, unsigned char *data_p) ++{ ++ unsigned char c0, c1; ++ unsigned int cx; ++ ++ switch (*ns_p) { ++ case PLIP_NB_BEGIN: ++ cx = nibble_timeout; ++ while (1) { ++ c0 = z_readb(PAR_STATUS(dev)); ++ udelay(PLIP_DELAY_UNIT); ++ if ((c0 & 0x80) == 0) { ++ c1 = z_readb(PAR_STATUS(dev)); ++ if (c0 == c1) ++ break; ++ } ++ if (--cx == 0) ++ return TIMEOUT; ++ } ++#if 0 ++ printk("received first nybble: %02X -> %02X\n", ++ c0, (c0 >> 3) & 0x0F); ++#endif ++ *data_p = (c0 >> 3) & 0x0f; ++ z_writeb(0x10, PAR_DATA(dev)); /* send ACK */ ++ *ns_p = PLIP_NB_1; ++ ++ case PLIP_NB_1: ++ cx = nibble_timeout; ++ while (1) { ++ c0 = z_readb(PAR_STATUS(dev)); ++ udelay(PLIP_DELAY_UNIT); ++ if (c0 & 0x80) { ++ c1 = z_readb(PAR_STATUS(dev)); ++ if (c0 == c1) ++ break; ++ } ++ if (--cx == 0) ++ return TIMEOUT; ++ } ++#if 0 ++ printk("received second nybble: %02X -> %02X\n", ++ c0, (c0 << 1) & 0xF0); ++#endif ++ *data_p |= (c0 << 1) & 0xf0; ++ z_writeb(0x00, PAR_DATA(dev)); /* send ACK */ ++ *ns_p = PLIP_NB_BEGIN; ++ case PLIP_NB_2: ++ break; ++ } ++ return OK; ++} ++ ++/* PLIP_RECEIVE_PACKET --- receive a packet */ ++static int ++plip_receive_packet(struct device *dev, struct net_local *nl, ++ struct plip_local *snd, struct plip_local *rcv) ++{ ++ unsigned short nibble_timeout = nl->nibble; ++ unsigned char *lbuf; ++ unsigned long flags; ++ ++ switch (rcv->state) { ++ case PLIP_PK_TRIGGER: ++ enable_par_irq(dev, 0); ++ dev->interrupt = 0; ++ z_writeb(0x01, PAR_DATA(dev)); /* send ACK */ ++ if (net_debug > 2) ++ printk(KERN_DEBUG "%s: receive start\n", dev->name); ++ rcv->state = PLIP_PK_LENGTH_LSB; ++ rcv->nibble = PLIP_NB_BEGIN; ++ ++ case PLIP_PK_LENGTH_LSB: ++ if (snd->state != PLIP_PK_DONE) { ++ if (plip_receive(dev, nl->trigger, ++ &rcv->nibble, &rcv->length.b.lsb)) { ++ /* collision, here dev->tbusy == 1 */ ++ rcv->state = PLIP_PK_DONE; ++ nl->is_deferred = 1; ++ nl->connection = PLIP_CN_SEND; ++ queue_task(&nl->deferred, &tq_timer); ++ enable_par_irq(dev, 1); ++ return OK; ++ } ++ } else { ++ if (plip_receive(dev, nibble_timeout, ++ &rcv->nibble, &rcv->length.b.lsb)) ++ return TIMEOUT; ++ } ++ rcv->state = PLIP_PK_LENGTH_MSB; ++ ++ case PLIP_PK_LENGTH_MSB: ++ if (plip_receive(dev, nibble_timeout, ++ &rcv->nibble, &rcv->length.b.msb)) ++ return TIMEOUT; ++ if (rcv->length.h > dev->mtu + dev->hard_header_len ++ || rcv->length.h < 8) { ++ printk(KERN_INFO "%s: bogus packet size %d.\n", ++ dev->name, rcv->length.h); ++ return ERROR; ++ } ++ /* Malloc up new buffer. */ ++ rcv->skb = dev_alloc_skb(rcv->length.h); ++ if (rcv->skb == NULL) { ++ printk(KERN_INFO "%s: Memory squeeze.\n", dev->name); ++ return ERROR; ++ } ++ skb_put(rcv->skb,rcv->length.h); ++ rcv->skb->dev = dev; ++ rcv->state = PLIP_PK_DATA; ++ rcv->byte = 0; ++ rcv->checksum = 0; ++ ++ case PLIP_PK_DATA: ++ lbuf = rcv->skb->data; ++ do ++ if (plip_receive(dev, nibble_timeout, ++ &rcv->nibble, &lbuf[rcv->byte])) ++ return TIMEOUT; ++ while (++rcv->byte < rcv->length.h); ++ do ++ rcv->checksum += lbuf[--rcv->byte]; ++ while (rcv->byte); ++ rcv->state = PLIP_PK_CHECKSUM; ++ ++ case PLIP_PK_CHECKSUM: ++ if (plip_receive(dev, nibble_timeout, ++ &rcv->nibble, &rcv->data)) ++ return TIMEOUT; ++ if (rcv->data != rcv->checksum) { ++ nl->enet_stats.rx_crc_errors++; ++ if (net_debug) ++ printk(KERN_INFO "%s: checksum error\n", ++ dev->name); ++ return ERROR; ++ } ++ rcv->state = PLIP_PK_DONE; ++ ++ case PLIP_PK_DONE: ++ /* Inform the upper layer for the arrival of a packet. */ ++ rcv->skb->protocol=eth_type_trans(rcv->skb, dev); ++ netif_rx(rcv->skb); ++ nl->enet_stats.rx_packets++; ++ rcv->skb = NULL; ++ if (net_debug > 2) ++ printk(KERN_DEBUG "%s: receive end\n", dev->name); ++ ++ /* Close the connection. */ ++ z_writeb (0x00, PAR_DATA(dev)); ++ ++ local_irq_save(flags); ++ if (snd->state != PLIP_PK_DONE) { ++ nl->connection = PLIP_CN_SEND; ++ local_irq_restore(flags); ++ queue_task(&nl->immediate, &tq_immediate); ++ mark_bh(IMMEDIATE_BH); ++ enable_par_irq(dev, 1); ++ return OK; ++ } else { ++ nl->connection = PLIP_CN_NONE; ++ local_irq_restore(flags); ++ enable_par_irq(dev, 1); ++ return OK; ++ } ++ } ++ return OK; ++} ++ ++/* PLIP_SEND --- send a byte (two nibbles) ++ Returns OK on success, TIMEOUT when timeout */ ++inline static int ++plip_send(struct device *dev, unsigned short nibble_timeout, ++ enum plip_nibble_state *ns_p, unsigned char data) ++{ ++ unsigned char c0; ++ unsigned int cx; ++ ++ switch (*ns_p) { ++ case PLIP_NB_BEGIN: ++ z_writeb((data & 0x0f), PAR_DATA(dev)); ++ *ns_p = PLIP_NB_1; ++ ++ case PLIP_NB_1: ++ z_writeb(0x10 | (data & 0x0f), PAR_DATA(dev)); ++ cx = nibble_timeout; ++ while (1) { ++ c0 = z_readb(PAR_STATUS(dev)); ++ if ((c0 & 0x80) == 0) ++ break; ++ if (--cx == 0) ++ return TIMEOUT; ++ udelay(PLIP_DELAY_UNIT); ++ } ++ z_writeb(0x10 | (data >> 4), PAR_DATA(dev)); ++ *ns_p = PLIP_NB_2; ++ ++ case PLIP_NB_2: ++ z_writeb((data >> 4), PAR_DATA(dev)); ++ cx = nibble_timeout; ++ while (1) { ++ c0 = z_readb(PAR_STATUS(dev)); ++ if (c0 & 0x80) ++ break; ++ if (--cx == 0) ++ return TIMEOUT; ++ udelay(PLIP_DELAY_UNIT); ++ } ++ *ns_p = PLIP_NB_BEGIN; ++ return OK; ++ } ++ return OK; ++} ++ ++/* PLIP_SEND_PACKET --- send a packet */ ++static int ++plip_send_packet(struct device *dev, struct net_local *nl, ++ struct plip_local *snd, struct plip_local *rcv) ++{ ++ unsigned short nibble_timeout = nl->nibble; ++ unsigned char *lbuf; ++ unsigned char c0; ++ unsigned int cx; ++ unsigned long flags; ++ ++ if (snd->skb == NULL || (lbuf = snd->skb->data) == NULL) { ++ printk(KERN_INFO "%s: send skb lost\n", dev->name); ++ snd->state = PLIP_PK_DONE; ++ snd->skb = NULL; ++ return ERROR; ++ } ++ ++ if (snd->length.h == 0) { ++ return OK; ++ } ++ ++ switch (snd->state) { ++ case PLIP_PK_TRIGGER: ++ if ((z_readb(PAR_STATUS(dev)) & 0xf8) != 0x80) ++ return TIMEOUT; ++ ++ /* Trigger remote rx interrupt. */ ++ z_writeb(0x08, PAR_DATA(dev)); ++ cx = nl->trigger; ++ while (1) { ++ udelay(PLIP_DELAY_UNIT); ++ local_irq_save(flags); ++ if (nl->connection == PLIP_CN_RECEIVE) { ++ local_irq_restore(flags); ++ /* interrupted */ ++ nl->enet_stats.collisions++; ++ if (net_debug > 1) ++ printk(KERN_INFO "%s: collision.\n", ++ dev->name); ++ return OK; ++ } ++ c0 = z_readb(PAR_STATUS(dev)); ++ if (c0 & 0x08) { ++ enable_par_irq(dev, 0); ++ if (net_debug > 2) ++ printk(KERN_DEBUG "%s: send start\n", ++ dev->name); ++ snd->state = PLIP_PK_LENGTH_LSB; ++ snd->nibble = PLIP_NB_BEGIN; ++ nl->timeout_count = 0; ++ local_irq_restore(flags); ++ break; ++ } ++ local_irq_restore(flags); ++ if (--cx == 0) { ++ z_writeb(0x00, PAR_DATA(dev)); ++ return TIMEOUT; ++ } ++ } ++ ++ case PLIP_PK_LENGTH_LSB: ++ if (plip_send(dev, nibble_timeout, ++ &snd->nibble, snd->length.b.lsb)) ++ return TIMEOUT; ++ snd->state = PLIP_PK_LENGTH_MSB; ++ ++ case PLIP_PK_LENGTH_MSB: ++ if (plip_send(dev, nibble_timeout, ++ &snd->nibble, snd->length.b.msb)) ++ return TIMEOUT; ++ snd->state = PLIP_PK_DATA; ++ snd->byte = 0; ++ snd->checksum = 0; ++ ++ case PLIP_PK_DATA: ++ do ++ if (plip_send(dev, nibble_timeout, ++ &snd->nibble, lbuf[snd->byte])) ++ return TIMEOUT; ++ while (++snd->byte < snd->length.h); ++ do ++ snd->checksum += lbuf[--snd->byte]; ++ while (snd->byte); ++ snd->state = PLIP_PK_CHECKSUM; ++ ++ case PLIP_PK_CHECKSUM: ++ if (plip_send(dev, nibble_timeout, ++ &snd->nibble, snd->checksum)) ++ return TIMEOUT; ++ ++ dev_kfree_skb(snd->skb); ++ nl->enet_stats.tx_packets++; ++ snd->state = PLIP_PK_DONE; ++ ++ case PLIP_PK_DONE: ++ /* Close the connection */ ++ z_writeb (0x00, PAR_DATA(dev)); ++ snd->skb = NULL; ++ if (net_debug > 2) ++ printk(KERN_DEBUG "%s: send end\n", dev->name); ++ nl->connection = PLIP_CN_CLOSING; ++ nl->is_deferred = 1; ++ queue_task(&nl->deferred, &tq_timer); ++ enable_par_irq(dev, 1); ++ return OK; ++ } ++ return OK; ++} ++ ++static int ++plip_connection_close(struct device *dev, struct net_local *nl, ++ struct plip_local *snd, struct plip_local *rcv) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ if (nl->connection == PLIP_CN_CLOSING) { ++ nl->connection = PLIP_CN_NONE; ++ dev->tbusy = 0; ++ mark_bh(NET_BH); ++ } ++ local_irq_restore(flags); ++ return OK; ++} ++ ++/* PLIP_ERROR --- wait till other end settled */ ++static int ++plip_error(struct device *dev, struct net_local *nl, ++ struct plip_local *snd, struct plip_local *rcv) ++{ ++ unsigned char status; ++ ++ status = z_readb(PAR_STATUS(dev)); ++ if ((status & 0xf8) == 0x80) { ++ if (net_debug > 2) ++ printk(KERN_DEBUG "%s: reset interface.\n", dev->name); ++ nl->connection = PLIP_CN_NONE; ++ dev->tbusy = 0; ++ dev->interrupt = 0; ++ enable_par_irq(dev, 1); ++ mark_bh(NET_BH); ++ } else { ++ nl->is_deferred = 1; ++ queue_task(&nl->deferred, &tq_timer); ++ } ++ ++ return OK; ++} ++ ++/* We don't need to send arp, for plip is point-to-point. */ ++static int ++plip_rebuild_header(struct sk_buff *skb) ++{ ++ struct device *dev = skb->dev; ++ struct net_local *nl = (struct net_local *)dev->priv; ++ struct ethhdr *eth = (struct ethhdr *)skb->data; ++ int i; ++ ++ if ((dev->flags & IFF_NOARP)==0) ++ return nl->orig_rebuild_header(skb); ++ ++ if (eth->h_proto != __constant_htons(ETH_P_IP) ++#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) ++ && eth->h_proto != __constant_htons(ETH_P_IPV6) ++#endif ++ ) { ++ printk(KERN_ERR "plip_rebuild_header: Don't know how to resolve type %d addresses?\n", (int)eth->h_proto); ++ memcpy(eth->h_source, dev->dev_addr, dev->addr_len); ++ return 0; ++ } ++ ++ for (i=0; i < ETH_ALEN - sizeof(u32); i++) ++ eth->h_dest[i] = 0xfc; ++#if 0 ++ *(u32 *)(eth->h_dest+i) = dst; ++#else ++ /* Do not want to include net/route.h here. ++ * In any case, it is TOP of silliness to emulate ++ * hardware addresses on PtP link. --ANK ++ */ ++ *(u32 *)(eth->h_dest+i) = 0; ++#endif ++ return 0; ++} ++ ++static int ++plip_tx_packet(struct sk_buff *skb, struct device *dev) ++{ ++ struct net_local *nl = (struct net_local *)dev->priv; ++ struct plip_local *snd = &nl->snd_data; ++ unsigned long flags; ++ ++ if (dev->tbusy) ++ return 1; ++ ++ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { ++ printk(KERN_ERR "%s: Transmitter access conflict.\n", ++ dev->name); ++ return 1; ++ } ++ ++ if (skb->len > dev->mtu + dev->hard_header_len) { ++ printk(KERN_ERR "%s: packet too big, %d.\n", ++ dev->name, (int)skb->len); ++ dev->tbusy = 0; ++ return 0; ++ } ++ ++ if (net_debug > 2) ++ printk(KERN_DEBUG "%s: send request\n", dev->name); ++ ++ local_irq_save(flags); ++ dev->trans_start = jiffies; ++ snd->skb = skb; ++ snd->length.h = skb->len; ++ snd->state = PLIP_PK_TRIGGER; ++ if (nl->connection == PLIP_CN_NONE) { ++ nl->connection = PLIP_CN_SEND; ++ nl->timeout_count = 0; ++ } ++ queue_task(&nl->immediate, &tq_immediate); ++ mark_bh(IMMEDIATE_BH); ++ local_irq_restore(flags); ++ ++ return 0; ++} ++ ++/* Open/initialize the board. This is called (in the current kernel) ++ sometime after booting when the 'ifconfig' program is run. ++ ++ */ ++static int ++plip_open(struct device *dev) ++{ ++ struct net_local *nl = (struct net_local *)dev->priv; ++ struct in_device *in_dev; ++ ++#if defined(CONFIG_GVPIOEXT_LP) || defined(CONFIG_GVPIOEXT_LP_MODULE) ++ /* Yes, there is a race condition here. Fix it later */ ++ if (PLIP_DEV(dev)->par_use & IOEXT_PAR_LP) { ++ /* Can't open if lp is in use */ ++#if DEBUG ++ printk("par is in use by lp\n"); ++#endif ++ return(-EBUSY); ++ } ++#endif ++ PLIP_DEV(dev)->par_use |= IOEXT_PAR_PLIP; ++ ++#if DEBUG ++ printk("plip_open(): sending 00 to data port\n"); ++#endif ++ ++ /* Clear the data port. */ ++ z_writeb (0x00, PAR_DATA(dev)); ++ ++#if DEBUG ++ printk("plip_open(): sent\n"); ++#endif ++ ++ /* Initialize the state machine. */ ++ nl->rcv_data.state = nl->snd_data.state = PLIP_PK_DONE; ++ nl->rcv_data.skb = nl->snd_data.skb = NULL; ++ nl->connection = PLIP_CN_NONE; ++ nl->is_deferred = 0; ++ ++ /* Fill in the MAC-level header. ++ (ab)Use "dev->broadcast" to store point-to-point MAC address. ++ ++ PLIP doesn't have a real mac address, but we need to create one ++ to be DOS compatible. */ ++ memset(dev->dev_addr, 0xfc, ETH_ALEN); ++ memset(dev->broadcast, 0xfc, ETH_ALEN); ++ ++ if ((in_dev=dev->ip_ptr) != NULL) { ++ /* ++ * Any address will do - we take the first ++ */ ++ struct in_ifaddr *ifa=in_dev->ifa_list; ++ if (ifa != NULL) { ++ memcpy(dev->dev_addr+2, &ifa->ifa_local, 4); ++ memcpy(dev->broadcast+2, &ifa->ifa_address, 4); ++ } ++ } ++ ++ dev->interrupt = 0; ++ dev->start = 1; ++ dev->tbusy = 0; ++ ++ MOD_INC_USE_COUNT; ++ ++ /* Enable rx interrupt. */ ++ enable_par_irq(dev, 1); ++ ++ return 0; ++} ++ ++/* The inverse routine to plip_open (). */ ++static int ++plip_close(struct device *dev) ++{ ++ struct net_local *nl = (struct net_local *)dev->priv; ++ struct plip_local *snd = &nl->snd_data; ++ struct plip_local *rcv = &nl->rcv_data; ++ unsigned long flags; ++ ++ dev->tbusy = 1; ++ dev->start = 0; ++ local_irq_save(flags); ++ nl->is_deferred = 0; ++ nl->connection = PLIP_CN_NONE; ++ local_irq_restore(flags); ++ z_writeb(0x00, PAR_DATA(dev)); ++ ++ snd->state = PLIP_PK_DONE; ++ if (snd->skb) { ++ dev_kfree_skb(snd->skb); ++ snd->skb = NULL; ++ } ++ rcv->state = PLIP_PK_DONE; ++ if (rcv->skb) { ++ kfree_skb(rcv->skb); ++ rcv->skb = NULL; ++ } ++ ++ PLIP_DEV(dev)->par_use &= ~IOEXT_PAR_PLIP; ++ ++ MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++static struct enet_statistics * ++plip_get_stats(struct device *dev) ++{ ++ struct net_local *nl = (struct net_local *)dev->priv; ++ struct enet_statistics *r = &nl->enet_stats; ++ ++ return r; ++} ++ ++static int ++plip_config(struct device *dev, struct ifmap *map) ++{ ++ if (dev->flags & IFF_UP) ++ return -EBUSY; ++ ++ printk(KERN_INFO "%s: This interface is autodetected (ignored).\n", ++ dev->name); ++ ++ return 0; ++} ++ ++static int ++plip_ioctl(struct device *dev, struct ifreq *rq, int cmd) ++{ ++ struct net_local *nl = (struct net_local *) dev->priv; ++ struct plipconf *pc = (struct plipconf *) &rq->ifr_data; ++ ++ switch(pc->pcmd) { ++ case PLIP_GET_TIMEOUT: ++ pc->trigger = nl->trigger; ++ pc->nibble = nl->nibble; ++ break; ++ case PLIP_SET_TIMEOUT: ++ nl->trigger = pc->trigger; ++ nl->nibble = pc->nibble; ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ return 0; ++} ++ ++/* ++ * Detect and initialize all IO-Extenders in this system. ++ * ++ * Both PLIP and serial devices are configured. ++ */ ++int plip_init(struct device *dev) ++{ ++ IOEXT_struct *board; ++ struct net_local *nl; ++ ++ if (ioext_num == 0) { ++ printk(KERN_INFO "%s\n", version); ++ } ++ ++ board = PLIP_DEV(dev)->board; ++ dev->base_addr = (unsigned long)&board->par.DATA; ++ ++ /* Cheat and use irq to index into our table */ ++ dev->irq = ioext_num; ++ ++ printk(KERN_INFO "%s: IO-Extender parallel port at 0x%08lX\n", dev->name, dev->base_addr); ++ ++ /* Fill in the generic fields of the device structure. */ ++ ether_setup(dev); ++ ++ /* Then, override parts of it */ ++ dev->hard_start_xmit = plip_tx_packet; ++ dev->open = plip_open; ++ dev->stop = plip_close; ++ dev->get_stats = plip_get_stats; ++ dev->set_config = plip_config; ++ dev->do_ioctl = plip_ioctl; ++ dev->tx_queue_len = 10; ++ dev->flags = IFF_POINTOPOINT|IFF_NOARP; ++ ++ /* Set the private structure */ ++ dev->priv = kmalloc(sizeof (struct net_local), GFP_KERNEL); ++ if (dev->priv == NULL) { ++ printk(KERN_ERR "%s: out of memory\n", dev->name); ++ return -ENOMEM; ++ } ++ memset(dev->priv, 0, sizeof(struct net_local)); ++ nl = (struct net_local *) dev->priv; ++ ++ nl->orig_rebuild_header = dev->rebuild_header; ++ dev->rebuild_header = plip_rebuild_header; ++ ++ /* Initialize constants */ ++ nl->trigger = PLIP_TRIGGER_WAIT; ++ nl->nibble = PLIP_NIBBLE_WAIT; ++ ++ /* Initialize task queue structures */ ++ nl->immediate.next = NULL; ++ nl->immediate.sync = 0; ++ nl->immediate.routine = (void *)(void *)plip_bh; ++ nl->immediate.data = dev; ++ ++ nl->deferred.next = NULL; ++ nl->deferred.sync = 0; ++ nl->deferred.routine = (void *)(void *)plip_kick_bh; ++ nl->deferred.data = dev; ++ ++ /* Don't enable interrupts yet */ ++ ++ return 0; ++} diff --git a/debian/patches/bugfix/m68k/149-mc68681.diff b/debian/patches/bugfix/m68k/149-mc68681.diff new file mode 100644 index 000000000000..eaad1204f97f --- /dev/null +++ b/debian/patches/bugfix/m68k/149-mc68681.diff @@ -0,0 +1,146 @@ +To: linus, alan +Cc: lkml +Subject: [PATCH] MC68681 DUART + +From: Linux/m68k legacy + +MC68681 DUART register definitions for the Amiga MultiFace III serial driver. + +--- + drivers/char/mc68681.h | 131 +++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 131 insertions(+) + +--- /dev/null ++++ linux-m68k-2.6.21/drivers/char/mc68681.h +@@ -0,0 +1,131 @@ ++#ifndef _MC68681_H_ ++#define _MC68681_H_ ++ ++/* ++ * This describes an MC68681 DUART. It has almost only overlayed registers, which ++ * the structure very ugly. ++ * Note that the ri-register isn't really a register of the duart but a kludge of bsc ++ * to make the ring indicator available. ++ * ++ * The data came from the MFC-31-Developer Kit (from Ralph Seidel, ++ * zodiac@darkness.gun.de) and the data sheet of Phillip's clone device (SCN68681) ++ * (from Richard Hirst, srh@gpt.co.uk) ++ * ++ * 11.11.95 copyright Joerg Dorchain (dorchain@mpi-sb.mpg.de) ++ * ++ */ ++ ++struct duarthalf { ++union { ++volatile u_char mr1; /* rw */ ++volatile u_char mr2; /* rw */ ++} mr; ++volatile u_char ri; /* special, read */ ++union { ++volatile u_char sr; /* read */ ++volatile u_char csr; /* write */ ++} sr_csr; ++u_char pad1; ++volatile u_char cr; /* write */ ++u_char pad2; ++union { ++volatile u_char rhr; /* read */ ++volatile u_char thr; /* write */ ++} hr; ++u_char pad3; ++}; ++ ++struct duart { ++struct duarthalf pa; ++union { ++volatile u_char ipcr; /* read */ ++volatile u_char acr; /* write */ ++} ipcr_acr; ++u_char pad1; ++union { ++volatile u_char isr; /* read */ ++volatile u_char imr; /* write */ ++} ir; ++u_char pad2; ++volatile u_char ctu; ++u_char pad3; ++volatile u_char ctl; ++u_char pad4; ++struct duarthalf pb; ++volatile u_char ivr; ++u_char pad5; ++union { ++volatile u_char ipr; /* read */ ++volatile u_char opcr; /* write */ ++} ipr_opcr; ++u_char pad6; ++union { ++volatile u_char start; /* read */ ++volatile u_char sopc; /* write */ ++} start_sopc; ++u_char pad7; ++union { ++volatile u_char stop; /* read */ ++volatile u_char ropc; /* write */ ++} stop_ropc; ++u_char pad8; ++}; ++ ++#define MR1_BITS 3 ++#define MR1_5BITS 0 ++#define MR1_6BITS 1 ++#define MR1_7BITS 2 ++#define MR1_8BITS 3 ++ ++#define MR1_PARITY_ODD 4 ++ ++#define MR1_PARITY 24 ++#define MR1_PARITY_WITH 0 ++#define MR1_PARITY_FORCE 8 ++#define MR1_PARITY_NO 16 ++#define MR1_PARITY_MULTIDROP 24 ++ ++#define MR1_ERROR_BLOCK 32 ++#define MR1_FFULL_IRQ 64 ++#define MR1_RxRTS_ON 128 ++ ++#define MR2_STOPS 15 ++#define MR2_1STOP 7 ++#define MR2_2STOP 15 ++ ++#define MR2_CTS_ON 16 ++#define MR2_TxRTS_ON 32 ++ ++#define MR2_MODE 192 ++#define MR2_NORMAL 0 ++#define MR2_ECHO 64 ++#define MR2_LOCALLOOP 128 ++#define MR2_REMOTELOOP 192 ++ ++#define CR_RXCOMMAND 3 ++#define CR_NONE 0 ++#define CR_RX_ON 1 ++#define CR_RX_OFF 2 ++#define CR_TXCOMMAND 12 ++#define CR_TX_ON 4 ++#define CR_TX_OFF 8 ++#define CR_MISC 112 ++#define CR_RESET_MR 16 ++#define CR_RESET_RX 32 ++#define CR_RESET_TX 48 ++#define CR_RESET_ERR 64 ++#define CR_RESET_BREAK 80 ++#define CR_START_BREAK 96 ++#define CR_STOP_BREAK 112 ++ ++#define SR_RXRDY 1 ++#define SR_FFULL 2 ++#define SR_TXRDY 4 ++#define SR_TXEMPT 8 ++#define SR_OVERRUN 16 ++#define SR_PARITY 32 ++#define SR_FRAMING 64 ++#define SR_BREAK 128 ++ ++ ++#endif diff --git a/debian/patches/bugfix/m68k/152-pci.diff b/debian/patches/bugfix/m68k/152-pci.diff new file mode 100644 index 000000000000..71e738b66aa5 --- /dev/null +++ b/debian/patches/bugfix/m68k/152-pci.diff @@ -0,0 +1,21 @@ +To: linus, alan +Cc: lkml +Subject: [PATCH] M68k PCI + +First steps in making m68k PCI support compilable again + +--- + arch/m68k/kernel/bios32.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- linux-m68k-2.6.21.orig/arch/m68k/kernel/bios32.c ++++ linux-m68k-2.6.21/arch/m68k/kernel/bios32.c +@@ -284,7 +284,7 @@ static void __init layout_bus(struct pci + + DBG_DEVS(("layout_bus: starting bus %d\n", bus->number)); + +- if (!bus->devices && !bus->children) ++ if (list_empty(&bus->devices) && list_empty(&bus->children)) + return; + + /* diff --git a/debian/patches/bugfix/m68k/357-mac89x0.diff b/debian/patches/bugfix/m68k/357-mac89x0.diff new file mode 100644 index 000000000000..6827b6698c8d --- /dev/null +++ b/debian/patches/bugfix/m68k/357-mac89x0.diff @@ -0,0 +1,177 @@ +Subject: [PATCH] m68k: Mac89x0 Ethernet netif updates +Cc: Jeff Garzik <jgarzik@pobox.com>, netdev@vger.kernel.org + +From: Matthias Urlichs <smurf@smurf.noris.de> + +Macintosh CS89x0 Ethernet: Netif updates +Addition of netif_stop_queue() before transmission by Michael Schmitz + +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + drivers/net/Kconfig | 2 - + drivers/net/mac89x0.c | 90 +++++++++++++++++--------------------------------- + 2 files changed, 33 insertions(+), 59 deletions(-) + +--- linux-m68k-2.6.21.orig/drivers/net/Kconfig ++++ linux-m68k-2.6.21/drivers/net/Kconfig +@@ -311,7 +311,7 @@ config MAC8390 + + config MAC89x0 + tristate "Macintosh CS89x0 based ethernet cards" +- depends on NET_ETHERNET && MAC && BROKEN ++ depends on NET_ETHERNET && MAC + ---help--- + Support for CS89x0 chipset based Ethernet cards. If you have a + Nubus or LC-PDS network (Ethernet) card of this type, say Y and +--- linux-m68k-2.6.21.orig/drivers/net/mac89x0.c ++++ linux-m68k-2.6.21/drivers/net/mac89x0.c +@@ -128,7 +128,7 @@ struct net_local { + extern void reset_chip(struct net_device *dev); + #endif + static int net_open(struct net_device *dev); +-static int net_send_packet(struct sk_buff *skb, struct net_device *dev); ++static int net_send_packet(struct sk_buff *skb, struct net_device *dev); + static irqreturn_t net_interrupt(int irq, void *dev_id); + static void set_multicast_list(struct net_device *dev); + static void net_rx(struct net_device *dev); +@@ -374,56 +374,38 @@ net_open(struct net_device *dev) + static int + net_send_packet(struct sk_buff *skb, struct net_device *dev) + { +- if (dev->tbusy) { +- /* If we get here, some higher level has decided we are broken. +- There should really be a "kick me" function call instead. */ +- int tickssofar = jiffies - dev->trans_start; +- if (tickssofar < 5) +- return 1; +- if (net_debug > 0) printk("%s: transmit timed out, %s?\n", dev->name, +- tx_done(dev) ? "IRQ conflict" : "network cable problem"); +- /* Try to restart the adaptor. */ +- dev->tbusy=0; +- dev->trans_start = jiffies; +- } +- +- /* Block a timer-based transmit from overlapping. This could better be +- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ +- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) +- printk("%s: Transmitter access conflict.\n", dev->name); +- else { +- struct net_local *lp = netdev_priv(dev); +- unsigned long flags; +- +- if (net_debug > 3) +- printk("%s: sent %d byte packet of type %x\n", +- dev->name, skb->len, +- (skb->data[ETH_ALEN+ETH_ALEN] << 8) +- | skb->data[ETH_ALEN+ETH_ALEN+1]); +- +- /* keep the upload from being interrupted, since we +- ask the chip to start transmitting before the +- whole packet has been completely uploaded. */ +- local_irq_save(flags); +- +- /* initiate a transmit sequence */ +- writereg(dev, PP_TxCMD, lp->send_cmd); +- writereg(dev, PP_TxLength, skb->len); +- +- /* Test to see if the chip has allocated memory for the packet */ +- if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) { +- /* Gasp! It hasn't. But that shouldn't happen since +- we're waiting for TxOk, so return 1 and requeue this packet. */ +- local_irq_restore(flags); +- return 1; +- } ++ struct net_local *lp = netdev_priv(dev); ++ unsigned long flags; + +- /* Write the contents of the packet */ +- memcpy_toio(dev->mem_start + PP_TxFrame, skb->data, skb->len+1); ++ if (net_debug > 3) ++ printk("%s: sent %d byte packet of type %x\n", ++ dev->name, skb->len, ++ (skb->data[ETH_ALEN+ETH_ALEN] << 8) ++ | skb->data[ETH_ALEN+ETH_ALEN+1]); ++ ++ /* keep the upload from being interrupted, since we ++ ask the chip to start transmitting before the ++ whole packet has been completely uploaded. */ ++ local_irq_save(flags); ++ netif_stop_queue(dev); + ++ /* initiate a transmit sequence */ ++ writereg(dev, PP_TxCMD, lp->send_cmd); ++ writereg(dev, PP_TxLength, skb->len); ++ ++ /* Test to see if the chip has allocated memory for the packet */ ++ if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) { ++ /* Gasp! It hasn't. But that shouldn't happen since ++ we're waiting for TxOk, so return 1 and requeue this packet. */ + local_irq_restore(flags); +- dev->trans_start = jiffies; ++ return 1; + } ++ ++ /* Write the contents of the packet */ ++ memcpy((void *)(dev->mem_start + PP_TxFrame), skb->data, skb->len+1); ++ ++ local_irq_restore(flags); ++ dev->trans_start = jiffies; + dev_kfree_skb (skb); + + return 0; +@@ -441,9 +423,6 @@ static irqreturn_t net_interrupt(int irq + printk ("net_interrupt(): irq %d for unknown device.\n", irq); + return IRQ_NONE; + } +- if (dev->interrupt) +- printk("%s: Re-entering the interrupt handler.\n", dev->name); +- dev->interrupt = 1; + + ioaddr = dev->base_addr; + lp = netdev_priv(dev); +@@ -464,8 +443,7 @@ static irqreturn_t net_interrupt(int irq + break; + case ISQ_TRANSMITTER_EVENT: + lp->stats.tx_packets++; +- dev->tbusy = 0; +- mark_bh(NET_BH); /* Inform upper layers. */ ++ netif_wake_queue(dev); + if ((status & TX_OK) == 0) lp->stats.tx_errors++; + if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++; + if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++; +@@ -479,8 +457,7 @@ static irqreturn_t net_interrupt(int irq + That shouldn't happen since we only ever + load one packet. Shrug. Do the right + thing anyway. */ +- dev->tbusy = 0; +- mark_bh(NET_BH); /* Inform upper layers. */ ++ netif_wake_queue(dev); + } + if (status & TX_UNDERRUN) { + if (net_debug > 0) printk("%s: transmit underrun\n", dev->name); +@@ -497,7 +474,6 @@ static irqreturn_t net_interrupt(int irq + break; + } + } +- dev->interrupt = 0; + return IRQ_HANDLED; + } + +@@ -532,7 +508,7 @@ net_rx(struct net_device *dev) + skb_put(skb, length); + skb->dev = dev; + +- memcpy_fromio(skb->data, dev->mem_start + PP_RxFrame, length); ++ memcpy(skb->data, (void *)(dev->mem_start + PP_RxFrame), length); + + if (net_debug > 3)printk("%s: received %d byte packet of type %x\n", + dev->name, length, +@@ -611,8 +587,6 @@ static void set_multicast_list(struct ne + static int set_mac_address(struct net_device *dev, void *addr) + { + int i; +- if (dev->start) +- return -EBUSY; + printk("%s: Setting MAC address to ", dev->name); + for (i = 0; i < 6; i++) + printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]); diff --git a/debian/patches/bugfix/m68k/448-ide.diff b/debian/patches/bugfix/m68k/448-ide.diff new file mode 100644 index 000000000000..8d4c0aec061f --- /dev/null +++ b/debian/patches/bugfix/m68k/448-ide.diff @@ -0,0 +1,23 @@ +To: linus, akpm, B.Zolnierkiewicz@elka.pw.edu.pl +Cc: lkml +Subject: [PATCH] m68k IDE compiler bug + +From: Roman Zippel <zippel@linux-m68k.org> + +IDE: Avoid compiler bug in gcc 3.2 (from Roman Zippel) + +--- + include/linux/ide.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- linux-m68k-2.6.21.orig/include/linux/ide.h ++++ linux-m68k-2.6.21/include/linux/ide.h +@@ -513,7 +513,7 @@ typedef union { + * sense_key : Sense key of the last failed packet command + */ + typedef union { +- unsigned all :8; ++ u8 all; + struct { + #if defined(__LITTLE_ENDIAN_BITFIELD) + unsigned ili :1; diff --git a/debian/patches/bugfix/m68k/478-serial.diff b/debian/patches/bugfix/m68k/478-serial.diff new file mode 100644 index 000000000000..efa2d962d563 --- /dev/null +++ b/debian/patches/bugfix/m68k/478-serial.diff @@ -0,0 +1,30 @@ +To: linus, akpm +Cc: lkml +Subject: [PATCH] M68k SERIAL_PORT_DFNS only if CONFIG_ISA + +From: Kars de Jong <jongk@linux-m68k.org> + +M68k serial: Only define SERIAL_PORT_DFNS when CONFIG_ISA is defined. Otherwise +the first 4 slots in the 8250 driver are unavailable on non-ISA machines. + +Signed-off-by: Kars de Jong <jongk@linux-m68k.org> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> + +--- + include/asm-m68k/serial.h | 2 ++ + 1 file changed, 2 insertions(+) + +--- linux-m68k-2.6.21.orig/include/asm-m68k/serial.h ++++ linux-m68k-2.6.21/include/asm-m68k/serial.h +@@ -25,9 +25,11 @@ + #define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF + #endif + ++#ifdef CONFIG_ISA + #define SERIAL_PORT_DFNS \ + /* UART CLK PORT IRQ FLAGS */ \ + { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \ + { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */ \ + { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \ + { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */ ++#endif diff --git a/debian/patches/bugfix/m68k/577-module-arch.diff b/debian/patches/bugfix/m68k/577-module-arch.diff new file mode 100644 index 000000000000..10e6823bbcf8 --- /dev/null +++ b/debian/patches/bugfix/m68k/577-module-arch.diff @@ -0,0 +1,37 @@ +Subject: [PATCH] Allow arch to initialize arch field of the module structure + +From: Roman Zippel <zippel@linux-m68k.org> + +This will later allow an arch to add module specific information via +linker generated tables instead of poking directly in the module object +structure. + +Signed-off-by: Roman Zippel <zippel@linux-m68k.org> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + include/linux/module.h | 3 +++ + scripts/mod/modpost.c | 1 + + 2 files changed, 4 insertions(+) + +--- linux-m68k-2.6.21.orig/include/linux/module.h ++++ linux-m68k-2.6.21/include/linux/module.h +@@ -356,6 +356,9 @@ struct module + keeping pointers to this stuff */ + char *args; + }; ++#ifndef MODULE_ARCH_INIT ++#define MODULE_ARCH_INIT {} ++#endif + + /* FIXME: It'd be nice to isolate modules during init, too, so they + aren't used before they (may) fail. But presently too much code +--- linux-m68k-2.6.21.orig/scripts/mod/modpost.c ++++ linux-m68k-2.6.21/scripts/mod/modpost.c +@@ -1249,6 +1249,7 @@ static void add_header(struct buffer *b, + buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n" + " .exit = cleanup_module,\n" + "#endif\n"); ++ buf_printf(b, " .arch = MODULE_ARCH_INIT,\n"); + buf_printf(b, "};\n"); + } + diff --git a/debian/patches/bugfix/m68k/600-task_thread_info.diff b/debian/patches/bugfix/m68k/600-task_thread_info.diff new file mode 100644 index 000000000000..7ea927520c2d --- /dev/null +++ b/debian/patches/bugfix/m68k/600-task_thread_info.diff @@ -0,0 +1,43 @@ +Subject: [PATCH] Wrap access to thread_info + +From: Roman Zippel <zippel@linux-m68k.org> + +Wrap direct thread_info access + +Signed-off-by: Roman Zippel <zippel@linux-m68k.org> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + kernel/mutex.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- linux-m68k-2.6.21.orig/kernel/mutex.c ++++ linux-m68k-2.6.21/kernel/mutex.c +@@ -133,7 +133,7 @@ __mutex_lock_common(struct mutex *lock, + + debug_mutex_lock_common(lock, &waiter); + mutex_acquire(&lock->dep_map, subclass, 0, _RET_IP_); +- debug_mutex_add_waiter(lock, &waiter, task->thread_info); ++ debug_mutex_add_waiter(lock, &waiter, task_thread_info(task)); + + /* add waiting tasks to the end of the waitqueue (FIFO): */ + list_add_tail(&waiter.list, &lock->wait_list); +@@ -159,7 +159,7 @@ __mutex_lock_common(struct mutex *lock, + */ + if (unlikely(state == TASK_INTERRUPTIBLE && + signal_pending(task))) { +- mutex_remove_waiter(lock, &waiter, task->thread_info); ++ mutex_remove_waiter(lock, &waiter, task_thread_info(task)); + mutex_release(&lock->dep_map, 1, _RET_IP_); + spin_unlock_mutex(&lock->wait_lock, flags); + +@@ -175,8 +175,8 @@ __mutex_lock_common(struct mutex *lock, + } + + /* got the lock - rejoice! */ +- mutex_remove_waiter(lock, &waiter, task->thread_info); +- debug_mutex_set_owner(lock, task->thread_info); ++ mutex_remove_waiter(lock, &waiter, task_thread_info(task)); ++ debug_mutex_set_owner(lock, task_thread_info(task)); + + /* set it to 0 if there are no waiters left: */ + if (likely(list_empty(&lock->wait_list))) diff --git a/debian/patches/bugfix/m68k/611-module_fixup.diff b/debian/patches/bugfix/m68k/611-module_fixup.diff new file mode 100644 index 000000000000..94aa02f4698c --- /dev/null +++ b/debian/patches/bugfix/m68k/611-module_fixup.diff @@ -0,0 +1,214 @@ +Subject: [PATCH] m68k: runtime patching infrastructure + +From: Roman Zippel <zippel@linux-m68k.org> + +Add the basic infrastructure to allow runtime patching of kernel and +modules to optimize a few functions with parameters, which are only +calculated once during bootup and are otherwise constant. +Use this for the conversion between virtual and physical addresses. + +Signed-off-by: Roman Zippel <zippel@linux-m68k.org> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + arch/m68k/Makefile | 1 + + arch/m68k/kernel/module.c | 24 +++++++++++++++++++++++- + arch/m68k/kernel/module.lds | 7 +++++++ + arch/m68k/kernel/vmlinux-std.lds | 5 +++++ + arch/m68k/kernel/vmlinux-sun3.lds | 5 +++++ + arch/m68k/mm/motorola.c | 3 +++ + include/asm-m68k/module.h | 33 ++++++++++++++++++++++++++++++++- + include/asm-m68k/page.h | 29 ++++++++++++++++++++++++++--- + 8 files changed, 102 insertions(+), 5 deletions(-) + +--- linux-m68k-2.6.21.orig/arch/m68k/Makefile ++++ linux-m68k-2.6.21/arch/m68k/Makefile +@@ -19,6 +19,7 @@ COMPILE_ARCH = $(shell uname -m) + # override top level makefile + AS += -m68020 + LDFLAGS := -m m68kelf ++LDFLAGS_MODULE += -T $(srctree)/arch/m68k/kernel/module.lds + ifneq ($(COMPILE_ARCH),$(ARCH)) + # prefix for cross-compiling binaries + CROSS_COMPILE = m68k-linux-gnu- +--- linux-m68k-2.6.21.orig/arch/m68k/kernel/module.c ++++ linux-m68k-2.6.21/arch/m68k/kernel/module.c +@@ -1,3 +1,9 @@ ++/* ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive ++ * for more details. ++ */ ++ + #include <linux/moduleloader.h> + #include <linux/elf.h> + #include <linux/vmalloc.h> +@@ -116,10 +122,26 @@ int apply_relocate_add(Elf32_Shdr *sechd + return 0; + } + ++void module_fixup(struct module *mod, struct m68k_fixup_info *start, ++ struct m68k_fixup_info *end) ++{ ++ struct m68k_fixup_info *fixup; ++ ++ for (fixup = start; fixup < end; fixup++) { ++ switch (fixup->type) { ++ case m68k_fixup_memoffset: ++ *(u32 *)fixup->addr = m68k_memoffset; ++ break; ++ } ++ } ++} ++ + int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, +- struct module *me) ++ struct module *mod) + { ++ module_fixup(mod, mod->arch.fixup_start, mod->arch.fixup_end); ++ + return 0; + } + +--- /dev/null ++++ linux-m68k-2.6.21/arch/m68k/kernel/module.lds +@@ -0,0 +1,7 @@ ++SECTIONS { ++ .m68k_fixup : { ++ __start_fixup = .; ++ *(.m68k_fixup) ++ __stop_fixup = .; ++ } ++} +--- linux-m68k-2.6.21.orig/arch/m68k/kernel/vmlinux-std.lds ++++ linux-m68k-2.6.21/arch/m68k/kernel/vmlinux-std.lds +@@ -60,6 +60,11 @@ SECTIONS + __con_initcall_start = .; + .con_initcall.init : { *(.con_initcall.init) } + __con_initcall_end = .; ++ .m68k_fixup : { ++ __start_fixup = .; ++ *(.m68k_fixup) ++ __stop_fixup = .; ++ } + SECURITY_INIT + #ifdef CONFIG_BLK_DEV_INITRD + . = ALIGN(8192); +--- linux-m68k-2.6.21.orig/arch/m68k/kernel/vmlinux-sun3.lds ++++ linux-m68k-2.6.21/arch/m68k/kernel/vmlinux-sun3.lds +@@ -54,6 +54,11 @@ __init_begin = .; + __con_initcall_start = .; + .con_initcall.init : { *(.con_initcall.init) } + __con_initcall_end = .; ++ .m68k_fixup : { ++ __start_fixup = .; ++ *(.m68k_fixup) ++ __stop_fixup = .; ++ } + SECURITY_INIT + #ifdef CONFIG_BLK_DEV_INITRD + . = ALIGN(8192); +--- linux-m68k-2.6.21.orig/arch/m68k/mm/motorola.c ++++ linux-m68k-2.6.21/arch/m68k/mm/motorola.c +@@ -222,6 +222,9 @@ void __init paging_init(void) + pgprot_val(protection_map[i]) |= _PAGE_CACHE040; + } + ++ module_fixup(NULL, __start_fixup, __stop_fixup); ++ flush_icache(); ++ + /* + * Map the physical memory available into the kernel virtual + * address space. It may allocate some memory for page +--- linux-m68k-2.6.21.orig/include/asm-m68k/module.h ++++ linux-m68k-2.6.21/include/asm-m68k/module.h +@@ -1,7 +1,38 @@ + #ifndef _ASM_M68K_MODULE_H + #define _ASM_M68K_MODULE_H +-struct mod_arch_specific { }; ++ ++struct mod_arch_specific { ++ struct m68k_fixup_info *fixup_start, *fixup_end; ++}; ++ ++#define MODULE_ARCH_INIT { \ ++ .fixup_start = __start_fixup, \ ++ .fixup_end = __stop_fixup, \ ++} ++ + #define Elf_Shdr Elf32_Shdr + #define Elf_Sym Elf32_Sym + #define Elf_Ehdr Elf32_Ehdr ++ ++ ++enum m68k_fixup_type { ++ m68k_fixup_memoffset, ++}; ++ ++struct m68k_fixup_info { ++ enum m68k_fixup_type type; ++ void *addr; ++}; ++ ++#define m68k_fixup(type, addr) \ ++ " .section \".m68k_fixup\",\"aw\"\n" \ ++ " .long " #type "," #addr "\n" \ ++ " .previous\n" ++ ++extern struct m68k_fixup_info __start_fixup[], __stop_fixup[]; ++ ++struct module; ++extern void module_fixup(struct module *mod, struct m68k_fixup_info *start, ++ struct m68k_fixup_info *end); ++ + #endif /* _ASM_M68K_MODULE_H */ +--- linux-m68k-2.6.21.orig/include/asm-m68k/page.h ++++ linux-m68k-2.6.21/include/asm-m68k/page.h +@@ -27,6 +27,8 @@ + + #ifndef __ASSEMBLY__ + ++#include <asm/module.h> ++ + #define get_user_page(vaddr) __get_free_page(GFP_KERNEL) + #define free_user_page(page, addr) free_page(addr) + +@@ -114,14 +116,35 @@ typedef struct { unsigned long pgprot; } + + #ifndef __ASSEMBLY__ + ++extern unsigned long m68k_memoffset; ++ + #ifndef CONFIG_SUN3 + + #define WANT_PAGE_VIRTUAL + #ifdef CONFIG_SINGLE_MEMORY_CHUNK +-extern unsigned long m68k_memoffset; + +-#define __pa(vaddr) ((unsigned long)(vaddr)+m68k_memoffset) +-#define __va(paddr) ((void *)((unsigned long)(paddr)-m68k_memoffset)) ++static inline unsigned long ___pa(void *vaddr) ++{ ++ unsigned long paddr; ++ asm ( ++ "1: addl #0,%0\n" ++ m68k_fixup(%c2, 1b+2) ++ : "=r" (paddr) ++ : "0" (vaddr), "i" (m68k_fixup_memoffset)); ++ return paddr; ++} ++#define __pa(vaddr) ___pa((void *)(vaddr)) ++static inline void *__va(unsigned long paddr) ++{ ++ void *vaddr; ++ asm ( ++ "1: subl #0,%0\n" ++ m68k_fixup(%c2, 1b+2) ++ : "=r" (vaddr) ++ : "0" (paddr), "i" (m68k_fixup_memoffset)); ++ return vaddr; ++} ++ + #else + #define __pa(vaddr) virt_to_phys((void *)(vaddr)) + #define __va(paddr) phys_to_virt((unsigned long)(paddr)) diff --git a/debian/patches/bugfix/m68k/618-discontig.diff b/debian/patches/bugfix/m68k/618-discontig.diff new file mode 100644 index 000000000000..ef8ec464fa93 --- /dev/null +++ b/debian/patches/bugfix/m68k/618-discontig.diff @@ -0,0 +1,868 @@ +To: linus, akpm +Cc: lkml +Subject: [PATCH] m68k: Discontinuous memory support + +From: Roman Zippel <zippel@linux-m68k.org> + +Fix support for discontinuous memory + +Signed-off-by: Roman Zippel <zippel@linux-m68k.org> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + arch/m68k/Kconfig | 13 +++ + arch/m68k/kernel/module.c | 3 + arch/m68k/kernel/setup.c | 37 ++--------- + arch/m68k/mm/init.c | 119 +++++++++++++++++++++++------------- + arch/m68k/mm/memory.c | 73 ---------------------- + arch/m68k/mm/motorola.c | 102 +++++++++++++++++++++--------- + arch/m68k/sun3/config.c | 2 + include/asm-m68k/mmzone.h | 9 ++ + include/asm-m68k/module.h | 1 + include/asm-m68k/motorola_pgtable.h | 10 +-- + include/asm-m68k/page.h | 52 ++++++++++++--- + include/asm-m68k/pgalloc.h | 3 + include/asm-m68k/pgtable.h | 17 ----- + include/asm-m68k/sun3_pgtable.h | 4 - + include/asm-m68k/virtconvert.h | 48 +++----------- + mm/page_alloc.c | 2 + 16 files changed, 247 insertions(+), 248 deletions(-) + +--- linux-m68k-2.6.21.orig/arch/m68k/Kconfig ++++ linux-m68k-2.6.21/arch/m68k/Kconfig +@@ -355,8 +355,9 @@ config RMW_INSNS + adventurous. + + config SINGLE_MEMORY_CHUNK +- bool "Use one physical chunk of memory only" +- depends on ADVANCED && !SUN3 ++ bool "Use one physical chunk of memory only" if ADVANCED && !SUN3 ++ default y if SUN3 ++ select NEED_MULTIPLE_NODES + help + Ignore all but the first contiguous chunk of physical memory for VM + purposes. This will save a few bytes kernel size and may speed up +@@ -377,6 +378,14 @@ config 060_WRITETHROUGH + is hardwired on. The 53c710 SCSI driver is known to suffer from + this problem. + ++config ARCH_DISCONTIGMEM_ENABLE ++ def_bool !SINGLE_MEMORY_CHUNK ++ ++config NODES_SHIFT ++ int ++ default "3" ++ depends on !SINGLE_MEMORY_CHUNK ++ + source "mm/Kconfig" + + endmenu +--- linux-m68k-2.6.21.orig/arch/m68k/kernel/module.c ++++ linux-m68k-2.6.21/arch/m68k/kernel/module.c +@@ -132,6 +132,9 @@ void module_fixup(struct module *mod, st + case m68k_fixup_memoffset: + *(u32 *)fixup->addr = m68k_memoffset; + break; ++ case m68k_fixup_vnode_shift: ++ *(u16 *)fixup->addr += m68k_virt_to_node_shift; ++ break; + } + } + } +--- linux-m68k-2.6.21.orig/arch/m68k/kernel/setup.c ++++ linux-m68k-2.6.21/arch/m68k/kernel/setup.c +@@ -60,14 +60,12 @@ extern unsigned long availmem; + int m68k_num_memory; + int m68k_realnum_memory; + EXPORT_SYMBOL(m68k_realnum_memory); +-#ifdef CONFIG_SINGLE_MEMORY_CHUNK + unsigned long m68k_memoffset; + EXPORT_SYMBOL(m68k_memoffset); +-#endif + struct mem_info m68k_memory[NUM_MEMINFO]; + EXPORT_SYMBOL(m68k_memory); + +-static struct mem_info m68k_ramdisk; ++struct mem_info m68k_ramdisk; + + static char m68k_command_line[CL_SIZE]; + +@@ -208,9 +206,6 @@ static void __init m68k_parse_bootinfo(c + void __init setup_arch(char **cmdline_p) + { + extern int _etext, _edata, _end; +-#ifndef CONFIG_SUN3 +- unsigned long endmem, startmem; +-#endif + int i; + + /* The bootinfo is located right after the kernel bss */ +@@ -320,30 +315,16 @@ void __init setup_arch(char **cmdline_p) + panic("No configuration setup"); + } + +-#ifndef CONFIG_SUN3 +- startmem= m68k_memory[0].addr; +- endmem = startmem + m68k_memory[0].size; +- high_memory = (void *)PAGE_OFFSET; +- for (i = 0; i < m68k_num_memory; i++) { +- m68k_memory[i].size &= MASK_256K; +- if (m68k_memory[i].addr < startmem) +- startmem = m68k_memory[i].addr; +- if (m68k_memory[i].addr+m68k_memory[i].size > endmem) +- endmem = m68k_memory[i].addr+m68k_memory[i].size; +- high_memory += m68k_memory[i].size; +- } +- +- availmem += init_bootmem_node(NODE_DATA(0), availmem >> PAGE_SHIFT, +- startmem >> PAGE_SHIFT, endmem >> PAGE_SHIFT); +- +- for (i = 0; i < m68k_num_memory; i++) +- free_bootmem(m68k_memory[i].addr, m68k_memory[i].size); +- +- reserve_bootmem(m68k_memory[0].addr, availmem - m68k_memory[0].addr); ++ paging_init(); + ++#ifndef CONFIG_SUN3 ++ for (i = 1; i < m68k_num_memory; i++) ++ free_bootmem_node(NODE_DATA(i), m68k_memory[i].addr, ++ m68k_memory[i].size); + #ifdef CONFIG_BLK_DEV_INITRD + if (m68k_ramdisk.size) { +- reserve_bootmem(m68k_ramdisk.addr, m68k_ramdisk.size); ++ reserve_bootmem_node(__virt_to_node(phys_to_virt(m68k_ramdisk.addr)), ++ m68k_ramdisk.addr, m68k_ramdisk.size); + initrd_start = (unsigned long)phys_to_virt(m68k_ramdisk.addr); + initrd_end = initrd_start + m68k_ramdisk.size; + printk("initrd: %08lx - %08lx\n", initrd_start, initrd_end); +@@ -362,8 +343,6 @@ void __init setup_arch(char **cmdline_p) + + #endif /* !CONFIG_SUN3 */ + +- paging_init(); +- + /* set ISA defs early as possible */ + #if defined(CONFIG_ISA) && defined(MULTI_ISA) + #if defined(CONFIG_Q40) +--- linux-m68k-2.6.21.orig/arch/m68k/mm/init.c ++++ linux-m68k-2.6.21/arch/m68k/mm/init.c +@@ -7,6 +7,7 @@ + * to motorola.c and sun3mmu.c + */ + ++#include <linux/module.h> + #include <linux/signal.h> + #include <linux/sched.h> + #include <linux/mm.h> +@@ -31,6 +32,37 @@ + + DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); + ++static bootmem_data_t __initdata bootmem_data[MAX_NUMNODES]; ++ ++pg_data_t pg_data_map[MAX_NUMNODES]; ++EXPORT_SYMBOL(pg_data_map); ++ ++int m68k_virt_to_node_shift; ++ ++#ifndef CONFIG_SINGLE_MEMORY_CHUNK ++pg_data_t *pg_data_table[65]; ++EXPORT_SYMBOL(pg_data_table); ++#endif ++ ++void m68k_setup_node(int node) ++{ ++#ifndef CONFIG_SINGLE_MEMORY_CHUNK ++ struct mem_info *info = m68k_memory + node; ++ int i, end; ++ ++ i = (unsigned long)phys_to_virt(info->addr) >> __virt_to_node_shift(); ++ end = (unsigned long)phys_to_virt(info->addr + info->size - 1) >> __virt_to_node_shift(); ++ for (; i <= end; i++) { ++ if (pg_data_table[i]) ++ printk("overlap at %u for chunk %u\n", i, node); ++ pg_data_table[i] = pg_data_map + node; ++ } ++#endif ++ pg_data_map[node].bdata = bootmem_data + node; ++ node_set_online(node); ++} ++ ++ + /* + * ZERO_PAGE is a special page that is used for zero-initialized + * data and COW. +@@ -40,52 +72,51 @@ void *empty_zero_page; + + void show_mem(void) + { +- unsigned long i; +- int free = 0, total = 0, reserved = 0, shared = 0; +- int cached = 0; +- +- printk("\nMem-info:\n"); +- show_free_areas(); +- printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); +- i = max_mapnr; +- while (i-- > 0) { +- total++; +- if (PageReserved(mem_map+i)) +- reserved++; +- else if (PageSwapCache(mem_map+i)) +- cached++; +- else if (!page_count(mem_map+i)) +- free++; +- else +- shared += page_count(mem_map+i) - 1; +- } +- printk("%d pages of RAM\n",total); +- printk("%d free pages\n",free); +- printk("%d reserved pages\n",reserved); +- printk("%d pages shared\n",shared); +- printk("%d pages swap cached\n",cached); ++ pg_data_t *pgdat; ++ int free = 0, total = 0, reserved = 0, shared = 0; ++ int cached = 0; ++ int i; ++ ++ printk("\nMem-info:\n"); ++ show_free_areas(); ++ printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); ++ for_each_online_pgdat(pgdat) { ++ for (i = 0; i < pgdat->node_spanned_pages; i++) { ++ struct page *page = pgdat->node_mem_map + i; ++ total++; ++ if (PageReserved(page)) ++ reserved++; ++ else if (PageSwapCache(page)) ++ cached++; ++ else if (!page_count(page)) ++ free++; ++ else ++ shared += page_count(page) - 1; ++ } ++ } ++ printk("%d pages of RAM\n",total); ++ printk("%d free pages\n",free); ++ printk("%d reserved pages\n",reserved); ++ printk("%d pages shared\n",shared); ++ printk("%d pages swap cached\n",cached); + } + + extern void init_pointer_table(unsigned long ptable); + + /* References to section boundaries */ + +-extern char _text, _etext, _edata, __bss_start, _end; +-extern char __init_begin, __init_end; ++extern char _text[], _etext[]; ++extern char __init_begin[], __init_end[]; + + extern pmd_t *zero_pgtable; + + void __init mem_init(void) + { ++ pg_data_t *pgdat; + int codepages = 0; + int datapages = 0; + int initpages = 0; +- unsigned long tmp; +-#ifndef CONFIG_SUN3 + int i; +-#endif +- +- max_mapnr = num_physpages = (((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT); + + #ifdef CONFIG_ATARI + if (MACH_IS_ATARI) +@@ -93,19 +124,25 @@ void __init mem_init(void) + #endif + + /* this will put all memory onto the freelists */ +- totalram_pages = free_all_bootmem(); +- +- for (tmp = PAGE_OFFSET ; tmp < (unsigned long)high_memory; tmp += PAGE_SIZE) { +- if (PageReserved(virt_to_page(tmp))) { +- if (tmp >= (unsigned long)&_text +- && tmp < (unsigned long)&_etext) ++ totalram_pages = num_physpages = 0; ++ for_each_online_pgdat(pgdat) { ++ num_physpages += pgdat->node_present_pages; ++ ++ totalram_pages += free_all_bootmem_node(pgdat); ++ for (i = 0; i < pgdat->node_spanned_pages; i++) { ++ struct page *page = pgdat->node_mem_map + i; ++ char *addr = page_to_virt(page); ++ ++ if (!PageReserved(page)) ++ continue; ++ if (addr >= _text && ++ addr < _etext) + codepages++; +- else if (tmp >= (unsigned long) &__init_begin +- && tmp < (unsigned long) &__init_end) ++ else if (addr >= __init_begin && ++ addr < __init_end) + initpages++; + else + datapages++; +- continue; + } + } + +@@ -124,7 +161,7 @@ void __init mem_init(void) + + printk("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init)\n", + (unsigned long)nr_free_pages() << (PAGE_SHIFT-10), +- max_mapnr << (PAGE_SHIFT-10), ++ totalram_pages << (PAGE_SHIFT-10), + codepages << (PAGE_SHIFT-10), + datapages << (PAGE_SHIFT-10), + initpages << (PAGE_SHIFT-10)); +--- linux-m68k-2.6.21.orig/arch/m68k/mm/memory.c ++++ linux-m68k-2.6.21/arch/m68k/mm/memory.c +@@ -127,67 +127,6 @@ int free_pointer_table (pmd_t *ptable) + return 0; + } + +-#ifdef DEBUG_INVALID_PTOV +-int mm_inv_cnt = 5; +-#endif +- +-#ifndef CONFIG_SINGLE_MEMORY_CHUNK +-/* +- * The following two routines map from a physical address to a kernel +- * virtual address and vice versa. +- */ +-unsigned long mm_vtop(unsigned long vaddr) +-{ +- int i=0; +- unsigned long voff = (unsigned long)vaddr - PAGE_OFFSET; +- +- do { +- if (voff < m68k_memory[i].size) { +-#ifdef DEBUGPV +- printk ("VTOP(%p)=%lx\n", vaddr, +- m68k_memory[i].addr + voff); +-#endif +- return m68k_memory[i].addr + voff; +- } +- voff -= m68k_memory[i].size; +- } while (++i < m68k_num_memory); +- +- /* As a special case allow `__pa(high_memory)'. */ +- if (voff == 0) +- return m68k_memory[i-1].addr + m68k_memory[i-1].size; +- +- return -1; +-} +-EXPORT_SYMBOL(mm_vtop); +- +-unsigned long mm_ptov (unsigned long paddr) +-{ +- int i = 0; +- unsigned long poff, voff = PAGE_OFFSET; +- +- do { +- poff = paddr - m68k_memory[i].addr; +- if (poff < m68k_memory[i].size) { +-#ifdef DEBUGPV +- printk ("PTOV(%lx)=%lx\n", paddr, poff + voff); +-#endif +- return poff + voff; +- } +- voff += m68k_memory[i].size; +- } while (++i < m68k_num_memory); +- +-#ifdef DEBUG_INVALID_PTOV +- if (mm_inv_cnt > 0) { +- mm_inv_cnt--; +- printk("Invalid use of phys_to_virt(0x%lx) at 0x%p!\n", +- paddr, __builtin_return_address(0)); +- } +-#endif +- return -1; +-} +-EXPORT_SYMBOL(mm_ptov); +-#endif +- + /* invalidate page in both caches */ + static inline void clear040(unsigned long paddr) + { +@@ -354,15 +293,3 @@ void cache_push (unsigned long paddr, in + } + EXPORT_SYMBOL(cache_push); + +-#ifndef CONFIG_SINGLE_MEMORY_CHUNK +-int mm_end_of_chunk (unsigned long addr, int len) +-{ +- int i; +- +- for (i = 0; i < m68k_num_memory; i++) +- if (m68k_memory[i].addr + m68k_memory[i].size == addr + len) +- return 1; +- return 0; +-} +-EXPORT_SYMBOL(mm_end_of_chunk); +-#endif +--- linux-m68k-2.6.21.orig/arch/m68k/mm/motorola.c ++++ linux-m68k-2.6.21/arch/m68k/mm/motorola.c +@@ -43,6 +43,12 @@ unsigned long mm_cachebits; + EXPORT_SYMBOL(mm_cachebits); + #endif + ++/* size of memory already mapped in head.S */ ++#define INIT_MAPPED_SIZE (4UL<<20) ++ ++extern unsigned long availmem; ++extern struct mem_info m68k_ramdisk; ++ + static pte_t * __init kernel_page_table(void) + { + pte_t *ptablep; +@@ -98,19 +104,20 @@ static pmd_t * __init kernel_ptr_table(v + return last_pgtable; + } + +-static unsigned long __init +-map_chunk (unsigned long addr, long size) ++static void __init map_node(int node) + { + #define PTRTREESIZE (256*1024) + #define ROOTTREESIZE (32*1024*1024) +- static unsigned long virtaddr = PAGE_OFFSET; +- unsigned long physaddr; ++ unsigned long physaddr, virtaddr, size; + pgd_t *pgd_dir; + pmd_t *pmd_dir; + pte_t *pte_dir; + +- physaddr = (addr | m68k_supervisor_cachemode | +- _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY); ++ size = m68k_memory[node].size; ++ physaddr = m68k_memory[node].addr; ++ virtaddr = (unsigned long)phys_to_virt(physaddr); ++ physaddr |= m68k_supervisor_cachemode | ++ _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY; + if (CPU_IS_040_OR_060) + physaddr |= _PAGE_GLOBAL040; + +@@ -190,8 +197,6 @@ map_chunk (unsigned long addr, long size + #ifdef DEBUG + printk("\n"); + #endif +- +- return virtaddr; + } + + /* +@@ -200,15 +205,16 @@ map_chunk (unsigned long addr, long size + */ + void __init paging_init(void) + { +- int chunk; +- unsigned long mem_avail = 0; + unsigned long zones_size[MAX_NR_ZONES] = { 0, }; ++ unsigned long min_addr, max_addr; ++ unsigned long addr, size, end; ++ int i; + + #ifdef DEBUG + { + extern unsigned long availmem; +- printk ("start of paging_init (%p, %lx, %lx, %lx)\n", +- kernel_pg_dir, availmem, start_mem, end_mem); ++ printk ("start of paging_init (%p, %lx)\n", ++ kernel_pg_dir, availmem); + } + #endif + +@@ -222,27 +228,62 @@ void __init paging_init(void) + pgprot_val(protection_map[i]) |= _PAGE_CACHE040; + } + ++ min_addr = m68k_memory[0].addr; ++ max_addr = min_addr + m68k_memory[0].size; ++ for (i = 1; i < m68k_num_memory;) { ++ if (m68k_memory[i].addr < min_addr) { ++ printk("Ignoring memory chunk at 0x%lx:0x%lx before the first chunk\n", ++ m68k_memory[i].addr, m68k_memory[i].size); ++ printk("Fix your bootloader or use a memfile to make use of this area!\n"); ++ m68k_num_memory--; ++ memmove(m68k_memory + i, m68k_memory + i + 1, ++ (m68k_num_memory - i) * sizeof(struct mem_info)); ++ continue; ++ } ++ addr = m68k_memory[i].addr + m68k_memory[i].size; ++ if (addr > max_addr) ++ max_addr = addr; ++ i++; ++ } ++ m68k_memoffset = min_addr - PAGE_OFFSET; ++ m68k_virt_to_node_shift = fls(max_addr - min_addr - 1) - 6; ++ + module_fixup(NULL, __start_fixup, __stop_fixup); + flush_icache(); + ++ high_memory = phys_to_virt(max_addr); ++ ++ min_low_pfn = availmem >> PAGE_SHIFT; ++ max_low_pfn = max_addr >> PAGE_SHIFT; ++ ++ for (i = 0; i < m68k_num_memory; i++) { ++ addr = m68k_memory[i].addr; ++ end = addr + m68k_memory[i].size; ++ m68k_setup_node(i); ++ availmem = PAGE_ALIGN(availmem); ++ availmem += init_bootmem_node(NODE_DATA(i), ++ availmem >> PAGE_SHIFT, ++ addr >> PAGE_SHIFT, ++ end >> PAGE_SHIFT); ++ } ++ + /* + * Map the physical memory available into the kernel virtual +- * address space. It may allocate some memory for page +- * tables and thus modify availmem. ++ * address space. First initialize the bootmem allocator with ++ * the memory we already mapped, so map_node() has something ++ * to allocate. + */ ++ addr = m68k_memory[0].addr; ++ size = m68k_memory[0].size; ++ free_bootmem_node(NODE_DATA(0), availmem, min(INIT_MAPPED_SIZE, size) - (availmem - addr)); ++ map_node(0); ++ if (size > INIT_MAPPED_SIZE) ++ free_bootmem_node(NODE_DATA(0), addr + INIT_MAPPED_SIZE, size - INIT_MAPPED_SIZE); + +- for (chunk = 0; chunk < m68k_num_memory; chunk++) { +- mem_avail = map_chunk (m68k_memory[chunk].addr, +- m68k_memory[chunk].size); +- +- } ++ for (i = 1; i < m68k_num_memory; i++) ++ map_node(i); + + flush_tlb_all(); +-#ifdef DEBUG +- printk ("memory available is %ldKB\n", mem_avail >> 10); +- printk ("start_mem is %#lx\nvirtual_end is %#lx\n", +- start_mem, end_mem); +-#endif + + /* + * initialize the bad page table and bad page to point +@@ -259,14 +300,11 @@ void __init paging_init(void) + #ifdef DEBUG + printk ("before free_area_init\n"); + #endif +- zones_size[ZONE_DMA] = (mach_max_dma_address < (unsigned long)high_memory ? +- (mach_max_dma_address+1) : (unsigned long)high_memory); +- zones_size[ZONE_NORMAL] = (unsigned long)high_memory - zones_size[0]; +- +- zones_size[ZONE_DMA] = (zones_size[ZONE_DMA] - PAGE_OFFSET) >> PAGE_SHIFT; +- zones_size[ZONE_NORMAL] >>= PAGE_SHIFT; +- +- free_area_init(zones_size); ++ for (i = 0; i < m68k_num_memory; i++) { ++ zones_size[ZONE_DMA] = m68k_memory[i].size >> PAGE_SHIFT; ++ free_area_init_node(i, pg_data_map + i, zones_size, ++ m68k_memory[i].addr >> PAGE_SHIFT, NULL); ++ } + } + + extern char __init_begin, __init_end; +--- linux-m68k-2.6.21.orig/arch/m68k/sun3/config.c ++++ linux-m68k-2.6.21/arch/m68k/sun3/config.c +@@ -21,6 +21,7 @@ + #include <asm/contregs.h> + #include <asm/movs.h> + #include <asm/pgtable.h> ++#include <asm/pgalloc.h> + #include <asm/sun3-head.h> + #include <asm/sun3mmu.h> + #include <asm/rtc.h> +@@ -127,6 +128,7 @@ void __init sun3_bootmem_alloc(unsigned + high_memory = (void *)memory_end; + availmem = memory_start; + ++ m68k_setup_node(0); + availmem += init_bootmem_node(NODE_DATA(0), start_page, 0, num_pages); + availmem = (availmem + (PAGE_SIZE-1)) & PAGE_MASK; + +--- /dev/null ++++ linux-m68k-2.6.21/include/asm-m68k/mmzone.h +@@ -0,0 +1,9 @@ ++#ifndef _ASM_M68K_MMZONE_H_ ++#define _ASM_M68K_MMZONE_H_ ++ ++extern pg_data_t pg_data_map[]; ++ ++#define NODE_DATA(nid) (&pg_data_map[nid]) ++#define NODE_MEM_MAP(nid) (NODE_DATA(nid)->node_mem_map) ++ ++#endif /* _ASM_M68K_MMZONE_H_ */ +--- linux-m68k-2.6.21.orig/include/asm-m68k/module.h ++++ linux-m68k-2.6.21/include/asm-m68k/module.h +@@ -17,6 +17,7 @@ struct mod_arch_specific { + + enum m68k_fixup_type { + m68k_fixup_memoffset, ++ m68k_fixup_vnode_shift, + }; + + struct m68k_fixup_info { +--- linux-m68k-2.6.21.orig/include/asm-m68k/motorola_pgtable.h ++++ linux-m68k-2.6.21/include/asm-m68k/motorola_pgtable.h +@@ -130,7 +130,7 @@ static inline void pgd_set(pgd_t *pgdp, + #define pte_present(pte) (pte_val(pte) & (_PAGE_PRESENT | _PAGE_PROTNONE)) + #define pte_clear(mm,addr,ptep) ({ pte_val(*(ptep)) = 0; }) + +-#define pte_page(pte) (mem_map + ((unsigned long)(__va(pte_val(pte)) - PAGE_OFFSET) >> PAGE_SHIFT)) ++#define pte_page(pte) virt_to_page(__va(pte_val(pte))) + #define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT) + #define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) + +@@ -143,7 +143,7 @@ static inline void pgd_set(pgd_t *pgdp, + while (--__i >= 0) \ + *__ptr++ = 0; \ + }) +-#define pmd_page(pmd) (mem_map + ((unsigned long)(__va(pmd_val(pmd)) - PAGE_OFFSET) >> PAGE_SHIFT)) ++#define pmd_page(pmd) virt_to_page(__va(pmd_val(pmd))) + + + #define pgd_none(pgd) (!pgd_val(pgd)) +@@ -223,10 +223,10 @@ static inline pte_t *pte_offset_kernel(p + return (pte_t *)__pmd_page(*pmdp) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)); + } + +-#define pte_offset_map(pmdp,address) ((pte_t *)kmap(pmd_page(*pmdp)) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))) ++#define pte_offset_map(pmdp,address) ((pte_t *)__pmd_page(*pmdp) + (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))) + #define pte_offset_map_nested(pmdp, address) pte_offset_map(pmdp, address) +-#define pte_unmap(pte) kunmap(pte) +-#define pte_unmap_nested(pte) kunmap(pte) ++#define pte_unmap(pte) ((void)0) ++#define pte_unmap_nested(pte) ((void)0) + + /* + * Allocate and free page tables. The xxx_kernel() versions are +--- linux-m68k-2.6.21.orig/include/asm-m68k/page.h ++++ linux-m68k-2.6.21/include/asm-m68k/page.h +@@ -121,7 +121,6 @@ extern unsigned long m68k_memoffset; + #ifndef CONFIG_SUN3 + + #define WANT_PAGE_VIRTUAL +-#ifdef CONFIG_SINGLE_MEMORY_CHUNK + + static inline unsigned long ___pa(void *vaddr) + { +@@ -133,7 +132,7 @@ static inline unsigned long ___pa(void * + : "0" (vaddr), "i" (m68k_fixup_memoffset)); + return paddr; + } +-#define __pa(vaddr) ___pa((void *)(vaddr)) ++#define __pa(vaddr) ___pa((void *)(vaddr)) + static inline void *__va(unsigned long paddr) + { + void *vaddr; +@@ -145,11 +144,6 @@ static inline void *__va(unsigned long p + return vaddr; + } + +-#else +-#define __pa(vaddr) virt_to_phys((void *)(vaddr)) +-#define __va(paddr) phys_to_virt((unsigned long)(paddr)) +-#endif +- + #else /* !CONFIG_SUN3 */ + /* This #define is a horrible hack to suppress lots of warnings. --m */ + #define __pa(x) ___pa((unsigned long)(x)) +@@ -184,11 +178,47 @@ static inline void *__va(unsigned long x + #define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) + #define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT) + +-#define virt_to_page(kaddr) (mem_map + (((unsigned long)(kaddr)-PAGE_OFFSET) >> PAGE_SHIFT)) +-#define page_to_virt(page) ((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET) ++extern int m68k_virt_to_node_shift; ++ ++#ifdef CONFIG_SINGLE_MEMORY_CHUNK ++#define __virt_to_node(addr) (&pg_data_map[0]) ++#else ++extern struct pglist_data *pg_data_table[]; ++ ++static inline __attribute_const__ int __virt_to_node_shift(void) ++{ ++ int shift; ++ ++ asm ( ++ "1: moveq #0,%0\n" ++ m68k_fixup(%c1, 1b) ++ : "=d" (shift) ++ : "i" (m68k_fixup_vnode_shift)); ++ return shift; ++} ++ ++#define __virt_to_node(addr) (pg_data_table[(unsigned long)(addr) >> __virt_to_node_shift()]) ++#endif + +-#define pfn_to_page(pfn) virt_to_page(pfn_to_virt(pfn)) +-#define page_to_pfn(page) virt_to_pfn(page_to_virt(page)) ++#define virt_to_page(addr) ({ \ ++ pfn_to_page(virt_to_pfn(addr)); \ ++}) ++#define page_to_virt(page) ({ \ ++ pfn_to_virt(page_to_pfn(page)); \ ++}) ++ ++#define pfn_to_page(pfn) ({ \ ++ unsigned long __pfn = (pfn); \ ++ struct pglist_data *pgdat; \ ++ pgdat = __virt_to_node((unsigned long)pfn_to_virt(__pfn)); \ ++ pgdat->node_mem_map + (__pfn - pgdat->node_start_pfn); \ ++}) ++#define page_to_pfn(_page) ({ \ ++ struct page *__p = (_page); \ ++ struct pglist_data *pgdat; \ ++ pgdat = &pg_data_map[page_to_nid(__p)]; \ ++ ((__p) - pgdat->node_mem_map) + pgdat->node_start_pfn; \ ++}) + + #define virt_addr_valid(kaddr) ((void *)(kaddr) >= (void *)PAGE_OFFSET && (void *)(kaddr) < high_memory) + #define pfn_valid(pfn) virt_addr_valid(pfn_to_virt(pfn)) +--- linux-m68k-2.6.21.orig/include/asm-m68k/pgalloc.h ++++ linux-m68k-2.6.21/include/asm-m68k/pgalloc.h +@@ -8,11 +8,12 @@ + #include <asm/virtconvert.h> + + +- + #ifdef CONFIG_SUN3 + #include <asm/sun3_pgalloc.h> + #else + #include <asm/motorola_pgalloc.h> + #endif + ++extern void m68k_setup_node(int node); ++ + #endif /* M68K_PGALLOC_H */ +--- linux-m68k-2.6.21.orig/include/asm-m68k/pgtable.h ++++ linux-m68k-2.6.21/include/asm-m68k/pgtable.h +@@ -107,22 +107,7 @@ extern void *empty_zero_page; + /* 64-bit machines, beware! SRB. */ + #define SIZEOF_PTR_LOG2 2 + +-/* +- * Check if the addr/len goes up to the end of a physical +- * memory chunk. Used for DMA functions. +- */ +-#ifdef CONFIG_SINGLE_MEMORY_CHUNK +-/* +- * It makes no sense to consider whether we cross a memory boundary if +- * we support just one physical chunk of memory. +- */ +-static inline int mm_end_of_chunk(unsigned long addr, int len) +-{ +- return 0; +-} +-#else +-int mm_end_of_chunk (unsigned long addr, int len); +-#endif ++#define mm_end_of_chunk(addr, len) 0 + + extern void kernel_set_cachemode(void *addr, unsigned long size, int cmode); + +--- linux-m68k-2.6.21.orig/include/asm-m68k/sun3_pgtable.h ++++ linux-m68k-2.6.21/include/asm-m68k/sun3_pgtable.h +@@ -132,8 +132,8 @@ static inline void pte_clear (struct mm_ + #define pfn_pte(pfn, pgprot) \ + ({ pte_t __pte; pte_val(__pte) = pfn | pgprot_val(pgprot); __pte; }) + +-#define pte_page(pte) (mem_map+((__pte_page(pte) - PAGE_OFFSET) >> PAGE_SHIFT)) +-#define pmd_page(pmd) (mem_map+((__pmd_page(pmd) - PAGE_OFFSET) >> PAGE_SHIFT)) ++#define pte_page(pte) virt_to_page(__pte_page(pte)) ++#define pmd_page(pmd) virt_to_page(__pmd_page(pmd)) + + + static inline int pmd_none2 (pmd_t *pmd) { return !pmd_val (*pmd); } +--- linux-m68k-2.6.21.orig/include/asm-m68k/virtconvert.h ++++ linux-m68k-2.6.21/include/asm-m68k/virtconvert.h +@@ -8,56 +8,34 @@ + #ifdef __KERNEL__ + + #include <linux/compiler.h> ++#include <linux/mmzone.h> + #include <asm/setup.h> + #include <asm/page.h> + +-#ifdef CONFIG_AMIGA +-#include <asm/amigahw.h> +-#endif +- + /* + * Change virtual addresses to physical addresses and vv. + */ +-#ifndef CONFIG_SUN3 +-extern unsigned long mm_vtop(unsigned long addr) __attribute_const__; +-extern unsigned long mm_ptov(unsigned long addr) __attribute_const__; +-#else +-static inline unsigned long mm_vtop(unsigned long vaddr) +-{ +- return __pa(vaddr); +-} +- +-static inline unsigned long mm_ptov(unsigned long paddr) +-{ +- return (unsigned long)__va(paddr); +-} +-#endif +- +-#ifdef CONFIG_SINGLE_MEMORY_CHUNK +-static inline unsigned long virt_to_phys(void *vaddr) +-{ +- return (unsigned long)vaddr - PAGE_OFFSET + m68k_memory[0].addr; +-} +- +-static inline void * phys_to_virt(unsigned long paddr) +-{ +- return (void *)(paddr - m68k_memory[0].addr + PAGE_OFFSET); +-} +-#else + static inline unsigned long virt_to_phys(void *address) + { +- return mm_vtop((unsigned long)address); ++ return __pa(address); + } + + static inline void *phys_to_virt(unsigned long address) + { +- return (void *) mm_ptov(address); ++ return __va(address); + } +-#endif + + /* Permanent address of a page. */ +-#define __page_address(page) (PAGE_OFFSET + (((page) - mem_map) << PAGE_SHIFT)) +-#define page_to_phys(page) virt_to_phys((void *)__page_address(page)) ++#ifdef CONFIG_SINGLE_MEMORY_CHUNK ++#define page_to_phys(page) \ ++ __pa(PAGE_OFFSET + (((page) - pg_data_map[0].node_mem_map) << PAGE_SHIFT)) ++#else ++#define page_to_phys(page) ({ \ ++ struct pglist_data *pgdat; \ ++ pgdat = pg_data_table[page_to_nid(page)]; \ ++ page_to_pfn(page) << PAGE_SHIFT; \ ++}) ++#endif + + /* + * IO bus memory addresses are 1:1 with the physical address, +--- linux-m68k-2.6.21.orig/mm/page_alloc.c ++++ linux-m68k-2.6.21/mm/page_alloc.c +@@ -2713,7 +2713,7 @@ static void __init alloc_node_mem_map(st + map = alloc_bootmem_node(pgdat, size); + pgdat->node_mem_map = map + (pgdat->node_start_pfn - start); + } +-#ifdef CONFIG_FLATMEM ++#ifndef CONFIG_NEED_MULTIPLE_NODES + /* + * With no DISCONTIG, the global mem_map is just set as node 0's + */ diff --git a/debian/patches/bugfix/m68k/630-extern-cleanup.diff b/debian/patches/bugfix/m68k/630-extern-cleanup.diff new file mode 100644 index 000000000000..823760ceeb7f --- /dev/null +++ b/debian/patches/bugfix/m68k/630-extern-cleanup.diff @@ -0,0 +1,34 @@ +To: linus, akpm +Cc: lkml +Subject: [PATCH] m68k: Kill superfluous externs + +Kill a few superfluous extern declarations. + +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + arch/m68k/mm/motorola.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +--- linux-m68k-2.6.21.orig/arch/m68k/mm/motorola.c ++++ linux-m68k-2.6.21/arch/m68k/mm/motorola.c +@@ -47,7 +47,6 @@ EXPORT_SYMBOL(mm_cachebits); + #define INIT_MAPPED_SIZE (4UL<<20) + + extern unsigned long availmem; +-extern struct mem_info m68k_ramdisk; + + static pte_t * __init kernel_page_table(void) + { +@@ -211,11 +210,7 @@ void __init paging_init(void) + int i; + + #ifdef DEBUG +- { +- extern unsigned long availmem; +- printk ("start of paging_init (%p, %lx)\n", +- kernel_pg_dir, availmem); +- } ++ printk ("start of paging_init (%p, %lx)\n", kernel_pg_dir, availmem); + #endif + + /* Fix the cache mode in the page descriptors for the 680[46]0. */ diff --git a/debian/patches/bugfix/m68k/631-thread_stack.diff b/debian/patches/bugfix/m68k/631-thread_stack.diff new file mode 100644 index 000000000000..71342f24a0cc --- /dev/null +++ b/debian/patches/bugfix/m68k/631-thread_stack.diff @@ -0,0 +1,117 @@ +To: linus, akpm +Cc: lkml +Subject: [PATCH] Thread stack abstractions + +From: Roman Zippel <zippel@linux-m68k.org> + +Thread stack abstractions: + - Move thread_info into task_struct + - Adapt thread_info initialization + - Abstract thread_info access + - Thread_info field becomes stack + - Change get_task_struct/put_task_struct into inline functions + - Move task_struct into <linux/task_struct.h> + +Signed-off-by: Roman Zippel <zippel@linux-m68k.org> + +--- + include/asm-m68k/thread_info.h | 12 ++++++------ + include/linux/init_task.h | 2 +- + include/linux/sched.h | 3 ++- + kernel/fork.c | 10 +++++----- + 4 files changed, 14 insertions(+), 13 deletions(-) + +--- linux-m68k-2.6.21.orig/include/asm-m68k/thread_info.h ++++ linux-m68k-2.6.21/include/asm-m68k/thread_info.h +@@ -26,24 +26,24 @@ struct thread_info { + + /* THREAD_SIZE should be 8k, so handle differently for 4k and 8k machines */ + #if PAGE_SHIFT == 13 /* 8k machines */ +-#define alloc_thread_info(tsk) ((struct thread_info *)__get_free_pages(GFP_KERNEL,0)) +-#define free_thread_info(ti) free_pages((unsigned long)(ti),0) ++#define alloc_thread_stack(tsk) ((void *)__get_free_pages(GFP_KERNEL,0)) ++#define free_thread_stack(ti) free_pages((unsigned long)(ti),0) + #else /* otherwise assume 4k pages */ +-#define alloc_thread_info(tsk) ((struct thread_info *)__get_free_pages(GFP_KERNEL,1)) +-#define free_thread_info(ti) free_pages((unsigned long)(ti),1) ++#define alloc_thread_stack(tsk) ((void *)__get_free_pages(GFP_KERNEL,1)) ++#define free_thread_stack(ti) free_pages((unsigned long)(ti),1) + #endif /* PAGE_SHIFT == 13 */ + + #define init_thread_info (init_task.thread.info) + #define init_stack (init_thread_union.stack) + + #define task_thread_info(tsk) (&(tsk)->thread.info) +-#define task_stack_page(tsk) ((void *)(tsk)->thread_info) ++#define task_stack_page(tsk) ((void *)(tsk)->stack) + #define current_thread_info() task_thread_info(current) + + #define __HAVE_THREAD_FUNCTIONS + + #define setup_thread_stack(p, org) ({ \ +- *(struct task_struct **)(p)->thread_info = (p); \ ++ *(struct task_struct **)(p)->stack = (p); \ + task_thread_info(p)->task = (p); \ + }) + +--- linux-m68k-2.6.21.orig/include/linux/init_task.h ++++ linux-m68k-2.6.21/include/linux/init_task.h +@@ -95,7 +95,7 @@ extern struct group_info init_groups; + #define INIT_TASK(tsk) \ + { \ + .state = 0, \ +- .thread_info = &init_thread_info, \ ++ .stack = &init_stack, \ + .usage = ATOMIC_INIT(2), \ + .flags = 0, \ + .lock_depth = -1, \ +--- linux-m68k-2.6.21.orig/include/linux/sched.h ++++ linux-m68k-2.6.21/include/linux/sched.h +@@ -799,7 +799,8 @@ struct prio_array; + + struct task_struct { + volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ +- struct thread_info *thread_info; ++ //struct thread_info *thread_info; ++ void *stack; + atomic_t usage; + unsigned long flags; /* per process flags, defined below */ + unsigned long ptrace; +--- linux-m68k-2.6.21.orig/kernel/fork.c ++++ linux-m68k-2.6.21/kernel/fork.c +@@ -106,7 +106,7 @@ static struct kmem_cache *mm_cachep; + + void free_task(struct task_struct *tsk) + { +- free_thread_info(tsk->thread_info); ++ free_thread_stack(tsk->stack); + rt_mutex_debug_task_free(tsk); + free_task_struct(tsk); + } +@@ -161,7 +161,7 @@ void __init fork_init(unsigned long memp + static struct task_struct *dup_task_struct(struct task_struct *orig) + { + struct task_struct *tsk; +- struct thread_info *ti; ++ void *stack; + + prepare_to_copy(orig); + +@@ -169,14 +169,14 @@ static struct task_struct *dup_task_stru + if (!tsk) + return NULL; + +- ti = alloc_thread_info(tsk); +- if (!ti) { ++ stack = alloc_thread_stack(tsk); ++ if (!stack) { + free_task_struct(tsk); + return NULL; + } + + *tsk = *orig; +- tsk->thread_info = ti; ++ tsk->stack = stack; + setup_thread_stack(tsk, orig); + + #ifdef CONFIG_CC_STACKPROTECTOR diff --git a/debian/patches/bugfix/m68k/633-atari_scc.diff b/debian/patches/bugfix/m68k/633-atari_scc.diff new file mode 100644 index 000000000000..11897918653e --- /dev/null +++ b/debian/patches/bugfix/m68k/633-atari_scc.diff @@ -0,0 +1,1739 @@ +To: linus, akpm +Cc: lkml +Subject: [PATCH] m68k: Atari SCC serial driver + +From: Michael Schmitz <schmitz@opal.biophys.uni-duesseldorf.de> + +Atari SCC serial driver - this one works less well in 2.6 than it did in 2.4, +most likely due to the way flip buffer push is handled now - i.e. no +immediate push of received characters to the line disc. if the handler +runs in interrupt context, and the bottom half for pushing is run as +delayed task. 9 out of 10 ping packets end up in the bit bucket this way. +I haven't figured out how to prevent overruns yet, and getting this right +will require a bit more testing. + +Anyway, the basics are working, and maybe someone can figure out a better +way to push characters up to the ldisc. + +Signed-off-by: Michael Schmitz <schmitz@debian.org> +Signed-off-by: Roman Zippel <zippel@linux-m68k.org> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + drivers/char/Makefile | 1 + drivers/char/atari_scc.c | 1701 +++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 1702 insertions(+) + +--- linux-m68k-2.6.21.orig/drivers/char/Makefile ++++ linux-m68k-2.6.21/drivers/char/Makefile +@@ -29,6 +29,7 @@ obj-$(CONFIG_DIGIEPCA) += epca.o + obj-$(CONFIG_SPECIALIX) += specialix.o + obj-$(CONFIG_MOXA_INTELLIO) += moxa.o + obj-$(CONFIG_A2232) += ser_a2232.o generic_serial.o ++obj-$(CONFIG_ATARI_SCC) += atari_scc.o generic_serial.o + obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o + obj-$(CONFIG_MOXA_SMARTIO) += mxser.o + obj-$(CONFIG_MOXA_SMARTIO_NEW) += mxser_new.o +--- /dev/null ++++ linux-m68k-2.6.21/drivers/char/atari_scc.c +@@ -0,0 +1,1701 @@ ++/* ++ * drivers/char/atari_scc.c: Atari TT/Falcon Am8530 SCC serial ports implementation. ++ * ++ * Copyright 2005 Michael Schmitz ++ * ++ * Based on: ++ * drivers/char/vme_scc.c: MVME147, MVME162, BVME6000 SCC serial ports ++ * implementation. ++ * Copyright 1999 Richard Hirst <richard@sleepie.demon.co.uk> ++ * ++ * which, in turn, was ++ * ++ * Based on atari_SCC.c which was ++ * Copyright 1994-95 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> ++ * Partially based on PC-Linux serial.c by Linus Torvalds and Theodore Ts'o ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive ++ * for more details. ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/kdev_t.h> ++#include <asm/io.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/ioport.h> ++#include <linux/interrupt.h> ++#include <linux/errno.h> ++#include <linux/tty.h> ++#include <linux/tty_flip.h> ++#include <linux/mm.h> ++#include <linux/serial.h> ++#include <linux/fcntl.h> ++#include <linux/major.h> ++#include <linux/delay.h> ++#include <linux/slab.h> ++#include <linux/miscdevice.h> ++#include <linux/console.h> ++#include <linux/init.h> ++#include <asm/setup.h> ++#include <asm/uaccess.h> ++#include <asm/bootinfo.h> ++ ++#include <asm/atarihw.h> ++#include <asm/atariints.h> ++ ++#include <linux/generic_serial.h> ++#include "scc.h" ++ ++#define CONFIG_TT_SCC 1 ++#define CONFIG_FALCON_SCC 1 ++ ++#define CHANNEL_A 0 ++#define CHANNEL_B 1 ++ ++#define SCC_MINOR_BASE 64 ++ ++/* Shadows for all SCC write registers */ ++static unsigned char scc_shadow[2][16]; ++ ++/* Location to access for SCC register access delay */ ++static volatile unsigned char *scc_del = NULL; ++ ++/* To keep track of STATUS_REG state for detection of Ext/Status int source */ ++static unsigned char scc_last_status_reg[2]; ++ ++/***************************** Prototypes *****************************/ ++ ++/* Function prototypes */ ++static void scc_disable_tx_interrupts(void *ptr); ++static void scc_enable_tx_interrupts(void *ptr); ++static void scc_disable_rx_interrupts(void *ptr); ++static void scc_enable_rx_interrupts(void *ptr); ++static int scc_get_CD(void *ptr); ++static void scc_shutdown_port(void *ptr); ++static int scc_set_real_termios(void *ptr); ++static void scc_hungup(void *ptr); ++static void scc_close(void *ptr); ++static int scc_chars_in_buffer(void *ptr); ++static int scc_open(struct tty_struct *tty, struct file *filp); ++static int scc_ioctl(struct tty_struct *tty, struct file *filp, ++ unsigned int cmd, unsigned long arg); ++static void scc_throttle(struct tty_struct *tty); ++static void scc_unthrottle(struct tty_struct *tty); ++static irqreturn_t scc_tx_int(int irq, void *data); ++static irqreturn_t scc_rx_int(int irq, void *data); ++static irqreturn_t scc_stat_int(int irq, void *data); ++static irqreturn_t scc_spcond_int(int irq, void *data); ++static void scc_setsignals(struct scc_port *port, int dtr, int rts); ++static void scc_break_ctl(struct tty_struct *tty, int break_state); ++ ++static struct tty_driver *scc_driver; ++ ++struct scc_port scc_ports[2]; ++ ++int scc_initialized = 0; ++ ++/* ++ * Flags to indicate one of the serial ports has already been initialized by the ++ * serial debug driver. We may want to hold off reinitializing ... ++ */ ++ ++/* Flag that Modem1 port is already initialized and used */ ++extern int atari_SCC_init_done; ++/* Can be set somewhere, if a SCC master reset has already be done and should ++ * not be repeated; used by kgdb */ ++extern int atari_SCC_reset_done; ++ ++/*--------------------------------------------------------------------------- ++ * Interface from generic_serial.c back here ++ *--------------------------------------------------------------------------*/ ++ ++static struct real_driver scc_real_driver = { ++ .disable_tx_interrupts = scc_disable_tx_interrupts, ++ .enable_tx_interrupts = scc_enable_tx_interrupts, ++ .disable_rx_interrupts = scc_disable_rx_interrupts, ++ .enable_rx_interrupts = scc_enable_rx_interrupts, ++ .get_CD = scc_get_CD, ++ .shutdown_port = scc_shutdown_port, ++ .set_real_termios = scc_set_real_termios, ++ .chars_in_buffer = scc_chars_in_buffer, ++ .close = scc_close, ++ .hungup = scc_hungup, ++}; ++ ++static struct tty_operations scc_ops = { ++ .open = scc_open, ++ .close = gs_close, ++ .write = gs_write, ++ .put_char = gs_put_char, ++ .flush_chars = gs_flush_chars, ++ .write_room = gs_write_room, ++ .chars_in_buffer = gs_chars_in_buffer, ++ .flush_buffer = gs_flush_buffer, ++ .ioctl = scc_ioctl, ++ .throttle = scc_throttle, ++ .unthrottle = scc_unthrottle, ++ .set_termios = gs_set_termios, ++ .stop = gs_stop, ++ .start = gs_start, ++ .hangup = gs_hangup, ++ .break_ctl = scc_break_ctl, ++}; ++ ++/* BRG values for the standard speeds and the various clock sources */ ++ ++typedef struct { ++ unsigned clksrc; /* clock source to use or -1 for not possible */ ++ unsigned div; /* divisor: 1, 2 and 4 correspond to ++ * direct 1:16, 1:32 and 1:64 modes, ++ * divisors >= 4 yield a BRG value of ++ * div/2-2 (in 1:16 mode) ++ */ ++} BAUD_ENTRY; ++ ++/* A pointer for each channel to the current baud table */ ++static BAUD_ENTRY *scc_baud_table[2]; ++ ++/* Baud table format: ++ * ++ * Each entry consists of the clock source (CLK_RTxC, CLK_TRxC or ++ * CLK_PCLK) and a divisor. The following rules apply to the divisor: ++ * ++ * - CLK_RTxC: 1 or even (1, 2 and 4 are the direct modes, > 4 use ++ * the BRG) ++ * ++ * - CLK_TRxC: 1, 2 or 4 (no BRG, only direct modes possible) ++ * ++ * - CLK_PCLK: >= 4 and even (no direct modes, only BRG) ++ * ++ */ ++ ++/* This table is used if RTxC = 3.672 MHz. This is the case for TT's ++ * channel A and for both channels on the Mega STE/Falcon. (TRxC is unused) ++ */ ++ ++static BAUD_ENTRY bdtab_norm[20] = { ++ /* B0 */ { 0, 0 }, ++ /* B50 */ { CLK_RTxC, 4590 }, ++ /* B75 */ { CLK_RTxC, 3060 }, ++ /* B110 */ { CLK_PCLK, 4576 }, ++ /* B134 */ { CLK_PCLK, 3756 }, ++ /* B150 */ { CLK_RTxC, 1530 }, ++ /* B200 */ { CLK_PCLK, 2516 }, ++ /* B300 */ { CLK_PCLK, 1678 }, ++ /* B600 */ { CLK_PCLK, 838 }, ++ /* B1200 */ { CLK_PCLK, 420 }, ++ /* B1800 */ { CLK_PCLK, 280 }, ++ /* B2400 */ { CLK_PCLK, 210 }, ++ /* B4800 */ { CLK_RTxC, 48 }, ++ /* B9600 */ { CLK_RTxC, 24 }, ++ /* B19200 */ { CLK_RTxC, 12 }, ++ /* B38400 */ { CLK_RTxC, 6 }, /* #15 spd_extra */ ++ /* B57600 */ { CLK_RTxC, 4 }, /* #16 spd_hi */ ++ /* B115200 */ { CLK_RTxC, 2 }, /* #17 spd_vhi */ ++ /* B230400 */ { CLK_RTxC, 1 }, /* #18 spd_shi */ ++ /* B460800 */ { 0, 0 } /* #19 spd_warp: Impossible */ ++}; ++ ++/* This is a special table for the TT channel B with 307.2 kHz at RTxC ++ * and 2.4576 MHz at TRxC ++ */ ++static BAUD_ENTRY bdtab_TTChB[20] = { ++ /* B0 */ { 0, 0 }, ++ /* B50 */ { CLK_RTxC, 384 }, ++ /* B75 */ { CLK_RTxC, 256 }, ++ /* B110 */ { CLK_PCLK, 4576 }, ++ /* B134 */ { CLK_PCLK, 3756 }, ++ /* B150 */ { CLK_RTxC, 128 }, ++ /* B200 */ { CLK_RTxC, 96 }, ++ /* B300 */ { CLK_RTxC, 64 }, ++ /* B600 */ { CLK_RTxC, 32 }, ++ /* B1200 */ { CLK_RTxC, 16 }, ++ /* B1800 */ { CLK_PCLK, 280 }, ++ /* B2400 */ { CLK_RTxC, 8 }, ++ /* B4800 */ { CLK_RTxC, 4 }, ++ /* B9600 */ { CLK_RTxC, 2 }, ++ /* B19200 */ { CLK_RTxC, 1 }, ++ /* B38400 */ { CLK_TRxC, 4 }, ++ /* B57600 */ { CLK_TRxC, 2 }, /* 57600 is not possible, use 76800 instead */ ++ /* B115200 */ { CLK_TRxC, 1 }, /* 115200 is not possible, use 153600 instead */ ++ /* B230400 */ { 0, 0 }, /* #18 spd_shi: Impossible */ ++ /* B460800 */ { 0, 0 } /* #19 spd_warp: Impossible */ ++}; ++ ++ ++/*---------------------------------------------------------------------------- ++ * atari_scc_init() and support functions ++ *---------------------------------------------------------------------------*/ ++ ++static int scc_init_drivers(void) ++{ ++ int error; ++ ++ scc_driver = alloc_tty_driver(2); ++ if (!scc_driver) ++ return -ENOMEM; ++ scc_driver->owner = THIS_MODULE; ++ scc_driver->driver_name = "scc"; ++ scc_driver->name = "ttyS"; ++ scc_driver->major = TTY_MAJOR; ++ scc_driver->minor_start = SCC_MINOR_BASE; ++ scc_driver->type = TTY_DRIVER_TYPE_SERIAL; ++ scc_driver->subtype = SERIAL_TYPE_NORMAL; ++ scc_driver->init_termios = tty_std_termios; ++ scc_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; ++ scc_driver->flags = TTY_DRIVER_REAL_RAW; ++ ++ tty_set_operations(scc_driver, &scc_ops); ++ ++ if ((error = tty_register_driver(scc_driver))) { ++ printk(KERN_ERR "scc: Couldn't register scc driver, error = %d\n", ++ error); ++ put_tty_driver(scc_driver); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++ ++/* ports[] array is indexed by line no (i.e. [0] for ttyS0, [1] for ttyS1). ++ */ ++ ++static void scc_init_portstructs(void) ++{ ++ struct scc_port *port; ++ int i; ++ ++ for (i = 0; i < 2; i++) { ++ port = scc_ports + i; ++ port->gs.magic = SCC_MAGIC; ++ port->gs.close_delay = HZ/2; ++ port->gs.closing_wait = 30 * HZ; ++ port->gs.rd = &scc_real_driver; ++#ifdef NEW_WRITE_LOCKING ++ port->gs.port_write_sem = MUTEX; ++#endif ++ init_waitqueue_head(&port->gs.open_wait); ++ init_waitqueue_head(&port->gs.close_wait); ++ } ++} ++ ++ ++#ifdef CONFIG_TT_SCC ++static int atari_tt_scc_init(void) ++{ ++ struct scc_port *port; ++ ++ printk(KERN_INFO "SCC: Atari TT Serial Driver\n"); ++ /* FIXME channel A may be switchable between modem and LAN port */ ++ /* Init channel A */ ++ if (atari_SCC_init_done) ++ printk(KERN_INFO "SCC: already initialized, expect trouble!\n"); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: init channel A\n"); ++#endif ++ port = &scc_ports[0]; ++ port->channel = CHANNEL_A; ++ port->ctrlp = (volatile unsigned char *)&scc.cha_a_ctrl; ++ port->datap = port->ctrlp + 1; ++ port->port_a = &scc_ports[0]; ++ port->port_b = &scc_ports[1]; ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: request channel A irqs, port = %p\n", port); ++#endif ++ request_irq(IRQ_SCCA_TX, scc_tx_int, IRQ_TYPE_PRIO, "SCC-A TX", port); ++ request_irq(IRQ_SCCA_STAT, scc_stat_int, IRQ_TYPE_PRIO, ++ "SCC-A status", port); ++ request_irq(IRQ_SCCA_RX, scc_rx_int, IRQ_TYPE_PRIO, "SCC-A RX", port); ++ request_irq(IRQ_SCCA_SPCOND, scc_spcond_int, IRQ_TYPE_PRIO, ++ "SCC-A special cond", port); ++ { ++ SCC_ACCESS_INIT(port); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: read SCC status\n"); ++#endif ++ /* on the first access, read status register to reset internal pointers */ ++ SCCread(STATUS_REG); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: reset SCC\n"); ++#endif ++ /* FIXME: master reset, once only */ ++ SCCwrite(MASTER_INT_CTRL, MIC_HARD_RESET); ++ udelay(40); ++ ++ /* disable interrupts for this channel */ ++ SCCwrite(INT_AND_DMA_REG, 0); ++ /* Set the interrupt vector ; 0x60 for all Atari models */ ++ SCCwrite(INT_VECTOR_REG, 0x60); ++ /* Interrupt parameters: vector includes status, status low */ ++ SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT); ++ SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB); ++ ++ /* disable interrupts for this channel */ ++ SCCwrite(INT_AND_DMA_REG, 0); ++ } ++ ++ if (!atari_SCC_init_done) { ++ /* Init channel B */ ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: init channel B\n"); ++#endif ++ port = &scc_ports[1]; ++ port->channel = CHANNEL_B; ++ port->ctrlp = (volatile unsigned char *)&scc.cha_b_ctrl; ++ port->datap = port->ctrlp + 1; ++ port->port_a = &scc_ports[0]; ++ port->port_b = &scc_ports[1]; ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: request channel B irqs, port = %p\n", port); ++#endif ++ request_irq(IRQ_SCCB_TX, scc_tx_int, IRQ_TYPE_PRIO, ++ "SCC-B TX", port); ++ request_irq(IRQ_SCCB_STAT, scc_stat_int, IRQ_TYPE_PRIO, ++ "SCC-B status", port); ++ request_irq(IRQ_SCCB_RX, scc_rx_int, IRQ_TYPE_PRIO, ++ "SCC-B RX", port); ++ request_irq(IRQ_SCCB_SPCOND, scc_spcond_int, IRQ_TYPE_PRIO, ++ "SCC-B special cond", port); ++ { ++ SCC_ACCESS_INIT(port); ++ ++ /* disable interrupts for this channel */ ++ SCCwrite(INT_AND_DMA_REG, 0); ++ } ++/* not implemented yet */ ++#if 0 ++ request_irq(IRQ_TT_MFP_RI, scc_ri_int, IRQ_TYPE_SLOW, ++ "TT-MFP ring indicator (modem 2)", port); ++#endif ++ ++ } ++ ++ /* once only: initalize MFP timer C for RTxC */ ++ tt_mfp.tim_ct_cd = (tt_mfp.tim_ct_cd & ~0x70) | 0x10; ++ tt_mfp.tim_dt_c = 1; ++ atari_turnoff_irq(IRQ_TT_MFP_TIMC); ++ ++ /* set baud tables */ ++ scc_baud_table[CHANNEL_A] = bdtab_norm; ++ scc_baud_table[CHANNEL_B] = bdtab_TTChB; ++ ++ /* Initialise the tty driver structures and register */ ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: scc_init_portstructs()\n"); ++#endif ++ scc_init_portstructs(); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: scc_init_drivers()\n"); ++#endif ++ scc_init_drivers(); ++ ++ return 0; ++} ++#endif ++ ++ ++#ifdef CONFIG_FALCON_SCC ++static int atari_falcon_scc_init(void) ++{ ++ struct scc_port *port; ++ ++ printk(KERN_INFO "SCC: Atari Falcon Serial Driver\n"); ++ if (atari_SCC_init_done) ++ printk(KERN_INFO "SCC: already initialized, expect trouble!\n"); ++ ++ /* Init channel A */ ++ port = &scc_ports[0]; ++ port->channel = CHANNEL_A; ++ port->ctrlp = (volatile unsigned char *)&scc.cha_a_ctrl; ++ port->datap = port->ctrlp + 2; ++ port->port_a = &scc_ports[0]; ++ port->port_b = &scc_ports[1]; ++ request_irq(IRQ_SCCA_TX, scc_tx_int, IRQ_TYPE_PRIO, "SCC-A TX", port); ++ request_irq(IRQ_SCCA_STAT, scc_stat_int, IRQ_TYPE_PRIO, ++ "SCC-A status", port); ++ request_irq(IRQ_SCCA_RX, scc_rx_int, IRQ_TYPE_PRIO, "SCC-A RX", port); ++ request_irq(IRQ_SCCA_SPCOND, scc_spcond_int, IRQ_TYPE_PRIO, ++ "SCC-A special cond", port); ++ { ++ SCC_ACCESS_INIT(port); ++ ++ /* on the first access, read status register to reset internal pointers */ ++ SCCread(STATUS_REG); ++ ++ /* FIXME: master reset, once only */ ++ SCCwrite(MASTER_INT_CTRL, MIC_HARD_RESET); ++ udelay(40); ++ ++ /* disable interrupts for this channel */ ++ SCCwrite(INT_AND_DMA_REG, 0); ++ /* Set the interrupt vector */ ++ SCCwrite(INT_VECTOR_REG, 0x60); ++ /* Interrupt parameters: vector includes status, status low */ ++ SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT); ++ SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB); ++ } ++ ++ /* conditionalize if port in use by console ?? */ ++ /* Init channel B */ ++ port = &scc_ports[1]; ++ port->channel = CHANNEL_B; ++ port->ctrlp = (volatile unsigned char *)&scc.cha_b_ctrl; ++ port->datap = port->ctrlp + 2; ++ port->port_a = &scc_ports[0]; ++ port->port_b = &scc_ports[1]; ++ request_irq(IRQ_SCCB_TX, scc_tx_int, IRQ_TYPE_PRIO, "SCC-B TX", port); ++ request_irq(IRQ_SCCB_STAT, scc_stat_int, IRQ_TYPE_PRIO, ++ "SCC-B status", port); ++ request_irq(IRQ_SCCB_RX, scc_rx_int, IRQ_TYPE_PRIO, "SCC-B RX", port); ++ request_irq(IRQ_SCCB_SPCOND, scc_spcond_int, IRQ_TYPE_PRIO, ++ "SCC-B special cond", port); ++ ++ { ++ SCC_ACCESS_INIT(port); /* Either channel will do */ ++ ++ /* disable interrupts for this channel */ ++ SCCwrite(INT_AND_DMA_REG, 0); ++ } ++ ++ /* set baud tables */ ++ scc_baud_table[CHANNEL_A] = bdtab_norm; ++ scc_baud_table[CHANNEL_B] = bdtab_norm; ++ ++ /* Initialise the tty driver structures and register */ ++ scc_init_portstructs(); ++ scc_init_drivers(); ++ ++ return 0; ++} ++#endif ++ ++ ++#ifdef CONFIG_ST_SCC ++static int atari_st_scc_init(void) ++{ ++ struct scc_port *port; ++ ++ int escc = ATARIHW_PRESENT(ST_ESCC); ++ ++ printk(KERN_INFO "SCC: Atari MegaST/E Serial Driver\n"); ++ /* FIXME: ports reversed logic */ ++ /* Init channel A */ ++ port = &scc_ports[1]; ++ port->channel = CHANNEL_A; ++ port->ctrlp = (volatile unsigned char *)(escc ? &st_escc.cha_a_ctrl : &scc.cha_a_ctrl); ++ port->datap = port->ctrlp + 4; ++ port->port_a = &scc_ports[1]; ++ port->port_b = &scc_ports[0]; ++ request_irq(IRQ_SCCA_TX, scc_tx_int, IRQ_TYPE_PRIO, "SCC-A TX", port); ++ request_irq(IRQ_SCCA_STAT, scc_stat_int, IRQ_TYPE_PRIO, ++ "SCC-A status", port); ++ request_irq(IRQ_SCCA_RX, scc_rx_int, IRQ_TYPE_PRIO, "SCC-A RX", port); ++ request_irq(SCCA_SPCOND, scc_spcond_int, IRQ_TYPE_PRIO, ++ "SCC-A special cond", port); ++ { ++ SCC_ACCESS_INIT(port); ++ ++ /* on the first access, read status register to reset internal pointers */ ++ SCCread(STATUS_REG); ++ ++ /* FIXME: master reset, once only */ ++ SCCwrite(MASTER_INT_CTRL, MIC_HARD_RESET); ++ udelay(40); ++ ++ /* disable interrupts for this channel */ ++ SCCwrite(INT_AND_DMA_REG, 0); ++ /* Set the interrupt vector */ ++ SCCwrite(INT_VECTOR_REG, BVME_IRQ_SCC_BASE); ++ /* Interrupt parameters: vector includes status, status low */ ++ SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT); ++ SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB); ++ } ++ ++ /* Init channel B */ ++ port = &scc_ports[0]; ++ port->channel = CHANNEL_B; ++ port->ctrlp = (volatile unsigned char *)(escc ? &st_escc.cha_b_ctrl : &scc.cha_b_ctrl); ++ port->datap = port->ctrlp + 4; ++ port->port_a = &scc_ports[0]; ++ port->port_b = &scc_ports[1]; ++ request_irq(IRQ_SCCB_TX, scc_tx_int, IRQ_TYPE_PRIO, "SCC-B TX", port); ++ request_irq(IRQ_SCCB_STAT, scc_stat_int, IRQ_TYPE_PRIO, ++ "SCC-B status", port); ++ request_irq(IRQ_SCCB_RX, scc_rx_int, IRQ_TYPE_PRIO, "SCC-B RX", port); ++ request_irq(IRQ_SCCB_SPCOND, scc_spcond_int, IRQ_TYPE_PRIO, ++ "SCC-B special cond", port); ++ ++ { ++ SCC_ACCESS_INIT(port); /* Either channel will do */ ++ ++ /* disable interrupts for this channel */ ++ SCCwrite(INT_AND_DMA_REG, 0); ++ } ++ ++ /* set baud tables */ ++ scc_baud_table[CHANNEL_A] = bdtab_norm; ++ scc_baud_table[CHANNEL_B] = bdtab_norm; ++ ++ /* Initialise the tty driver structures and register */ ++ scc_init_portstructs(); ++ scc_init_drivers(); ++ ++ return 0; ++} ++#endif ++ ++ ++int atari_scc_init(void) ++{ ++ int res = -ENODEV; ++ static int called = 0; ++ ++ if (called) ++ return res; ++ called = 1; ++ ++ if (!(ATARIHW_PRESENT(SCC) || ATARIHW_PRESENT(ST_ESCC))) ++ return -ENODEV; ++ ++ scc_del = &mfp.par_dt_reg; ++ ++#ifdef CONFIG_TT_SCC ++ if (MACH_IS_TT) ++ res = atari_tt_scc_init(); ++#endif ++#ifdef CONFIG_FALCON_SCC ++ if (MACH_IS_FALCON) ++ res = atari_falcon_scc_init(); ++#endif ++#ifdef CONFIG_ST_SCC ++ if (MACH_IS_ST) ++ res = atari_st_scc_init(); ++#endif ++ return res; ++} ++ ++void atari_scc_cleanup(void) ++{ ++ struct scc_port *port; ++ ++ tty_unregister_driver(scc_driver); ++ port = &scc_ports[0]; ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: free channel A irqs, port = %p\n", port); ++#endif ++ free_irq(IRQ_SCCA_TX, port); ++ free_irq(IRQ_SCCA_STAT, port); ++ free_irq(IRQ_SCCA_RX, port); ++ free_irq(IRQ_SCCA_SPCOND, port); ++ ++ port = &scc_ports[1]; ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: free channel A irqs, port = %p\n", port); ++#endif ++ free_irq(IRQ_SCCB_TX, port); ++ free_irq(IRQ_SCCB_STAT, port); ++ free_irq(IRQ_SCCB_RX, port); ++ free_irq(IRQ_SCCB_SPCOND, port); ++ ++} ++ ++module_init(atari_scc_init); ++module_exit(atari_scc_cleanup); ++ ++/*--------------------------------------------------------------------------- ++ * Interrupt handlers ++ *--------------------------------------------------------------------------*/ ++ ++static irqreturn_t scc_rx_int(int irq, void *data) ++{ ++ unsigned char ch; ++ struct scc_port *port = data; ++ struct tty_struct *tty = port->gs.tty; ++ SCC_ACCESS_INIT(port); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: rx_int ...\n"); ++#endif ++ ch = SCCread_NB(RX_DATA_REG); ++ if (!tty) { ++ printk(KERN_WARNING "scc_rx_int with NULL tty!\n"); ++ SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); ++ return IRQ_HANDLED; ++ } ++ tty_insert_flip_char(tty, ch, 0); ++#if 0 ++ if (tty->flip.count < TTY_FLIPBUF_SIZE) { ++ *tty->flip.char_buf_ptr = ch; ++ *tty->flip.flag_buf_ptr = 0; ++ tty->flip.flag_buf_ptr++; ++ tty->flip.char_buf_ptr++; ++ tty->flip.count++; ++ } ++#endif ++ /* Check if another character is already ready; in that case, the ++ * spcond_int() function must be used, because this character may have an ++ * error condition that isn't signalled by the interrupt vector used! ++ */ ++ if (SCCread(INT_PENDING_REG) & ++ (port->channel == CHANNEL_A ? IPR_A_RX : IPR_B_RX)) { ++ scc_spcond_int(irq, data); ++ return IRQ_HANDLED; ++ } ++ ++ SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); ++ ++ tty_flip_buffer_push(tty); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: rx_int done\n"); ++#endif ++ return IRQ_HANDLED; ++} ++ ++ ++static irqreturn_t scc_spcond_int(int irq, void *data) ++{ ++ struct scc_port *port = data; ++ struct tty_struct *tty = port->gs.tty; ++ unsigned char stat, ch, err; ++ int int_pending_mask = port->channel == CHANNEL_A ? IPR_A_RX : IPR_B_RX; ++ ++ SCC_ACCESS_INIT(port); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: spcond_int ...\n"); ++#endif ++ if (!tty) { ++ printk(KERN_WARNING "scc_spcond_int with NULL tty!\n"); ++ SCCwrite(COMMAND_REG, CR_ERROR_RESET); ++ SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); ++ return IRQ_HANDLED; ++ } ++ do { ++ stat = SCCread(SPCOND_STATUS_REG); ++ ch = SCCread_NB(RX_DATA_REG); ++ ++ if (stat & SCSR_RX_OVERRUN) ++ err = TTY_OVERRUN; ++ else if (stat & SCSR_PARITY_ERR) ++ err = TTY_PARITY; ++ else if (stat & SCSR_CRC_FRAME_ERR) ++ err = TTY_FRAME; ++ else ++ err = 0; ++ ++ tty_insert_flip_char(tty, ch, err); ++#if 0 ++ if (tty->flip.count < TTY_FLIPBUF_SIZE) { ++ *tty->flip.char_buf_ptr = ch; ++ *tty->flip.flag_buf_ptr = err; ++ tty->flip.flag_buf_ptr++; ++ tty->flip.char_buf_ptr++; ++ tty->flip.count++; ++ } ++#endif ++ /* ++TeSche: *All* errors have to be cleared manually, ++ * else the condition persists for the next chars ++ */ ++ if (err) ++ SCCwrite(COMMAND_REG, CR_ERROR_RESET); ++ ++ } while (SCCread(INT_PENDING_REG) & int_pending_mask); ++ ++ SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); ++ ++ tty_flip_buffer_push(tty); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: spcond_int done\n"); ++#endif ++ return IRQ_HANDLED; ++} ++ ++/* not implemented yet */ ++#if 0 ++static void scc_ri_int(int irq, void *data) ++{ ++ struct scc_port *port = data; ++ /* update input line counter */ ++ port->icount.rng++; ++ wake_up_interruptible(&port->delta_msr_wait); ++} ++#endif ++ ++static irqreturn_t scc_tx_int(int irq, void *data) ++{ ++ struct scc_port *port = data; ++ SCC_ACCESS_INIT(port); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: tx_int irq %d port %p ...\n", irq, data); ++#endif ++ if (!port->gs.tty) { ++ printk(KERN_WARNING "scc_tx_int with NULL tty!\n"); ++ SCCmod(INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); ++ SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET); ++ SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); ++ return IRQ_HANDLED; ++ } ++ while ((SCCread_NB(STATUS_REG) & SR_TX_BUF_EMPTY)) { ++ if (port->x_char) { ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: tx_int writing char %c\n", ++ port->x_char); ++#endif ++ SCCwrite(TX_DATA_REG, port->x_char); ++ port->x_char = 0; ++ } else if ((port->gs.xmit_cnt <= 0) || port->gs.tty->stopped || ++ port->gs.tty->hw_stopped) { ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: nothing to do!\n"); ++#endif ++ break; ++ } else { ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: tx_int writing buf %c\n", ++ port->gs.xmit_buf[port->gs.xmit_tail]); ++#endif ++ SCCwrite(TX_DATA_REG, port->gs.xmit_buf[port->gs.xmit_tail++]); ++ port->gs.xmit_tail = port->gs.xmit_tail & (SERIAL_XMIT_SIZE-1); ++ if (--port->gs.xmit_cnt <= 0) ++ break; ++ } ++ } ++ if ((port->gs.xmit_cnt <= 0) || port->gs.tty->stopped || ++ port->gs.tty->hw_stopped) { ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: nothing to do, disabling int\n"); ++#endif ++ /* disable tx interrupts */ ++ SCCmod(INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); ++ SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET); /* disable tx_int on next tx underrun? */ ++ port->gs.flags &= ~GS_TX_INTEN; ++ } ++ if (port->gs.tty && port->gs.xmit_cnt <= port->gs.wakeup_chars) { ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: waking up tty!\n"); ++#endif ++ tty_wakeup(port->gs.tty); ++ } ++ ++ SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: tx_int done\n"); ++#endif ++ return IRQ_HANDLED; ++} ++ ++ ++static irqreturn_t scc_stat_int(int irq, void *data) ++{ ++ struct scc_port *port = data; ++ unsigned channel = port->channel; ++ unsigned char last_sr, sr, changed; ++ SCC_ACCESS_INIT(port); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: stat_int ...\n"); ++#endif ++ last_sr = scc_last_status_reg[channel]; ++ sr = scc_last_status_reg[channel] = SCCread_NB(STATUS_REG); ++ changed = last_sr ^ sr; ++ ++ if (changed & SR_DCD) { ++ port->c_dcd = !!(sr & SR_DCD); ++ if (!(port->gs.flags & ASYNC_CHECK_CD)) ++ ; /* Don't report DCD changes */ ++ else if (port->c_dcd) { ++ /* Are we blocking in open? */ ++ wake_up_interruptible(&port->gs.open_wait); ++ } else { ++ if (port->gs.tty) ++ tty_hangup(port->gs.tty); ++ } ++ } ++ ++ // FIXME: CTS and DSR status changes? ++ ++ SCCwrite(COMMAND_REG, CR_EXTSTAT_RESET); ++ SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: stat_int done\n"); ++#endif ++ return IRQ_HANDLED; ++} ++ ++ ++/*--------------------------------------------------------------------------- ++ * generic_serial.c callback funtions ++ *--------------------------------------------------------------------------*/ ++ ++static void scc_disable_tx_interrupts(void *ptr) ++{ ++ struct scc_port *port = ptr; ++ unsigned long flags; ++ SCC_ACCESS_INIT(port); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: disable_tx_int ...\n"); ++#endif ++ local_irq_save(flags); ++ SCCmod(INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0); ++ port->gs.flags &= ~GS_TX_INTEN; ++ local_irq_restore(flags); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: disable_tx_int done!\n"); ++#endif ++} ++ ++ ++static void scc_enable_tx_interrupts(void *ptr) ++{ ++ struct scc_port *port = ptr; ++ unsigned long flags; ++ ++ SCC_ACCESS_INIT(port); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: enable_tx_int ...\n"); ++#endif ++ local_irq_save(flags); ++ SCCmod(INT_AND_DMA_REG, 0xff, IDR_TX_INT_ENAB); ++ /* restart the transmitter */ ++ scc_tx_int(0, port); ++ local_irq_restore(flags); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: enable_tx_int done!\n"); ++#endif ++} ++ ++ ++static void scc_disable_rx_interrupts(void *ptr) ++{ ++ struct scc_port *port = ptr; ++ unsigned long flags; ++ ++ SCC_ACCESS_INIT(port); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: disable_rx_int ...\n"); ++#endif ++ local_irq_save(flags); ++ SCCmod(INT_AND_DMA_REG, ++ ~(IDR_RX_INT_MASK|IDR_PARERR_AS_SPCOND|IDR_EXTSTAT_INT_ENAB), 0); ++ local_irq_restore(flags); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: disable_rx_int done!\n"); ++#endif ++} ++ ++ ++static void scc_enable_rx_interrupts(void *ptr) ++{ ++ struct scc_port *port = ptr; ++ unsigned long flags; ++ ++ SCC_ACCESS_INIT(port); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: enable_rx_int ...\n"); ++#endif ++ local_irq_save(flags); ++ SCCmod(INT_AND_DMA_REG, 0xff, ++ IDR_EXTSTAT_INT_ENAB|IDR_PARERR_AS_SPCOND|IDR_RX_INT_ALL); ++ local_irq_restore(flags); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: enable_rx_int done!\n"); ++#endif ++} ++ ++ ++static int scc_get_CD(void *ptr) ++{ ++ struct scc_port *port = ptr; ++ unsigned channel = port->channel; ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: get_CD!\n"); ++#endif ++ return !!(scc_last_status_reg[channel] & SR_DCD); ++} ++ ++ ++static void scc_shutdown_port(void *ptr) ++{ ++ struct scc_port *port = ptr; ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: shutdown_port ...\n"); ++#endif ++ port->gs.flags &= ~GS_ACTIVE; ++ if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL) ++ scc_setsignals(port, 0, 0); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: shutdown_port done!\n"); ++#endif ++} ++ ++ ++static int scc_set_real_termios(void *ptr) ++{ ++ /* the SCC has char sizes 5,7,6,8 in that order! */ ++ static int chsize_map[4] = { 0, 2, 1, 3 }; ++ unsigned int cflag, baud, baudbits, baudidx, brgmode; ++ unsigned int clkmode, clksrc, div, chsize, channel, brgval = 0; ++ unsigned long flags; ++ struct scc_port *port = ptr; ++ SCC_ACCESS_INIT(port); ++ ++ if (!port->gs.tty || !port->gs.tty->termios) ++ return 0; ++ ++ channel = port->channel; ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: termios for channel %p\n", channel); ++#endif ++ cflag = port->gs.tty->termios->c_cflag; ++ baud = port->gs.baud; ++ baudbits = cflag & CBAUD; ++ chsize = (cflag & CSIZE) >> 4; ++ ++ if (baud == 0) { ++ /* speed == 0 -> drop DTR */ ++ local_irq_save(flags); ++ SCCmod(TX_CTRL_REG, ~TCR_DTR, 0); ++ local_irq_restore(flags); ++ return 0; ++ } else if ((MACH_IS_TT && (baud < 50 || baud > 115200)) || ++ (MACH_IS_FALCON && (baud < 50 || baud > 230400))) { ++ printk(KERN_NOTICE "SCC: Bad speed requested, %d\n", baud); ++ return 0; ++ } ++ ++ if (cflag & CLOCAL) ++ port->gs.flags &= ~ASYNC_CHECK_CD; ++ else ++ port->gs.flags |= ASYNC_CHECK_CD; ++ ++ // calculate brgval for Atari; enable direct modes! ++ ++ /* convert baud rate from gs.baud to table index, set custom divisor eventually */ ++ ++ div = 0; ++ clksrc = 0; ++ baudidx = 0; ++ ++ switch (baud) { ++ case 50: ++ baudidx = 1; ++ break; ++ case 75: ++ baudidx = 2; ++ break; ++ case 110: ++ baudidx = 3; ++ break; ++ case 134: ++ baudidx = 4; ++ break; ++ case 150: ++ baudidx = 5; ++ break; ++ case 200: ++ baudidx = 6; ++ break; ++ case 300: ++ baudidx = 7; ++ break; ++ case 600: ++ baudidx = 8; ++ break; ++ case 1200: ++ baudidx = 9; ++ break; ++ case 1800: ++ baudidx = 10; ++ break; ++ case 2400: ++ baudidx = 11; ++ break; ++ case 4800: ++ baudidx = 12; ++ break; ++ case 9600: ++ baudidx = 13; ++ break; ++ case 19200: ++ baudidx = 14; ++ break; ++ case 38400: ++ baudidx = 15; ++ break; ++ case 57600: ++ baudidx = 16; ++ break; ++ case 115200: ++ baudidx = 17; ++ break; ++ case 230400: ++ baudidx = 18; ++ break; ++ default: ++ baudidx = 15; ++ break; ++ } ++ ++ /* do we have a custom divisor ?? */ ++ if (!div) { ++ if (baudidx > 19) ++ baudidx = 19; ++ clksrc = scc_baud_table[channel][baudidx].clksrc; ++ div = scc_baud_table[channel][baudidx].div; ++ if (!div) { ++ printk(" SCC_change_speed: divisor = 0 !!!"); ++ return 0; ++ } ++ } ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: termios baud %d baudbits %d baudidx %d \n clksrc %d div %d\n", ++ baud, baudbits, baudidx, clksrc, div); ++#endif ++ /* compute the SCC's clock source, clock mode, BRG mode and BRG ++ * value from clksrc and div ++ */ ++ if (div <= 4) { ++ clkmode = (div == 1 ? A1CR_CLKMODE_x16 : ++ div == 2 ? A1CR_CLKMODE_x32 : ++ A1CR_CLKMODE_x64); ++ clksrc = (clksrc == CLK_RTxC ++ ? CCR_TXCLK_RTxC | CCR_RXCLK_RTxC ++ : CCR_TXCLK_TRxC | CCR_RXCLK_TRxC); ++ brgmode = 0; /* off */ ++ brgval = 0; ++ } else { ++ brgval = div/2 - 2; ++ brgmode = (DCR_BRG_ENAB | ++ (clksrc == CLK_PCLK ? DCR_BRG_USE_PCLK : 0)); ++ clkmode = A1CR_CLKMODE_x16; ++ clksrc = CCR_TXCLK_BRG | CCR_RXCLK_BRG; ++ } ++ ++ //printk(KERN_INFO "SCC: termios baud %d baudbits %d baudidx %d \n clksrc %d clkmode %d div %d brgval %d brgmode %d\n", ++ // baud, baudbits, baudidx, clksrc, clkmode, div, brgval, brgmode); ++ ++ /* Now we have all parameters and can go to set them: */ ++ local_irq_save(flags); ++ ++#ifdef DEBUG ++ printk(" brgval=%d brgmode=%02x clkmode=%02x clksrc=%02x\n", ++ brgval, brgmode, clkmode, clksrc); ++#endif ++ /* receiver's character size and auto-enables */ ++#if 0 // auto-enable considered harmful ... ++ SCCmod(RX_CTRL_REG, ~(RCR_CHSIZE_MASK|RCR_AUTO_ENAB_MODE), ++ (chsize_map[chsize] << 6) | ++ ((cflag & CRTSCTS) ? RCR_AUTO_ENAB_MODE : 0)); ++#else ++ /* receiver's character size */ ++ SCCmod(RX_CTRL_REG, ~RCR_CHSIZE_MASK, chsize_map[chsize] << 6); ++#endif ++#ifdef DEBUG ++ printk(" RX_CTRL_REG <- %02x\n", SCCread( RX_CTRL_REG )); ++#endif ++ ++ // clock mode changes depending on baud rate ++ /* parity and stop bits (both, Tx and Rx) and clock mode */ ++ SCCmod(AUX1_CTRL_REG, ++ ~(A1CR_PARITY_MASK | A1CR_MODE_MASK | A1CR_CLKMODE_MASK), ++ ((cflag & PARENB ++ ? (cflag & PARODD ? A1CR_PARITY_ODD : A1CR_PARITY_EVEN) ++ : A1CR_PARITY_NONE) ++ | (cflag & CSTOPB ? A1CR_MODE_ASYNC_2 : A1CR_MODE_ASYNC_1) ++ | clkmode)); ++ ++#ifdef DEBUG ++ printk(" AUX1_CTRL_REG <- %02x\n", SCCread(AUX1_CTRL_REG)); ++#endif ++ /* sender's character size, set DTR for valid baud rate */ ++ SCCmod(TX_CTRL_REG, ~TCR_CHSIZE_MASK, chsize_map[chsize] << 5 | TCR_DTR); ++#ifdef DEBUG ++ printk(" TX_CTRL_REG <- %02x\n", SCCread(TX_CTRL_REG)); ++#endif ++ ++ // clock sources change for TT !! ++ /* clock sources never change */ ++ /* clock sources */ ++ SCCmod(CLK_CTRL_REG, ~(CCR_TXCLK_MASK | CCR_RXCLK_MASK), clksrc); ++#ifdef DEBUG ++ printk(" CLK_CTRL_REG <- %02x\n", SCCread(CLK_CTRL_REG)); ++#endif ++ ++ /* disable BRG before changing the value */ ++ SCCmod(DPLL_CTRL_REG, ~DCR_BRG_ENAB, 0); ++ /* BRG value */ ++ SCCwrite(TIMER_LOW_REG, brgval & 0xff); ++ SCCwrite(TIMER_HIGH_REG, (brgval >> 8) & 0xff); ++ /* BRG enable, and clock source never changes */ ++ //SCCmod(DPLL_CTRL_REG, 0xff, DCR_BRG_ENAB); ++ SCCmod(DPLL_CTRL_REG, ~(DCR_BRG_ENAB | DCR_BRG_USE_PCLK), brgmode); ++#ifdef DEBUG ++ printk(" TIMER_LOW_REG <- %02x\n", SCCread(TIMER_LOW_REG)); ++ printk(" TIMER_HIGH_REG <- %02x\n", SCCread(TIMER_HIGH_REG)); ++#endif ++#ifdef DEBUG ++ printk(" DPLL_CTRL_REG <- %02x\n", SCCread(DPLL_CTRL_REG)); ++#endif ++ ++ local_irq_restore(flags); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: done termios for channel %d\n", channel); ++#endif ++ return 0; ++} ++ ++ ++static int scc_chars_in_buffer(void *ptr) ++{ ++ struct scc_port *port = ptr; ++#ifdef DEBUG ++ int rv; ++#endif ++ SCC_ACCESS_INIT(port); ++#ifdef DEBUG ++ rv = (SCCread(SPCOND_STATUS_REG) & SCSR_ALL_SENT) ? 0 : 1; ++ printk(KERN_INFO "SCC: chars_in_buffer: %d\n", rv); ++ return rv; ++#else ++ return (SCCread(SPCOND_STATUS_REG) & SCSR_ALL_SENT) ? 0 : 1; ++#endif ++} ++ ++ ++/* Comment taken from sx.c (2.4.0): ++ I haven't the foggiest why the decrement use count has to happen ++ here. The whole linux serial drivers stuff needs to be redesigned. ++ My guess is that this is a hack to minimize the impact of a bug ++ elsewhere. Thinking about it some more. (try it sometime) Try ++ running minicom on a serial port that is driven by a modularized ++ driver. Have the modem hangup. Then remove the driver module. Then ++ exit minicom. I expect an "oops". -- REW */ ++ ++static void scc_hungup(void *ptr) ++{ ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: hungup ...\n"); ++#endif ++ scc_disable_tx_interrupts(ptr); ++ scc_disable_rx_interrupts(ptr); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: hungup done\n"); ++#endif ++} ++ ++ ++static void scc_close(void *ptr) ++{ ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: close ...\n"); ++#endif ++ scc_disable_tx_interrupts(ptr); ++ scc_disable_rx_interrupts(ptr); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: close done\n"); ++#endif ++} ++ ++ ++/*--------------------------------------------------------------------------- ++ * Internal support functions ++ *--------------------------------------------------------------------------*/ ++ ++static void scc_setsignals(struct scc_port *port, int dtr, int rts) ++{ ++ unsigned long flags; ++ unsigned char t; ++ SCC_ACCESS_INIT(port); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: setsignals dtr %d rts %d...\n", dtr, rts); ++#endif ++ local_irq_save(flags); ++ t = SCCread(TX_CTRL_REG); ++ if (dtr >= 0) ++ t = dtr? (t | TCR_DTR): (t & ~TCR_DTR); ++ if (rts >= 0) ++ t = rts? (t | TCR_RTS): (t & ~TCR_RTS); ++ SCCwrite(TX_CTRL_REG, t); ++ local_irq_restore(flags); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: setsignals done\n"); ++#endif ++} ++ ++ ++static void scc_send_xchar(struct tty_struct *tty, char ch) ++{ ++ struct scc_port *port = (struct scc_port *)tty->driver_data; ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: send_xchar ...\n"); ++#endif ++ port->x_char = ch; ++ if (ch) ++ scc_enable_tx_interrupts(port); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: send_xchar done\n"); ++#endif ++} ++ ++ ++/*--------------------------------------------------------------------------- ++ * Driver entrypoints referenced from above ++ *--------------------------------------------------------------------------*/ ++ ++static int scc_open(struct tty_struct *tty, struct file *filp) ++{ ++ int line = tty->index; ++ int retval; ++ struct scc_port *port = &scc_ports[line]; ++ int i, channel = port->channel; ++ unsigned long flags; ++ SCC_ACCESS_INIT(port); ++ ++ static const struct { ++ unsigned reg, val; ++ } scc_init_tab[] = { ++ /* no parity, 1 stop bit, async, 1:16 */ ++ { AUX1_CTRL_REG, A1CR_PARITY_NONE|A1CR_MODE_ASYNC_1|A1CR_CLKMODE_x64 }, ++ /* parity error is special cond, ints disabled, no DMA */ ++ { INT_AND_DMA_REG, IDR_PARERR_AS_SPCOND | IDR_RX_INT_DISAB }, ++ /* Rx 8 bits/char, no auto enable, Rx off */ ++ { RX_CTRL_REG, RCR_CHSIZE_8 }, ++ /* DTR off, Tx 8 bits/char, RTS off, Tx off */ ++ { TX_CTRL_REG, TCR_CHSIZE_8 }, ++ /* special features off */ ++ { AUX2_CTRL_REG, 0 }, ++ /* RTxC is XTAL, TRxC is input, both clocks = RTxC */ ++ { CLK_CTRL_REG, CCR_TRxCOUT_XTAL | CCR_TXCLK_RTxC | CCR_RXCLK_RTxC }, ++ { DPLL_CTRL_REG, 0 }, ++ /* Start Rx */ ++ { RX_CTRL_REG, RCR_RX_ENAB | RCR_CHSIZE_8 }, ++ /* Start Tx */ ++ { TX_CTRL_REG, TCR_TX_ENAB | TCR_RTS | TCR_DTR | TCR_CHSIZE_8 }, ++ /* Ext/Stat ints: CTS, DCD, SYNC (DSR) */ ++ { INT_CTRL_REG, ICR_ENAB_DCD_INT | ICR_ENAB_CTS_INT | ICR_ENAB_SYNC_INT }, ++ /* Reset Ext/Stat ints */ ++ { COMMAND_REG, CR_EXTSTAT_RESET }, ++ /* ...again */ ++ { COMMAND_REG, CR_EXTSTAT_RESET }, ++ /* Rx int always, TX int off, Ext/Stat int on */ ++ { INT_AND_DMA_REG, IDR_EXTSTAT_INT_ENAB | ++ IDR_PARERR_AS_SPCOND | IDR_RX_INT_ALL } ++ }; ++ ++ if (atari_SCC_init_done && line == 1) ++ return -ENODEV; ++ ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: open port ...\n"); ++#endif ++ if (!(port->gs.flags & ASYNC_INITIALIZED)) { ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: init port ...\n"); ++#endif ++ local_irq_save(flags); ++ ++ SCCmod(MASTER_INT_CTRL, 0x3f, ++ channel == 0 ? MIC_CH_A_RESET : MIC_CH_B_RESET); ++ udelay(40); /* extra delay after a reset */ ++ ++ for (i = 0; i < sizeof(scc_init_tab)/sizeof(*scc_init_tab); ++i) ++ SCCwrite(scc_init_tab[i].reg, scc_init_tab[i].val); ++ ++ ++ /* remember status register for detection of DCD and CTS changes */ ++ scc_last_status_reg[channel] = SCCread(STATUS_REG); ++ ++ port->c_dcd = 0; /* Prevent initial 1->0 interrupt */ ++ scc_setsignals(port, 1, 1); ++ local_irq_restore(flags); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: init port done!\n"); ++#endif ++ } ++ ++ tty->driver_data = port; ++ port->gs.tty = tty; ++ port->gs.count++; ++#ifdef DEBUG ++ printk(KERN_WARNING "SCC: gs init port ...\n"); ++#endif ++ retval = gs_init_port(&port->gs); ++ if (retval) { ++ port->gs.count--; ++ return retval; ++ } ++#ifdef DEBUG ++ printk(KERN_WARNING "SCC: gs init port done!\n"); ++#endif ++ port->gs.flags |= GS_ACTIVE; ++ ++#ifdef DEBUG ++ printk(KERN_WARNING "SCC: gs wait ready ...\n"); ++#endif ++ retval = gs_block_til_ready(port, filp); ++#ifdef DEBUG ++ printk(KERN_WARNING "SCC: gs wait ready done!\n"); ++#endif ++ if (retval) { ++ port->gs.count--; ++ return retval; ++ } ++ ++ port->c_dcd = scc_get_CD(port); ++ ++#ifdef DEBUG ++ printk(KERN_WARNING "SCC: enable rx ints ...\n"); ++#endif ++ scc_enable_rx_interrupts(port); ++#ifdef DEBUG ++ printk(KERN_WARNING "SCC: enable rx ints done!\n"); ++ ++ printk(KERN_INFO "SCC: open port done!\n"); ++#endif ++ return 0; ++} ++ ++ ++static void scc_throttle(struct tty_struct *tty) ++{ ++ struct scc_port *port = (struct scc_port *)tty->driver_data; ++ unsigned long flags; ++ SCC_ACCESS_INIT(port); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: throttle ...\n"); ++#endif ++ if (tty->termios->c_cflag & CRTSCTS) { ++ local_irq_save(flags); ++ SCCmod(TX_CTRL_REG, ~TCR_RTS, 0); ++ local_irq_restore(flags); ++ } ++ if (I_IXOFF(tty)) ++ scc_send_xchar(tty, STOP_CHAR(tty)); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: throttle done!\n"); ++#endif ++} ++ ++ ++static void scc_unthrottle(struct tty_struct *tty) ++{ ++ struct scc_port *port = (struct scc_port *)tty->driver_data; ++ unsigned long flags; ++ SCC_ACCESS_INIT(port); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: unthrottle ...\n"); ++#endif ++ if (tty->termios->c_cflag & CRTSCTS) { ++ local_irq_save(flags); ++ SCCmod(TX_CTRL_REG, 0xff, TCR_RTS); ++ local_irq_restore(flags); ++ } ++ if (I_IXOFF(tty)) ++ scc_send_xchar(tty, START_CHAR(tty)); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: unthrottle done!\n"); ++#endif ++} ++ ++ ++static int scc_ioctl(struct tty_struct *tty, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ struct scc_port *port = (struct scc_port *)tty->driver_data; ++ int retval; ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: ioctl! cmd %d, arg %p \n", cmd, arg); ++#endif ++ //if (serial_paranoia_check(info, tty->device, "zs_ioctl")) ++ // return -ENODEV; ++ ++ if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && ++ (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && ++ (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { ++ if (tty->flags & (1 << TTY_IO_ERROR)) ++ return -EIO; ++ } ++ ++ switch (cmd) { ++ case TCSBRK: /* SVID version: non-zero arg --> no break */ ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: ioctl TCSBRK\n"); ++#endif ++ retval = tty_check_change(tty); ++ if (retval) ++ return retval; ++ tty_wait_until_sent(tty, 0); ++ //if (!arg) ++ // send_break(info, HZ/4); /* 1/4 second */ ++ return 0; ++ case TCSBRKP: /* support for POSIX tcsendbreak() */ ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: ioctl TCSBRKP\n"); ++#endif ++ retval = tty_check_change(tty); ++ if (retval) ++ return retval; ++ tty_wait_until_sent(tty, 0); ++ //send_break(info, arg ? arg*(HZ/10) : HZ/4); ++ return 0; ++ case TIOCGSOFTCAR: ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: ioctl TIOCGSOFTCAR\n"); ++#endif ++ if (put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg)) ++ return -EFAULT; ++ return 0; ++ case TIOCSSOFTCAR: ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: ioctl TIOCSSOFTCAR\n"); ++#endif ++ if (get_user(arg, (unsigned long *)arg)) ++ return -EFAULT; ++ tty->termios->c_cflag = ++ ((tty->termios->c_cflag & ~CLOCAL) | ++ (arg ? CLOCAL : 0)); ++ return 0; ++ case TIOCMGET: ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: ioctl TIOCMGET\n"); ++#endif ++ //return get_modem_info(info, (unsigned int *)arg); ++ return 0; ++ case TIOCMBIS: ++ case TIOCMBIC: ++ case TIOCMSET: ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: ioctl TIOCMSET\n"); ++#endif ++ //return set_modem_info(info, cmd, (unsigned int *)arg); ++ return 0; ++ case TIOCGSERIAL: ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: ioctl TIOCGSERIAL\n"); ++#endif ++ return 0; ++ //return get_serial_info(info, ++ // (struct serial_struct *)arg); ++ case TIOCSSERIAL: ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: ioctl TIOCSSERIAL\n"); ++#endif ++ return 0; ++ //return set_serial_info(info, ++ // (struct serial_struct *)arg); ++ case TIOCSERGETLSR: /* Get line status register */ ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: ioctl TIOCSERGETLSR\n"); ++#endif ++ return 0; ++ //return get_lsr_info(info, (unsigned int *)arg); ++ ++ case TIOCSERGSTRUCT: ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: ioctl TIOCSERGSTRUCT\n"); ++#endif ++ return 0; ++ if (copy_to_user((struct scc_port *)arg, ++ port, sizeof(struct scc_port))) ++ return -EFAULT; ++ return 0; ++ ++ default: ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: ioctl default\n"); ++#endif ++ return -ENOIOCTLCMD; ++ } ++ return 0; ++} ++ ++ ++static void scc_break_ctl(struct tty_struct *tty, int break_state) ++{ ++ struct scc_port *port = (struct scc_port *)tty->driver_data; ++ unsigned long flags; ++ SCC_ACCESS_INIT(port); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: break ctl ...\n"); ++#endif ++ local_irq_save(flags); ++ SCCmod(TX_CTRL_REG, ~TCR_SEND_BREAK, break_state ? TCR_SEND_BREAK : 0); ++ local_irq_restore(flags); ++#ifdef DEBUG ++ printk(KERN_INFO "SCC: break ctl done!\n"); ++#endif ++} ++ ++ ++/*--------------------------------------------------------------------------- ++ * Serial console stuff... ++ *--------------------------------------------------------------------------*/ ++#if 1 ++#define scc_delay() \ ++ asm volatile ("tstb %0" : : "m" (*scc_del) : "cc") ++ ++#define SCC_WRITE(reg,val) \ ++ do { \ ++ scc.cha_b_ctrl = (reg); \ ++ scc_delay(); \ ++ scc.cha_b_ctrl = (val); \ ++ scc_delay(); \ ++ } while (0) ++ ++/* loops_per_jiffy isn't initialized yet, so we can't use udelay(). This does a ++ * delay of ~ 60us. */ ++#define LONG_DELAY() \ ++ do { \ ++ int i; \ ++ for (i = 100; i > 0; --i) \ ++ scc_delay(); \ ++ } while (0) ++ ++static void atari_init_scc_port(int cflag) ++{ ++ extern int atari_SCC_reset_done; ++ static int clksrc_table[9] = ++ /* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */ ++ { 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 }; ++ static int brgsrc_table[9] = ++ /* reg 14: 0 = RTxC, 2 = PCLK */ ++ { 2, 2, 2, 2, 2, 2, 0, 2, 2 }; ++ static int clkmode_table[9] = ++ /* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */ ++ { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 }; ++ static int div_table[9] = ++ /* reg12 (BRG low) */ ++ { 208, 138, 103, 50, 24, 11, 1, 0, 0 }; ++ ++ int baud = cflag & CBAUD; ++ int clksrc, clkmode, div, reg3, reg5; ++ ++ scc_del = &mfp.par_dt_reg; ++ ++ if (cflag & CBAUDEX) ++ baud += B38400; ++ if (baud < B1200 || baud > B38400+2) ++ baud = B9600; /* use default 9600bps for non-implemented rates */ ++ baud -= B1200; /* tables starts at 1200bps */ ++ ++ clksrc = clksrc_table[baud]; ++ clkmode = clkmode_table[baud]; ++ div = div_table[baud]; ++ if (ATARIHW_PRESENT(TT_MFP) && baud >= 6) { ++ /* special treatment for TT, where rates >= 38400 are done via TRxC */ ++ clksrc = 0x28; /* TRxC */ ++ clkmode = baud == 6 ? 0xc0 : ++ baud == 7 ? 0x80 : /* really 76800bps */ ++ 0x40; /* really 153600bps */ ++ div = 0; ++ } ++ ++ reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40; ++ reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */; ++ ++ (void)scc.cha_b_ctrl; /* reset reg pointer */ ++ SCC_WRITE(9, 0xc0); /* reset */ ++ LONG_DELAY(); /* extra delay after WR9 access */ ++ SCC_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 | ++ 0x04 /* 1 stopbit */ | ++ clkmode); ++ SCC_WRITE(3, reg3); ++ SCC_WRITE(5, reg5); ++ SCC_WRITE(9, 0); /* no interrupts */ ++ LONG_DELAY(); /* extra delay after WR9 access */ ++ SCC_WRITE(10, 0); /* NRZ mode */ ++ SCC_WRITE(11, clksrc); /* main clock source */ ++ SCC_WRITE(12, div); /* BRG value */ ++ SCC_WRITE(13, 0); /* BRG high byte */ ++ SCC_WRITE(14, brgsrc_table[baud]); ++ SCC_WRITE(14, brgsrc_table[baud] | (div ? 1 : 0)); ++ SCC_WRITE(3, reg3 | 1); ++ SCC_WRITE(5, reg5 | 8); ++ ++ atari_SCC_reset_done = 1; ++ atari_SCC_init_done = 1; ++} ++ ++static void scc_ch_write(char ch) ++{ ++ volatile char *p = NULL; ++ ++ if (MACH_IS_TT || MACH_IS_FALCON) ++ p = (volatile char *)&scc.cha_b_ctrl; ++ ++ if (MACH_IS_ST) ++ p = (volatile char *)&scc.cha_b_ctrl; ++ ++ if (MACH_IS_STE) ++ p = (volatile char *)&st_escc.cha_b_ctrl; ++ ++ do { ++ scc_delay(); ++ } ++ while (!(*p & 4)); ++ // scc_delay(); ++ // *p = 8; ++ scc_delay(); ++ *(p+1) = ch; ++} ++ ++/* The console must be locked when we get here. */ ++ ++static void scc_console_write(struct console *co, const char *str, unsigned count) ++{ ++ unsigned long flags; ++ ++ //printk("scc_console_write: %s\n", str); ++ local_irq_save(flags); ++ ++ while (count--) { ++ if (*str == '\n') ++ scc_ch_write('\r'); ++ scc_ch_write(*str++); ++ } ++ local_irq_restore(flags); ++ //printk("scc_console_write done!\n"); ++} ++ ++static struct tty_driver *scc_console_device(struct console *c, int *index) ++{ ++ *index = c->index; ++ return scc_driver; ++} ++ ++ ++static int __init scc_console_setup(struct console *co, char *options) ++{ ++ printk("scc_console_setup: initializing SCC port B\n"); ++ atari_init_scc_port(B9600|CS8); ++ printk("scc_console_setup: done!\n"); ++ return 0; ++} ++ ++ ++static struct console sercons = { ++ .name = "ttyS", ++ .write = scc_console_write, ++ .device = scc_console_device, ++ .setup = scc_console_setup, ++ .flags = CON_PRINTBUFFER, ++ .index = -1, ++}; ++ ++ ++static int __init vme_scc_console_init(void) ++{ ++ if (MACH_IS_TT || MACH_IS_ST || MACH_IS_FALCON) ++ register_console(&sercons); ++ return 0; ++} ++ ++console_initcall(vme_scc_console_init); ++#endif ++ ++/***************************** End of Functions *********************/ ++ ++MODULE_AUTHOR("Michael Schmitz"); ++MODULE_DESCRIPTION("Atari Amd8350 SCC serial driver"); ++MODULE_LICENSE("GPL"); diff --git a/debian/patches/bugfix/m68k/634-atari_scsi.diff b/debian/patches/bugfix/m68k/634-atari_scsi.diff new file mode 100644 index 000000000000..af34018334ac --- /dev/null +++ b/debian/patches/bugfix/m68k/634-atari_scsi.diff @@ -0,0 +1,228 @@ +Cc: James E.J. Bottomley <James.Bottomley@SteelEye.com>, + linux-scsi@vger.kernel.org +Subject: [PATCH] m68k: Atari SCSI revival + +From: Michael Schmitz <schmitz@opal.biophys.uni-duesseldorf.de> + +SCSI should be working on a TT (but someone should really try!) but causes +trouble on a Falcon (as in: it ate a filesystem of mine) at least when +used concurrently with IDE. I have the notion it's because locking of the +ST-DMA interrupt by IDE is broken in 2.6 (the IDE driver always complains +about trying to release an already-released ST-DMA). Needs more work, but +that's on the IDE or m68k interrupt side rather than SCSI. + +Signed-off-by: Michael Schmitz <schmitz@debian.org> +Signed-off-by: Roman Zippel <zippel@linux-m68k.org> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + drivers/scsi/Kconfig | 2 - + drivers/scsi/atari_NCR5380.c | 52 ++++++++++++++++++++++++++++++++++++++----- + drivers/scsi/atari_scsi.c | 10 +++----- + drivers/scsi/atari_scsi.h | 30 +++++++++++++++++++++--- + 4 files changed, 77 insertions(+), 17 deletions(-) + +--- linux-m68k-2.6.21.orig/drivers/scsi/Kconfig ++++ linux-m68k-2.6.21/drivers/scsi/Kconfig +@@ -1649,7 +1649,7 @@ config OKTAGON_SCSI + + config ATARI_SCSI + tristate "Atari native SCSI support" +- depends on ATARI && SCSI && BROKEN ++ depends on ATARI && SCSI + select SCSI_SPI_ATTRS + ---help--- + If you have an Atari with built-in NCR5380 SCSI controller (TT, +--- linux-m68k-2.6.21.orig/drivers/scsi/atari_NCR5380.c ++++ linux-m68k-2.6.21/drivers/scsi/atari_NCR5380.c +@@ -264,7 +264,7 @@ static struct scsi_host_template *the_te + (struct NCR5380_hostdata *)(in)->hostdata + #define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata) + +-#define NEXT(cmd) ((Scsi_Cmnd *)((cmd)->host_scribble)) ++#define NEXT(cmd) ((cmd)->host_scribble) + #define NEXTADDR(cmd) ((Scsi_Cmnd **)&((cmd)->host_scribble)) + + #define HOSTNO instance->host_no +@@ -716,7 +716,7 @@ static void NCR5380_print_status (struct + printk("NCR5380_print_status: no memory for print buffer\n"); + return; + } +- len = NCR5380_proc_info(pr_bfr, &start, 0, PAGE_SIZE, HOSTNO, 0); ++ len = NCR5380_proc_info(instance, pr_bfr, &start, 0, PAGE_SIZE, 0); + pr_bfr[len] = 0; + printk("\n%s\n", pr_bfr); + free_page((unsigned long) pr_bfr); +@@ -878,6 +878,46 @@ static int NCR5380_init (struct Scsi_Hos + } + + /* ++ * our own old-style timeout update ++ */ ++/* ++ * The strategy is to cause the timer code to call scsi_times_out() ++ * when the soonest timeout is pending. ++ * The arguments are used when we are queueing a new command, because ++ * we do not want to subtract the time used from this time, but when we ++ * set the timer, we want to take this value into account. ++ */ ++ ++int atari_scsi_update_timeout(Scsi_Cmnd * SCset, int timeout) ++{ ++ int rtn; ++ ++ /* ++ * We are using the new error handling code to actually register/deregister ++ * timers for timeout. ++ */ ++ ++ if (!timer_pending(&SCset->eh_timeout)) { ++ rtn = 0; ++ } else { ++ rtn = SCset->eh_timeout.expires - jiffies; ++ } ++ ++ if (timeout == 0) { ++ del_timer(&SCset->eh_timeout); ++ SCset->eh_timeout.data = (unsigned long) NULL; ++ SCset->eh_timeout.expires = 0; ++ } else { ++ if (SCset->eh_timeout.data != (unsigned long) NULL) ++ del_timer(&SCset->eh_timeout); ++ SCset->eh_timeout.data = (unsigned long) SCset; ++ SCset->eh_timeout.expires = jiffies + timeout; ++ add_timer(&SCset->eh_timeout); ++ } ++ return rtn; ++} ++ ++/* + * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, + * void (*done)(Scsi_Cmnd *)) + * +@@ -902,7 +942,7 @@ int NCR5380_queue_command (Scsi_Cmnd *cm + Scsi_Cmnd *tmp; + int oldto; + unsigned long flags; +- extern int update_timeout(Scsi_Cmnd * SCset, int timeout); ++ // extern int update_timeout(Scsi_Cmnd * SCset, int timeout); + + #if (NDEBUG & NDEBUG_NO_WRITE) + switch (cmd->cmnd[0]) { +@@ -978,9 +1018,9 @@ int NCR5380_queue_command (Scsi_Cmnd *cm + * alter queues and touch the lock. + */ + if (!IS_A_TT()) { +- oldto = update_timeout(cmd, 0); ++ oldto = atari_scsi_update_timeout(cmd, 0); + falcon_get_lock(); +- update_timeout(cmd, oldto); ++ atari_scsi_update_timeout(cmd, oldto); + } + if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) { + LIST(cmd, hostdata->issue_queue); +@@ -1435,7 +1475,7 @@ static int NCR5380_select (struct Scsi_H + local_irq_restore(flags); + + /* Wait for arbitration logic to complete */ +-#if NCR_TIMEOUT ++#if defined(NCR_TIMEOUT) + { + unsigned long timeout = jiffies + 2*NCR_TIMEOUT; + +--- linux-m68k-2.6.21.orig/drivers/scsi/atari_scsi.c ++++ linux-m68k-2.6.21/drivers/scsi/atari_scsi.c +@@ -395,7 +395,7 @@ static irqreturn_t scsi_tt_intr (int irq + + #endif /* REAL_DMA */ + +- NCR5380_intr (0, 0, 0); ++ NCR5380_intr(0, 0); + + #if 0 + /* To be sure the int is not masked */ +@@ -461,7 +461,7 @@ static irqreturn_t scsi_falcon_intr (int + + #endif /* REAL_DMA */ + +- NCR5380_intr (0, 0, 0); ++ NCR5380_intr(0, 0); + return IRQ_HANDLED; + } + +@@ -557,11 +557,11 @@ static void falcon_get_lock( void ) + + local_irq_save(flags); + +- while( !in_interrupt() && falcon_got_lock && stdma_others_waiting() ) ++ while (!in_irq() && falcon_got_lock && stdma_others_waiting()) + sleep_on( &falcon_fairness_wait ); + + while (!falcon_got_lock) { +- if (in_interrupt()) ++ if (in_irq()) + panic( "Falcon SCSI hasn't ST-DMA lock in interrupt" ); + if (!falcon_trying_lock) { + falcon_trying_lock = 1; +@@ -763,7 +763,6 @@ int atari_scsi_detect (struct scsi_host_ + return( 1 ); + } + +-#ifdef MODULE + int atari_scsi_release (struct Scsi_Host *sh) + { + if (IS_A_TT()) +@@ -772,7 +771,6 @@ int atari_scsi_release (struct Scsi_Host + atari_stram_free (atari_dma_buffer); + return 1; + } +-#endif + + void __init atari_scsi_setup(char *str, int *ints) + { +--- linux-m68k-2.6.21.orig/drivers/scsi/atari_scsi.h ++++ linux-m68k-2.6.21/drivers/scsi/atari_scsi.h +@@ -21,11 +21,7 @@ + int atari_scsi_detect (struct scsi_host_template *); + const char *atari_scsi_info (struct Scsi_Host *); + int atari_scsi_reset (Scsi_Cmnd *, unsigned int); +-#ifdef MODULE + int atari_scsi_release (struct Scsi_Host *); +-#else +-#define atari_scsi_release NULL +-#endif + + /* The values for CMD_PER_LUN and CAN_QUEUE are somehow arbitrary. Higher + * values should work, too; try it! (but cmd_per_lun costs memory!) */ +@@ -63,6 +59,32 @@ int atari_scsi_release (struct Scsi_Host + #define NCR5380_dma_xfer_len(i,cmd,phase) \ + atari_dma_xfer_len(cmd->SCp.this_residual,cmd,((phase) & SR_IO) ? 0 : 1) + ++/* former generic SCSI error handling stuff */ ++ ++#define SCSI_ABORT_SNOOZE 0 ++#define SCSI_ABORT_SUCCESS 1 ++#define SCSI_ABORT_PENDING 2 ++#define SCSI_ABORT_BUSY 3 ++#define SCSI_ABORT_NOT_RUNNING 4 ++#define SCSI_ABORT_ERROR 5 ++ ++#define SCSI_RESET_SNOOZE 0 ++#define SCSI_RESET_PUNT 1 ++#define SCSI_RESET_SUCCESS 2 ++#define SCSI_RESET_PENDING 3 ++#define SCSI_RESET_WAKEUP 4 ++#define SCSI_RESET_NOT_RUNNING 5 ++#define SCSI_RESET_ERROR 6 ++ ++#define SCSI_RESET_SYNCHRONOUS 0x01 ++#define SCSI_RESET_ASYNCHRONOUS 0x02 ++#define SCSI_RESET_SUGGEST_BUS_RESET 0x04 ++#define SCSI_RESET_SUGGEST_HOST_RESET 0x08 ++ ++#define SCSI_RESET_BUS_RESET 0x100 ++#define SCSI_RESET_HOST_RESET 0x200 ++#define SCSI_RESET_ACTION 0xff ++ + /* Debugging printk definitions: + * + * ARB -> arbitration diff --git a/debian/patches/bugfix/m68k/635-atari_input.diff b/debian/patches/bugfix/m68k/635-atari_input.diff new file mode 100644 index 000000000000..2aed8c8c889f --- /dev/null +++ b/debian/patches/bugfix/m68k/635-atari_input.diff @@ -0,0 +1,1162 @@ +Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>, + linux-input@atrey.karlin.mff.cuni.cz +Subject: [PATCH] m68k: Atari keyboard and mouse support. + +From: Michael Schmitz <schmitz@opal.biophys.uni-duesseldorf.de> + +Atari keyboard and mouse support. +(reformating and Kconfig fixes by Roman Zippel) + +Signed-off-by: Michael Schmitz <schmitz@debian.org> +Signed-off-by: Roman Zippel <zippel@linux-m68k.org> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + arch/m68k/Kconfig | 3 + arch/m68k/atari/Makefile | 1 + arch/m68k/atari/atakeyb.c | 730 +++++++++++++++++++++++++++++++++++++++ + drivers/input/keyboard/Kconfig | 11 + drivers/input/keyboard/Makefile | 1 + drivers/input/keyboard/atakbd.c | 134 +++++++ + drivers/input/mouse/Kconfig | 11 + drivers/input/mouse/Makefile | 1 + drivers/input/mouse/atarimouse.c | 160 ++++++++ + include/asm-m68k/atarikb.h | 6 + include/linux/input.h | 1 + 11 files changed, 1059 insertions(+) + +--- linux-m68k-2.6.21.orig/arch/m68k/Kconfig ++++ linux-m68k-2.6.21/arch/m68k/Kconfig +@@ -409,6 +409,9 @@ config STRAM_PROC + help + Say Y here to report ST-RAM usage statistics in /proc/stram. + ++config ATARI_KBD_CORE ++ bool ++ + config HEARTBEAT + bool "Use power LED as a heartbeat" if AMIGA || APOLLO || ATARI || MAC ||Q40 + default y if !AMIGA && !APOLLO && !ATARI && !MAC && !Q40 && HP300 +--- linux-m68k-2.6.21.orig/arch/m68k/atari/Makefile ++++ linux-m68k-2.6.21/arch/m68k/atari/Makefile +@@ -8,3 +8,4 @@ obj-y := config.o time.o debug.o ataint + ifeq ($(CONFIG_PCI),y) + obj-$(CONFIG_HADES) += hades-pci.o + endif ++obj-$(CONFIG_ATARI_KBD_CORE) += atakeyb.o +--- /dev/null ++++ linux-m68k-2.6.21/arch/m68k/atari/atakeyb.c +@@ -0,0 +1,730 @@ ++/* ++ * linux/atari/atakeyb.c ++ * ++ * Atari Keyboard driver for 680x0 Linux ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive ++ * for more details. ++ */ ++ ++/* ++ * Atari support by Robert de Vries ++ * enhanced by Bjoern Brauel and Roman Hodek ++ */ ++ ++#include <linux/sched.h> ++#include <linux/kernel.h> ++#include <linux/interrupt.h> ++#include <linux/errno.h> ++#include <linux/keyboard.h> ++#include <linux/delay.h> ++#include <linux/timer.h> ++#include <linux/kd.h> ++#include <linux/random.h> ++#include <linux/init.h> ++#include <linux/kbd_kern.h> ++ ++#include <asm/atariints.h> ++#include <asm/atarihw.h> ++#include <asm/atarikb.h> ++#include <asm/atari_joystick.h> ++#include <asm/irq.h> ++ ++static void atakeyb_rep(unsigned long ignore); ++extern unsigned int keymap_count; ++ ++/* Hook for MIDI serial driver */ ++void (*atari_MIDI_interrupt_hook) (void); ++/* Hook for mouse driver */ ++void (*atari_mouse_interrupt_hook) (char *); ++/* Hook for keyboard inputdev driver */ ++void (*atari_input_keyboard_interrupt_hook) (unsigned char, char); ++/* Hook for mouse inputdev driver */ ++void (*atari_input_mouse_interrupt_hook) (char *); ++ ++/* variables for IKBD self test: */ ++ ++/* state: 0: off; >0: in progress; >1: 0xf1 received */ ++static volatile int ikbd_self_test; ++/* timestamp when last received a char */ ++static volatile unsigned long self_test_last_rcv; ++/* bitmap of keys reported as broken */ ++static unsigned long broken_keys[128/(sizeof(unsigned long)*8)] = { 0, }; ++ ++#define BREAK_MASK (0x80) ++ ++/* ++ * ++roman: The following changes were applied manually: ++ * ++ * - The Alt (= Meta) key works in combination with Shift and ++ * Control, e.g. Alt+Shift+a sends Meta-A (0xc1), Alt+Control+A sends ++ * Meta-Ctrl-A (0x81) ... ++ * ++ * - The parentheses on the keypad send '(' and ')' with all ++ * modifiers (as would do e.g. keypad '+'), but they cannot be used as ++ * application keys (i.e. sending Esc O c). ++ * ++ * - HELP and UNDO are mapped to be F21 and F24, resp, that send the ++ * codes "\E[M" and "\E[P". (This is better than the old mapping to ++ * F11 and F12, because these codes are on Shift+F1/2 anyway.) This ++ * way, applications that allow their own keyboard mappings ++ * (e.g. tcsh, X Windows) can be configured to use them in the way ++ * the label suggests (providing help or undoing). ++ * ++ * - Console switching is done with Alt+Fx (consoles 1..10) and ++ * Shift+Alt+Fx (consoles 11..20). ++ * ++ * - The misc. special function implemented in the kernel are mapped ++ * to the following key combinations: ++ * ++ * ClrHome -> Home/Find ++ * Shift + ClrHome -> End/Select ++ * Shift + Up -> Page Up ++ * Shift + Down -> Page Down ++ * Alt + Help -> show system status ++ * Shift + Help -> show memory info ++ * Ctrl + Help -> show registers ++ * Ctrl + Alt + Del -> Reboot ++ * Alt + Undo -> switch to last console ++ * Shift + Undo -> send interrupt ++ * Alt + Insert -> stop/start output (same as ^S/^Q) ++ * Alt + Up -> Scroll back console (if implemented) ++ * Alt + Down -> Scroll forward console (if implemented) ++ * Alt + CapsLock -> NumLock ++ * ++ * ++Andreas: ++ * ++ * - Help mapped to K_HELP ++ * - Undo mapped to K_UNDO (= K_F246) ++ * - Keypad Left/Right Parenthesis mapped to new K_PPAREN[LR] ++ */ ++ ++static u_short ataplain_map[NR_KEYS] __initdata = { ++ 0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, ++ 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf009, ++ 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, ++ 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73, ++ 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b, ++ 0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76, ++ 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf200, ++ 0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, ++ 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114, ++ 0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200, ++ 0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200, ++ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, ++ 0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307, ++ 0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303, ++ 0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, ++ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200 ++}; ++ ++typedef enum kb_state_t { ++ KEYBOARD, AMOUSE, RMOUSE, JOYSTICK, CLOCK, RESYNC ++} KB_STATE_T; ++ ++#define IS_SYNC_CODE(sc) ((sc) >= 0x04 && (sc) <= 0xfb) ++ ++typedef struct keyboard_state { ++ unsigned char buf[6]; ++ int len; ++ KB_STATE_T state; ++} KEYBOARD_STATE; ++ ++KEYBOARD_STATE kb_state; ++ ++#define DEFAULT_KEYB_REP_DELAY (HZ/4) ++#define DEFAULT_KEYB_REP_RATE (HZ/25) ++ ++/* These could be settable by some ioctl() in future... */ ++static unsigned int key_repeat_delay = DEFAULT_KEYB_REP_DELAY; ++static unsigned int key_repeat_rate = DEFAULT_KEYB_REP_RATE; ++ ++static unsigned char rep_scancode; ++static struct timer_list atakeyb_rep_timer = { ++ .function = atakeyb_rep, ++}; ++ ++static void atakeyb_rep(unsigned long ignore) ++{ ++ /* Disable keyboard for the time we call handle_scancode(), else a race ++ * in the keyboard tty queue may happen */ ++ atari_disable_irq(IRQ_MFP_ACIA); ++ del_timer(&atakeyb_rep_timer); ++ ++ /* A keyboard int may have come in before we disabled the irq, so ++ * double-check whether rep_scancode is still != 0 */ ++ if (rep_scancode) { ++ init_timer(&atakeyb_rep_timer); ++ atakeyb_rep_timer.expires = jiffies + key_repeat_rate; ++ add_timer(&atakeyb_rep_timer); ++ ++ //handle_scancode(rep_scancode, 1); ++ if (atari_input_keyboard_interrupt_hook) ++ atari_input_keyboard_interrupt_hook(rep_scancode, 1); ++ } ++ ++ atari_enable_irq(IRQ_MFP_ACIA); ++} ++ ++ ++/* ++roman: If a keyboard overrun happened, we can't tell in general how much ++ * bytes have been lost and in which state of the packet structure we are now. ++ * This usually causes keyboards bytes to be interpreted as mouse movements ++ * and vice versa, which is very annoying. It seems better to throw away some ++ * bytes (that are usually mouse bytes) than to misinterpret them. Therefor I ++ * introduced the RESYNC state for IKBD data. In this state, the bytes up to ++ * one that really looks like a key event (0x04..0xf2) or the start of a mouse ++ * packet (0xf8..0xfb) are thrown away, but at most 2 bytes. This at least ++ * speeds up the resynchronization of the event structure, even if maybe a ++ * mouse movement is lost. However, nothing is perfect. For bytes 0x01..0x03, ++ * it's really hard to decide whether they're mouse or keyboard bytes. Since ++ * overruns usually occur when moving the Atari mouse rapidly, they're seen as ++ * mouse bytes here. If this is wrong, only a make code of the keyboard gets ++ * lost, which isn't too bad. Loosing a break code would be disastrous, ++ * because then the keyboard repeat strikes... ++ */ ++ ++static irqreturn_t atari_keyboard_interrupt(int irq, void *dummy) ++{ ++ u_char acia_stat; ++ int scancode; ++ int break_flag; ++ ++repeat: ++ if (acia.mid_ctrl & ACIA_IRQ) ++ if (atari_MIDI_interrupt_hook) ++ atari_MIDI_interrupt_hook(); ++ acia_stat = acia.key_ctrl; ++ /* check out if the interrupt came from this ACIA */ ++ if (!((acia_stat | acia.mid_ctrl) & ACIA_IRQ)) ++ return IRQ_HANDLED; ++ ++ if (acia_stat & ACIA_OVRN) { ++ /* a very fast typist or a slow system, give a warning */ ++ /* ...happens often if interrupts were disabled for too long */ ++ printk(KERN_DEBUG "Keyboard overrun\n"); ++ scancode = acia.key_data; ++ /* Turn off autorepeating in case a break code has been lost */ ++ del_timer(&atakeyb_rep_timer); ++ rep_scancode = 0; ++ if (ikbd_self_test) ++ /* During self test, don't do resyncing, just process the code */ ++ goto interpret_scancode; ++ else if (IS_SYNC_CODE(scancode)) { ++ /* This code seem already to be the start of a new packet or a ++ * single scancode */ ++ kb_state.state = KEYBOARD; ++ goto interpret_scancode; ++ } else { ++ /* Go to RESYNC state and skip this byte */ ++ kb_state.state = RESYNC; ++ kb_state.len = 1; /* skip max. 1 another byte */ ++ goto repeat; ++ } ++ } ++ ++ if (acia_stat & ACIA_RDRF) { ++ /* received a character */ ++ scancode = acia.key_data; /* get it or reset the ACIA, I'll get it! */ ++ tasklet_schedule(&keyboard_tasklet); ++ interpret_scancode: ++ switch (kb_state.state) { ++ case KEYBOARD: ++ switch (scancode) { ++ case 0xF7: ++ kb_state.state = AMOUSE; ++ kb_state.len = 0; ++ break; ++ ++ case 0xF8: ++ case 0xF9: ++ case 0xFA: ++ case 0xFB: ++ kb_state.state = RMOUSE; ++ kb_state.len = 1; ++ kb_state.buf[0] = scancode; ++ break; ++ ++ case 0xFC: ++ kb_state.state = CLOCK; ++ kb_state.len = 0; ++ break; ++ ++ case 0xFE: ++ case 0xFF: ++ kb_state.state = JOYSTICK; ++ kb_state.len = 1; ++ kb_state.buf[0] = scancode; ++ break; ++ ++ case 0xF1: ++ /* during self-test, note that 0xf1 received */ ++ if (ikbd_self_test) { ++ ++ikbd_self_test; ++ self_test_last_rcv = jiffies; ++ break; ++ } ++ /* FALL THROUGH */ ++ ++ default: ++ break_flag = scancode & BREAK_MASK; ++ scancode &= ~BREAK_MASK; ++ if (ikbd_self_test) { ++ /* Scancodes sent during the self-test stand for broken ++ * keys (keys being down). The code *should* be a break ++ * code, but nevertheless some AT keyboard interfaces send ++ * make codes instead. Therefore, simply ignore ++ * break_flag... ++ */ ++ int keyval = plain_map[scancode], keytyp; ++ ++ set_bit(scancode, broken_keys); ++ self_test_last_rcv = jiffies; ++ keyval = plain_map[scancode]; ++ keytyp = KTYP(keyval) - 0xf0; ++ keyval = KVAL(keyval); ++ ++ printk(KERN_WARNING "Key with scancode %d ", scancode); ++ if (keytyp == KT_LATIN || keytyp == KT_LETTER) { ++ if (keyval < ' ') ++ printk("('^%c') ", keyval + '@'); ++ else ++ printk("('%c') ", keyval); ++ } ++ printk("is broken -- will be ignored.\n"); ++ break; ++ } else if (test_bit(scancode, broken_keys)) ++ break; ++ ++#if 0 // FIXME; hangs at boot ++ if (break_flag) { ++ del_timer(&atakeyb_rep_timer); ++ rep_scancode = 0; ++ } else { ++ del_timer(&atakeyb_rep_timer); ++ rep_scancode = scancode; ++ atakeyb_rep_timer.expires = jiffies + key_repeat_delay; ++ add_timer(&atakeyb_rep_timer); ++ } ++#endif ++ ++ // handle_scancode(scancode, !break_flag); ++ if (atari_input_keyboard_interrupt_hook) ++ atari_input_keyboard_interrupt_hook((unsigned char)scancode, !break_flag); ++ break; ++ } ++ break; ++ ++ case AMOUSE: ++ kb_state.buf[kb_state.len++] = scancode; ++ if (kb_state.len == 5) { ++ kb_state.state = KEYBOARD; ++ /* not yet used */ ++ /* wake up someone waiting for this */ ++ } ++ break; ++ ++ case RMOUSE: ++ kb_state.buf[kb_state.len++] = scancode; ++ if (kb_state.len == 3) { ++ kb_state.state = KEYBOARD; ++ if (atari_mouse_interrupt_hook) ++ atari_mouse_interrupt_hook(kb_state.buf); ++ } ++ break; ++ ++ case JOYSTICK: ++ kb_state.buf[1] = scancode; ++ kb_state.state = KEYBOARD; ++#ifdef FIXED_ATARI_JOYSTICK ++ atari_joystick_interrupt(kb_state.buf); ++#endif ++ break; ++ ++ case CLOCK: ++ kb_state.buf[kb_state.len++] = scancode; ++ if (kb_state.len == 6) { ++ kb_state.state = KEYBOARD; ++ /* wake up someone waiting for this. ++ But will this ever be used, as Linux keeps its own time. ++ Perhaps for synchronization purposes? */ ++ /* wake_up_interruptible(&clock_wait); */ ++ } ++ break; ++ ++ case RESYNC: ++ if (kb_state.len <= 0 || IS_SYNC_CODE(scancode)) { ++ kb_state.state = KEYBOARD; ++ goto interpret_scancode; ++ } ++ kb_state.len--; ++ break; ++ } ++ } ++ ++#if 0 ++ if (acia_stat & ACIA_CTS) ++ /* cannot happen */; ++#endif ++ ++ if (acia_stat & (ACIA_FE | ACIA_PE)) { ++ printk("Error in keyboard communication\n"); ++ } ++ ++ /* handle_scancode() can take a lot of time, so check again if ++ * some character arrived ++ */ ++ goto repeat; ++} ++ ++/* ++ * I write to the keyboard without using interrupts, I poll instead. ++ * This takes for the maximum length string allowed (7) at 7812.5 baud ++ * 8 data 1 start 1 stop bit: 9.0 ms ++ * If this takes too long for normal operation, interrupt driven writing ++ * is the solution. (I made a feeble attempt in that direction but I ++ * kept it simple for now.) ++ */ ++void ikbd_write(const char *str, int len) ++{ ++ u_char acia_stat; ++ ++ if ((len < 1) || (len > 7)) ++ panic("ikbd: maximum string length exceeded"); ++ while (len) { ++ acia_stat = acia.key_ctrl; ++ if (acia_stat & ACIA_TDRE) { ++ acia.key_data = *str++; ++ len--; ++ } ++ } ++} ++ ++/* Reset (without touching the clock) */ ++void ikbd_reset(void) ++{ ++ static const char cmd[2] = { 0x80, 0x01 }; ++ ++ ikbd_write(cmd, 2); ++ ++ /* ++ * if all's well code 0xF1 is returned, else the break codes of ++ * all keys making contact ++ */ ++} ++ ++/* Set mouse button action */ ++void ikbd_mouse_button_action(int mode) ++{ ++ char cmd[2] = { 0x07, mode }; ++ ++ ikbd_write(cmd, 2); ++} ++ ++/* Set relative mouse position reporting */ ++void ikbd_mouse_rel_pos(void) ++{ ++ static const char cmd[1] = { 0x08 }; ++ ++ ikbd_write(cmd, 1); ++} ++ ++/* Set absolute mouse position reporting */ ++void ikbd_mouse_abs_pos(int xmax, int ymax) ++{ ++ char cmd[5] = { 0x09, xmax>>8, xmax&0xFF, ymax>>8, ymax&0xFF }; ++ ++ ikbd_write(cmd, 5); ++} ++ ++/* Set mouse keycode mode */ ++void ikbd_mouse_kbd_mode(int dx, int dy) ++{ ++ char cmd[3] = { 0x0A, dx, dy }; ++ ++ ikbd_write(cmd, 3); ++} ++ ++/* Set mouse threshold */ ++void ikbd_mouse_thresh(int x, int y) ++{ ++ char cmd[3] = { 0x0B, x, y }; ++ ++ ikbd_write(cmd, 3); ++} ++ ++/* Set mouse scale */ ++void ikbd_mouse_scale(int x, int y) ++{ ++ char cmd[3] = { 0x0C, x, y }; ++ ++ ikbd_write(cmd, 3); ++} ++ ++/* Interrogate mouse position */ ++void ikbd_mouse_pos_get(int *x, int *y) ++{ ++ static const char cmd[1] = { 0x0D }; ++ ++ ikbd_write(cmd, 1); ++ ++ /* wait for returning bytes */ ++} ++ ++/* Load mouse position */ ++void ikbd_mouse_pos_set(int x, int y) ++{ ++ char cmd[6] = { 0x0E, 0x00, x>>8, x&0xFF, y>>8, y&0xFF }; ++ ++ ikbd_write(cmd, 6); ++} ++ ++/* Set Y=0 at bottom */ ++void ikbd_mouse_y0_bot(void) ++{ ++ static const char cmd[1] = { 0x0F }; ++ ++ ikbd_write(cmd, 1); ++} ++ ++/* Set Y=0 at top */ ++void ikbd_mouse_y0_top(void) ++{ ++ static const char cmd[1] = { 0x10 }; ++ ++ ikbd_write(cmd, 1); ++} ++ ++/* Resume */ ++void ikbd_resume(void) ++{ ++ static const char cmd[1] = { 0x11 }; ++ ++ ikbd_write(cmd, 1); ++} ++ ++/* Disable mouse */ ++void ikbd_mouse_disable(void) ++{ ++ static const char cmd[1] = { 0x12 }; ++ ++ ikbd_write(cmd, 1); ++} ++ ++/* Pause output */ ++void ikbd_pause(void) ++{ ++ static const char cmd[1] = { 0x13 }; ++ ++ ikbd_write(cmd, 1); ++} ++ ++/* Set joystick event reporting */ ++void ikbd_joystick_event_on(void) ++{ ++ static const char cmd[1] = { 0x14 }; ++ ++ ikbd_write(cmd, 1); ++} ++ ++/* Set joystick interrogation mode */ ++void ikbd_joystick_event_off(void) ++{ ++ static const char cmd[1] = { 0x15 }; ++ ++ ikbd_write(cmd, 1); ++} ++ ++/* Joystick interrogation */ ++void ikbd_joystick_get_state(void) ++{ ++ static const char cmd[1] = { 0x16 }; ++ ++ ikbd_write(cmd, 1); ++} ++ ++#if 0 ++/* This disables all other ikbd activities !!!! */ ++/* Set joystick monitoring */ ++void ikbd_joystick_monitor(int rate) ++{ ++ static const char cmd[2] = { 0x17, rate }; ++ ++ ikbd_write(cmd, 2); ++ ++ kb_state.state = JOYSTICK_MONITOR; ++} ++#endif ++ ++/* some joystick routines not in yet (0x18-0x19) */ ++ ++/* Disable joysticks */ ++void ikbd_joystick_disable(void) ++{ ++ static const char cmd[1] = { 0x1A }; ++ ++ ikbd_write(cmd, 1); ++} ++ ++/* Time-of-day clock set */ ++void ikbd_clock_set(int year, int month, int day, int hour, int minute, int second) ++{ ++ char cmd[7] = { 0x1B, year, month, day, hour, minute, second }; ++ ++ ikbd_write(cmd, 7); ++} ++ ++/* Interrogate time-of-day clock */ ++void ikbd_clock_get(int *year, int *month, int *day, int *hour, int *minute, int second) ++{ ++ static const char cmd[1] = { 0x1C }; ++ ++ ikbd_write(cmd, 1); ++} ++ ++/* Memory load */ ++void ikbd_mem_write(int address, int size, char *data) ++{ ++ panic("Attempt to write data into keyboard memory"); ++} ++ ++/* Memory read */ ++void ikbd_mem_read(int address, char data[6]) ++{ ++ char cmd[3] = { 0x21, address>>8, address&0xFF }; ++ ++ ikbd_write(cmd, 3); ++ ++ /* receive data and put it in data */ ++} ++ ++/* Controller execute */ ++void ikbd_exec(int address) ++{ ++ char cmd[3] = { 0x22, address>>8, address&0xFF }; ++ ++ ikbd_write(cmd, 3); ++} ++ ++/* Status inquiries (0x87-0x9A) not yet implemented */ ++ ++/* Set the state of the caps lock led. */ ++void atari_kbd_leds(unsigned int leds) ++{ ++ char cmd[6] = {32, 0, 4, 1, 254 + ((leds & 4) != 0), 0}; ++ ++ ikbd_write(cmd, 6); ++} ++ ++/* ++ * The original code sometimes left the interrupt line of ++ * the ACIAs low forever. I hope, it is fixed now. ++ * ++ * Martin Rogge, 20 Aug 1995 ++ */ ++ ++static int atari_keyb_done = 0; ++ ++int __init atari_keyb_init(void) ++{ ++ if (atari_keyb_done) ++ return 0; ++ ++ /* setup key map */ ++ memcpy(key_maps[0], ataplain_map, sizeof(plain_map)); ++ ++ kb_state.state = KEYBOARD; ++ kb_state.len = 0; ++ ++ request_irq(IRQ_MFP_ACIA, atari_keyboard_interrupt, IRQ_TYPE_SLOW, ++ "keyboard/mouse/MIDI", atari_keyboard_interrupt); ++ ++ atari_turnoff_irq(IRQ_MFP_ACIA); ++ do { ++ /* reset IKBD ACIA */ ++ acia.key_ctrl = ACIA_RESET | ++ (atari_switches & ATARI_SWITCH_IKBD) ? ACIA_RHTID : 0; ++ (void)acia.key_ctrl; ++ (void)acia.key_data; ++ ++ /* reset MIDI ACIA */ ++ acia.mid_ctrl = ACIA_RESET | ++ (atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0; ++ (void)acia.mid_ctrl; ++ (void)acia.mid_data; ++ ++ /* divide 500kHz by 64 gives 7812.5 baud */ ++ /* 8 data no parity 1 start 1 stop bit */ ++ /* receive interrupt enabled */ ++ /* RTS low (except if switch selected), transmit interrupt disabled */ ++ acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RIE) | ++ ((atari_switches & ATARI_SWITCH_IKBD) ? ++ ACIA_RHTID : ACIA_RLTID); ++ ++ acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ++ (atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0; ++ ++ /* make sure the interrupt line is up */ ++ } while ((mfp.par_dt_reg & 0x10) == 0); ++ ++ /* enable ACIA Interrupts */ ++ mfp.active_edge &= ~0x10; ++ atari_turnon_irq(IRQ_MFP_ACIA); ++ ++ ikbd_self_test = 1; ++ ikbd_reset(); ++ /* wait for a period of inactivity (here: 0.25s), then assume the IKBD's ++ * self-test is finished */ ++ self_test_last_rcv = jiffies; ++ while (time_before(jiffies, self_test_last_rcv + HZ/4)) ++ barrier(); ++ /* if not incremented: no 0xf1 received */ ++ if (ikbd_self_test == 1) ++ printk(KERN_ERR "WARNING: keyboard self test failed!\n"); ++ ikbd_self_test = 0; ++ ++ ikbd_mouse_disable(); ++ ikbd_joystick_disable(); ++ ++#ifdef FIXED_ATARI_JOYSTICK ++ atari_joystick_init(); ++#endif ++ ++ // flag init done ++ atari_keyb_done = 1; ++ return 0; ++} ++ ++ ++int atari_kbdrate(struct kbd_repeat *k) ++{ ++ if (k->delay > 0) { ++ /* convert from msec to jiffies */ ++ key_repeat_delay = (k->delay * HZ + 500) / 1000; ++ if (key_repeat_delay < 1) ++ key_repeat_delay = 1; ++ } ++ if (k->period > 0) { ++ key_repeat_rate = (k->period * HZ + 500) / 1000; ++ if (key_repeat_rate < 1) ++ key_repeat_rate = 1; ++ } ++ ++ k->delay = key_repeat_delay * 1000 / HZ; ++ k->period = key_repeat_rate * 1000 / HZ; ++ ++ return 0; ++} ++ ++int atari_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode) ++{ ++#ifdef CONFIG_MAGIC_SYSRQ ++ /* ALT+HELP pressed? */ ++ if ((keycode == 98) && ((shift_state & 0xff) == 8)) ++ *keycodep = 0xff; ++ else ++#endif ++ *keycodep = keycode; ++ return 1; ++} +--- linux-m68k-2.6.21.orig/drivers/input/keyboard/Kconfig ++++ linux-m68k-2.6.21/drivers/input/keyboard/Kconfig +@@ -164,6 +164,17 @@ config KEYBOARD_AMIGA + To compile this driver as a module, choose M here: the + module will be called amikbd. + ++config KEYBOARD_ATARI ++ tristate "Atari keyboard" ++ depends on ATARI ++ select ATARI_KBD_CORE ++ help ++ Say Y here if you are running Linux on any Atari and have a keyboard ++ attached. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called atakbd. ++ + config KEYBOARD_HIL_OLD + tristate "HP HIL keyboard support (simple driver)" + depends on GSC || HP300 +--- linux-m68k-2.6.21.orig/drivers/input/keyboard/Makefile ++++ linux-m68k-2.6.21/drivers/input/keyboard/Makefile +@@ -9,6 +9,7 @@ obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd + obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o + obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o + obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o ++obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o + obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o + obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o + obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o +--- /dev/null ++++ linux-m68k-2.6.21/drivers/input/keyboard/atakbd.c +@@ -0,0 +1,134 @@ ++/* ++ * atakbd.c ++ * ++ * Copyright (c) 2005 Michael Schmitz ++ * ++ * Based on amikbd.c, which is ++ * ++ * Copyright (c) 2000-2001 Vojtech Pavlik ++ * ++ * Based on the work of: ++ * Hamish Macdonald ++ */ ++ ++/* ++ * Atari keyboard driver for Linux/m68k ++ * ++ * The low level init and interrupt stuff is handled in arch/mm68k/atari/atakeyb.c ++ * (the keyboard ACIA also handles the mouse and joystick data, and the keyboard ++ * interrupt is shared with the MIDI ACIA so MIDI data also get handled there). ++ * This driver only deals with handing key events off to the input layer. ++ */ ++ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * Should you need to contact me, the author, you can do so either by ++ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: ++ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic ++ */ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/input.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++ ++#include <asm/atariints.h> ++#include <asm/atarihw.h> ++#include <asm/atarikb.h> ++#include <asm/irq.h> ++ ++MODULE_AUTHOR("Michael Schmitz <schmitz@biophys.uni-duesseldorf.de>"); ++MODULE_DESCRIPTION("Atari keyboard driver"); ++MODULE_LICENSE("GPL"); ++ ++static unsigned char atakbd_keycode[0x72]; ++ ++static struct input_dev *atakbd_dev; ++ ++static void atakbd_interrupt(unsigned char scancode, char down) ++{ ++ ++ if (scancode < 0x72) { /* scancodes < 0xf2 are keys */ ++ ++ // report raw events here? ++ ++ scancode = atakbd_keycode[scancode]; ++ ++ if (scancode == KEY_CAPSLOCK) { /* CapsLock is a toggle switch key on Amiga */ ++ input_report_key(atakbd_dev, scancode, 1); ++ input_report_key(atakbd_dev, scancode, 0); ++ input_sync(atakbd_dev); ++ } else { ++ input_report_key(atakbd_dev, scancode, down); ++ input_sync(atakbd_dev); ++ } ++ } else /* scancodes >= 0xf2 are mouse data, most likely */ ++ printk(KERN_INFO "atakbd: unhandled scancode %x\n", scancode); ++ ++ return; ++} ++ ++static int __init atakbd_init(void) ++{ ++ int i; ++ ++ if (!ATARIHW_PRESENT(ST_MFP)) ++ return -EIO; ++ ++ // TODO: request_mem_region if not done in arch code ++ ++ if (!(atakbd_dev = input_allocate_device())) ++ return -ENOMEM; ++ ++ // need to init core driver if not already done so ++ if (atari_keyb_init()) ++ return -ENODEV; ++ ++ atakbd_dev->name = "Atari Keyboard"; ++ atakbd_dev->phys = "atakbd/input0"; ++ atakbd_dev->id.bustype = BUS_ATARI; ++ atakbd_dev->id.vendor = 0x0001; ++ atakbd_dev->id.product = 0x0001; ++ atakbd_dev->id.version = 0x0100; ++ ++ atakbd_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); ++ atakbd_dev->keycode = atakbd_keycode; ++ atakbd_dev->keycodesize = sizeof(unsigned char); ++ atakbd_dev->keycodemax = ARRAY_SIZE(atakbd_keycode); ++ ++ for (i = 1; i < 0x72; i++) { ++ atakbd_keycode[i] = i; ++ set_bit(atakbd_keycode[i], atakbd_dev->keybit); ++ } ++ ++ input_register_device(atakbd_dev); ++ ++ atari_input_keyboard_interrupt_hook = atakbd_interrupt; ++ ++ printk(KERN_INFO "input: %s at IKBD ACIA\n", atakbd_dev->name); ++ ++ return 0; ++} ++ ++static void __exit atakbd_exit(void) ++{ ++ atari_input_keyboard_interrupt_hook = NULL; ++ input_unregister_device(atakbd_dev); ++} ++ ++module_init(atakbd_init); ++module_exit(atakbd_exit); +--- linux-m68k-2.6.21.orig/drivers/input/mouse/Kconfig ++++ linux-m68k-2.6.21/drivers/input/mouse/Kconfig +@@ -96,6 +96,17 @@ config MOUSE_AMIGA + To compile this driver as a module, choose M here: the + module will be called amimouse. + ++config MOUSE_ATARI ++ tristate "Atari mouse" ++ depends on ATARI ++ select ATARI_KBD_CORE ++ help ++ Say Y here if you have an Atari and want its native mouse ++ supported by the kernel. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called atarimouse. ++ + config MOUSE_RISCPC + tristate "Acorn RiscPC mouse" + depends on ARCH_ACORN +--- linux-m68k-2.6.21.orig/drivers/input/mouse/Makefile ++++ linux-m68k-2.6.21/drivers/input/mouse/Makefile +@@ -5,6 +5,7 @@ + # Each configuration option enables a list of files. + + obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o ++obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o + obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o + obj-$(CONFIG_MOUSE_INPORT) += inport.o + obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o +--- /dev/null ++++ linux-m68k-2.6.21/drivers/input/mouse/atarimouse.c +@@ -0,0 +1,160 @@ ++/* ++ * Atari mouse driver for Linux/m68k ++ * ++ * Copyright (c) 2005 Michael Schmitz ++ * ++ * Based on: ++ * Amiga mouse driver for Linux/m68k ++ * ++ * Copyright (c) 2000-2002 Vojtech Pavlik ++ * ++ */ ++/* ++ * The low level init and interrupt stuff is handled in arch/mm68k/atari/atakeyb.c ++ * (the keyboard ACIA also handles the mouse and joystick data, and the keyboard ++ * interrupt is shared with the MIDI ACIA so MIDI data also get handled there). ++ * This driver only deals with handing key events off to the input layer. ++ * ++ * Largely based on the old: ++ * ++ * Atari Mouse Driver for Linux ++ * by Robert de Vries (robert@and.nl) 19Jul93 ++ * ++ * 16 Nov 1994 Andreas Schwab ++ * Compatibility with busmouse ++ * Support for three button mouse (shamelessly stolen from MiNT) ++ * third button wired to one of the joystick directions on joystick 1 ++ * ++ * 1996/02/11 Andreas Schwab ++ * Module support ++ * Allow multiple open's ++ * ++ * Converted to use new generic busmouse code. 5 Apr 1998 ++ * Russell King <rmk@arm.uk.linux.org> ++ */ ++ ++ ++/* ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published by ++ * the Free Software Foundation ++ */ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/input.h> ++#include <linux/interrupt.h> ++ ++#include <asm/irq.h> ++#include <asm/setup.h> ++#include <asm/system.h> ++#include <asm/uaccess.h> ++#include <asm/atarihw.h> ++#include <asm/atarikb.h> ++#include <asm/atariints.h> ++ ++MODULE_AUTHOR("Michael Schmitz <schmitz@biophys.uni-duesseldorf.de>"); ++MODULE_DESCRIPTION("Atari mouse driver"); ++MODULE_LICENSE("GPL"); ++ ++static int mouse_threshold[2] = {2,2}; ++ ++#ifdef __MODULE__ ++MODULE_PARM(mouse_threshold, "2i"); ++#endif ++#ifdef FIXED_ATARI_JOYSTICK ++extern int atari_mouse_buttons; ++#endif ++static int atamouse_used = 0; ++ ++static struct input_dev *atamouse_dev; ++ ++static void atamouse_interrupt(char *buf) ++{ ++ int buttons, dx, dy; ++ ++/* ikbd_mouse_disable(); */ ++ ++ buttons = (buf[0] & 1) | ((buf[0] & 2) << 1); ++#ifdef FIXED_ATARI_JOYSTICK ++ buttons |= atari_mouse_buttons & 2; ++ atari_mouse_buttons = buttons; ++#endif ++/* ikbd_mouse_rel_pos(); */ ++ ++ /* only relative events get here */ ++ dx = buf[1]; ++ dy = -buf[2]; ++ ++ input_report_rel(atamouse_dev, REL_X, dx); ++ input_report_rel(atamouse_dev, REL_Y, dy); ++ ++ input_report_key(atamouse_dev, BTN_LEFT, buttons & 0x1); ++ input_report_key(atamouse_dev, BTN_MIDDLE, buttons & 0x2); ++ input_report_key(atamouse_dev, BTN_RIGHT, buttons & 0x4); ++ ++ input_sync(atamouse_dev); ++ ++ return; ++} ++ ++static int atamouse_open(struct input_dev *dev) ++{ ++ if (atamouse_used++) ++ return 0; ++ ++#ifdef FIXED_ATARI_JOYSTICK ++ atari_mouse_buttons = 0; ++#endif ++ ikbd_mouse_y0_top(); ++ ikbd_mouse_thresh(mouse_threshold[0], mouse_threshold[1]); ++ ikbd_mouse_rel_pos(); ++ atari_input_mouse_interrupt_hook = atamouse_interrupt; ++ return 0; ++} ++ ++static void atamouse_close(struct input_dev *dev) ++{ ++ if (!--atamouse_used) { ++ ikbd_mouse_disable(); ++ atari_mouse_interrupt_hook = NULL; ++ } ++} ++ ++static int __init atamouse_init(void) ++{ ++ if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP)) ++ return -ENODEV; ++ ++ if (!(atamouse_dev = input_allocate_device())) ++ return -ENOMEM; ++ ++ if (!(atari_keyb_init())) ++ return -ENODEV; ++ ++ atamouse_dev->name = "Atari mouse"; ++ atamouse_dev->phys = "atamouse/input0"; ++ atamouse_dev->id.bustype = BUS_ATARI; ++ atamouse_dev->id.vendor = 0x0001; ++ atamouse_dev->id.product = 0x0002; ++ atamouse_dev->id.version = 0x0100; ++ ++ atamouse_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); ++ atamouse_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); ++ atamouse_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); ++ atamouse_dev->open = atamouse_open; ++ atamouse_dev->close = atamouse_close; ++ ++ input_register_device(atamouse_dev); ++ ++ printk(KERN_INFO "input: %s at keyboard ACIA\n", atamouse_dev->name); ++ return 0; ++} ++ ++static void __exit atamouse_exit(void) ++{ ++ input_unregister_device(atamouse_dev); ++} ++ ++module_init(atamouse_init); ++module_exit(atamouse_exit); +--- linux-m68k-2.6.21.orig/include/asm-m68k/atarikb.h ++++ linux-m68k-2.6.21/include/asm-m68k/atarikb.h +@@ -36,5 +36,11 @@ void ikbd_joystick_disable(void); + extern void (*atari_MIDI_interrupt_hook) (void); + /* Hook for mouse driver */ + extern void (*atari_mouse_interrupt_hook) (char *); ++/* Hook for keyboard inputdev driver */ ++extern void (*atari_input_keyboard_interrupt_hook) (unsigned char, char); ++/* Hook for mouse inputdev driver */ ++extern void (*atari_input_mouse_interrupt_hook) (char *); ++ ++int atari_keyb_init(void); + + #endif /* _LINUX_ATARIKB_H */ +--- linux-m68k-2.6.21.orig/include/linux/input.h ++++ linux-m68k-2.6.21/include/linux/input.h +@@ -676,6 +676,7 @@ struct input_absinfo { + #define BUS_I2C 0x18 + #define BUS_HOST 0x19 + #define BUS_GSC 0x1A ++#define BUS_ATARI 0x1B + + /* + * Values describing the status of a force-feedback effect diff --git a/debian/patches/bugfix/m68k/636-atafb.diff b/debian/patches/bugfix/m68k/636-atafb.diff new file mode 100644 index 000000000000..da79fd9df523 --- /dev/null +++ b/debian/patches/bugfix/m68k/636-atafb.diff @@ -0,0 +1,5530 @@ +Cc: Antonino Daplas <adaplas@gmail.com>, + James Simmons <jsimmons@infradead.org>, + linux-fbdev-devel@lists.sourceforge.net +Subject: [PATCH] m68k: Atari fb revival + +From: Michael Schmitz <schmitz@opal.biophys.uni-duesseldorf.de> + +Update the atari fb to 2.6 by Michael Schmitz, +Reformatting and rewrite of bit plane functions by Roman Zippel, +A few more fixes by Geert Uytterhoeven. + +Signed-off-by: Michael Schmitz <schmitz@debian.org> +Signed-off-by: Roman Zippel <zippel@linux-m68k.org> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + drivers/video/Kconfig | 5 + drivers/video/Makefile | 3 + drivers/video/atafb.c | 2799 +++++++++++++++++++++-------------------- + drivers/video/atafb.h | 36 + drivers/video/atafb_iplan2p2.c | 293 ++++ + drivers/video/atafb_iplan2p4.c | 308 ++++ + drivers/video/atafb_iplan2p8.c | 345 +++++ + drivers/video/atafb_mfb.c | 112 + + drivers/video/atafb_utils.h | 400 +++++ + 9 files changed, 2986 insertions(+), 1315 deletions(-) + +--- linux-m68k-2.6.21.orig/drivers/video/Kconfig ++++ linux-m68k-2.6.21/drivers/video/Kconfig +@@ -389,7 +389,10 @@ config FB_ARC + + config FB_ATARI + bool "Atari native chipset support" +- depends on (FB = y) && ATARI && BROKEN ++ depends on (FB = y) && ATARI ++ select FB_CFB_FILLRECT ++ select FB_CFB_COPYAREA ++ select FB_CFB_IMAGEBLIT + help + This is the frame buffer device driver for the builtin graphics + chipset found in Ataris. +--- linux-m68k-2.6.21.orig/drivers/video/Makefile ++++ linux-m68k-2.6.21/drivers/video/Makefile +@@ -63,7 +63,8 @@ obj-$(CONFIG_FB_TCX) += tcx + obj-$(CONFIG_FB_LEO) += leo.o sbuslib.o + obj-$(CONFIG_FB_SGIVW) += sgivwfb.o + obj-$(CONFIG_FB_ACORN) += acornfb.o +-obj-$(CONFIG_FB_ATARI) += atafb.o ++obj-$(CONFIG_FB_ATARI) += atafb.o c2p.o atafb_mfb.o \ ++ atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o + obj-$(CONFIG_FB_MAC) += macfb.o + obj-$(CONFIG_FB_HGA) += hgafb.o + obj-$(CONFIG_FB_IGA) += igafb.o +--- linux-m68k-2.6.21.orig/drivers/video/atafb.c ++++ linux-m68k-2.6.21/drivers/video/atafb.c +@@ -2,7 +2,7 @@ + * linux/drivers/video/atafb.c -- Atari builtin chipset frame buffer device + * + * Copyright (C) 1994 Martin Schaller & Roman Hodek +- * ++ * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. +@@ -70,14 +70,8 @@ + #include <linux/fb.h> + #include <asm/atarikb.h> + +-#include <video/fbcon.h> +-#include <video/fbcon-cfb8.h> +-#include <video/fbcon-cfb16.h> +-#include <video/fbcon-iplan2p2.h> +-#include <video/fbcon-iplan2p4.h> +-#include <video/fbcon-iplan2p8.h> +-#include <video/fbcon-mfb.h> +- ++#include "c2p.h" ++#include "atafb.h" + + #define SWITCH_ACIA 0x01 /* modes for switch on OverScan */ + #define SWITCH_SND6 0x40 +@@ -87,22 +81,48 @@ + + #define up(x, r) (((x) + (r) - 1) & ~((r)-1)) + ++ /* ++ * Interface to the world ++ */ ++ ++static int atafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info); ++static int atafb_set_par(struct fb_info *info); ++static int atafb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, ++ unsigned int blue, unsigned int transp, ++ struct fb_info *info); ++static int atafb_blank(int blank, struct fb_info *info); ++static int atafb_pan_display(struct fb_var_screeninfo *var, ++ struct fb_info *info); ++static void atafb_fillrect(struct fb_info *info, ++ const struct fb_fillrect *rect); ++static void atafb_copyarea(struct fb_info *info, ++ const struct fb_copyarea *region); ++static void atafb_imageblit(struct fb_info *info, const struct fb_image *image); ++static int atafb_ioctl(struct fb_info *info, unsigned int cmd, ++ unsigned long arg); + +-static int default_par=0; /* default resolution (0=none) */ + +-static unsigned long default_mem_req=0; ++static int default_par; /* default resolution (0=none) */ + +-static int hwscroll=-1; ++static unsigned long default_mem_req; ++ ++static int hwscroll = -1; + + static int use_hwscroll = 1; + +-static int sttt_xres=640,st_yres=400,tt_yres=480; +-static int sttt_xres_virtual=640,sttt_yres_virtual=400; +-static int ovsc_offset=0, ovsc_addlen=0; ++static int sttt_xres = 640, st_yres = 400, tt_yres = 480; ++static int sttt_xres_virtual = 640, sttt_yres_virtual = 400; ++static int ovsc_offset, ovsc_addlen; ++ ++ /* ++ * Hardware parameters for current mode ++ */ + + static struct atafb_par { + void *screen_base; + int yres_virtual; ++ u_long next_line; ++ u_long next_plane; + #if defined ATAFB_TT || defined ATAFB_STE + union { + struct { +@@ -138,7 +158,7 @@ static struct atafb_par { + /* Don't calculate an own resolution, and thus don't change the one found when + * booting (currently used for the Falcon to keep settings for internal video + * hardware extensions (e.g. ScreenBlaster) */ +-static int DontCalcRes = 0; ++static int DontCalcRes = 0; + + #ifdef ATAFB_FALCON + #define HHT hw.falcon.hht +@@ -163,83 +183,84 @@ static int DontCalcRes = 0; + #define VMO_PREMASK 0x0c + #endif + +-static struct fb_info fb_info; ++static struct fb_info fb_info = { ++ .fix = { ++ .id = "Atari ", ++ .visual = FB_VISUAL_PSEUDOCOLOR, ++ .accel = FB_ACCEL_NONE, ++ } ++}; + + static void *screen_base; /* base address of screen */ + static void *real_screen_base; /* (only for Overscan) */ + + static int screen_len; + +-static int current_par_valid=0; +- +-static int mono_moni=0; ++static int current_par_valid; + +-static struct display disp; ++static int mono_moni; + + + #ifdef ATAFB_EXT +-/* external video handling */ + +-static unsigned external_xres; +-static unsigned external_xres_virtual; +-static unsigned external_yres; +-/* not needed - atafb will never support panning/hardwarescroll with external +- * static unsigned external_yres_virtual; +-*/ ++/* external video handling */ ++static unsigned int external_xres; ++static unsigned int external_xres_virtual; ++static unsigned int external_yres; + +-static unsigned external_depth; +-static int external_pmode; +-static void *external_addr = 0; +-static unsigned long external_len; +-static unsigned long external_vgaiobase = 0; +-static unsigned int external_bitspercol = 6; +- +-/* +-JOE <joe@amber.dinoco.de>: +-added card type for external driver, is only needed for +-colormap handling. +-*/ ++/* ++ * not needed - atafb will never support panning/hardwarescroll with external ++ * static unsigned int external_yres_virtual; ++ */ ++static unsigned int external_depth; ++static int external_pmode; ++static void *external_addr; ++static unsigned long external_len; ++static unsigned long external_vgaiobase; ++static unsigned int external_bitspercol = 6; + ++/* ++ * JOE <joe@amber.dinoco.de>: ++ * added card type for external driver, is only needed for ++ * colormap handling. ++ */ + enum cardtype { IS_VGA, IS_MV300 }; + static enum cardtype external_card_type = IS_VGA; + + /* +-The MV300 mixes the color registers. So we need an array of munged +-indices in order to access the correct reg. +-*/ +-static int MV300_reg_1bit[2]={0,1}; +-static int MV300_reg_4bit[16]={ +-0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 }; +-static int MV300_reg_8bit[256]={ +-0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, +-8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, +-4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, +-12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, +-2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, +-10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, +-6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, +-14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, +-1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, +-9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, +-5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, +-13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, +-3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, +-11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, +-7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, +-15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255 }; ++ * The MV300 mixes the color registers. So we need an array of munged ++ * indices in order to access the correct reg. ++ */ ++static int MV300_reg_1bit[2] = { ++ 0, 1 ++}; ++static int MV300_reg_4bit[16] = { ++ 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 ++}; ++static int MV300_reg_8bit[256] = { ++ 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, ++ 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, ++ 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, ++ 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, ++ 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, ++ 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, ++ 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, ++ 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, ++ 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, ++ 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, ++ 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, ++ 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, ++ 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, ++ 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, ++ 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, ++ 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255 ++}; + + static int *MV300_reg = MV300_reg_8bit; +- +-/* +-And on the MV300 it's difficult to read out the hardware palette. So we +-just keep track of the set colors in our own array here, and use that! +-*/ +- +-static struct { unsigned char red,green,blue,pad; } ext_color[256]; + #endif /* ATAFB_EXT */ + + +-static int inverse=0; ++static int inverse; + + extern int fontheight_8x8; + extern int fontwidth_8x8; +@@ -249,96 +270,154 @@ extern int fontheight_8x16; + extern int fontwidth_8x16; + extern unsigned char fontdata_8x16[]; + ++/* ++ * struct fb_ops { ++ * * open/release and usage marking ++ * struct module *owner; ++ * int (*fb_open)(struct fb_info *info, int user); ++ * int (*fb_release)(struct fb_info *info, int user); ++ * ++ * * For framebuffers with strange non linear layouts or that do not ++ * * work with normal memory mapped access ++ * ssize_t (*fb_read)(struct file *file, char __user *buf, size_t count, loff_t *ppos); ++ * ssize_t (*fb_write)(struct file *file, const char __user *buf, size_t count, loff_t *ppos); ++ * ++ * * checks var and eventually tweaks it to something supported, ++ * * DOES NOT MODIFY PAR * ++ * int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info); ++ * ++ * * set the video mode according to info->var * ++ * int (*fb_set_par)(struct fb_info *info); ++ * ++ * * set color register * ++ * int (*fb_setcolreg)(unsigned int regno, unsigned int red, unsigned int green, ++ * unsigned int blue, unsigned int transp, struct fb_info *info); ++ * ++ * * set color registers in batch * ++ * int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info); ++ * ++ * * blank display * ++ * int (*fb_blank)(int blank, struct fb_info *info); ++ * ++ * * pan display * ++ * int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info); ++ * ++ * *** The meat of the drawing engine *** ++ * * Draws a rectangle * ++ * void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect); ++ * * Copy data from area to another * ++ * void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region); ++ * * Draws a image to the display * ++ * void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image); ++ * ++ * * Draws cursor * ++ * int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor); ++ * ++ * * Rotates the display * ++ * void (*fb_rotate)(struct fb_info *info, int angle); ++ * ++ * * wait for blit idle, optional * ++ * int (*fb_sync)(struct fb_info *info); ++ * ++ * * perform fb specific ioctl (optional) * ++ * int (*fb_ioctl)(struct fb_info *info, unsigned int cmd, ++ * unsigned long arg); ++ * ++ * * Handle 32bit compat ioctl (optional) * ++ * int (*fb_compat_ioctl)(struct fb_info *info, unsigned int cmd, ++ * unsigned long arg); ++ * ++ * * perform fb specific mmap * ++ * int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma); ++ * ++ * * save current hardware state * ++ * void (*fb_save_state)(struct fb_info *info); ++ * ++ * * restore saved state * ++ * void (*fb_restore_state)(struct fb_info *info); ++ * } ; ++ */ ++ ++ + /* ++roman: This structure abstracts from the underlying hardware (ST(e), + * TT, or Falcon. + * +- * int (*detect)( void ) ++ * int (*detect)(void) + * This function should detect the current video mode settings and + * store them in atafb_predefined[0] for later reference by the + * user. Return the index+1 of an equivalent predefined mode or 0 + * if there is no such. +- * +- * int (*encode_fix)( struct fb_fix_screeninfo *fix, +- * struct atafb_par *par ) ++ * ++ * int (*encode_fix)(struct fb_fix_screeninfo *fix, ++ * struct atafb_par *par) + * This function should fill in the 'fix' structure based on the + * values in the 'par' structure. +- * +- * int (*decode_var)( struct fb_var_screeninfo *var, +- * struct atafb_par *par ) ++ * !!! Obsolete, perhaps !!! ++ * ++ * int (*decode_var)(struct fb_var_screeninfo *var, ++ * struct atafb_par *par) + * Get the video params out of 'var'. If a value doesn't fit, round + * it up, if it's too big, return EINVAL. +- * Round up in the following order: bits_per_pixel, xres, yres, +- * xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields, ++ * Round up in the following order: bits_per_pixel, xres, yres, ++ * xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields, + * horizontal timing, vertical timing. + * +- * int (*encode_var)( struct fb_var_screeninfo *var, +- * struct atafb_par *par ); ++ * int (*encode_var)(struct fb_var_screeninfo *var, ++ * struct atafb_par *par); + * Fill the 'var' structure based on the values in 'par' and maybe + * other values read out of the hardware. +- * +- * void (*get_par)( struct atafb_par *par ) ++ * ++ * void (*get_par)(struct atafb_par *par) + * Fill the hardware's 'par' structure. +- * +- * void (*set_par)( struct atafb_par *par ) ++ * !!! Used only by detect() !!! ++ * ++ * void (*set_par)(struct atafb_par *par) + * Set the hardware according to 'par'. +- * +- * int (*getcolreg)( unsigned regno, unsigned *red, +- * unsigned *green, unsigned *blue, +- * unsigned *transp, struct fb_info *info ) +- * Read a single color register and split it into +- * colors/transparent. Return != 0 for invalid regno. + * + * void (*set_screen_base)(void *s_base) + * Set the base address of the displayed frame buffer. Only called + * if yres_virtual > yres or xres_virtual > xres. + * +- * int (*blank)( int blank_mode ) +- * Blank the screen if blank_mode!=0, else unblank. If blank==NULL then ++ * int (*blank)(int blank_mode) ++ * Blank the screen if blank_mode != 0, else unblank. If blank == NULL then + * the caller blanks by setting the CLUT to all black. Return 0 if blanking + * succeeded, !=0 if un-/blanking failed due to e.g. a video mode which + * doesn't support it. Implements VESA suspend and powerdown modes on + * hardware that supports disabling hsync/vsync: +- * blank_mode==2: suspend vsync, 3:suspend hsync, 4: powerdown. ++ * blank_mode == 2: suspend vsync, 3:suspend hsync, 4: powerdown. + */ + + static struct fb_hwswitch { +- int (*detect)( void ); +- int (*encode_fix)( struct fb_fix_screeninfo *fix, +- struct atafb_par *par ); +- int (*decode_var)( struct fb_var_screeninfo *var, +- struct atafb_par *par ); +- int (*encode_var)( struct fb_var_screeninfo *var, +- struct atafb_par *par ); +- void (*get_par)( struct atafb_par *par ); +- void (*set_par)( struct atafb_par *par ); +- int (*getcolreg)( unsigned regno, unsigned *red, +- unsigned *green, unsigned *blue, +- unsigned *transp, struct fb_info *info ); ++ int (*detect)(void); ++ int (*encode_fix)(struct fb_fix_screeninfo *fix, ++ struct atafb_par *par); ++ int (*decode_var)(struct fb_var_screeninfo *var, ++ struct atafb_par *par); ++ int (*encode_var)(struct fb_var_screeninfo *var, ++ struct atafb_par *par); ++ void (*get_par)(struct atafb_par *par); ++ void (*set_par)(struct atafb_par *par); + void (*set_screen_base)(void *s_base); +- int (*blank)( int blank_mode ); +- int (*pan_display)( struct fb_var_screeninfo *var, +- struct atafb_par *par); ++ int (*blank)(int blank_mode); ++ int (*pan_display)(struct fb_var_screeninfo *var, ++ struct fb_info *info); + } *fbhw; + +-static char *autodetect_names[] = {"autodetect", NULL}; +-static char *stlow_names[] = {"stlow", NULL}; +-static char *stmid_names[] = {"stmid", "default5", NULL}; +-static char *sthigh_names[] = {"sthigh", "default4", NULL}; +-static char *ttlow_names[] = {"ttlow", NULL}; +-static char *ttmid_names[]= {"ttmid", "default1", NULL}; +-static char *tthigh_names[]= {"tthigh", "default2", NULL}; +-static char *vga2_names[] = {"vga2", NULL}; +-static char *vga4_names[] = {"vga4", NULL}; +-static char *vga16_names[] = {"vga16", "default3", NULL}; +-static char *vga256_names[] = {"vga256", NULL}; +-static char *falh2_names[] = {"falh2", NULL}; +-static char *falh16_names[] = {"falh16", NULL}; ++static char *autodetect_names[] = { "autodetect", NULL }; ++static char *stlow_names[] = { "stlow", NULL }; ++static char *stmid_names[] = { "stmid", "default5", NULL }; ++static char *sthigh_names[] = { "sthigh", "default4", NULL }; ++static char *ttlow_names[] = { "ttlow", NULL }; ++static char *ttmid_names[] = { "ttmid", "default1", NULL }; ++static char *tthigh_names[] = { "tthigh", "default2", NULL }; ++static char *vga2_names[] = { "vga2", NULL }; ++static char *vga4_names[] = { "vga4", NULL }; ++static char *vga16_names[] = { "vga16", "default3", NULL }; ++static char *vga256_names[] = { "vga256", NULL }; ++static char *falh2_names[] = { "falh2", NULL }; ++static char *falh16_names[] = { "falh16", NULL }; + + static char **fb_var_names[] = { +- /* Writing the name arrays directly in this array (via "(char *[]){...}") +- * crashes gcc 2.5.8 (sigsegv) if the inner array +- * contains more than two items. I've also seen that all elements +- * were identical to the last (my cross-gcc) :-(*/ + autodetect_names, + stlow_names, + stmid_names, +@@ -353,18 +432,17 @@ static char **fb_var_names[] = { + falh2_names, + falh16_names, + NULL +- /* ,NULL */ /* this causes a sigsegv on my gcc-2.5.8 */ + }; + + static struct fb_var_screeninfo atafb_predefined[] = { +- /* +- * yres_virtual==0 means use hw-scrolling if possible, else yres +- */ +- { /* autodetect */ +- 0, 0, 0, 0, 0, 0, 0, 0, /* xres-grayscale */ +- {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, /* red green blue tran*/ ++ /* ++ * yres_virtual == 0 means use hw-scrolling if possible, else yres ++ */ ++ { /* autodetect */ ++ 0, 0, 0, 0, 0, 0, 0, 0, /* xres-grayscale */ ++ {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, /* red green blue tran*/ + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, +- { /* st low */ ++ { /* st low */ + 320, 200, 320, 0, 0, 0, 4, 0, + {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, +@@ -414,27 +492,100 @@ static struct fb_var_screeninfo atafb_pr + 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, + }; + +-static int num_atafb_predefined=ARRAY_SIZE(atafb_predefined); ++static int num_atafb_predefined = ARRAY_SIZE(atafb_predefined); + ++static struct fb_videomode atafb_modedb[] __initdata = { ++ /* ++ * Atari Video Modes ++ * ++ * If you change these, make sure to update DEFMODE_* as well! ++ */ + +-static int +-get_video_mode(char *vname) ++ /* ++ * ST/TT Video Modes ++ */ ++ ++ { ++ /* 320x200, 15 kHz, 60 Hz (ST low) */ ++ "st-low", 60, 320, 200, 32000, 32, 16, 31, 14, 96, 4, ++ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP ++ }, { ++ /* 640x200, 15 kHz, 60 Hz (ST medium) */ ++ "st-mid", 60, 640, 200, 32000, 32, 16, 31, 14, 96, 4, ++ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP ++ }, { ++ /* 640x400, 30.25 kHz, 63.5 Hz (ST high) */ ++ "st-high", 63, 640, 400, 32000, 128, 0, 40, 14, 128, 4, ++ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP ++ }, { ++ /* 320x480, 15 kHz, 60 Hz (TT low) */ ++ "tt-low", 60, 320, 480, 31041, 120, 100, 8, 16, 140, 30, ++ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP ++ }, { ++ /* 640x480, 29 kHz, 57 Hz (TT medium) */ ++ "tt-mid", 60, 640, 480, 31041, 120, 100, 8, 16, 140, 30, ++ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP ++ }, { ++ /* 1280x960, 29 kHz, 60 Hz (TT high) */ ++ "tt-high", 57, 640, 960, 31041, 120, 100, 8, 16, 140, 30, ++ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP ++ }, ++ ++ /* ++ * VGA Video Modes ++ */ ++ ++ { ++ /* 640x480, 31 kHz, 60 Hz (VGA) */ ++ "vga", 63.5, 640, 480, 32000, 18, 42, 31, 11, 96, 3, ++ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP ++ }, { ++ /* 640x400, 31 kHz, 70 Hz (VGA) */ ++ "vga70", 70, 640, 400, 32000, 18, 42, 31, 11, 96, 3, ++ FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP ++ }, ++ ++ /* ++ * Falcon HiRes Video Modes ++ */ ++ ++ { ++ /* 896x608, 31 kHz, 60 Hz (Falcon High) */ ++ "falh", 60, 896, 608, 32000, 18, 42, 31, 1, 96,3, ++ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP ++ }, ++}; ++ ++#define NUM_TOTAL_MODES ARRAY_SIZE(atafb_modedb) ++ ++static char *mode_option __initdata = NULL; ++ ++ /* default modes */ ++ ++#define DEFMODE_TT 5 /* "tt-high" for TT */ ++#define DEFMODE_F30 7 /* "vga70" for Falcon */ ++#define DEFMODE_STE 2 /* "st-high" for ST/E */ ++#define DEFMODE_EXT 6 /* "vga" for external */ ++ ++ ++static int get_video_mode(char *vname) + { +- char ***name_list; +- char **name; +- int i; +- name_list=fb_var_names; +- for (i = 0 ; i < num_atafb_predefined ; i++) { +- name=*(name_list++); +- if (! name || ! *name) +- break; +- while (*name) { +- if (! strcmp(vname, *name)) +- return i+1; +- name++; ++ char ***name_list; ++ char **name; ++ int i; ++ ++ name_list = fb_var_names; ++ for (i = 0; i < num_atafb_predefined; i++) { ++ name = *name_list++; ++ if (!name || !*name) ++ break; ++ while (*name) { ++ if (!strcmp(vname, *name)) ++ return i + 1; ++ name++; ++ } + } +- } +- return 0; ++ return 0; + } + + +@@ -443,93 +594,84 @@ get_video_mode(char *vname) + + #ifdef ATAFB_TT + +-static int tt_encode_fix( struct fb_fix_screeninfo *fix, +- struct atafb_par *par ) +- ++static int tt_encode_fix(struct fb_fix_screeninfo *fix, struct atafb_par *par) + { + int mode; + +- strcpy(fix->id,"Atari Builtin"); ++ strcpy(fix->id, "Atari Builtin"); + fix->smem_start = (unsigned long)real_screen_base; + fix->smem_len = screen_len; +- fix->type=FB_TYPE_INTERLEAVED_PLANES; +- fix->type_aux=2; +- fix->visual=FB_VISUAL_PSEUDOCOLOR; ++ fix->type = FB_TYPE_INTERLEAVED_PLANES; ++ fix->type_aux = 2; ++ fix->visual = FB_VISUAL_PSEUDOCOLOR; + mode = par->hw.tt.mode & TT_SHIFTER_MODEMASK; + if (mode == TT_SHIFTER_TTHIGH || mode == TT_SHIFTER_STHIGH) { +- fix->type=FB_TYPE_PACKED_PIXELS; +- fix->type_aux=0; ++ fix->type = FB_TYPE_PACKED_PIXELS; ++ fix->type_aux = 0; + if (mode == TT_SHIFTER_TTHIGH) +- fix->visual=FB_VISUAL_MONO01; ++ fix->visual = FB_VISUAL_MONO01; + } +- fix->xpanstep=0; +- fix->ypanstep=1; +- fix->ywrapstep=0; ++ fix->xpanstep = 0; ++ fix->ypanstep = 1; ++ fix->ywrapstep = 0; + fix->line_length = 0; + fix->accel = FB_ACCEL_ATARIBLITT; + return 0; + } + +- +-static int tt_decode_var( struct fb_var_screeninfo *var, +- struct atafb_par *par ) ++static int tt_decode_var(struct fb_var_screeninfo *var, struct atafb_par *par) + { +- int xres=var->xres; +- int yres=var->yres; +- int bpp=var->bits_per_pixel; ++ int xres = var->xres; ++ int yres = var->yres; ++ int bpp = var->bits_per_pixel; + int linelen; + int yres_virtual = var->yres_virtual; + + if (mono_moni) { +- if (bpp > 1 || xres > sttt_xres*2 || yres >tt_yres*2) ++ if (bpp > 1 || xres > sttt_xres * 2 || yres > tt_yres * 2) + return -EINVAL; +- par->hw.tt.mode=TT_SHIFTER_TTHIGH; +- xres=sttt_xres*2; +- yres=tt_yres*2; +- bpp=1; ++ par->hw.tt.mode = TT_SHIFTER_TTHIGH; ++ xres = sttt_xres * 2; ++ yres = tt_yres * 2; ++ bpp = 1; + } else { + if (bpp > 8 || xres > sttt_xres || yres > tt_yres) + return -EINVAL; + if (bpp > 4) { +- if (xres > sttt_xres/2 || yres > tt_yres) ++ if (xres > sttt_xres / 2 || yres > tt_yres) + return -EINVAL; +- par->hw.tt.mode=TT_SHIFTER_TTLOW; +- xres=sttt_xres/2; +- yres=tt_yres; +- bpp=8; +- } +- else if (bpp > 2) { ++ par->hw.tt.mode = TT_SHIFTER_TTLOW; ++ xres = sttt_xres / 2; ++ yres = tt_yres; ++ bpp = 8; ++ } else if (bpp > 2) { + if (xres > sttt_xres || yres > tt_yres) + return -EINVAL; +- if (xres > sttt_xres/2 || yres > st_yres/2) { +- par->hw.tt.mode=TT_SHIFTER_TTMID; +- xres=sttt_xres; +- yres=tt_yres; +- bpp=4; ++ if (xres > sttt_xres / 2 || yres > st_yres / 2) { ++ par->hw.tt.mode = TT_SHIFTER_TTMID; ++ xres = sttt_xres; ++ yres = tt_yres; ++ bpp = 4; ++ } else { ++ par->hw.tt.mode = TT_SHIFTER_STLOW; ++ xres = sttt_xres / 2; ++ yres = st_yres / 2; ++ bpp = 4; + } +- else { +- par->hw.tt.mode=TT_SHIFTER_STLOW; +- xres=sttt_xres/2; +- yres=st_yres/2; +- bpp=4; +- } +- } +- else if (bpp > 1) { +- if (xres > sttt_xres || yres > st_yres/2) ++ } else if (bpp > 1) { ++ if (xres > sttt_xres || yres > st_yres / 2) + return -EINVAL; +- par->hw.tt.mode=TT_SHIFTER_STMID; +- xres=sttt_xres; +- yres=st_yres/2; +- bpp=2; +- } +- else if (var->xres > sttt_xres || var->yres > st_yres) { ++ par->hw.tt.mode = TT_SHIFTER_STMID; ++ xres = sttt_xres; ++ yres = st_yres / 2; ++ bpp = 2; ++ } else if (var->xres > sttt_xres || var->yres > st_yres) { + return -EINVAL; +- } +- else { +- par->hw.tt.mode=TT_SHIFTER_STHIGH; +- xres=sttt_xres; +- yres=st_yres; +- bpp=1; ++ } else { ++ par->hw.tt.mode = TT_SHIFTER_STHIGH; ++ xres = sttt_xres; ++ yres = st_yres; ++ bpp = 1; + } + } + if (yres_virtual <= 0) +@@ -537,10 +679,10 @@ static int tt_decode_var( struct fb_var_ + else if (yres_virtual < yres) + yres_virtual = yres; + if (var->sync & FB_SYNC_EXT) +- par->hw.tt.sync=0; ++ par->hw.tt.sync = 0; + else +- par->hw.tt.sync=1; +- linelen=xres*bpp/8; ++ par->hw.tt.sync = 1; ++ linelen = xres * bpp / 8; + if (yres_virtual * linelen > screen_len && screen_len) + return -EINVAL; + if (yres * linelen > screen_len && screen_len) +@@ -552,154 +694,123 @@ static int tt_decode_var( struct fb_var_ + return 0; + } + +-static int tt_encode_var( struct fb_var_screeninfo *var, +- struct atafb_par *par ) ++static int tt_encode_var(struct fb_var_screeninfo *var, struct atafb_par *par) + { + int linelen; + memset(var, 0, sizeof(struct fb_var_screeninfo)); +- var->red.offset=0; +- var->red.length=4; +- var->red.msb_right=0; +- var->grayscale=0; +- +- var->pixclock=31041; +- var->left_margin=120; /* these may be incorrect */ +- var->right_margin=100; +- var->upper_margin=8; +- var->lower_margin=16; +- var->hsync_len=140; +- var->vsync_len=30; ++ var->red.offset = 0; ++ var->red.length = 4; ++ var->red.msb_right = 0; ++ var->grayscale = 0; ++ ++ var->pixclock = 31041; ++ var->left_margin = 120; /* these may be incorrect */ ++ var->right_margin = 100; ++ var->upper_margin = 8; ++ var->lower_margin = 16; ++ var->hsync_len = 140; ++ var->vsync_len = 30; + +- var->height=-1; +- var->width=-1; ++ var->height = -1; ++ var->width = -1; + + if (par->hw.tt.sync & 1) +- var->sync=0; ++ var->sync = 0; + else +- var->sync=FB_SYNC_EXT; ++ var->sync = FB_SYNC_EXT; + + switch (par->hw.tt.mode & TT_SHIFTER_MODEMASK) { + case TT_SHIFTER_STLOW: +- var->xres=sttt_xres/2; +- var->xres_virtual=sttt_xres_virtual/2; +- var->yres=st_yres/2; +- var->bits_per_pixel=4; ++ var->xres = sttt_xres / 2; ++ var->xres_virtual = sttt_xres_virtual / 2; ++ var->yres = st_yres / 2; ++ var->bits_per_pixel = 4; + break; + case TT_SHIFTER_STMID: +- var->xres=sttt_xres; +- var->xres_virtual=sttt_xres_virtual; +- var->yres=st_yres/2; +- var->bits_per_pixel=2; ++ var->xres = sttt_xres; ++ var->xres_virtual = sttt_xres_virtual; ++ var->yres = st_yres / 2; ++ var->bits_per_pixel = 2; + break; + case TT_SHIFTER_STHIGH: +- var->xres=sttt_xres; +- var->xres_virtual=sttt_xres_virtual; +- var->yres=st_yres; +- var->bits_per_pixel=1; ++ var->xres = sttt_xres; ++ var->xres_virtual = sttt_xres_virtual; ++ var->yres = st_yres; ++ var->bits_per_pixel = 1; + break; + case TT_SHIFTER_TTLOW: +- var->xres=sttt_xres/2; +- var->xres_virtual=sttt_xres_virtual/2; +- var->yres=tt_yres; +- var->bits_per_pixel=8; ++ var->xres = sttt_xres / 2; ++ var->xres_virtual = sttt_xres_virtual / 2; ++ var->yres = tt_yres; ++ var->bits_per_pixel = 8; + break; + case TT_SHIFTER_TTMID: +- var->xres=sttt_xres; +- var->xres_virtual=sttt_xres_virtual; +- var->yres=tt_yres; +- var->bits_per_pixel=4; ++ var->xres = sttt_xres; ++ var->xres_virtual = sttt_xres_virtual; ++ var->yres = tt_yres; ++ var->bits_per_pixel = 4; + break; + case TT_SHIFTER_TTHIGH: +- var->red.length=0; +- var->xres=sttt_xres*2; +- var->xres_virtual=sttt_xres_virtual*2; +- var->yres=tt_yres*2; +- var->bits_per_pixel=1; ++ var->red.length = 0; ++ var->xres = sttt_xres * 2; ++ var->xres_virtual = sttt_xres_virtual * 2; ++ var->yres = tt_yres * 2; ++ var->bits_per_pixel = 1; + break; +- } +- var->blue=var->green=var->red; +- var->transp.offset=0; +- var->transp.length=0; +- var->transp.msb_right=0; +- linelen=var->xres_virtual * var->bits_per_pixel / 8; +- if (! use_hwscroll) +- var->yres_virtual=var->yres; ++ } ++ var->blue = var->green = var->red; ++ var->transp.offset = 0; ++ var->transp.length = 0; ++ var->transp.msb_right = 0; ++ linelen = var->xres_virtual * var->bits_per_pixel / 8; ++ if (!use_hwscroll) ++ var->yres_virtual = var->yres; + else if (screen_len) { + if (par->yres_virtual) + var->yres_virtual = par->yres_virtual; + else +- /* yres_virtual==0 means use maximum */ ++ /* yres_virtual == 0 means use maximum */ + var->yres_virtual = screen_len / linelen; + } else { + if (hwscroll < 0) + var->yres_virtual = 2 * var->yres; + else +- var->yres_virtual=var->yres+hwscroll * 16; ++ var->yres_virtual = var->yres + hwscroll * 16; + } +- var->xoffset=0; ++ var->xoffset = 0; + if (screen_base) +- var->yoffset=(par->screen_base - screen_base)/linelen; ++ var->yoffset = (par->screen_base - screen_base) / linelen; + else +- var->yoffset=0; +- var->nonstd=0; +- var->activate=0; +- var->vmode=FB_VMODE_NONINTERLACED; ++ var->yoffset = 0; ++ var->nonstd = 0; ++ var->activate = 0; ++ var->vmode = FB_VMODE_NONINTERLACED; + return 0; + } + +- +-static void tt_get_par( struct atafb_par *par ) ++static void tt_get_par(struct atafb_par *par) + { + unsigned long addr; +- par->hw.tt.mode=shifter_tt.tt_shiftmode; +- par->hw.tt.sync=shifter.syncmode; ++ par->hw.tt.mode = shifter_tt.tt_shiftmode; ++ par->hw.tt.sync = shifter.syncmode; + addr = ((shifter.bas_hi & 0xff) << 16) | + ((shifter.bas_md & 0xff) << 8) | + ((shifter.bas_lo & 0xff)); + par->screen_base = phys_to_virt(addr); + } + +-static void tt_set_par( struct atafb_par *par ) ++static void tt_set_par(struct atafb_par *par) + { +- shifter_tt.tt_shiftmode=par->hw.tt.mode; +- shifter.syncmode=par->hw.tt.sync; ++ shifter_tt.tt_shiftmode = par->hw.tt.mode; ++ shifter.syncmode = par->hw.tt.sync; + /* only set screen_base if really necessary */ + if (current_par.screen_base != par->screen_base) + fbhw->set_screen_base(par->screen_base); + } + +- +-static int tt_getcolreg(unsigned regno, unsigned *red, +- unsigned *green, unsigned *blue, +- unsigned *transp, struct fb_info *info) +-{ +- int t, col; +- +- if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH) +- regno += 254; +- if (regno > 255) +- return 1; +- t = tt_palette[regno]; +- col = t & 15; +- col |= col << 4; +- col |= col << 8; +- *blue = col; +- col = (t >> 4) & 15; +- col |= col << 4; +- col |= col << 8; +- *green = col; +- col = (t >> 8) & 15; +- col |= col << 4; +- col |= col << 8; +- *red = col; +- *transp = 0; +- return 0; +-} +- +- +-static int tt_setcolreg(unsigned regno, unsigned red, +- unsigned green, unsigned blue, +- unsigned transp, struct fb_info *info) ++static int tt_setcolreg(unsigned int regno, unsigned int red, ++ unsigned int green, unsigned int blue, ++ unsigned int transp, struct fb_info *info) + { + if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH) + regno += 254; +@@ -708,15 +819,14 @@ static int tt_setcolreg(unsigned regno, + tt_palette[regno] = (((red >> 12) << 8) | ((green >> 12) << 4) | + (blue >> 12)); + if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == +- TT_SHIFTER_STHIGH && regno == 254) ++ TT_SHIFTER_STHIGH && regno == 254) + tt_palette[0] = 0; + return 0; + } + +- +-static int tt_detect( void ) +- +-{ struct atafb_par par; ++static int tt_detect(void) ++{ ++ struct atafb_par par; + + /* Determine the connected monitor: The DMA sound must be + * disabled before reading the MFP GPIP, because the Sound +@@ -726,9 +836,9 @@ static int tt_detect( void ) + * announced that the Eagle is TT compatible, but only the PCM is + * missing... + */ +- if (ATARIHW_PRESENT(PCM_8BIT)) { ++ if (ATARIHW_PRESENT(PCM_8BIT)) { + tt_dmasnd.ctrl = DMASND_CTRL_OFF; +- udelay(20); /* wait a while for things to settle down */ ++ udelay(20); /* wait a while for things to settle down */ + } + mono_moni = (mfp.par_dt_reg & 0x80) == 0; + +@@ -755,19 +865,24 @@ static struct pixel_clock { + unsigned long f; /* f/[Hz] */ + unsigned long t; /* t/[ps] (=1/f) */ + int right, hsync, left; /* standard timing in clock cycles, not pixel */ +- /* hsync initialized in falcon_detect() */ ++ /* hsync initialized in falcon_detect() */ + int sync_mask; /* or-mask for hw.falcon.sync to set this clock */ + int control_mask; /* ditto, for hw.falcon.vid_control */ +-} +-f25 = {25175000, 39721, 18, 0, 42, 0x0, VCO_CLOCK25}, +-f32 = {32000000, 31250, 18, 0, 42, 0x0, 0}, +-fext = { 0, 0, 18, 0, 42, 0x1, 0}; ++} f25 = { ++ 25175000, 39721, 18, 0, 42, 0x0, VCO_CLOCK25 ++}, f32 = { ++ 32000000, 31250, 18, 0, 42, 0x0, 0 ++}, fext = { ++ 0, 0, 18, 0, 42, 0x1, 0 ++}; + + /* VIDEL-prescale values [mon_type][pixel_length from VCO] */ +-static int vdl_prescale[4][3] = {{4,2,1}, {4,2,1}, {4,2,2}, {4,2,1}}; ++static int vdl_prescale[4][3] = { ++ { 4,2,1 }, { 4,2,1 }, { 4,2,2 }, { 4,2,1 } ++}; + + /* Default hsync timing [mon_type] in picoseconds */ +-static long h_syncs[4] = {3000000, 4875000, 4000000, 4875000}; ++static long h_syncs[4] = { 3000000, 4875000, 4000000, 4875000 }; + + #ifdef FBCON_HAS_CFB16 + static u16 fbcon_cfb16_cmap[16]; +@@ -775,12 +890,12 @@ static u16 fbcon_cfb16_cmap[16]; + + static inline int hxx_prescale(struct falcon_hw *hw) + { +- return hw->ste_mode ? 16 : +- vdl_prescale[mon_type][hw->vid_mode >> 2 & 0x3]; ++ return hw->ste_mode ? 16 ++ : vdl_prescale[mon_type][hw->vid_mode >> 2 & 0x3]; + } + +-static int falcon_encode_fix( struct fb_fix_screeninfo *fix, +- struct atafb_par *par ) ++static int falcon_encode_fix(struct fb_fix_screeninfo *fix, ++ struct atafb_par *par) + { + strcpy(fix->id, "Atari Builtin"); + fix->smem_start = (unsigned long)real_screen_base; +@@ -796,8 +911,7 @@ static int falcon_encode_fix( struct fb_ + fix->type_aux = 0; + /* no smooth scrolling with longword aligned video mem */ + fix->xpanstep = 32; +- } +- else if (par->hw.falcon.f_shift & 0x100) { ++ } else if (par->hw.falcon.f_shift & 0x100) { + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; + /* Is this ok or should it be DIRECTCOLOR? */ +@@ -809,9 +923,8 @@ static int falcon_encode_fix( struct fb_ + return 0; + } + +- +-static int falcon_decode_var( struct fb_var_screeninfo *var, +- struct atafb_par *par ) ++static int falcon_decode_var(struct fb_var_screeninfo *var, ++ struct atafb_par *par) + { + int bpp = var->bits_per_pixel; + int xres = var->xres; +@@ -823,17 +936,19 @@ static int falcon_decode_var( struct fb_ + int linelen; + int interlace = 0, doubleline = 0; + struct pixel_clock *pclock; +- int plen; /* width of pixel in clock cycles */ ++ int plen; /* width of pixel in clock cycles */ + int xstretch; + int prescale; + int longoffset = 0; + int hfreq, vfreq; ++ int hdb_off, hde_off, base_off; ++ int gstart, gend1, gend2, align; + + /* + Get the video params out of 'var'. If a value doesn't fit, round + it up, if it's too big, return EINVAL. +- Round up in the following order: bits_per_pixel, xres, yres, +- xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields, ++ Round up in the following order: bits_per_pixel, xres, yres, ++ xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields, + horizontal timing, vertical timing. + + There is a maximum of screen resolution determined by pixelclock +@@ -843,11 +958,11 @@ static int falcon_decode_var( struct fb_ + Frequency range for multisync monitors is given via command line. + For TV and SM124 both frequencies are fixed. + +- X % 16 == 0 to fit 8x?? font (except 1 bitplane modes must use X%32==0) ++ X % 16 == 0 to fit 8x?? font (except 1 bitplane modes must use X%32 == 0) + Y % 16 == 0 to fit 8x16 font + Y % 8 == 0 if Y<400 + +- Currently interlace and doubleline mode in var are ignored. ++ Currently interlace and doubleline mode in var are ignored. + On SM124 and TV only the standard resolutions can be used. + */ + +@@ -855,43 +970,38 @@ static int falcon_decode_var( struct fb_ + if (!xres || !yres || !bpp) + return -EINVAL; + +- if (mon_type == F_MON_SM && bpp != 1) { ++ if (mon_type == F_MON_SM && bpp != 1) + return -EINVAL; +- } +- else if (bpp <= 1) { ++ ++ if (bpp <= 1) { + bpp = 1; + par->hw.falcon.f_shift = 0x400; + par->hw.falcon.st_shift = 0x200; +- } +- else if (bpp <= 2) { ++ } else if (bpp <= 2) { + bpp = 2; + par->hw.falcon.f_shift = 0x000; + par->hw.falcon.st_shift = 0x100; +- } +- else if (bpp <= 4) { ++ } else if (bpp <= 4) { + bpp = 4; + par->hw.falcon.f_shift = 0x000; + par->hw.falcon.st_shift = 0x000; +- } +- else if (bpp <= 8) { ++ } else if (bpp <= 8) { + bpp = 8; + par->hw.falcon.f_shift = 0x010; +- } +- else if (bpp <= 16) { +- bpp = 16; /* packed pixel mode */ +- par->hw.falcon.f_shift = 0x100; /* hicolor, no overlay */ +- } +- else ++ } else if (bpp <= 16) { ++ bpp = 16; /* packed pixel mode */ ++ par->hw.falcon.f_shift = 0x100; /* hicolor, no overlay */ ++ } else + return -EINVAL; + par->hw.falcon.bpp = bpp; + + if (mon_type == F_MON_SM || DontCalcRes) { + /* Skip all calculations. VGA/TV/SC1224 only supported. */ + struct fb_var_screeninfo *myvar = &atafb_predefined[0]; +- ++ + if (bpp > myvar->bits_per_pixel || +- var->xres > myvar->xres || +- var->yres > myvar->yres) ++ var->xres > myvar->xres || ++ var->yres > myvar->yres) + return -EINVAL; + fbhw->get_par(par); /* Current par will be new par */ + goto set_screen_base; /* Don't forget this */ +@@ -910,8 +1020,8 @@ static int falcon_decode_var( struct fb_ + yres = 400; + + /* 2 planes must use STE compatibility mode */ +- par->hw.falcon.ste_mode = bpp==2; +- par->hw.falcon.mono = bpp==1; ++ par->hw.falcon.ste_mode = bpp == 2; ++ par->hw.falcon.mono = bpp == 1; + + /* Total and visible scanline length must be a multiple of one longword, + * this and the console fontwidth yields the alignment for xres and +@@ -967,8 +1077,7 @@ static int falcon_decode_var( struct fb_ + left_margin = hsync_len = 128 / plen; + right_margin = 0; + /* TODO set all margins */ +- } +- else ++ } else + #endif + if (mon_type == F_MON_SC || mon_type == F_MON_TV) { + plen = 2 * xstretch; +@@ -1002,26 +1111,24 @@ static int falcon_decode_var( struct fb_ + vsync_len *= 2; + } + } +- } +- else +- { /* F_MON_VGA */ ++ } else { /* F_MON_VGA */ + if (bpp == 16) +- xstretch = 2; /* Double pixel width only for hicolor */ ++ xstretch = 2; /* Double pixel width only for hicolor */ + /* Default values are used for vert./hor. timing if no pixelclock given. */ + if (var->pixclock == 0) { + int linesize; + + /* Choose master pixelclock depending on hor. timing */ + plen = 1 * xstretch; +- if ((plen * xres + f25.right+f25.hsync+f25.left) * ++ if ((plen * xres + f25.right + f25.hsync + f25.left) * + fb_info.monspecs.hfmin < f25.f) + pclock = &f25; +- else if ((plen * xres + f32.right+f32.hsync+f32.left) * +- fb_info.monspecs.hfmin < f32.f) ++ else if ((plen * xres + f32.right + f32.hsync + ++ f32.left) * fb_info.monspecs.hfmin < f32.f) + pclock = &f32; +- else if ((plen * xres + fext.right+fext.hsync+fext.left) * +- fb_info.monspecs.hfmin < fext.f +- && fext.f) ++ else if ((plen * xres + fext.right + fext.hsync + ++ fext.left) * fb_info.monspecs.hfmin < fext.f && ++ fext.f) + pclock = &fext; + else + return -EINVAL; +@@ -1033,22 +1140,24 @@ static int falcon_decode_var( struct fb_ + upper_margin = 31; + lower_margin = 11; + vsync_len = 3; +- } +- else { ++ } else { + /* Choose largest pixelclock <= wanted clock */ + int i; + unsigned long pcl = ULONG_MAX; + pclock = 0; +- for (i=1; i <= 4; i *= 2) { +- if (f25.t*i >= var->pixclock && f25.t*i < pcl) { ++ for (i = 1; i <= 4; i *= 2) { ++ if (f25.t * i >= var->pixclock && ++ f25.t * i < pcl) { + pcl = f25.t * i; + pclock = &f25; + } +- if (f32.t*i >= var->pixclock && f32.t*i < pcl) { ++ if (f32.t * i >= var->pixclock && ++ f32.t * i < pcl) { + pcl = f32.t * i; + pclock = &f32; + } +- if (fext.t && fext.t*i >= var->pixclock && fext.t*i < pcl) { ++ if (fext.t && fext.t * i >= var->pixclock && ++ fext.t * i < pcl) { + pcl = fext.t * i; + pclock = &fext; + } +@@ -1070,8 +1179,7 @@ static int falcon_decode_var( struct fb_ + upper_margin = (upper_margin + 1) / 2; + lower_margin = (lower_margin + 1) / 2; + vsync_len = (vsync_len + 1) / 2; +- } +- else if (var->vmode & FB_VMODE_DOUBLE) { ++ } else if (var->vmode & FB_VMODE_DOUBLE) { + /* External unit is [double lines per frame] */ + upper_margin *= 2; + lower_margin *= 2; +@@ -1079,7 +1187,7 @@ static int falcon_decode_var( struct fb_ + } + } + if (pclock == &fext) +- longoffset = 1; /* VIDEL doesn't synchronize on short offset */ ++ longoffset = 1; /* VIDEL doesn't synchronize on short offset */ + } + /* Is video bus bandwidth (32MB/s) too low for this resolution? */ + /* this is definitely wrong if bus clock != 32MHz */ +@@ -1098,7 +1206,7 @@ static int falcon_decode_var( struct fb_ + * between interlace and non-interlace without messing around + * with these. + */ +- again: ++again: + /* Set base_offset 128 and video bus width */ + par->hw.falcon.vid_control = mon_type | f030_bus_width; + if (!longoffset) +@@ -1112,37 +1220,34 @@ static int falcon_decode_var( struct fb_ + /* External or internal clock */ + par->hw.falcon.sync = pclock->sync_mask | 0x2; + /* Pixellength and prescale */ +- par->hw.falcon.vid_mode = (2/plen) << 2; ++ par->hw.falcon.vid_mode = (2 / plen) << 2; + if (doubleline) + par->hw.falcon.vid_mode |= VMO_DOUBLE; + if (interlace) + par->hw.falcon.vid_mode |= VMO_INTER; + + /********************* +- Horizontal timing: unit = [master clock cycles] +- unit of hxx-registers: [master clock cycles * prescale] +- Hxx-registers are 9 bit wide +- +- 1 line = ((hht + 2) * 2 * prescale) clock cycles +- +- graphic output = hdb & 0x200 ? +- ((hht+2)*2 - hdb + hde) * prescale - hdboff + hdeoff: +- ( hht + 2 - hdb + hde) * prescale - hdboff + hdeoff +- (this must be a multiple of plen*128/bpp, on VGA pixels +- to the right may be cut off with a bigger right margin) +- +- start of graphics relative to start of 1st halfline = hdb & 0x200 ? +- (hdb - hht - 2) * prescale + hdboff : +- hdb * prescale + hdboff +- +- end of graphics relative to start of 1st halfline = +- (hde + hht + 2) * prescale + hdeoff +- *********************/ ++ * Horizontal timing: unit = [master clock cycles] ++ * unit of hxx-registers: [master clock cycles * prescale] ++ * Hxx-registers are 9 bit wide ++ * ++ * 1 line = ((hht + 2) * 2 * prescale) clock cycles ++ * ++ * graphic output = hdb & 0x200 ? ++ * ((hht + 2) * 2 - hdb + hde) * prescale - hdboff + hdeoff: ++ * (hht + 2 - hdb + hde) * prescale - hdboff + hdeoff ++ * (this must be a multiple of plen*128/bpp, on VGA pixels ++ * to the right may be cut off with a bigger right margin) ++ * ++ * start of graphics relative to start of 1st halfline = hdb & 0x200 ? ++ * (hdb - hht - 2) * prescale + hdboff : ++ * hdb * prescale + hdboff ++ * ++ * end of graphics relative to start of 1st halfline = ++ * (hde + hht + 2) * prescale + hdeoff ++ *********************/ + /* Calculate VIDEL registers */ +- { +- int hdb_off, hde_off, base_off; +- int gstart, gend1, gend2, align; +- ++{ + prescale = hxx_prescale(&par->hw.falcon); + base_off = par->hw.falcon.vid_control & VCO_SHORTOFFS ? 64 : 128; + +@@ -1154,8 +1259,7 @@ static int falcon_decode_var( struct fb_ + align = 1; + hde_off = 0; + hdb_off = (base_off + 16 * plen) + prescale; +- } +- else { ++ } else { + align = 128 / bpp; + hde_off = ((128 / bpp + 2) * plen); + if (par->hw.falcon.ste_mode) +@@ -1164,23 +1268,24 @@ static int falcon_decode_var( struct fb_ + hdb_off = (base_off + (128 / bpp + 18) * plen) + prescale; + } + +- gstart = (prescale/2 + plen * left_margin) / prescale; ++ gstart = (prescale / 2 + plen * left_margin) / prescale; + /* gend1 is for hde (gend-gstart multiple of align), shifter's xres */ +- gend1 = gstart + ((xres + align-1) / align)*align * plen / prescale; ++ gend1 = gstart + ((xres + align - 1) / align) * align * plen / prescale; + /* gend2 is for hbb, visible xres (rest to gend1 is cut off by hblank) */ + gend2 = gstart + xres * plen / prescale; + par->HHT = plen * (left_margin + xres + right_margin) / + (2 * prescale) - 2; + /* par->HHT = (gend2 + plen * right_margin / prescale) / 2 - 2;*/ + +- par->HDB = gstart - hdb_off/prescale; ++ par->HDB = gstart - hdb_off / prescale; + par->HBE = gstart; +- if (par->HDB < 0) par->HDB += par->HHT + 2 + 0x200; +- par->HDE = gend1 - par->HHT - 2 - hde_off/prescale; ++ if (par->HDB < 0) ++ par->HDB += par->HHT + 2 + 0x200; ++ par->HDE = gend1 - par->HHT - 2 - hde_off / prescale; + par->HBB = gend2 - par->HHT - 2; + #if 0 + /* One more Videl constraint: data fetch of two lines must not overlap */ +- if ((par->HDB & 0x200) && (par->HDB & ~0x200) - par->HDE <= 5) { ++ if ((par->HDB & 0x200) && (par->HDB & ~0x200) - par->HDE <= 5) { + /* if this happens increase margins, decrease hfreq. */ + } + #endif +@@ -1189,11 +1294,11 @@ static int falcon_decode_var( struct fb_ + par->HSS = par->HHT + 2 - plen * hsync_len / prescale; + if (par->HSS < par->HBB) + par->HSS = par->HBB; +- } ++} + + /* check hor. frequency */ +- hfreq = pclock->f / ((par->HHT+2)*prescale*2); +- if (hfreq > fb_info.monspecs.hfmax && mon_type!=F_MON_VGA) { ++ hfreq = pclock->f / ((par->HHT + 2) * prescale * 2); ++ if (hfreq > fb_info.monspecs.hfmax && mon_type != F_MON_VGA) { + /* ++guenther: ^^^^^^^^^^^^^^^^^^^ can't remember why I did this */ + /* Too high -> enlarge margin */ + left_margin += 1; +@@ -1213,12 +1318,14 @@ static int falcon_decode_var( struct fb_ + par->VBE = (upper_margin * 2 + 1); /* must begin on odd halfline */ + par->VDB = par->VBE; + par->VDE = yres; +- if (!interlace) par->VDE <<= 1; +- if (doubleline) par->VDE <<= 1; /* VDE now half lines per (half-)frame */ ++ if (!interlace) ++ par->VDE <<= 1; ++ if (doubleline) ++ par->VDE <<= 1; /* VDE now half lines per (half-)frame */ + par->VDE += par->VDB; + par->VBB = par->VDE; + par->VFT = par->VBB + (lower_margin * 2 - 1) - 1; +- par->VSS = par->VFT+1 - (vsync_len * 2 - 1); ++ par->VSS = par->VFT + 1 - (vsync_len * 2 - 1); + /* vbb,vss,vft must be even in interlace mode */ + if (interlace) { + par->VBB++; +@@ -1229,55 +1336,53 @@ static int falcon_decode_var( struct fb_ + /* V-frequency check, hope I didn't create any loop here. */ + /* Interlace and doubleline are mutually exclusive. */ + vfreq = (hfreq * 2) / (par->VFT + 1); +- if (vfreq > fb_info.monspecs.vfmax && !doubleline && !interlace) { ++ if (vfreq > fb_info.monspecs.vfmax && !doubleline && !interlace) { + /* Too high -> try again with doubleline */ + doubleline = 1; + goto again; +- } +- else if (vfreq < fb_info.monspecs.vfmin && !interlace && !doubleline) { ++ } else if (vfreq < fb_info.monspecs.vfmin && !interlace && !doubleline) { + /* Too low -> try again with interlace */ + interlace = 1; + goto again; +- } +- else if (vfreq < fb_info.monspecs.vfmin && doubleline) { ++ } else if (vfreq < fb_info.monspecs.vfmin && doubleline) { + /* Doubleline too low -> clear doubleline and enlarge margins */ + int lines; + doubleline = 0; +- for (lines=0; +- (hfreq*2)/(par->VFT+1+4*lines-2*yres)>fb_info.monspecs.vfmax; ++ for (lines = 0; ++ (hfreq * 2) / (par->VFT + 1 + 4 * lines - 2 * yres) > ++ fb_info.monspecs.vfmax; + lines++) + ; + upper_margin += lines; + lower_margin += lines; + goto again; +- } +- else if (vfreq > fb_info.monspecs.vfmax && doubleline) { ++ } else if (vfreq > fb_info.monspecs.vfmax && doubleline) { + /* Doubleline too high -> enlarge margins */ + int lines; +- for (lines=0; +- (hfreq*2)/(par->VFT+1+4*lines)>fb_info.monspecs.vfmax; +- lines+=2) ++ for (lines = 0; ++ (hfreq * 2) / (par->VFT + 1 + 4 * lines) > ++ fb_info.monspecs.vfmax; ++ lines += 2) + ; + upper_margin += lines; + lower_margin += lines; + goto again; +- } +- else if (vfreq > fb_info.monspecs.vfmax && interlace) { ++ } else if (vfreq > fb_info.monspecs.vfmax && interlace) { + /* Interlace, too high -> enlarge margins */ + int lines; +- for (lines=0; +- (hfreq*2)/(par->VFT+1+4*lines)>fb_info.monspecs.vfmax; ++ for (lines = 0; ++ (hfreq * 2) / (par->VFT + 1 + 4 * lines) > ++ fb_info.monspecs.vfmax; + lines++) + ; + upper_margin += lines; + lower_margin += lines; + goto again; +- } +- else if (vfreq < fb_info.monspecs.vfmin || +- vfreq > fb_info.monspecs.vfmax) ++ } else if (vfreq < fb_info.monspecs.vfmin || ++ vfreq > fb_info.monspecs.vfmax) + return -EINVAL; + +- set_screen_base: ++set_screen_base: + linelen = xres_virtual * bpp / 8; + if (yres_virtual * linelen > screen_len && screen_len) + return -EINVAL; +@@ -1289,11 +1394,20 @@ static int falcon_decode_var( struct fb_ + par->screen_base = screen_base + var->yoffset * linelen; + par->hw.falcon.xoffset = 0; + ++ // FIXME!!! sort of works, no crash ++ //par->next_line = linelen; ++ //par->next_plane = yres_virtual * linelen; ++ par->next_line = linelen; ++ par->next_plane = 2; ++ // crashes ++ //par->next_plane = linelen; ++ //par->next_line = yres_virtual * linelen; ++ + return 0; + } + +-static int falcon_encode_var( struct fb_var_screeninfo *var, +- struct atafb_par *par ) ++static int falcon_encode_var(struct fb_var_screeninfo *var, ++ struct atafb_par *par) + { + /* !!! only for VGA !!! */ + int linelen; +@@ -1306,10 +1420,10 @@ static int falcon_encode_var( struct fb_ + var->pixclock = hw->sync & 0x1 ? fext.t : + hw->vid_control & VCO_CLOCK25 ? f25.t : f32.t; + +- var->height=-1; +- var->width=-1; ++ var->height = -1; ++ var->width = -1; + +- var->sync=0; ++ var->sync = 0; + if (hw->vid_control & VCO_HSYPOS) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (hw->vid_control & VCO_VSYPOS) +@@ -1320,7 +1434,7 @@ static int falcon_encode_var( struct fb_ + var->vmode |= FB_VMODE_INTERLACED; + if (hw->vid_mode & VMO_DOUBLE) + var->vmode |= FB_VMODE_DOUBLE; +- ++ + /* visible y resolution: + * Graphics display starts at line VDB and ends at line + * VDE. If interlace mode off unit of VC-registers is +@@ -1332,14 +1446,15 @@ static int falcon_encode_var( struct fb_ + if (var->vmode & FB_VMODE_DOUBLE) + var->yres >>= 1; + +- /* to get bpp, we must examine f_shift and st_shift. ++ /* ++ * to get bpp, we must examine f_shift and st_shift. + * f_shift is valid if any of bits no. 10, 8 or 4 + * is set. Priority in f_shift is: 10 ">" 8 ">" 4, i.e. + * if bit 10 set then bit 8 and bit 4 don't care... + * If all these bits are 0 get display depth from st_shift + * (as for ST and STE) + */ +- if (hw->f_shift & 0x400) /* 2 colors */ ++ if (hw->f_shift & 0x400) /* 2 colors */ + var->bits_per_pixel = 1; + else if (hw->f_shift & 0x100) /* hicolor */ + var->bits_per_pixel = 16; +@@ -1349,7 +1464,7 @@ static int falcon_encode_var( struct fb_ + var->bits_per_pixel = 4; + else if (hw->st_shift == 0x100) + var->bits_per_pixel = 2; +- else /* if (hw->st_shift == 0x200) */ ++ else /* if (hw->st_shift == 0x200) */ + var->bits_per_pixel = 1; + + var->xres = hw->line_width * 16 / var->bits_per_pixel; +@@ -1358,42 +1473,42 @@ static int falcon_encode_var( struct fb_ + var->xres_virtual += 16; + + if (var->bits_per_pixel == 16) { +- var->red.offset=11; +- var->red.length=5; +- var->red.msb_right=0; +- var->green.offset=5; +- var->green.length=6; +- var->green.msb_right=0; +- var->blue.offset=0; +- var->blue.length=5; +- var->blue.msb_right=0; +- } +- else { +- var->red.offset=0; ++ var->red.offset = 11; ++ var->red.length = 5; ++ var->red.msb_right = 0; ++ var->green.offset = 5; ++ var->green.length = 6; ++ var->green.msb_right = 0; ++ var->blue.offset = 0; ++ var->blue.length = 5; ++ var->blue.msb_right = 0; ++ } else { ++ var->red.offset = 0; + var->red.length = hw->ste_mode ? 4 : 6; +- var->red.msb_right=0; +- var->grayscale=0; +- var->blue=var->green=var->red; +- } +- var->transp.offset=0; +- var->transp.length=0; +- var->transp.msb_right=0; ++ if (var->red.length > var->bits_per_pixel) ++ var->red.length = var->bits_per_pixel; ++ var->red.msb_right = 0; ++ var->grayscale = 0; ++ var->blue = var->green = var->red; ++ } ++ var->transp.offset = 0; ++ var->transp.length = 0; ++ var->transp.msb_right = 0; + + linelen = var->xres_virtual * var->bits_per_pixel / 8; + if (screen_len) { + if (par->yres_virtual) + var->yres_virtual = par->yres_virtual; + else +- /* yres_virtual==0 means use maximum */ ++ /* yres_virtual == 0 means use maximum */ + var->yres_virtual = screen_len / linelen; +- } +- else { ++ } else { + if (hwscroll < 0) + var->yres_virtual = 2 * var->yres; + else +- var->yres_virtual=var->yres+hwscroll * 16; ++ var->yres_virtual = var->yres + hwscroll * 16; + } +- var->xoffset=0; /* TODO change this */ ++ var->xoffset = 0; /* TODO change this */ + + /* hdX-offsets */ + prescale = hxx_prescale(hw); +@@ -1402,8 +1517,7 @@ static int falcon_encode_var( struct fb_ + if (hw->f_shift & 0x100) { + hde_off = 0; + hdb_off = (base_off + 16 * plen) + prescale; +- } +- else { ++ } else { + hde_off = ((128 / var->bits_per_pixel + 2) * plen); + if (hw->ste_mode) + hdb_off = (64 + base_off + (128 / var->bits_per_pixel + 2) * plen) +@@ -1415,8 +1529,8 @@ static int falcon_encode_var( struct fb_ + + /* Right margin includes hsync */ + var->left_margin = hdb_off + prescale * ((hw->hdb & 0x1ff) - +- (hw->hdb & 0x200 ? 2+hw->hht : 0)); +- if (hw->ste_mode || mon_type!=F_MON_VGA) ++ (hw->hdb & 0x200 ? 2 + hw->hht : 0)); ++ if (hw->ste_mode || mon_type != F_MON_VGA) + var->right_margin = prescale * (hw->hht + 2 - hw->hde) - hde_off; + else + /* can't use this in ste_mode, because hbb is +1 off */ +@@ -1424,15 +1538,14 @@ static int falcon_encode_var( struct fb_ + var->hsync_len = prescale * (hw->hht + 2 - hw->hss); + + /* Lower margin includes vsync */ +- var->upper_margin = hw->vdb / 2 ; /* round down to full lines */ +- var->lower_margin = (hw->vft+1 - hw->vde + 1) / 2; /* round up */ +- var->vsync_len = (hw->vft+1 - hw->vss + 1) / 2; /* round up */ ++ var->upper_margin = hw->vdb / 2; /* round down to full lines */ ++ var->lower_margin = (hw->vft + 1 - hw->vde + 1) / 2; /* round up */ ++ var->vsync_len = (hw->vft + 1 - hw->vss + 1) / 2; /* round up */ + if (var->vmode & FB_VMODE_INTERLACED) { + var->upper_margin *= 2; + var->lower_margin *= 2; + var->vsync_len *= 2; +- } +- else if (var->vmode & FB_VMODE_DOUBLE) { ++ } else if (var->vmode & FB_VMODE_DOUBLE) { + var->upper_margin = (var->upper_margin + 1) / 2; + var->lower_margin = (var->lower_margin + 1) / 2; + var->vsync_len = (var->vsync_len + 1) / 2; +@@ -1447,20 +1560,19 @@ static int falcon_encode_var( struct fb_ + var->lower_margin -= var->vsync_len; + + if (screen_base) +- var->yoffset=(par->screen_base - screen_base)/linelen; ++ var->yoffset = (par->screen_base - screen_base) / linelen; + else +- var->yoffset=0; +- var->nonstd=0; /* what is this for? */ +- var->activate=0; ++ var->yoffset = 0; ++ var->nonstd = 0; /* what is this for? */ ++ var->activate = 0; + return 0; + } + +- +-static int f_change_mode = 0; ++static int f_change_mode; + static struct falcon_hw f_new_mode; +-static int f_pan_display = 0; ++static int f_pan_display; + +-static void falcon_get_par( struct atafb_par *par ) ++static void falcon_get_par(struct atafb_par *par) + { + unsigned long addr; + struct falcon_hw *hw = &par->hw.falcon; +@@ -1492,12 +1604,12 @@ static void falcon_get_par( struct atafb + par->screen_base = phys_to_virt(addr); + + /* derived parameters */ +- hw->ste_mode = (hw->f_shift & 0x510)==0 && hw->st_shift==0x100; ++ hw->ste_mode = (hw->f_shift & 0x510) == 0 && hw->st_shift == 0x100; + hw->mono = (hw->f_shift & 0x400) || +- ((hw->f_shift & 0x510)==0 && hw->st_shift==0x200); ++ ((hw->f_shift & 0x510) == 0 && hw->st_shift == 0x200); + } + +-static void falcon_set_par( struct atafb_par *par ) ++static void falcon_set_par(struct atafb_par *par) + { + f_change_mode = 0; + +@@ -1519,8 +1631,7 @@ static void falcon_set_par( struct atafb + f_change_mode = 1; + } + +- +-static irqreturn_t falcon_vbl_switcher( int irq, void *dummy ) ++static irqreturn_t falcon_vbl_switcher(int irq, void *dummy) + { + struct falcon_hw *hw = &f_new_mode; + +@@ -1529,11 +1640,10 @@ static irqreturn_t falcon_vbl_switcher( + + if (hw->sync & 0x1) { + /* Enable external pixelclock. This code only for ScreenWonder */ +- *(volatile unsigned short*)0xffff9202 = 0xffbf; +- } +- else { ++ *(volatile unsigned short *)0xffff9202 = 0xffbf; ++ } else { + /* Turn off external clocks. Read sets all output bits to 1. */ +- *(volatile unsigned short*)0xffff9202; ++ *(volatile unsigned short *)0xffff9202; + } + shifter.syncmode = hw->sync; + +@@ -1550,15 +1660,14 @@ static irqreturn_t falcon_vbl_switcher( + videl.vde = hw->vde; + videl.vss = hw->vss; + +- videl.f_shift = 0; /* write enables Falcon palette, 0: 4 planes */ ++ videl.f_shift = 0; /* write enables Falcon palette, 0: 4 planes */ + if (hw->ste_mode) { +- videl.st_shift = hw->st_shift; /* write enables STE palette */ +- } +- else { ++ videl.st_shift = hw->st_shift; /* write enables STE palette */ ++ } else { + /* IMPORTANT: +- * set st_shift 0, so we can tell the screen-depth if f_shift==0. ++ * set st_shift 0, so we can tell the screen-depth if f_shift == 0. + * Writing 0 to f_shift enables 4 plane Falcon mode but +- * doesn't set st_shift. st_shift!=0 (!=4planes) is impossible ++ * doesn't set st_shift. st_shift != 0 (!= 4planes) is impossible + * with Falcon palette. + */ + videl.st_shift = 0; +@@ -1580,12 +1689,13 @@ static irqreturn_t falcon_vbl_switcher( + return IRQ_HANDLED; + } + +- +-static int falcon_pan_display( struct fb_var_screeninfo *var, +- struct atafb_par *par ) ++static int falcon_pan_display(struct fb_var_screeninfo *var, ++ struct fb_info *info) + { ++ struct atafb_par *par = (struct atafb_par *)info->par; ++ + int xoffset; +- int bpp = fb_display[fb_info.currcon].var.bits_per_pixel; ++ int bpp = info->var.bits_per_pixel; + + if (bpp == 1) + var->xoffset = up(var->xoffset, 32); +@@ -1596,45 +1706,24 @@ static int falcon_pan_display( struct fb + var->xoffset = up(var->xoffset, 2); + } + par->hw.falcon.line_offset = bpp * +- (fb_display[fb_info.currcon].var.xres_virtual - fb_display[fb_info.currcon].var.xres) / 16; ++ (info->var.xres_virtual - info->var.xres) / 16; + if (par->hw.falcon.xoffset) + par->hw.falcon.line_offset -= bpp; + xoffset = var->xoffset - par->hw.falcon.xoffset; + + par->screen_base = screen_base + +- (var->yoffset * fb_display[fb_info.currcon].var.xres_virtual + xoffset) * bpp / 8; ++ (var->yoffset * info->var.xres_virtual + xoffset) * bpp / 8; + if (fbhw->set_screen_base) +- fbhw->set_screen_base (par->screen_base); ++ fbhw->set_screen_base(par->screen_base); + else +- return -EINVAL; /* shouldn't happen */ ++ return -EINVAL; /* shouldn't happen */ + f_pan_display = 1; + return 0; + } + +- +-static int falcon_getcolreg( unsigned regno, unsigned *red, +- unsigned *green, unsigned *blue, +- unsigned *transp, struct fb_info *info ) +-{ unsigned long col; +- +- if (regno > 255) +- return 1; +- /* This works in STE-mode (with 4bit/color) since f030_col-registers +- * hold up to 6bit/color. +- * Even with hicolor r/g/b=5/6/5 bit! +- */ +- col = f030_col[regno]; +- *red = (col >> 16) & 0xff00; +- *green = (col >> 8) & 0xff00; +- *blue = (col << 8) & 0xff00; +- *transp = 0; +- return 0; +-} +- +- +-static int falcon_setcolreg( unsigned regno, unsigned red, +- unsigned green, unsigned blue, +- unsigned transp, struct fb_info *info ) ++static int falcon_setcolreg(unsigned int regno, unsigned int red, ++ unsigned int green, unsigned int blue, ++ unsigned int transp, struct fb_info *info) + { + if (regno > 255) + return 1; +@@ -1655,13 +1744,12 @@ static int falcon_setcolreg( unsigned re + return 0; + } + +- +-static int falcon_blank( int blank_mode ) ++static int falcon_blank(int blank_mode) + { +-/* ++guenther: we can switch off graphics by changing VDB and VDE, +- * so VIDEL doesn't hog the bus while saving. +- * (this may affect usleep()). +- */ ++ /* ++guenther: we can switch off graphics by changing VDB and VDE, ++ * so VIDEL doesn't hog the bus while saving. ++ * (this may affect usleep()). ++ */ + int vdb, vss, hbe, hss; + + if (mon_type == F_MON_SM) /* this doesn't work on SM124 */ +@@ -1694,14 +1782,13 @@ static int falcon_blank( int blank_mode + return 0; + } + +- +-static int falcon_detect( void ) ++static int falcon_detect(void) + { + struct atafb_par par; + unsigned char fhw; + + /* Determine connected monitor and set monitor parameters */ +- fhw = *(unsigned char*)0xffff8006; ++ fhw = *(unsigned char *)0xffff8006; + mon_type = fhw >> 6 & 0x3; + /* bit 1 of fhw: 1=32 bit ram bus, 0=16 bit */ + f030_bus_width = fhw << 6 & 0x80; +@@ -1715,7 +1802,7 @@ static int falcon_detect( void ) + case F_MON_SC: + case F_MON_TV: + /* PAL...NTSC */ +- fb_info.monspecs.vfmin = 49; /* not 50, since TOS defaults to 49.9x Hz */ ++ fb_info.monspecs.vfmin = 49; /* not 50, since TOS defaults to 49.9x Hz */ + fb_info.monspecs.vfmax = 60; + fb_info.monspecs.hfmin = 15620; + fb_info.monspecs.hfmax = 15755; +@@ -1740,13 +1827,12 @@ static int falcon_detect( void ) + + #ifdef ATAFB_STE + +-static int stste_encode_fix( struct fb_fix_screeninfo *fix, +- struct atafb_par *par ) +- ++static int stste_encode_fix(struct fb_fix_screeninfo *fix, ++ struct atafb_par *par) + { + int mode; + +- strcpy(fix->id,"Atari Builtin"); ++ strcpy(fix->id, "Atari Builtin"); + fix->smem_start = (unsigned long)real_screen_base; + fix->smem_len = screen_len; + fix->type = FB_TYPE_INTERLEAVED_PLANES; +@@ -1771,43 +1857,40 @@ static int stste_encode_fix( struct fb_f + return 0; + } + +- +-static int stste_decode_var( struct fb_var_screeninfo *var, +- struct atafb_par *par ) ++static int stste_decode_var(struct fb_var_screeninfo *var, ++ struct atafb_par *par) + { +- int xres=var->xres; +- int yres=var->yres; +- int bpp=var->bits_per_pixel; ++ int xres = var->xres; ++ int yres = var->yres; ++ int bpp = var->bits_per_pixel; + int linelen; + int yres_virtual = var->yres_virtual; + + if (mono_moni) { + if (bpp > 1 || xres > sttt_xres || yres > st_yres) + return -EINVAL; +- par->hw.st.mode=ST_HIGH; +- xres=sttt_xres; +- yres=st_yres; +- bpp=1; ++ par->hw.st.mode = ST_HIGH; ++ xres = sttt_xres; ++ yres = st_yres; ++ bpp = 1; + } else { + if (bpp > 4 || xres > sttt_xres || yres > st_yres) + return -EINVAL; + if (bpp > 2) { +- if (xres > sttt_xres/2 || yres > st_yres/2) ++ if (xres > sttt_xres / 2 || yres > st_yres / 2) + return -EINVAL; +- par->hw.st.mode=ST_LOW; +- xres=sttt_xres/2; +- yres=st_yres/2; +- bpp=4; +- } +- else if (bpp > 1) { +- if (xres > sttt_xres || yres > st_yres/2) ++ par->hw.st.mode = ST_LOW; ++ xres = sttt_xres / 2; ++ yres = st_yres / 2; ++ bpp = 4; ++ } else if (bpp > 1) { ++ if (xres > sttt_xres || yres > st_yres / 2) + return -EINVAL; +- par->hw.st.mode=ST_MID; +- xres=sttt_xres; +- yres=st_yres/2; +- bpp=2; +- } +- else ++ par->hw.st.mode = ST_MID; ++ xres = sttt_xres; ++ yres = st_yres / 2; ++ bpp = 2; ++ } else + return -EINVAL; + } + if (yres_virtual <= 0) +@@ -1815,10 +1898,10 @@ static int stste_decode_var( struct fb_v + else if (yres_virtual < yres) + yres_virtual = yres; + if (var->sync & FB_SYNC_EXT) +- par->hw.st.sync=(par->hw.st.sync & ~1) | 1; ++ par->hw.st.sync = (par->hw.st.sync & ~1) | 1; + else +- par->hw.st.sync=(par->hw.st.sync & ~1); +- linelen=xres*bpp/8; ++ par->hw.st.sync = (par->hw.st.sync & ~1); ++ linelen = xres * bpp / 8; + if (yres_virtual * linelen > screen_len && screen_len) + return -EINVAL; + if (yres * linelen > screen_len && screen_len) +@@ -1826,93 +1909,91 @@ static int stste_decode_var( struct fb_v + if (var->yoffset + yres > yres_virtual && yres_virtual) + return -EINVAL; + par->yres_virtual = yres_virtual; +- par->screen_base=screen_base+ var->yoffset*linelen; ++ par->screen_base = screen_base + var->yoffset * linelen; + return 0; + } + +-static int stste_encode_var( struct fb_var_screeninfo *var, +- struct atafb_par *par ) ++static int stste_encode_var(struct fb_var_screeninfo *var, ++ struct atafb_par *par) + { + int linelen; + memset(var, 0, sizeof(struct fb_var_screeninfo)); +- var->red.offset=0; ++ var->red.offset = 0; + var->red.length = ATARIHW_PRESENT(EXTD_SHIFTER) ? 4 : 3; +- var->red.msb_right=0; +- var->grayscale=0; ++ var->red.msb_right = 0; ++ var->grayscale = 0; + +- var->pixclock=31041; +- var->left_margin=120; /* these are incorrect */ +- var->right_margin=100; +- var->upper_margin=8; +- var->lower_margin=16; +- var->hsync_len=140; +- var->vsync_len=30; ++ var->pixclock = 31041; ++ var->left_margin = 120; /* these are incorrect */ ++ var->right_margin = 100; ++ var->upper_margin = 8; ++ var->lower_margin = 16; ++ var->hsync_len = 140; ++ var->vsync_len = 30; + +- var->height=-1; +- var->width=-1; ++ var->height = -1; ++ var->width = -1; + + if (!(par->hw.st.sync & 1)) +- var->sync=0; ++ var->sync = 0; + else +- var->sync=FB_SYNC_EXT; ++ var->sync = FB_SYNC_EXT; + + switch (par->hw.st.mode & 3) { + case ST_LOW: +- var->xres=sttt_xres/2; +- var->yres=st_yres/2; +- var->bits_per_pixel=4; ++ var->xres = sttt_xres / 2; ++ var->yres = st_yres / 2; ++ var->bits_per_pixel = 4; + break; + case ST_MID: +- var->xres=sttt_xres; +- var->yres=st_yres/2; +- var->bits_per_pixel=2; ++ var->xres = sttt_xres; ++ var->yres = st_yres / 2; ++ var->bits_per_pixel = 2; + break; + case ST_HIGH: +- var->xres=sttt_xres; +- var->yres=st_yres; +- var->bits_per_pixel=1; ++ var->xres = sttt_xres; ++ var->yres = st_yres; ++ var->bits_per_pixel = 1; + break; +- } +- var->blue=var->green=var->red; +- var->transp.offset=0; +- var->transp.length=0; +- var->transp.msb_right=0; +- var->xres_virtual=sttt_xres_virtual; +- linelen=var->xres_virtual * var->bits_per_pixel / 8; +- ovsc_addlen=linelen*(sttt_yres_virtual - st_yres); +- +- if (! use_hwscroll) +- var->yres_virtual=var->yres; ++ } ++ var->blue = var->green = var->red; ++ var->transp.offset = 0; ++ var->transp.length = 0; ++ var->transp.msb_right = 0; ++ var->xres_virtual = sttt_xres_virtual; ++ linelen = var->xres_virtual * var->bits_per_pixel / 8; ++ ovsc_addlen = linelen * (sttt_yres_virtual - st_yres); ++ ++ if (!use_hwscroll) ++ var->yres_virtual = var->yres; + else if (screen_len) { + if (par->yres_virtual) + var->yres_virtual = par->yres_virtual; + else +- /* yres_virtual==0 means use maximum */ ++ /* yres_virtual == 0 means use maximum */ + var->yres_virtual = screen_len / linelen; +- } +- else { ++ } else { + if (hwscroll < 0) + var->yres_virtual = 2 * var->yres; + else +- var->yres_virtual=var->yres+hwscroll * 16; ++ var->yres_virtual = var->yres + hwscroll * 16; + } +- var->xoffset=0; ++ var->xoffset = 0; + if (screen_base) +- var->yoffset=(par->screen_base - screen_base)/linelen; ++ var->yoffset = (par->screen_base - screen_base) / linelen; + else +- var->yoffset=0; +- var->nonstd=0; +- var->activate=0; +- var->vmode=FB_VMODE_NONINTERLACED; ++ var->yoffset = 0; ++ var->nonstd = 0; ++ var->activate = 0; ++ var->vmode = FB_VMODE_NONINTERLACED; + return 0; + } + +- +-static void stste_get_par( struct atafb_par *par ) ++static void stste_get_par(struct atafb_par *par) + { + unsigned long addr; +- par->hw.st.mode=shifter_tt.st_shiftmode; +- par->hw.st.sync=shifter.syncmode; ++ par->hw.st.mode = shifter_tt.st_shiftmode; ++ par->hw.st.sync = shifter.syncmode; + addr = ((shifter.bas_hi & 0xff) << 16) | + ((shifter.bas_md & 0xff) << 8); + if (ATARIHW_PRESENT(EXTD_SHIFTER)) +@@ -1920,55 +2001,18 @@ static void stste_get_par( struct atafb_ + par->screen_base = phys_to_virt(addr); + } + +-static void stste_set_par( struct atafb_par *par ) ++static void stste_set_par(struct atafb_par *par) + { +- shifter_tt.st_shiftmode=par->hw.st.mode; +- shifter.syncmode=par->hw.st.sync; ++ shifter_tt.st_shiftmode = par->hw.st.mode; ++ shifter.syncmode = par->hw.st.sync; + /* only set screen_base if really necessary */ + if (current_par.screen_base != par->screen_base) + fbhw->set_screen_base(par->screen_base); + } + +- +-static int stste_getcolreg(unsigned regno, unsigned *red, +- unsigned *green, unsigned *blue, +- unsigned *transp, struct fb_info *info) +-{ +- unsigned col, t; +- +- if (regno > 15) +- return 1; +- col = shifter_tt.color_reg[regno]; +- if (ATARIHW_PRESENT(EXTD_SHIFTER)) { +- t = ((col >> 7) & 0xe) | ((col >> 11) & 1); +- t |= t << 4; +- *red = t | (t << 8); +- t = ((col >> 3) & 0xe) | ((col >> 7) & 1); +- t |= t << 4; +- *green = t | (t << 8); +- t = ((col << 1) & 0xe) | ((col >> 3) & 1); +- t |= t << 4; +- *blue = t | (t << 8); +- } +- else { +- t = (col >> 7) & 0xe; +- t |= t << 4; +- *red = t | (t << 8); +- t = (col >> 3) & 0xe; +- t |= t << 4; +- *green = t | (t << 8); +- t = (col << 1) & 0xe; +- t |= t << 4; +- *blue = t | (t << 8); +- } +- *transp = 0; +- return 0; +-} +- +- +-static int stste_setcolreg(unsigned regno, unsigned red, +- unsigned green, unsigned blue, +- unsigned transp, struct fb_info *info) ++static int stste_setcolreg(unsigned int regno, unsigned int red, ++ unsigned int green, unsigned int blue, ++ unsigned int transp, struct fb_info *info) + { + if (regno > 15) + return 1; +@@ -1988,10 +2032,9 @@ static int stste_setcolreg(unsigned regn + return 0; + } + +- +-static int stste_detect( void ) +- +-{ struct atafb_par par; ++static int stste_detect(void) ++{ ++ struct atafb_par par; + + /* Determine the connected monitor: The DMA sound must be + * disabled before reading the MFP GPIP, because the Sound +@@ -1999,7 +2042,7 @@ static int stste_detect( void ) + */ + if (ATARIHW_PRESENT(PCM_8BIT)) { + tt_dmasnd.ctrl = DMASND_CTRL_OFF; +- udelay(20); /* wait a while for things to settle down */ ++ udelay(20); /* wait a while for things to settle down */ + } + mono_moni = (mfp.par_dt_reg & 0x80) == 0; + +@@ -2014,12 +2057,12 @@ static int stste_detect( void ) + static void stste_set_screen_base(void *s_base) + { + unsigned long addr; +- addr= virt_to_phys(s_base); ++ addr = virt_to_phys(s_base); + /* Setup Screen Memory */ +- shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16); +- shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8); ++ shifter.bas_hi = (unsigned char)((addr & 0xff0000) >> 16); ++ shifter.bas_md = (unsigned char)((addr & 0x00ff00) >> 8); + if (ATARIHW_PRESENT(EXTD_SHIFTER)) +- shifter.bas_lo=(unsigned char) (addr & 0x0000ff); ++ shifter.bas_lo = (unsigned char)(addr & 0x0000ff); + } + + #endif /* ATAFB_STE */ +@@ -2045,51 +2088,49 @@ static void stste_set_screen_base(void * + /* SWITCH_ACIA may be used for Falcon (ScreenBlaster III internal!) */ + static void st_ovsc_switch(void) + { +- unsigned long flags; +- register unsigned char old, new; ++ unsigned long flags; ++ register unsigned char old, new; + +- if (!(atari_switches & ATARI_SWITCH_OVSC_MASK)) +- return; +- local_irq_save(flags); ++ if (!(atari_switches & ATARI_SWITCH_OVSC_MASK)) ++ return; ++ local_irq_save(flags); + +- mfp.tim_ct_b = 0x10; +- mfp.active_edge |= 8; +- mfp.tim_ct_b = 0; +- mfp.tim_dt_b = 0xf0; +- mfp.tim_ct_b = 8; +- while (mfp.tim_dt_b > 1) /* TOS does it this way, don't ask why */ +- ; +- new = mfp.tim_dt_b; +- do { +- udelay(LINE_DELAY); +- old = new; ++ mfp.tim_ct_b = 0x10; ++ mfp.active_edge |= 8; ++ mfp.tim_ct_b = 0; ++ mfp.tim_dt_b = 0xf0; ++ mfp.tim_ct_b = 8; ++ while (mfp.tim_dt_b > 1) /* TOS does it this way, don't ask why */ ++ ; + new = mfp.tim_dt_b; +- } while (old != new); +- mfp.tim_ct_b = 0x10; +- udelay(SYNC_DELAY); +- +- if (atari_switches & ATARI_SWITCH_OVSC_IKBD) +- acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID | ACIA_RIE; +- if (atari_switches & ATARI_SWITCH_OVSC_MIDI) +- acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID; +- if (atari_switches & (ATARI_SWITCH_OVSC_SND6|ATARI_SWITCH_OVSC_SND7)) { +- sound_ym.rd_data_reg_sel = 14; +- sound_ym.wd_data = sound_ym.rd_data_reg_sel | +- ((atari_switches&ATARI_SWITCH_OVSC_SND6) ? 0x40:0) | +- ((atari_switches&ATARI_SWITCH_OVSC_SND7) ? 0x80:0); +- } +- local_irq_restore(flags); ++ do { ++ udelay(LINE_DELAY); ++ old = new; ++ new = mfp.tim_dt_b; ++ } while (old != new); ++ mfp.tim_ct_b = 0x10; ++ udelay(SYNC_DELAY); ++ ++ if (atari_switches & ATARI_SWITCH_OVSC_IKBD) ++ acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID | ACIA_RIE; ++ if (atari_switches & ATARI_SWITCH_OVSC_MIDI) ++ acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID; ++ if (atari_switches & (ATARI_SWITCH_OVSC_SND6|ATARI_SWITCH_OVSC_SND7)) { ++ sound_ym.rd_data_reg_sel = 14; ++ sound_ym.wd_data = sound_ym.rd_data_reg_sel | ++ ((atari_switches & ATARI_SWITCH_OVSC_SND6) ? 0x40:0) | ++ ((atari_switches & ATARI_SWITCH_OVSC_SND7) ? 0x80:0); ++ } ++ local_irq_restore(flags); + } + + /* ------------------- External Video ---------------------- */ + + #ifdef ATAFB_EXT + +-static int ext_encode_fix( struct fb_fix_screeninfo *fix, +- struct atafb_par *par ) +- ++static int ext_encode_fix(struct fb_fix_screeninfo *fix, struct atafb_par *par) + { +- strcpy(fix->id,"Unknown Extern"); ++ strcpy(fix->id, "Unknown Extern"); + fix->smem_start = (unsigned long)external_addr; + fix->smem_len = PAGE_ALIGN(external_len); + if (external_depth == 1) { +@@ -2099,31 +2140,29 @@ static int ext_encode_fix( struct fb_fix + fix->visual = + (external_pmode == FB_TYPE_INTERLEAVED_PLANES || + external_pmode == FB_TYPE_PACKED_PIXELS) ? +- FB_VISUAL_MONO10 : +- FB_VISUAL_MONO01; +- } +- else { ++ FB_VISUAL_MONO10 : FB_VISUAL_MONO01; ++ } else { + /* Use STATIC if we don't know how to access color registers */ + int visual = external_vgaiobase ? + FB_VISUAL_PSEUDOCOLOR : + FB_VISUAL_STATIC_PSEUDOCOLOR; + switch (external_pmode) { +- case -1: /* truecolor */ +- fix->type=FB_TYPE_PACKED_PIXELS; +- fix->visual=FB_VISUAL_TRUECOLOR; ++ case -1: /* truecolor */ ++ fix->type = FB_TYPE_PACKED_PIXELS; ++ fix->visual = FB_VISUAL_TRUECOLOR; + break; +- case FB_TYPE_PACKED_PIXELS: +- fix->type=FB_TYPE_PACKED_PIXELS; +- fix->visual=visual; ++ case FB_TYPE_PACKED_PIXELS: ++ fix->type = FB_TYPE_PACKED_PIXELS; ++ fix->visual = visual; + break; +- case FB_TYPE_PLANES: +- fix->type=FB_TYPE_PLANES; +- fix->visual=visual; ++ case FB_TYPE_PLANES: ++ fix->type = FB_TYPE_PLANES; ++ fix->visual = visual; + break; +- case FB_TYPE_INTERLEAVED_PLANES: +- fix->type=FB_TYPE_INTERLEAVED_PLANES; +- fix->type_aux=2; +- fix->visual=visual; ++ case FB_TYPE_INTERLEAVED_PLANES: ++ fix->type = FB_TYPE_INTERLEAVED_PLANES; ++ fix->type_aux = 2; ++ fix->visual = visual; + break; + } + } +@@ -2134,137 +2173,112 @@ static int ext_encode_fix( struct fb_fix + return 0; + } + +- +-static int ext_decode_var( struct fb_var_screeninfo *var, +- struct atafb_par *par ) ++static int ext_decode_var(struct fb_var_screeninfo *var, struct atafb_par *par) + { + struct fb_var_screeninfo *myvar = &atafb_predefined[0]; +- ++ + if (var->bits_per_pixel > myvar->bits_per_pixel || +- var->xres > myvar->xres || +- var->xres_virtual > myvar->xres_virtual || +- var->yres > myvar->yres || +- var->xoffset > 0 || +- var->yoffset > 0) ++ var->xres > myvar->xres || ++ var->xres_virtual > myvar->xres_virtual || ++ var->yres > myvar->yres || ++ var->xoffset > 0 || ++ var->yoffset > 0) + return -EINVAL; + return 0; + } + +- +-static int ext_encode_var( struct fb_var_screeninfo *var, +- struct atafb_par *par ) ++static int ext_encode_var(struct fb_var_screeninfo *var, struct atafb_par *par) + { + memset(var, 0, sizeof(struct fb_var_screeninfo)); +- var->red.offset=0; +- var->red.length=(external_pmode == -1) ? external_depth/3 : ++ var->red.offset = 0; ++ var->red.length = (external_pmode == -1) ? external_depth / 3 : + (external_vgaiobase ? external_bitspercol : 0); +- var->red.msb_right=0; +- var->grayscale=0; ++ var->red.msb_right = 0; ++ var->grayscale = 0; + +- var->pixclock=31041; +- var->left_margin=120; /* these are surely incorrect */ +- var->right_margin=100; +- var->upper_margin=8; +- var->lower_margin=16; +- var->hsync_len=140; +- var->vsync_len=30; ++ var->pixclock = 31041; ++ var->left_margin = 120; /* these are surely incorrect */ ++ var->right_margin = 100; ++ var->upper_margin = 8; ++ var->lower_margin = 16; ++ var->hsync_len = 140; ++ var->vsync_len = 30; + +- var->height=-1; +- var->width=-1; ++ var->height = -1; ++ var->width = -1; + +- var->sync=0; ++ var->sync = 0; + + var->xres = external_xres; + var->yres = external_yres; + var->xres_virtual = external_xres_virtual; + var->bits_per_pixel = external_depth; +- +- var->blue=var->green=var->red; +- var->transp.offset=0; +- var->transp.length=0; +- var->transp.msb_right=0; +- var->yres_virtual=var->yres; +- var->xoffset=0; +- var->yoffset=0; +- var->nonstd=0; +- var->activate=0; +- var->vmode=FB_VMODE_NONINTERLACED; ++ ++ var->blue = var->green = var->red; ++ var->transp.offset = 0; ++ var->transp.length = 0; ++ var->transp.msb_right = 0; ++ var->yres_virtual = var->yres; ++ var->xoffset = 0; ++ var->yoffset = 0; ++ var->nonstd = 0; ++ var->activate = 0; ++ var->vmode = FB_VMODE_NONINTERLACED; + return 0; + } + +- +-static void ext_get_par( struct atafb_par *par ) ++static void ext_get_par(struct atafb_par *par) + { + par->screen_base = external_addr; + } + +-static void ext_set_par( struct atafb_par *par ) ++static void ext_set_par(struct atafb_par *par) + { + } + + #define OUTB(port,val) \ +- *((unsigned volatile char *) ((port)+external_vgaiobase))=(val) ++ *((unsigned volatile char *) ((port)+external_vgaiobase)) = (val) + #define INB(port) \ + (*((unsigned volatile char *) ((port)+external_vgaiobase))) +-#define DACDelay \ ++#define DACDelay \ + do { \ +- unsigned char tmp=INB(0x3da); \ +- tmp=INB(0x3da); \ ++ unsigned char tmp = INB(0x3da); \ ++ tmp = INB(0x3da); \ + } while (0) + +-static int ext_getcolreg( unsigned regno, unsigned *red, +- unsigned *green, unsigned *blue, +- unsigned *transp, struct fb_info *info ) ++static int ext_setcolreg(unsigned int regno, unsigned int red, ++ unsigned int green, unsigned int blue, ++ unsigned int transp, struct fb_info *info) + { +- if (! external_vgaiobase) ++ unsigned char colmask = (1 << external_bitspercol) - 1; ++ ++ if (!external_vgaiobase) + return 1; + +- *red = ext_color[regno].red; +- *green = ext_color[regno].green; +- *blue = ext_color[regno].blue; +- *transp=0; +- return 0; +-} +- +-static int ext_setcolreg( unsigned regno, unsigned red, +- unsigned green, unsigned blue, +- unsigned transp, struct fb_info *info ) ++ switch (external_card_type) { ++ case IS_VGA: ++ OUTB(0x3c8, regno); ++ DACDelay; ++ OUTB(0x3c9, red & colmask); ++ DACDelay; ++ OUTB(0x3c9, green & colmask); ++ DACDelay; ++ OUTB(0x3c9, blue & colmask); ++ DACDelay; ++ return 0; + +-{ unsigned char colmask = (1 << external_bitspercol) - 1; ++ case IS_MV300: ++ OUTB((MV300_reg[regno] << 2) + 1, red); ++ OUTB((MV300_reg[regno] << 2) + 1, green); ++ OUTB((MV300_reg[regno] << 2) + 1, blue); ++ return 0; + +- if (! external_vgaiobase) ++ default: + return 1; +- +- ext_color[regno].red = red; +- ext_color[regno].green = green; +- ext_color[regno].blue = blue; +- +- switch (external_card_type) { +- case IS_VGA: +- OUTB(0x3c8, regno); +- DACDelay; +- OUTB(0x3c9, red & colmask); +- DACDelay; +- OUTB(0x3c9, green & colmask); +- DACDelay; +- OUTB(0x3c9, blue & colmask); +- DACDelay; +- return 0; +- +- case IS_MV300: +- OUTB((MV300_reg[regno] << 2)+1, red); +- OUTB((MV300_reg[regno] << 2)+1, green); +- OUTB((MV300_reg[regno] << 2)+1, blue); +- return 0; +- +- default: +- return 1; +- } ++ } + } +- +- +-static int ext_detect( void ) + ++static int ext_detect(void) + { + struct fb_var_screeninfo *myvar = &atafb_predefined[0]; + struct atafb_par dummy_par; +@@ -2284,213 +2298,182 @@ static int ext_detect( void ) + static void set_screen_base(void *s_base) + { + unsigned long addr; +- addr= virt_to_phys(s_base); ++ ++ addr = virt_to_phys(s_base); + /* Setup Screen Memory */ +- shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16); +- shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8); +- shifter.bas_lo=(unsigned char) (addr & 0x0000ff); ++ shifter.bas_hi = (unsigned char)((addr & 0xff0000) >> 16); ++ shifter.bas_md = (unsigned char)((addr & 0x00ff00) >> 8); ++ shifter.bas_lo = (unsigned char)(addr & 0x0000ff); + } + +- +-static int pan_display( struct fb_var_screeninfo *var, +- struct atafb_par *par ) ++static int pan_display(struct fb_var_screeninfo *var, struct fb_info *info) + { ++ struct atafb_par *par = (struct atafb_par *)info->par; ++ + if (!fbhw->set_screen_base || +- (!ATARIHW_PRESENT(EXTD_SHIFTER) && var->xoffset)) ++ (!ATARIHW_PRESENT(EXTD_SHIFTER) && var->xoffset)) + return -EINVAL; + var->xoffset = up(var->xoffset, 16); + par->screen_base = screen_base + +- (var->yoffset * fb_display[fb_info.currcon].var.xres_virtual + var->xoffset) +- * fb_display[fb_info.currcon].var.bits_per_pixel / 8; +- fbhw->set_screen_base (par->screen_base); ++ (var->yoffset * info->var.xres_virtual + var->xoffset) ++ * info->var.bits_per_pixel / 8; ++ fbhw->set_screen_base(par->screen_base); + return 0; + } + +- + /* ------------ Interfaces to hardware functions ------------ */ + +- + #ifdef ATAFB_TT + static struct fb_hwswitch tt_switch = { +- tt_detect, tt_encode_fix, tt_decode_var, tt_encode_var, +- tt_get_par, tt_set_par, tt_getcolreg, +- set_screen_base, NULL, pan_display ++ .detect = tt_detect, ++ .encode_fix = tt_encode_fix, ++ .decode_var = tt_decode_var, ++ .encode_var = tt_encode_var, ++ .get_par = tt_get_par, ++ .set_par = tt_set_par, ++ .set_screen_base = set_screen_base, ++ .pan_display = pan_display, + }; + #endif + + #ifdef ATAFB_FALCON + static struct fb_hwswitch falcon_switch = { +- falcon_detect, falcon_encode_fix, falcon_decode_var, falcon_encode_var, +- falcon_get_par, falcon_set_par, falcon_getcolreg, +- set_screen_base, falcon_blank, falcon_pan_display ++ .detect = falcon_detect, ++ .encode_fix = falcon_encode_fix, ++ .decode_var = falcon_decode_var, ++ .encode_var = falcon_encode_var, ++ .get_par = falcon_get_par, ++ .set_par = falcon_set_par, ++ .set_screen_base = set_screen_base, ++ .blank = falcon_blank, ++ .pan_display = falcon_pan_display, + }; + #endif + + #ifdef ATAFB_STE + static struct fb_hwswitch st_switch = { +- stste_detect, stste_encode_fix, stste_decode_var, stste_encode_var, +- stste_get_par, stste_set_par, stste_getcolreg, +- stste_set_screen_base, NULL, pan_display ++ .detect = stste_detect, ++ .encode_fix = stste_encode_fix, ++ .decode_var = stste_decode_var, ++ .encode_var = stste_encode_var, ++ .get_par = stste_get_par, ++ .set_par = stste_set_par, ++ .set_screen_base = stste_set_screen_base, ++ .pan_display = pan_display + }; + #endif + + #ifdef ATAFB_EXT + static struct fb_hwswitch ext_switch = { +- ext_detect, ext_encode_fix, ext_decode_var, ext_encode_var, +- ext_get_par, ext_set_par, ext_getcolreg, NULL, NULL, NULL ++ .detect = ext_detect, ++ .encode_fix = ext_encode_fix, ++ .decode_var = ext_decode_var, ++ .encode_var = ext_encode_var, ++ .get_par = ext_get_par, ++ .set_par = ext_set_par, + }; + #endif + +- +- +-static void atafb_get_par( struct atafb_par *par ) ++static void ata_get_par(struct atafb_par *par) + { +- if (current_par_valid) { +- *par=current_par; +- } ++ if (current_par_valid) ++ *par = current_par; + else + fbhw->get_par(par); + } + +- +-static void atafb_set_par( struct atafb_par *par ) ++static void ata_set_par(struct atafb_par *par) + { + fbhw->set_par(par); +- current_par=*par; +- current_par_valid=1; ++ current_par = *par; ++ current_par_valid = 1; + } + + +- + /* =========================================================== */ + /* ============== Hardware Independent Functions ============= */ + /* =========================================================== */ + +- + /* used for hardware scrolling */ + +-static int +-fb_update_var(int con, struct fb_info *info) +-{ +- int off=fb_display[con].var.yoffset*fb_display[con].var.xres_virtual* +- fb_display[con].var.bits_per_pixel>>3; +- +- current_par.screen_base=screen_base + off; +- +- if (fbhw->set_screen_base) +- fbhw->set_screen_base(current_par.screen_base); +- return 0; +-} +- +-static int +-do_fb_set_var(struct fb_var_screeninfo *var, int isactive) ++static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive) + { +- int err,activate; ++ int err, activate; + struct atafb_par par; +- if ((err=fbhw->decode_var(var, &par))) ++ ++ err = fbhw->decode_var(var, &par); ++ if (err) + return err; +- activate=var->activate; ++ activate = var->activate; + if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) +- atafb_set_par(&par); ++ ata_set_par(&par); + fbhw->encode_var(var, &par); +- var->activate=activate; ++ var->activate = activate; + return 0; + } + +-static int +-atafb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) ++static int atafb_get_fix(struct fb_fix_screeninfo *fix, struct fb_info *info) + { + struct atafb_par par; +- if (con == -1) +- atafb_get_par(&par); +- else { +- int err; +- if ((err=fbhw->decode_var(&fb_display[con].var,&par))) +- return err; +- } ++ int err; ++ // Get fix directly (case con == -1 before)?? ++ err = fbhw->decode_var(&info->var, &par); ++ if (err) ++ return err; + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + return fbhw->encode_fix(fix, &par); + } +- +-static int +-atafb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) ++ ++static int atafb_get_var(struct fb_var_screeninfo *var, struct fb_info *info) + { + struct atafb_par par; +- if (con == -1) { +- atafb_get_par(&par); +- fbhw->encode_var(var, &par); +- } +- else +- *var=fb_display[con].var; ++ ++ ata_get_par(&par); ++ fbhw->encode_var(var, &par); ++ + return 0; + } + +-static void +-atafb_set_disp(int con, struct fb_info *info) ++// No longer called by fbcon! ++// Still called by set_var internally ++ ++static void atafb_set_disp(struct fb_info *info) + { +- struct fb_fix_screeninfo fix; +- struct fb_var_screeninfo var; +- struct display *display; ++ atafb_get_var(&info->var, info); ++ atafb_get_fix(&info->fix, info); + +- if (con >= 0) +- display = &fb_display[con]; +- else +- display = &disp; /* used during initialization */ ++ info->screen_base = (void *)info->fix.smem_start; + +- atafb_get_fix(&fix, con, info); +- atafb_get_var(&var, con, info); +- if (con == -1) +- con=0; +- info->screen_base = (void *)fix.smem_start; +- display->visual = fix.visual; +- display->type = fix.type; +- display->type_aux = fix.type_aux; +- display->ypanstep = fix.ypanstep; +- display->ywrapstep = fix.ywrapstep; +- display->line_length = fix.line_length; +- if (fix.visual != FB_VISUAL_PSEUDOCOLOR && +- fix.visual != FB_VISUAL_DIRECTCOLOR) +- display->can_soft_blank = 0; +- else +- display->can_soft_blank = 1; +- display->inverse = +- (fix.visual == FB_VISUAL_MONO01 ? !inverse : inverse); +- switch (fix.type) { +- case FB_TYPE_INTERLEAVED_PLANES: +- switch (var.bits_per_pixel) { +-#ifdef FBCON_HAS_IPLAN2P2 +- case 2: +- display->dispsw = &fbcon_iplan2p2; ++ switch (info->fix.type) { ++ case FB_TYPE_INTERLEAVED_PLANES: ++ switch (info->var.bits_per_pixel) { ++ case 2: ++ // display->dispsw = &fbcon_iplan2p2; + break; +-#endif +-#ifdef FBCON_HAS_IPLAN2P4 +- case 4: +- display->dispsw = &fbcon_iplan2p4; ++ case 4: ++ // display->dispsw = &fbcon_iplan2p4; + break; +-#endif +-#ifdef FBCON_HAS_IPLAN2P8 +- case 8: +- display->dispsw = &fbcon_iplan2p8; ++ case 8: ++ // display->dispsw = &fbcon_iplan2p8; + break; +-#endif + } + break; +- case FB_TYPE_PACKED_PIXELS: +- switch (var.bits_per_pixel) { ++ case FB_TYPE_PACKED_PIXELS: ++ switch (info->var.bits_per_pixel) { + #ifdef FBCON_HAS_MFB +- case 1: +- display->dispsw = &fbcon_mfb; ++ case 1: ++ // display->dispsw = &fbcon_mfb; + break; + #endif + #ifdef FBCON_HAS_CFB8 +- case 8: +- display->dispsw = &fbcon_cfb8; ++ case 8: ++ // display->dispsw = &fbcon_cfb8; + break; + #endif + #ifdef FBCON_HAS_CFB16 +- case 16: +- display->dispsw = &fbcon_cfb16; +- display->dispsw_data = fbcon_cfb16_cmap; ++ case 16: ++ // display->dispsw = &fbcon_cfb16; ++ // display->dispsw_data = fbcon_cfb16_cmap; + break; + #endif + } +@@ -2498,74 +2481,203 @@ atafb_set_disp(int con, struct fb_info * + } + } + ++static int atafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, ++ u_int transp, struct fb_info *info) ++{ ++ red >>= 8; ++ green >>= 8; ++ blue >>= 8; ++ ++ return info->fbops->fb_setcolreg(regno, red, green, blue, transp, info); ++} ++ + static int +-atafb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) ++atafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) + { +- int err,oldxres,oldyres,oldbpp,oldxres_virtual, +- oldyres_virtual,oldyoffset; +- if ((err=do_fb_set_var(var, con==info->currcon))) +- return err; +- if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { +- oldxres=fb_display[con].var.xres; +- oldyres=fb_display[con].var.yres; +- oldxres_virtual=fb_display[con].var.xres_virtual; +- oldyres_virtual=fb_display[con].var.yres_virtual; +- oldbpp=fb_display[con].var.bits_per_pixel; +- oldyoffset=fb_display[con].var.yoffset; +- fb_display[con].var=*var; +- if (oldxres != var->xres || oldyres != var->yres +- || oldxres_virtual != var->xres_virtual +- || oldyres_virtual != var->yres_virtual +- || oldbpp != var->bits_per_pixel +- || oldyoffset != var->yoffset) { +- atafb_set_disp(con, info); +- (*fb_info.changevar)(con); +- fb_alloc_cmap(&fb_display[con].cmap, 0, 0); +- do_install_cmap(con, info); +- } ++ int xoffset = var->xoffset; ++ int yoffset = var->yoffset; ++ int err; ++ ++ if (var->vmode & FB_VMODE_YWRAP) { ++ if (yoffset < 0 || yoffset >= info->var.yres_virtual || xoffset) ++ return -EINVAL; ++ } else { ++ if (xoffset + info->var.xres > info->var.xres_virtual || ++ yoffset + info->var.yres > info->var.yres_virtual) ++ return -EINVAL; + } +- var->activate=0; ++ ++ if (fbhw->pan_display) { ++ err = fbhw->pan_display(var, info); ++ if (err) ++ return err; ++ } else ++ return -EINVAL; ++ ++ info->var.xoffset = xoffset; ++ info->var.yoffset = yoffset; ++ ++ if (var->vmode & FB_VMODE_YWRAP) ++ info->var.vmode |= FB_VMODE_YWRAP; ++ else ++ info->var.vmode &= ~FB_VMODE_YWRAP; ++ + return 0; + } + ++/* ++ * generic drawing routines; imageblit needs updating for image depth > 1 ++ */ ++ ++#if BITS_PER_LONG == 32 ++#define BYTES_PER_LONG 4 ++#define SHIFT_PER_LONG 5 ++#elif BITS_PER_LONG == 64 ++#define BYTES_PER_LONG 8 ++#define SHIFT_PER_LONG 6 ++#else ++#define Please update me ++#endif + + +-static int +-atafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) ++static void atafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) + { +- if (con == info->currcon) /* current console ? */ +- return fb_get_cmap(cmap, kspc, fbhw->getcolreg, info); ++ struct atafb_par *par = (struct atafb_par *)info->par; ++ int x2, y2; ++ u32 width, height; ++ ++ if (!rect->width || !rect->height) ++ return; ++ ++ /* ++ * We could use hardware clipping but on many cards you get around ++ * hardware clipping by writing to framebuffer directly. ++ * */ ++ x2 = rect->dx + rect->width; ++ y2 = rect->dy + rect->height; ++ x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual; ++ y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual; ++ width = x2 - rect->dx; ++ height = y2 - rect->dy; ++ ++ if (info->var.bits_per_pixel == 1) ++ atafb_mfb_fillrect(info, par->next_line, rect->color, ++ rect->dy, rect->dx, height, width); ++ else if (info->var.bits_per_pixel == 2) ++ atafb_iplan2p2_fillrect(info, par->next_line, rect->color, ++ rect->dy, rect->dx, height, width); ++ else if (info->var.bits_per_pixel == 4) ++ atafb_iplan2p4_fillrect(info, par->next_line, rect->color, ++ rect->dy, rect->dx, height, width); + else +- if (fb_display[con].cmap.len) /* non default colormap ? */ +- fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); +- else +- fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), +- cmap, kspc ? 0 : 2); +- return 0; ++ atafb_iplan2p8_fillrect(info, par->next_line, rect->color, ++ rect->dy, rect->dx, height, width); ++ ++ return; + } + +-static int +-atafb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info) ++static void atafb_copyarea(struct fb_info *info, const struct fb_copyarea *area) + { +- int xoffset = var->xoffset; +- int yoffset = var->yoffset; +- int err; ++ struct atafb_par *par = (struct atafb_par *)info->par; ++ int x2, y2; ++ u32 dx, dy, sx, sy, width, height; ++ int rev_copy = 0; ++ ++ /* clip the destination */ ++ x2 = area->dx + area->width; ++ y2 = area->dy + area->height; ++ dx = area->dx > 0 ? area->dx : 0; ++ dy = area->dy > 0 ? area->dy : 0; ++ x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual; ++ y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual; ++ width = x2 - dx; ++ height = y2 - dy; ++ ++ /* update sx,sy */ ++ sx = area->sx + (dx - area->dx); ++ sy = area->sy + (dy - area->dy); ++ ++ /* the source must be completely inside the virtual screen */ ++ if (sx < 0 || sy < 0 || (sx + width) > info->var.xres_virtual || ++ (sy + height) > info->var.yres_virtual) ++ return; + +- if ( xoffset < 0 || xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual +- || yoffset < 0 || yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual) +- return -EINVAL; ++ if (dy > sy || (dy == sy && dx > sx)) { ++ dy += height; ++ sy += height; ++ rev_copy = 1; ++ } ++ ++ if (info->var.bits_per_pixel == 1) ++ atafb_mfb_copyarea(info, par->next_line, sy, sx, dy, dx, height, width); ++ else if (info->var.bits_per_pixel == 2) ++ atafb_iplan2p2_copyarea(info, par->next_line, sy, sx, dy, dx, height, width); ++ else if (info->var.bits_per_pixel == 4) ++ atafb_iplan2p4_copyarea(info, par->next_line, sy, sx, dy, dx, height, width); ++ else ++ atafb_iplan2p8_copyarea(info, par->next_line, sy, sx, dy, dx, height, width); ++ ++ return; ++} + +- if (con == info->currcon) { +- if (fbhw->pan_display) { +- if ((err = fbhw->pan_display(var, ¤t_par))) +- return err; ++static void atafb_imageblit(struct fb_info *info, const struct fb_image *image) ++{ ++ struct atafb_par *par = (struct atafb_par *)info->par; ++ int x2, y2; ++ unsigned long *dst; ++ int dst_idx; ++ const char *src; ++ u32 dx, dy, width, height, pitch; ++ ++ /* ++ * We could use hardware clipping but on many cards you get around ++ * hardware clipping by writing to framebuffer directly like we are ++ * doing here. ++ */ ++ x2 = image->dx + image->width; ++ y2 = image->dy + image->height; ++ dx = image->dx; ++ dy = image->dy; ++ x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual; ++ y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual; ++ width = x2 - dx; ++ height = y2 - dy; ++ ++ if (image->depth == 1) { ++ // used for font data ++ dst = (unsigned long *) ++ ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1)); ++ dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8; ++ dst_idx += dy * par->next_line * 8 + dx; ++ src = image->data; ++ pitch = (image->width + 7) / 8; ++ while (height--) { ++ ++ if (info->var.bits_per_pixel == 1) ++ atafb_mfb_linefill(info, par->next_line, ++ dy, dx, width, src, ++ image->bg_color, image->fg_color); ++ else if (info->var.bits_per_pixel == 2) ++ atafb_iplan2p2_linefill(info, par->next_line, ++ dy, dx, width, src, ++ image->bg_color, image->fg_color); ++ else if (info->var.bits_per_pixel == 4) ++ atafb_iplan2p4_linefill(info, par->next_line, ++ dy, dx, width, src, ++ image->bg_color, image->fg_color); ++ else ++ atafb_iplan2p8_linefill(info, par->next_line, ++ dy, dx, width, src, ++ image->bg_color, image->fg_color); ++ dy++; ++ src += pitch; + } +- else +- return -EINVAL; ++ } else { ++ // only used for logo; broken ++ c2p(info->screen_base, image->data, dx, dy, width, height, ++ par->next_line, par->next_plane, image->width, ++ info->var.bits_per_pixel); + } +- fb_display[con].var.xoffset = var->xoffset; +- fb_display[con].var.yoffset = var->yoffset; +- return 0; + } + + static int +@@ -2584,7 +2696,7 @@ atafb_ioctl(struct fb_info *info, unsign + if (copy_from_user((void *)¤t_par, (void *)arg, + sizeof(struct atafb_par))) + return -EFAULT; +- atafb_set_par(¤t_par); ++ ata_set_par(¤t_par); + return 0; + #endif + } +@@ -2598,42 +2710,82 @@ atafb_ioctl(struct fb_info *info, unsign + * 3 = suspend hsync + * 4 = off + */ +-static int +-atafb_blank(int blank, struct fb_info *info) ++static int atafb_blank(int blank, struct fb_info *info) + { + unsigned short black[16]; + struct fb_cmap cmap; + if (fbhw->blank && !fbhw->blank(blank)) + return 1; + if (blank) { +- memset(black, 0, 16*sizeof(unsigned short)); +- cmap.red=black; +- cmap.green=black; +- cmap.blue=black; +- cmap.transp=NULL; +- cmap.start=0; +- cmap.len=16; +- fb_set_cmap(&cmap, 1, info); ++ memset(black, 0, 16 * sizeof(unsigned short)); ++ cmap.red = black; ++ cmap.green = black; ++ cmap.blue = black; ++ cmap.transp = NULL; ++ cmap.start = 0; ++ cmap.len = 16; ++ fb_set_cmap(&cmap, info); + } ++#if 0 + else +- do_install_cmap(info->currcon, info); ++ do_install_cmap(info); ++#endif ++ return 0; ++} ++ ++ /* ++ * New fbcon interface ... ++ */ ++ ++ /* check var by decoding var into hw par, rounding if necessary, ++ * then encoding hw par back into new, validated var */ ++static int atafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) ++{ ++ int err; ++ struct atafb_par par; ++ ++ /* Validate wanted screen parameters */ ++ // if ((err = ata_decode_var(var, &par))) ++ err = fbhw->decode_var(var, &par); ++ if (err) ++ return err; ++ ++ /* Encode (possibly rounded) screen parameters */ ++ fbhw->encode_var(var, &par); + return 0; + } + ++ /* actually set hw par by decoding var, then setting hardware from ++ * hw par just decoded */ ++static int atafb_set_par(struct fb_info *info) ++{ ++ struct atafb_par *par = (struct atafb_par *)info->par; ++ ++ /* Decode wanted screen parameters */ ++ fbhw->decode_var(&info->var, par); ++ fbhw->encode_fix(&info->fix, par); ++ ++ /* Set new videomode */ ++ ata_set_par(par); ++ ++ return 0; ++} ++ ++ + static struct fb_ops atafb_ops = { + .owner = THIS_MODULE, +- .fb_get_fix = atafb_get_fix, +- .fb_get_var = atafb_get_var, +- .fb_set_var = atafb_set_var, +- .fb_get_cmap = atafb_get_cmap, +- .fb_set_cmap = gen_set_cmap, +- .fb_pan_display =atafb_pan_display, ++ .fb_check_var = atafb_check_var, ++ .fb_set_par = atafb_set_par, ++ .fb_setcolreg = atafb_setcolreg, + .fb_blank = atafb_blank, ++ .fb_pan_display = atafb_pan_display, ++ .fb_fillrect = atafb_fillrect, ++ .fb_copyarea = atafb_copyarea, ++ .fb_imageblit = atafb_imageblit, + .fb_ioctl = atafb_ioctl, + }; + +-static void +-check_default_par( int detected_mode ) ++static void check_default_par(int detected_mode) + { + char default_name[10]; + int i; +@@ -2642,199 +2794,41 @@ check_default_par( int detected_mode ) + + /* First try the user supplied mode */ + if (default_par) { +- var=atafb_predefined[default_par-1]; ++ var = atafb_predefined[default_par - 1]; + var.activate = FB_ACTIVATE_TEST; +- if (do_fb_set_var(&var,1)) +- default_par=0; /* failed */ ++ if (do_fb_set_var(&var, 1)) ++ default_par = 0; /* failed */ + } + /* Next is the autodetected one */ +- if (! default_par) { +- var=atafb_predefined[detected_mode-1]; /* autodetect */ ++ if (!default_par) { ++ var = atafb_predefined[detected_mode - 1]; /* autodetect */ + var.activate = FB_ACTIVATE_TEST; +- if (!do_fb_set_var(&var,1)) +- default_par=detected_mode; ++ if (!do_fb_set_var(&var, 1)) ++ default_par = detected_mode; + } + /* If that also failed, try some default modes... */ +- if (! default_par) { ++ if (!default_par) { + /* try default1, default2... */ +- for (i=1 ; i < 10 ; i++) { +- sprintf(default_name,"default%d",i); +- default_par=get_video_mode(default_name); +- if (! default_par) ++ for (i = 1; i < 10; i++) { ++ sprintf(default_name,"default%d", i); ++ default_par = get_video_mode(default_name); ++ if (!default_par) + panic("can't set default video mode"); +- var=atafb_predefined[default_par-1]; ++ var = atafb_predefined[default_par - 1]; + var.activate = FB_ACTIVATE_TEST; +- if (! do_fb_set_var(&var,1)) ++ if (!do_fb_set_var(&var,1)) + break; /* ok */ + } + } +- min_mem=var.xres_virtual * var.yres_virtual * var.bits_per_pixel/8; ++ min_mem = var.xres_virtual * var.yres_virtual * var.bits_per_pixel / 8; + if (default_mem_req < min_mem) +- default_mem_req=min_mem; +-} +- +-static int +-atafb_switch(int con, struct fb_info *info) +-{ +- /* Do we have to save the colormap ? */ +- if (fb_display[info->currcon].cmap.len) +- fb_get_cmap(&fb_display[info->currcon].cmap, 1, fbhw->getcolreg, +- info); +- do_fb_set_var(&fb_display[con].var,1); +- info->currcon=con; +- /* Install new colormap */ +- do_install_cmap(con, info); +- return 0; +-} +- +-int __init atafb_init(void) +-{ +- int pad; +- int detected_mode; +- unsigned long mem_req; +- +- if (!MACH_IS_ATARI) +- return -ENXIO; +- +- do { +-#ifdef ATAFB_EXT +- if (external_addr) { +- fbhw = &ext_switch; +- atafb_ops.fb_setcolreg = &ext_setcolreg; +- break; +- } +-#endif +-#ifdef ATAFB_TT +- if (ATARIHW_PRESENT(TT_SHIFTER)) { +- fbhw = &tt_switch; +- atafb_ops.fb_setcolreg = &tt_setcolreg; +- break; +- } +-#endif +-#ifdef ATAFB_FALCON +- if (ATARIHW_PRESENT(VIDEL_SHIFTER)) { +- fbhw = &falcon_switch; +- atafb_ops.fb_setcolreg = &falcon_setcolreg; +- request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO, +- "framebuffer/modeswitch", falcon_vbl_switcher); +- break; +- } +-#endif +-#ifdef ATAFB_STE +- if (ATARIHW_PRESENT(STND_SHIFTER) || +- ATARIHW_PRESENT(EXTD_SHIFTER)) { +- fbhw = &st_switch; +- atafb_ops.fb_setcolreg = &stste_setcolreg; +- break; +- } +- fbhw = &st_switch; +- atafb_ops.fb_setcolreg = &stste_setcolreg; +- printk("Cannot determine video hardware; defaulting to ST(e)\n"); +-#else /* ATAFB_STE */ +- /* no default driver included */ +- /* Nobody will ever see this message :-) */ +- panic("Cannot initialize video hardware"); +-#endif +- } while (0); +- +- /* Multisync monitor capabilities */ +- /* Atari-TOS defaults if no boot option present */ +- if (fb_info.monspecs.hfmin == 0) { +- fb_info.monspecs.hfmin = 31000; +- fb_info.monspecs.hfmax = 32000; +- fb_info.monspecs.vfmin = 58; +- fb_info.monspecs.vfmax = 62; +- } +- +- detected_mode = fbhw->detect(); +- check_default_par(detected_mode); +-#ifdef ATAFB_EXT +- if (!external_addr) { +-#endif /* ATAFB_EXT */ +- mem_req = default_mem_req + ovsc_offset + ovsc_addlen; +- mem_req = PAGE_ALIGN(mem_req) + PAGE_SIZE; +- screen_base = atari_stram_alloc(mem_req, "atafb"); +- if (!screen_base) +- panic("Cannot allocate screen memory"); +- memset(screen_base, 0, mem_req); +- pad = -(unsigned long)screen_base & (PAGE_SIZE-1); +- screen_base+=pad; +- real_screen_base=screen_base+ovsc_offset; +- screen_len = (mem_req - pad - ovsc_offset) & PAGE_MASK; +- st_ovsc_switch(); +- if (CPU_IS_040_OR_060) { +- /* On a '040+, the cache mode of video RAM must be set to +- * write-through also for internal video hardware! */ +- cache_push(virt_to_phys(screen_base), screen_len); +- kernel_set_cachemode(screen_base, screen_len, +- IOMAP_WRITETHROUGH); +- } +-#ifdef ATAFB_EXT +- } +- else { +- /* Map the video memory (physical address given) to somewhere +- * in the kernel address space. +- */ +- external_addr = +- ioremap_writethrough((unsigned long)external_addr, +- external_len); +- if (external_vgaiobase) +- external_vgaiobase = +- (unsigned long)ioremap(external_vgaiobase, 0x10000); +- screen_base = +- real_screen_base = external_addr; +- screen_len = external_len & PAGE_MASK; +- memset (screen_base, 0, external_len); +- } +-#endif /* ATAFB_EXT */ +- +- strcpy(fb_info.modename, "Atari Builtin "); +- fb_info.changevar = NULL; +- fb_info.fbops = &atafb_ops; +- fb_info.disp = &disp; +- fb_info.currcon = -1; +- fb_info.switch_con = &atafb_switch; +- fb_info.updatevar = &fb_update_var; +- fb_info.flags = FBINFO_FLAG_DEFAULT; +- do_fb_set_var(&atafb_predefined[default_par-1], 1); +- strcat(fb_info.modename, fb_var_names[default_par-1][0]); +- +- atafb_get_var(&disp.var, -1, &fb_info); +- atafb_set_disp(-1, &fb_info); +- do_install_cmap(0, &fb_info); +- +- if (register_framebuffer(&fb_info) < 0) { +-#ifdef ATAFB_EXT +- if (external_addr) { +- iounmap(external_addr); +- external_addr = NULL; +- } +- if (external_vgaiobase) { +- iounmap((void*)external_vgaiobase); +- external_vgaiobase = 0; +- } +-#endif +- return -EINVAL; +- } +- +- printk("Determined %dx%d, depth %d\n", +- disp.var.xres, disp.var.yres, disp.var.bits_per_pixel); +- if ((disp.var.xres != disp.var.xres_virtual) || +- (disp.var.yres != disp.var.yres_virtual)) +- printk(" virtual %dx%d\n", +- disp.var.xres_virtual, disp.var.yres_virtual); +- printk("fb%d: %s frame buffer device, using %dK of video memory\n", +- fb_info.node, fb_info.modename, screen_len>>10); +- +- /* TODO: This driver cannot be unloaded yet */ +- return 0; ++ default_mem_req = min_mem; + } + +- + #ifdef ATAFB_EXT + static void __init atafb_setup_ext(char *spec) + { +- int xres, xres_virtual, yres, depth, planes; ++ int xres, xres_virtual, yres, depth, planes; + unsigned long addr, len; + char *p; + +@@ -2848,27 +2842,31 @@ static void __init atafb_setup_ext(char + * + * Even xres_virtual is available, we neither support panning nor hw-scrolling! + */ +- if (!(p = strsep(&spec, ";")) || !*p) +- return; ++ p = strsep(&spec, ";"); ++ if (!p || !*p) ++ return; + xres_virtual = xres = simple_strtoul(p, NULL, 10); + if (xres <= 0) +- return; ++ return; + +- if (!(p = strsep(&spec, ";")) || !*p) +- return; ++ p = strsep(&spec, ";"); ++ if (!p || !*p) ++ return; + yres = simple_strtoul(p, NULL, 10); + if (yres <= 0) +- return; ++ return; + +- if (!(p = strsep(&spec, ";")) || !*p) +- return; ++ p = strsep(&spec, ";"); ++ if (!p || !*p) ++ return; + depth = simple_strtoul(p, NULL, 10); + if (depth != 1 && depth != 2 && depth != 4 && depth != 8 && +- depth != 16 && depth != 24) +- return; ++ depth != 16 && depth != 24) ++ return; + +- if (!(p = strsep(&spec, ";")) || !*p) +- return; ++ p = strsep(&spec, ";"); ++ if (!p || !*p) ++ return; + if (*p == 'i') + planes = FB_TYPE_INTERLEAVED_PLANES; + else if (*p == 'p') +@@ -2876,25 +2874,27 @@ static void __init atafb_setup_ext(char + else if (*p == 'n') + planes = FB_TYPE_PLANES; + else if (*p == 't') +- planes = -1; /* true color */ ++ planes = -1; /* true color */ + else + return; + +- +- if (!(p = strsep(&spec, ";")) || !*p) ++ p = strsep(&spec, ";"); ++ if (!p || !*p) + return; + addr = simple_strtoul(p, NULL, 0); + +- if (!(p = strsep(&spec, ";")) || !*p) +- len = xres*yres*depth/8; ++ p = strsep(&spec, ";"); ++ if (!p || !*p) ++ len = xres * yres * depth / 8; + else + len = simple_strtoul(p, NULL, 0); + +- if ((p = strsep(&spec, ";")) && *p) { +- external_vgaiobase=simple_strtoul(p, NULL, 0); +- } ++ p = strsep(&spec, ";"); ++ if (p && *p) ++ external_vgaiobase = simple_strtoul(p, NULL, 0); + +- if ((p = strsep(&spec, ";")) && *p) { ++ p = strsep(&spec, ";"); ++ if (p && *p) { + external_bitspercol = simple_strtoul(p, NULL, 0); + if (external_bitspercol > 8) + external_bitspercol = 8; +@@ -2902,59 +2902,61 @@ static void __init atafb_setup_ext(char + external_bitspercol = 1; + } + +- if ((p = strsep(&spec, ";")) && *p) { ++ p = strsep(&spec, ";"); ++ if (p && *p) { + if (!strcmp(p, "vga")) + external_card_type = IS_VGA; + if (!strcmp(p, "mv300")) + external_card_type = IS_MV300; + } + +- if ((p = strsep(&spec, ";")) && *p) { ++ p = strsep(&spec, ";"); ++ if (p && *p) { + xres_virtual = simple_strtoul(p, NULL, 10); + if (xres_virtual < xres) + xres_virtual = xres; +- if (xres_virtual*yres*depth/8 > len) +- len=xres_virtual*yres*depth/8; ++ if (xres_virtual * yres * depth / 8 > len) ++ len = xres_virtual * yres * depth / 8; + } + +- external_xres = xres; +- external_xres_virtual = xres_virtual; +- external_yres = yres; ++ external_xres = xres; ++ external_xres_virtual = xres_virtual; ++ external_yres = yres; + external_depth = depth; + external_pmode = planes; +- external_addr = (void *)addr; +- external_len = len; ++ external_addr = (void *)addr; ++ external_len = len; + +- if (external_card_type == IS_MV300) +- switch (external_depth) { +- case 1: +- MV300_reg = MV300_reg_1bit; +- break; +- case 4: +- MV300_reg = MV300_reg_4bit; +- break; +- case 8: +- MV300_reg = MV300_reg_8bit; +- break; +- } ++ if (external_card_type == IS_MV300) { ++ switch (external_depth) { ++ case 1: ++ MV300_reg = MV300_reg_1bit; ++ break; ++ case 4: ++ MV300_reg = MV300_reg_4bit; ++ break; ++ case 8: ++ MV300_reg = MV300_reg_8bit; ++ break; ++ } ++ } + } + #endif /* ATAFB_EXT */ + +- + static void __init atafb_setup_int(char *spec) + { + /* Format to config extended internal video hardware like OverScan: +- "internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>" +- Explanation: +- <xres>: x-resolution +- <yres>: y-resolution +- The following are only needed if you have an overscan which +- needs a black border: +- <xres_max>: max. length of a line in pixels your OverScan hardware would allow +- <yres_max>: max. number of lines your OverScan hardware would allow +- <offset>: Offset from physical beginning to visible beginning +- of screen in bytes +- */ ++ * "internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>" ++ * Explanation: ++ * <xres>: x-resolution ++ * <yres>: y-resolution ++ * The following are only needed if you have an overscan which ++ * needs a black border: ++ * <xres_max>: max. length of a line in pixels your OverScan hardware would allow ++ * <yres_max>: max. number of lines your OverScan hardware would allow ++ * <offset>: Offset from physical beginning to visible beginning ++ * of screen in bytes ++ */ + int xres; + char *p; + +@@ -2963,23 +2965,19 @@ static void __init atafb_setup_int(char + xres = simple_strtoul(p, NULL, 10); + if (!(p = strsep(&spec, ";")) || !*p) + return; +- sttt_xres=xres; +- tt_yres=st_yres=simple_strtoul(p, NULL, 10); +- if ((p=strsep(&spec, ";")) && *p) { +- sttt_xres_virtual=simple_strtoul(p, NULL, 10); +- } +- if ((p=strsep(&spec, ";")) && *p) { +- sttt_yres_virtual=simple_strtoul(p, NULL, 0); +- } +- if ((p=strsep(&spec, ";")) && *p) { +- ovsc_offset=simple_strtoul(p, NULL, 0); +- } ++ sttt_xres = xres; ++ tt_yres = st_yres = simple_strtoul(p, NULL, 10); ++ if ((p = strsep(&spec, ";")) && *p) ++ sttt_xres_virtual = simple_strtoul(p, NULL, 10); ++ if ((p = strsep(&spec, ";")) && *p) ++ sttt_yres_virtual = simple_strtoul(p, NULL, 0); ++ if ((p = strsep(&spec, ";")) && *p) ++ ovsc_offset = simple_strtoul(p, NULL, 0); + + if (ovsc_offset || (sttt_yres_virtual != st_yres)) +- use_hwscroll=0; ++ use_hwscroll = 0; + } + +- + #ifdef ATAFB_FALCON + static void __init atafb_setup_mcap(char *spec) + { +@@ -3018,7 +3016,6 @@ static void __init atafb_setup_mcap(char + } + #endif /* ATAFB_FALCON */ + +- + static void __init atafb_setup_user(char *spec) + { + /* Format of user defined video mode is: <xres>;<yres>;<depth> +@@ -3026,81 +3023,257 @@ static void __init atafb_setup_user(char + char *p; + int xres, yres, depth, temp; + +- if (!(p = strsep(&spec, ";")) || !*p) ++ p = strsep(&spec, ";"); ++ if (!p || !*p) + return; + xres = simple_strtoul(p, NULL, 10); +- if (!(p = strsep(&spec, ";")) || !*p) ++ p = strsep(&spec, ";"); ++ if (!p || !*p) + return; + yres = simple_strtoul(p, NULL, 10); +- if (!(p = strsep(&spec, "")) || !*p) ++ p = strsep(&spec, ""); ++ if (!p || !*p) + return; + depth = simple_strtoul(p, NULL, 10); +- if ((temp=get_video_mode("user0"))) { +- default_par=temp; +- atafb_predefined[default_par-1].xres = xres; +- atafb_predefined[default_par-1].yres = yres; +- atafb_predefined[default_par-1].bits_per_pixel = depth; ++ temp = get_video_mode("user0"); ++ if (temp) { ++ default_par = temp; ++ atafb_predefined[default_par - 1].xres = xres; ++ atafb_predefined[default_par - 1].yres = yres; ++ atafb_predefined[default_par - 1].bits_per_pixel = depth; + } + } + +-int __init atafb_setup( char *options ) ++int __init atafb_setup(char *options) + { +- char *this_opt; +- int temp; +- +- fb_info.fontname[0] = '\0'; ++ char *this_opt; ++ int temp; + +- if (!options || !*options) ++ if (!options || !*options) + return 0; +- +- while ((this_opt = strsep(&options, ",")) != NULL) { +- if (!*this_opt) continue; +- if ((temp=get_video_mode(this_opt))) +- default_par=temp; +- else if (! strcmp(this_opt, "inverse")) +- inverse=1; +- else if (!strncmp(this_opt, "font:", 5)) +- strcpy(fb_info.fontname, this_opt+5); +- else if (! strncmp(this_opt, "hwscroll_",9)) { +- hwscroll=simple_strtoul(this_opt+9, NULL, 10); +- if (hwscroll < 0) +- hwscroll = 0; +- if (hwscroll > 200) +- hwscroll = 200; +- } ++ ++ while ((this_opt = strsep(&options, ",")) != NULL) { ++ if (!*this_opt) ++ continue; ++ if ((temp = get_video_mode(this_opt))) { ++ default_par = temp; ++ mode_option = this_opt; ++ } else if (!strcmp(this_opt, "inverse")) ++ inverse = 1; ++ else if (!strncmp(this_opt, "hwscroll_", 9)) { ++ hwscroll = simple_strtoul(this_opt + 9, NULL, 10); ++ if (hwscroll < 0) ++ hwscroll = 0; ++ if (hwscroll > 200) ++ hwscroll = 200; ++ } + #ifdef ATAFB_EXT +- else if (!strcmp(this_opt,"mv300")) { +- external_bitspercol = 8; +- external_card_type = IS_MV300; ++ else if (!strcmp(this_opt, "mv300")) { ++ external_bitspercol = 8; ++ external_card_type = IS_MV300; ++ } else if (!strncmp(this_opt, "external:", 9)) ++ atafb_setup_ext(this_opt + 9); ++#endif ++ else if (!strncmp(this_opt, "internal:", 9)) ++ atafb_setup_int(this_opt + 9); ++#ifdef ATAFB_FALCON ++ else if (!strncmp(this_opt, "eclock:", 7)) { ++ fext.f = simple_strtoul(this_opt + 7, NULL, 10); ++ /* external pixelclock in kHz --> ps */ ++ fext.t = 1000000000 / fext.f; ++ fext.f *= 1000; ++ } else if (!strncmp(this_opt, "monitorcap:", 11)) ++ atafb_setup_mcap(this_opt + 11); ++#endif ++ else if (!strcmp(this_opt, "keep")) ++ DontCalcRes = 1; ++ else if (!strncmp(this_opt, "R", 1)) ++ atafb_setup_user(this_opt + 1); + } +- else if (!strncmp(this_opt,"external:",9)) +- atafb_setup_ext(this_opt+9); ++ return 0; ++} ++ ++int __init atafb_init(void) ++{ ++ int pad; ++ int detected_mode; ++ unsigned int defmode = 0; ++ unsigned long mem_req; ++ ++#ifndef MODULE ++ char *option = NULL; ++ ++ if (fb_get_options("atafb", &option)) ++ return -ENODEV; ++ atafb_setup(option); ++#endif ++ printk("atafb_init: start\n"); ++ ++ if (!MACH_IS_ATARI) ++ return -ENXIO; ++ ++ do { ++#ifdef ATAFB_EXT ++ if (external_addr) { ++ printk("atafb_init: initializing external hw\n"); ++ fbhw = &ext_switch; ++ atafb_ops.fb_setcolreg = &ext_setcolreg; ++ defmode = DEFMODE_EXT; ++ break; ++ } ++#endif ++#ifdef ATAFB_TT ++ if (ATARIHW_PRESENT(TT_SHIFTER)) { ++ printk("atafb_init: initializing TT hw\n"); ++ fbhw = &tt_switch; ++ atafb_ops.fb_setcolreg = &tt_setcolreg; ++ defmode = DEFMODE_TT; ++ break; ++ } + #endif +- else if (!strncmp(this_opt,"internal:",9)) +- atafb_setup_int(this_opt+9); + #ifdef ATAFB_FALCON +- else if (!strncmp(this_opt, "eclock:", 7)) { +- fext.f = simple_strtoul(this_opt+7, NULL, 10); +- /* external pixelclock in kHz --> ps */ +- fext.t = 1000000000/fext.f; +- fext.f *= 1000; +- } +- else if (!strncmp(this_opt, "monitorcap:", 11)) +- atafb_setup_mcap(this_opt+11); +-#endif +- else if (!strcmp(this_opt, "keep")) +- DontCalcRes = 1; +- else if (!strncmp(this_opt, "R", 1)) +- atafb_setup_user(this_opt+1); +- } +- return 0; ++ if (ATARIHW_PRESENT(VIDEL_SHIFTER)) { ++ printk("atafb_init: initializing Falcon hw\n"); ++ fbhw = &falcon_switch; ++ atafb_ops.fb_setcolreg = &falcon_setcolreg; ++ request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO, ++ "framebuffer/modeswitch", falcon_vbl_switcher); ++ defmode = DEFMODE_F30; ++ break; ++ } ++#endif ++#ifdef ATAFB_STE ++ if (ATARIHW_PRESENT(STND_SHIFTER) || ++ ATARIHW_PRESENT(EXTD_SHIFTER)) { ++ printk("atafb_init: initializing ST/E hw\n"); ++ fbhw = &st_switch; ++ atafb_ops.fb_setcolreg = &stste_setcolreg; ++ defmode = DEFMODE_STE; ++ break; ++ } ++ fbhw = &st_switch; ++ atafb_ops.fb_setcolreg = &stste_setcolreg; ++ printk("Cannot determine video hardware; defaulting to ST(e)\n"); ++#else /* ATAFB_STE */ ++ /* no default driver included */ ++ /* Nobody will ever see this message :-) */ ++ panic("Cannot initialize video hardware"); ++#endif ++ } while (0); ++ ++ /* Multisync monitor capabilities */ ++ /* Atari-TOS defaults if no boot option present */ ++ if (fb_info.monspecs.hfmin == 0) { ++ fb_info.monspecs.hfmin = 31000; ++ fb_info.monspecs.hfmax = 32000; ++ fb_info.monspecs.vfmin = 58; ++ fb_info.monspecs.vfmax = 62; ++ } ++ ++ detected_mode = fbhw->detect(); ++ check_default_par(detected_mode); ++#ifdef ATAFB_EXT ++ if (!external_addr) { ++#endif /* ATAFB_EXT */ ++ mem_req = default_mem_req + ovsc_offset + ovsc_addlen; ++ mem_req = PAGE_ALIGN(mem_req) + PAGE_SIZE; ++ screen_base = atari_stram_alloc(mem_req, "atafb"); ++ if (!screen_base) ++ panic("Cannot allocate screen memory"); ++ memset(screen_base, 0, mem_req); ++ pad = -(unsigned long)screen_base & (PAGE_SIZE - 1); ++ screen_base += pad; ++ real_screen_base = screen_base + ovsc_offset; ++ screen_len = (mem_req - pad - ovsc_offset) & PAGE_MASK; ++ st_ovsc_switch(); ++ if (CPU_IS_040_OR_060) { ++ /* On a '040+, the cache mode of video RAM must be set to ++ * write-through also for internal video hardware! */ ++ cache_push(virt_to_phys(screen_base), screen_len); ++ kernel_set_cachemode(screen_base, screen_len, ++ IOMAP_WRITETHROUGH); ++ } ++ printk("atafb: screen_base %p real_screen_base %p screen_len %d\n", ++ screen_base, real_screen_base, screen_len); ++#ifdef ATAFB_EXT ++ } else { ++ /* Map the video memory (physical address given) to somewhere ++ * in the kernel address space. ++ */ ++ external_addr = ioremap_writethrough((unsigned long)external_addr, ++ external_len); ++ if (external_vgaiobase) ++ external_vgaiobase = ++ (unsigned long)ioremap(external_vgaiobase, 0x10000); ++ screen_base = ++ real_screen_base = external_addr; ++ screen_len = external_len & PAGE_MASK; ++ memset (screen_base, 0, external_len); ++ } ++#endif /* ATAFB_EXT */ ++ ++// strcpy(fb_info.mode->name, "Atari Builtin "); ++ fb_info.fbops = &atafb_ops; ++ // try to set default (detected; requested) var ++ do_fb_set_var(&atafb_predefined[default_par - 1], 1); ++ // reads hw state into current par, which may not be sane yet ++ ata_get_par(¤t_par); ++ fb_info.par = ¤t_par; ++ // tries to read from HW which may not be initialized yet ++ // so set sane var first, then call atafb_set_par ++ atafb_get_var(&fb_info.var, &fb_info); ++ fb_info.flags = FBINFO_FLAG_DEFAULT; ++ ++ if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, atafb_modedb, ++ NUM_TOTAL_MODES, &atafb_modedb[defmode], ++ fb_info.var.bits_per_pixel)) { ++ return -EINVAL; ++ } ++ ++ atafb_set_disp(&fb_info); ++ ++ fb_alloc_cmap(&(fb_info.cmap), 1 << fb_info.var.bits_per_pixel, 0); ++ ++ ++ printk("Determined %dx%d, depth %d\n", ++ fb_info.var.xres, fb_info.var.yres, fb_info.var.bits_per_pixel); ++ if ((fb_info.var.xres != fb_info.var.xres_virtual) || ++ (fb_info.var.yres != fb_info.var.yres_virtual)) ++ printk(" virtual %dx%d\n", fb_info.var.xres_virtual, ++ fb_info.var.yres_virtual); ++ ++ if (register_framebuffer(&fb_info) < 0) { ++#ifdef ATAFB_EXT ++ if (external_addr) { ++ iounmap(external_addr); ++ external_addr = NULL; ++ } ++ if (external_vgaiobase) { ++ iounmap((void*)external_vgaiobase); ++ external_vgaiobase = 0; ++ } ++#endif ++ return -EINVAL; ++ } ++ ++ // FIXME: mode needs setting! ++ //printk("fb%d: %s frame buffer device, using %dK of video memory\n", ++ // fb_info.node, fb_info.mode->name, screen_len>>10); ++ printk("fb%d: frame buffer device, using %dK of video memory\n", ++ fb_info.node, screen_len >> 10); ++ ++ /* TODO: This driver cannot be unloaded yet */ ++ return 0; + } + ++module_init(atafb_init); ++ + #ifdef MODULE + MODULE_LICENSE("GPL"); + +-int init_module(void) ++int cleanup_module(void) + { +- return atafb_init(); ++ unregister_framebuffer(&fb_info); ++ return atafb_deinit(); + } + #endif /* MODULE */ +--- /dev/null ++++ linux-m68k-2.6.21/drivers/video/atafb.h +@@ -0,0 +1,36 @@ ++#ifndef _VIDEO_ATAFB_H ++#define _VIDEO_ATAFB_H ++ ++void atafb_mfb_copyarea(struct fb_info *info, u_long next_line, int sy, int sx, int dy, ++ int dx, int height, int width); ++void atafb_mfb_fillrect(struct fb_info *info, u_long next_line, u32 color, ++ int sy, int sx, int height, int width); ++void atafb_mfb_linefill(struct fb_info *info, u_long next_line, ++ int dy, int dx, u32 width, ++ const u8 *data, u32 bgcolor, u32 fgcolor); ++ ++void atafb_iplan2p2_copyarea(struct fb_info *info, u_long next_line, int sy, int sx, int dy, ++ int dx, int height, int width); ++void atafb_iplan2p2_fillrect(struct fb_info *info, u_long next_line, u32 color, ++ int sy, int sx, int height, int width); ++void atafb_iplan2p2_linefill(struct fb_info *info, u_long next_line, ++ int dy, int dx, u32 width, ++ const u8 *data, u32 bgcolor, u32 fgcolor); ++ ++void atafb_iplan2p4_copyarea(struct fb_info *info, u_long next_line, int sy, int sx, int dy, ++ int dx, int height, int width); ++void atafb_iplan2p4_fillrect(struct fb_info *info, u_long next_line, u32 color, ++ int sy, int sx, int height, int width); ++void atafb_iplan2p4_linefill(struct fb_info *info, u_long next_line, ++ int dy, int dx, u32 width, ++ const u8 *data, u32 bgcolor, u32 fgcolor); ++ ++void atafb_iplan2p8_copyarea(struct fb_info *info, u_long next_line, int sy, int sx, int dy, ++ int dx, int height, int width); ++void atafb_iplan2p8_fillrect(struct fb_info *info, u_long next_line, u32 color, ++ int sy, int sx, int height, int width); ++void atafb_iplan2p8_linefill(struct fb_info *info, u_long next_line, ++ int dy, int dx, u32 width, ++ const u8 *data, u32 bgcolor, u32 fgcolor); ++ ++#endif /* _VIDEO_ATAFB_H */ +--- /dev/null ++++ linux-m68k-2.6.21/drivers/video/atafb_iplan2p2.c +@@ -0,0 +1,293 @@ ++/* ++ * linux/drivers/video/iplan2p2.c -- Low level frame buffer operations for ++ * interleaved bitplanes à la Atari (2 ++ * planes, 2 bytes interleave) ++ * ++ * Created 5 Apr 1997 by Geert Uytterhoeven ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ */ ++ ++#include <linux/module.h> ++#include <linux/string.h> ++#include <linux/fb.h> ++ ++#include <asm/setup.h> ++ ++#include "atafb.h" ++ ++#define BPL 2 ++#include "atafb_utils.h" ++ ++void atafb_iplan2p2_copyarea(struct fb_info *info, u_long next_line, ++ int sy, int sx, int dy, int dx, ++ int height, int width) ++{ ++ /* bmove() has to distinguish two major cases: If both, source and ++ * destination, start at even addresses or both are at odd ++ * addresses, just the first odd and last even column (if present) ++ * require special treatment (memmove_col()). The rest between ++ * then can be copied by normal operations, because all adjacent ++ * bytes are affected and are to be stored in the same order. ++ * The pathological case is when the move should go from an odd ++ * address to an even or vice versa. Since the bytes in the plane ++ * words must be assembled in new order, it seems wisest to make ++ * all movements by memmove_col(). ++ */ ++ ++ u8 *src, *dst; ++ u32 *s, *d; ++ int w, l , i, j; ++ u_int colsize; ++ u_int upwards = (dy < sy) || (dy == sy && dx < sx); ++ ++ colsize = height; ++ if (!((sx ^ dx) & 15)) { ++ /* odd->odd or even->even */ ++ ++ if (upwards) { ++ src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL); ++ dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL); ++ if (sx & 15) { ++ memmove32_col(dst, src, 0xff00ff, height, next_line - BPL * 2); ++ src += BPL * 2; ++ dst += BPL * 2; ++ width -= 8; ++ } ++ w = width >> 4; ++ if (w) { ++ s = (u32 *)src; ++ d = (u32 *)dst; ++ w *= BPL / 2; ++ l = next_line - w * 4; ++ for (j = height; j > 0; j--) { ++ for (i = w; i > 0; i--) ++ *d++ = *s++; ++ s = (u32 *)((u8 *)s + l); ++ d = (u32 *)((u8 *)d + l); ++ } ++ } ++ if (width & 15) ++ memmove32_col(dst + width / (8 / BPL), src + width / (8 / BPL), ++ 0xff00ff00, height, next_line - BPL * 2); ++ } else { ++ src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL); ++ dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL); ++ ++ if ((sx + width) & 15) { ++ src -= BPL * 2; ++ dst -= BPL * 2; ++ memmove32_col(dst, src, 0xff00ff00, colsize, -next_line - BPL * 2); ++ width -= 8; ++ } ++ w = width >> 4; ++ if (w) { ++ s = (u32 *)src; ++ d = (u32 *)dst; ++ w *= BPL / 2; ++ l = next_line - w * 4; ++ for (j = height; j > 0; j--) { ++ for (i = w; i > 0; i--) ++ *--d = *--s; ++ s = (u32 *)((u8 *)s - l); ++ d = (u32 *)((u8 *)d - l); ++ } ++ } ++ if (sx & 15) ++ memmove32_col(dst - (width - 16) / (8 / BPL), ++ src - (width - 16) / (8 / BPL), ++ 0xff00ff, colsize, -next_line - BPL * 2); ++ } ++ } else { ++ /* odd->even or even->odd */ ++ if (upwards) { ++ u32 *src32, *dst32; ++ u32 pval[4], v, v1, mask; ++ int i, j, w, f; ++ ++ src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL); ++ dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL); ++ ++ mask = 0xff00ff00; ++ f = 0; ++ w = width; ++ if (sx & 15) { ++ f = 1; ++ w += 8; ++ } ++ if ((sx + width) & 15) ++ f |= 2; ++ w >>= 4; ++ for (i = height; i; i--) { ++ src32 = (u32 *)src; ++ dst32 = (u32 *)dst; ++ ++ if (f & 1) { ++ pval[0] = (*src32++ << 8) & mask; ++ } else { ++ pval[0] = dst32[0] & mask; ++ } ++ ++ for (j = w; j > 0; j--) { ++ v = *src32++; ++ v1 = v & mask; ++ *dst32++ = pval[0] | (v1 >> 8); ++ pval[0] = (v ^ v1) << 8; ++ } ++ ++ if (f & 2) { ++ dst32[0] = (dst32[0] & mask) | pval[0]; ++ } ++ ++ src += next_line; ++ dst += next_line; ++ } ++ } else { ++ u32 *src32, *dst32; ++ u32 pval[4], v, v1, mask; ++ int i, j, w, f; ++ ++ src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL); ++ dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL); ++ ++ mask = 0xff00ff; ++ f = 0; ++ w = width; ++ if ((dx + width) & 15) ++ f = 1; ++ if (sx & 15) { ++ f |= 2; ++ w += 8; ++ } ++ w >>= 4; ++ for (i = height; i; i--) { ++ src32 = (u32 *)src; ++ dst32 = (u32 *)dst; ++ ++ if (f & 1) { ++ pval[0] = dst32[-1] & mask; ++ } else { ++ pval[0] = (*--src32 >> 8) & mask; ++ } ++ ++ for (j = w; j > 0; j--) { ++ v = *--src32; ++ v1 = v & mask; ++ *--dst32 = pval[0] | (v1 << 8); ++ pval[0] = (v ^ v1) >> 8; ++ } ++ ++ if (!(f & 2)) { ++ dst32[-1] = (dst32[-1] & mask) | pval[0]; ++ } ++ ++ src -= next_line; ++ dst -= next_line; ++ } ++ } ++ } ++} ++ ++void atafb_iplan2p2_fillrect(struct fb_info *info, u_long next_line, u32 color, ++ int sy, int sx, int height, int width) ++{ ++ u32 *dest; ++ int rows, i; ++ u32 cval[4]; ++ ++ dest = (u32 *)(info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL)); ++ if (sx & 15) { ++ u8 *dest8 = (u8 *)dest + 1; ++ ++ expand8_col2mask(color, cval); ++ ++ for (i = height; i; i--) { ++ fill8_col(dest8, cval); ++ dest8 += next_line; ++ } ++ dest += BPL / 2; ++ width -= 8; ++ } ++ ++ expand16_col2mask(color, cval); ++ rows = width >> 4; ++ if (rows) { ++ u32 *d = dest; ++ u32 off = next_line - rows * BPL * 2; ++ for (i = height; i; i--) { ++ d = fill16_col(d, rows, cval); ++ d = (u32 *)((long)d + off); ++ } ++ dest += rows * BPL / 2; ++ width &= 15; ++ } ++ ++ if (width) { ++ u8 *dest8 = (u8 *)dest; ++ ++ expand8_col2mask(color, cval); ++ ++ for (i = height; i; i--) { ++ fill8_col(dest8, cval); ++ dest8 += next_line; ++ } ++ } ++} ++ ++void atafb_iplan2p2_linefill(struct fb_info *info, u_long next_line, ++ int dy, int dx, u32 width, ++ const u8 *data, u32 bgcolor, u32 fgcolor) ++{ ++ u32 *dest; ++ const u16 *data16; ++ int rows; ++ u32 fgm[4], bgm[4], m; ++ ++ dest = (u32 *)(info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL)); ++ if (dx & 15) { ++ fill8_2col((u8 *)dest + 1, fgcolor, bgcolor, *data++); ++ dest += BPL / 2; ++ width -= 8; ++ } ++ ++ if (width >= 16) { ++ data16 = (const u16 *)data; ++ expand16_2col2mask(fgcolor, bgcolor, fgm, bgm); ++ ++ for (rows = width / 16; rows; rows--) { ++ u16 d = *data16++; ++ m = d | ((u32)d << 16); ++ *dest++ = (m & fgm[0]) ^ bgm[0]; ++ } ++ ++ data = (const u8 *)data16; ++ width &= 15; ++ } ++ ++ if (width) ++ fill8_2col((u8 *)dest, fgcolor, bgcolor, *data); ++} ++ ++#ifdef MODULE ++MODULE_LICENSE("GPL"); ++ ++int init_module(void) ++{ ++ return 0; ++} ++ ++void cleanup_module(void) ++{ ++} ++#endif /* MODULE */ ++ ++ ++ /* ++ * Visible symbols for modules ++ */ ++ ++EXPORT_SYMBOL(atafb_iplan2p2_copyarea); ++EXPORT_SYMBOL(atafb_iplan2p2_fillrect); ++EXPORT_SYMBOL(atafb_iplan2p2_linefill); +--- /dev/null ++++ linux-m68k-2.6.21/drivers/video/atafb_iplan2p4.c +@@ -0,0 +1,308 @@ ++/* ++ * linux/drivers/video/iplan2p4.c -- Low level frame buffer operations for ++ * interleaved bitplanes à la Atari (4 ++ * planes, 2 bytes interleave) ++ * ++ * Created 5 Apr 1997 by Geert Uytterhoeven ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ */ ++ ++#include <linux/module.h> ++#include <linux/string.h> ++#include <linux/fb.h> ++ ++#include <asm/setup.h> ++ ++#include "atafb.h" ++ ++#define BPL 4 ++#include "atafb_utils.h" ++ ++void atafb_iplan2p4_copyarea(struct fb_info *info, u_long next_line, ++ int sy, int sx, int dy, int dx, ++ int height, int width) ++{ ++ /* bmove() has to distinguish two major cases: If both, source and ++ * destination, start at even addresses or both are at odd ++ * addresses, just the first odd and last even column (if present) ++ * require special treatment (memmove_col()). The rest between ++ * then can be copied by normal operations, because all adjacent ++ * bytes are affected and are to be stored in the same order. ++ * The pathological case is when the move should go from an odd ++ * address to an even or vice versa. Since the bytes in the plane ++ * words must be assembled in new order, it seems wisest to make ++ * all movements by memmove_col(). ++ */ ++ ++ u8 *src, *dst; ++ u32 *s, *d; ++ int w, l , i, j; ++ u_int colsize; ++ u_int upwards = (dy < sy) || (dy == sy && dx < sx); ++ ++ colsize = height; ++ if (!((sx ^ dx) & 15)) { ++ /* odd->odd or even->even */ ++ ++ if (upwards) { ++ src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL); ++ dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL); ++ if (sx & 15) { ++ memmove32_col(dst, src, 0xff00ff, height, next_line - BPL * 2); ++ src += BPL * 2; ++ dst += BPL * 2; ++ width -= 8; ++ } ++ w = width >> 4; ++ if (w) { ++ s = (u32 *)src; ++ d = (u32 *)dst; ++ w *= BPL / 2; ++ l = next_line - w * 4; ++ for (j = height; j > 0; j--) { ++ for (i = w; i > 0; i--) ++ *d++ = *s++; ++ s = (u32 *)((u8 *)s + l); ++ d = (u32 *)((u8 *)d + l); ++ } ++ } ++ if (width & 15) ++ memmove32_col(dst + width / (8 / BPL), src + width / (8 / BPL), ++ 0xff00ff00, height, next_line - BPL * 2); ++ } else { ++ src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL); ++ dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL); ++ ++ if ((sx + width) & 15) { ++ src -= BPL * 2; ++ dst -= BPL * 2; ++ memmove32_col(dst, src, 0xff00ff00, colsize, -next_line - BPL * 2); ++ width -= 8; ++ } ++ w = width >> 4; ++ if (w) { ++ s = (u32 *)src; ++ d = (u32 *)dst; ++ w *= BPL / 2; ++ l = next_line - w * 4; ++ for (j = height; j > 0; j--) { ++ for (i = w; i > 0; i--) ++ *--d = *--s; ++ s = (u32 *)((u8 *)s - l); ++ d = (u32 *)((u8 *)d - l); ++ } ++ } ++ if (sx & 15) ++ memmove32_col(dst - (width - 16) / (8 / BPL), ++ src - (width - 16) / (8 / BPL), ++ 0xff00ff, colsize, -next_line - BPL * 2); ++ } ++ } else { ++ /* odd->even or even->odd */ ++ if (upwards) { ++ u32 *src32, *dst32; ++ u32 pval[4], v, v1, mask; ++ int i, j, w, f; ++ ++ src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL); ++ dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL); ++ ++ mask = 0xff00ff00; ++ f = 0; ++ w = width; ++ if (sx & 15) { ++ f = 1; ++ w += 8; ++ } ++ if ((sx + width) & 15) ++ f |= 2; ++ w >>= 4; ++ for (i = height; i; i--) { ++ src32 = (u32 *)src; ++ dst32 = (u32 *)dst; ++ ++ if (f & 1) { ++ pval[0] = (*src32++ << 8) & mask; ++ pval[1] = (*src32++ << 8) & mask; ++ } else { ++ pval[0] = dst32[0] & mask; ++ pval[1] = dst32[1] & mask; ++ } ++ ++ for (j = w; j > 0; j--) { ++ v = *src32++; ++ v1 = v & mask; ++ *dst32++ = pval[0] | (v1 >> 8); ++ pval[0] = (v ^ v1) << 8; ++ v = *src32++; ++ v1 = v & mask; ++ *dst32++ = pval[1] | (v1 >> 8); ++ pval[1] = (v ^ v1) << 8; ++ } ++ ++ if (f & 2) { ++ dst32[0] = (dst32[0] & mask) | pval[0]; ++ dst32[1] = (dst32[1] & mask) | pval[1]; ++ } ++ ++ src += next_line; ++ dst += next_line; ++ } ++ } else { ++ u32 *src32, *dst32; ++ u32 pval[4], v, v1, mask; ++ int i, j, w, f; ++ ++ src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL); ++ dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL); ++ ++ mask = 0xff00ff; ++ f = 0; ++ w = width; ++ if ((dx + width) & 15) ++ f = 1; ++ if (sx & 15) { ++ f |= 2; ++ w += 8; ++ } ++ w >>= 4; ++ for (i = height; i; i--) { ++ src32 = (u32 *)src; ++ dst32 = (u32 *)dst; ++ ++ if (f & 1) { ++ pval[0] = dst32[-1] & mask; ++ pval[1] = dst32[-2] & mask; ++ } else { ++ pval[0] = (*--src32 >> 8) & mask; ++ pval[1] = (*--src32 >> 8) & mask; ++ } ++ ++ for (j = w; j > 0; j--) { ++ v = *--src32; ++ v1 = v & mask; ++ *--dst32 = pval[0] | (v1 << 8); ++ pval[0] = (v ^ v1) >> 8; ++ v = *--src32; ++ v1 = v & mask; ++ *--dst32 = pval[1] | (v1 << 8); ++ pval[1] = (v ^ v1) >> 8; ++ } ++ ++ if (!(f & 2)) { ++ dst32[-1] = (dst32[-1] & mask) | pval[0]; ++ dst32[-2] = (dst32[-2] & mask) | pval[1]; ++ } ++ ++ src -= next_line; ++ dst -= next_line; ++ } ++ } ++ } ++} ++ ++void atafb_iplan2p4_fillrect(struct fb_info *info, u_long next_line, u32 color, ++ int sy, int sx, int height, int width) ++{ ++ u32 *dest; ++ int rows, i; ++ u32 cval[4]; ++ ++ dest = (u32 *)(info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL)); ++ if (sx & 15) { ++ u8 *dest8 = (u8 *)dest + 1; ++ ++ expand8_col2mask(color, cval); ++ ++ for (i = height; i; i--) { ++ fill8_col(dest8, cval); ++ dest8 += next_line; ++ } ++ dest += BPL / 2; ++ width -= 8; ++ } ++ ++ expand16_col2mask(color, cval); ++ rows = width >> 4; ++ if (rows) { ++ u32 *d = dest; ++ u32 off = next_line - rows * BPL * 2; ++ for (i = height; i; i--) { ++ d = fill16_col(d, rows, cval); ++ d = (u32 *)((long)d + off); ++ } ++ dest += rows * BPL / 2; ++ width &= 15; ++ } ++ ++ if (width) { ++ u8 *dest8 = (u8 *)dest; ++ ++ expand8_col2mask(color, cval); ++ ++ for (i = height; i; i--) { ++ fill8_col(dest8, cval); ++ dest8 += next_line; ++ } ++ } ++} ++ ++void atafb_iplan2p4_linefill(struct fb_info *info, u_long next_line, ++ int dy, int dx, u32 width, ++ const u8 *data, u32 bgcolor, u32 fgcolor) ++{ ++ u32 *dest; ++ const u16 *data16; ++ int rows; ++ u32 fgm[4], bgm[4], m; ++ ++ dest = (u32 *)(info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL)); ++ if (dx & 15) { ++ fill8_2col((u8 *)dest + 1, fgcolor, bgcolor, *data++); ++ dest += BPL / 2; ++ width -= 8; ++ } ++ ++ if (width >= 16) { ++ data16 = (const u16 *)data; ++ expand16_2col2mask(fgcolor, bgcolor, fgm, bgm); ++ ++ for (rows = width / 16; rows; rows--) { ++ u16 d = *data16++; ++ m = d | ((u32)d << 16); ++ *dest++ = (m & fgm[0]) ^ bgm[0]; ++ *dest++ = (m & fgm[1]) ^ bgm[1]; ++ } ++ ++ data = (const u8 *)data16; ++ width &= 15; ++ } ++ ++ if (width) ++ fill8_2col((u8 *)dest, fgcolor, bgcolor, *data); ++} ++ ++#ifdef MODULE ++MODULE_LICENSE("GPL"); ++ ++int init_module(void) ++{ ++ return 0; ++} ++ ++void cleanup_module(void) ++{ ++} ++#endif /* MODULE */ ++ ++ ++ /* ++ * Visible symbols for modules ++ */ ++ ++EXPORT_SYMBOL(atafb_iplan2p4_copyarea); ++EXPORT_SYMBOL(atafb_iplan2p4_fillrect); ++EXPORT_SYMBOL(atafb_iplan2p4_linefill); +--- /dev/null ++++ linux-m68k-2.6.21/drivers/video/atafb_iplan2p8.c +@@ -0,0 +1,345 @@ ++/* ++ * linux/drivers/video/iplan2p8.c -- Low level frame buffer operations for ++ * interleaved bitplanes à la Atari (8 ++ * planes, 2 bytes interleave) ++ * ++ * Created 5 Apr 1997 by Geert Uytterhoeven ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ */ ++ ++#include <linux/module.h> ++#include <linux/string.h> ++#include <linux/fb.h> ++ ++#include <asm/setup.h> ++ ++#include "atafb.h" ++ ++#define BPL 8 ++#include "atafb_utils.h" ++ ++ ++/* Copies a 8 plane column from 's', height 'h', to 'd'. */ ++ ++/* This expands a 8 bit color into two longs for two movepl (8 plane) ++ * operations. ++ */ ++ ++void atafb_iplan2p8_copyarea(struct fb_info *info, u_long next_line, ++ int sy, int sx, int dy, int dx, ++ int height, int width) ++{ ++ /* bmove() has to distinguish two major cases: If both, source and ++ * destination, start at even addresses or both are at odd ++ * addresses, just the first odd and last even column (if present) ++ * require special treatment (memmove_col()). The rest between ++ * then can be copied by normal operations, because all adjacent ++ * bytes are affected and are to be stored in the same order. ++ * The pathological case is when the move should go from an odd ++ * address to an even or vice versa. Since the bytes in the plane ++ * words must be assembled in new order, it seems wisest to make ++ * all movements by memmove_col(). ++ */ ++ ++ u8 *src, *dst; ++ u32 *s, *d; ++ int w, l , i, j; ++ u_int colsize; ++ u_int upwards = (dy < sy) || (dy == sy && dx < sx); ++ ++ colsize = height; ++ if (!((sx ^ dx) & 15)) { ++ /* odd->odd or even->even */ ++ ++ if (upwards) { ++ src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL); ++ dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL); ++ if (sx & 15) { ++ memmove32_col(dst, src, 0xff00ff, height, next_line - BPL * 2); ++ src += BPL * 2; ++ dst += BPL * 2; ++ width -= 8; ++ } ++ w = width >> 4; ++ if (w) { ++ s = (u32 *)src; ++ d = (u32 *)dst; ++ w *= BPL / 2; ++ l = next_line - w * 4; ++ for (j = height; j > 0; j--) { ++ for (i = w; i > 0; i--) ++ *d++ = *s++; ++ s = (u32 *)((u8 *)s + l); ++ d = (u32 *)((u8 *)d + l); ++ } ++ } ++ if (width & 15) ++ memmove32_col(dst + width / (8 / BPL), src + width / (8 / BPL), ++ 0xff00ff00, height, next_line - BPL * 2); ++ } else { ++ src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL); ++ dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL); ++ ++ if ((sx + width) & 15) { ++ src -= BPL * 2; ++ dst -= BPL * 2; ++ memmove32_col(dst, src, 0xff00ff00, colsize, -next_line - BPL * 2); ++ width -= 8; ++ } ++ w = width >> 4; ++ if (w) { ++ s = (u32 *)src; ++ d = (u32 *)dst; ++ w *= BPL / 2; ++ l = next_line - w * 4; ++ for (j = height; j > 0; j--) { ++ for (i = w; i > 0; i--) ++ *--d = *--s; ++ s = (u32 *)((u8 *)s - l); ++ d = (u32 *)((u8 *)d - l); ++ } ++ } ++ if (sx & 15) ++ memmove32_col(dst - (width - 16) / (8 / BPL), ++ src - (width - 16) / (8 / BPL), ++ 0xff00ff, colsize, -next_line - BPL * 2); ++ } ++ } else { ++ /* odd->even or even->odd */ ++ if (upwards) { ++ u32 *src32, *dst32; ++ u32 pval[4], v, v1, mask; ++ int i, j, w, f; ++ ++ src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL); ++ dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL); ++ ++ mask = 0xff00ff00; ++ f = 0; ++ w = width; ++ if (sx & 15) { ++ f = 1; ++ w += 8; ++ } ++ if ((sx + width) & 15) ++ f |= 2; ++ w >>= 4; ++ for (i = height; i; i--) { ++ src32 = (u32 *)src; ++ dst32 = (u32 *)dst; ++ ++ if (f & 1) { ++ pval[0] = (*src32++ << 8) & mask; ++ pval[1] = (*src32++ << 8) & mask; ++ pval[2] = (*src32++ << 8) & mask; ++ pval[3] = (*src32++ << 8) & mask; ++ } else { ++ pval[0] = dst32[0] & mask; ++ pval[1] = dst32[1] & mask; ++ pval[2] = dst32[2] & mask; ++ pval[3] = dst32[3] & mask; ++ } ++ ++ for (j = w; j > 0; j--) { ++ v = *src32++; ++ v1 = v & mask; ++ *dst32++ = pval[0] | (v1 >> 8); ++ pval[0] = (v ^ v1) << 8; ++ v = *src32++; ++ v1 = v & mask; ++ *dst32++ = pval[1] | (v1 >> 8); ++ pval[1] = (v ^ v1) << 8; ++ v = *src32++; ++ v1 = v & mask; ++ *dst32++ = pval[2] | (v1 >> 8); ++ pval[2] = (v ^ v1) << 8; ++ v = *src32++; ++ v1 = v & mask; ++ *dst32++ = pval[3] | (v1 >> 8); ++ pval[3] = (v ^ v1) << 8; ++ } ++ ++ if (f & 2) { ++ dst32[0] = (dst32[0] & mask) | pval[0]; ++ dst32[1] = (dst32[1] & mask) | pval[1]; ++ dst32[2] = (dst32[2] & mask) | pval[2]; ++ dst32[3] = (dst32[3] & mask) | pval[3]; ++ } ++ ++ src += next_line; ++ dst += next_line; ++ } ++ } else { ++ u32 *src32, *dst32; ++ u32 pval[4], v, v1, mask; ++ int i, j, w, f; ++ ++ src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL); ++ dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL); ++ ++ mask = 0xff00ff; ++ f = 0; ++ w = width; ++ if ((dx + width) & 15) ++ f = 1; ++ if (sx & 15) { ++ f |= 2; ++ w += 8; ++ } ++ w >>= 4; ++ for (i = height; i; i--) { ++ src32 = (u32 *)src; ++ dst32 = (u32 *)dst; ++ ++ if (f & 1) { ++ pval[0] = dst32[-1] & mask; ++ pval[1] = dst32[-2] & mask; ++ pval[2] = dst32[-3] & mask; ++ pval[3] = dst32[-4] & mask; ++ } else { ++ pval[0] = (*--src32 >> 8) & mask; ++ pval[1] = (*--src32 >> 8) & mask; ++ pval[2] = (*--src32 >> 8) & mask; ++ pval[3] = (*--src32 >> 8) & mask; ++ } ++ ++ for (j = w; j > 0; j--) { ++ v = *--src32; ++ v1 = v & mask; ++ *--dst32 = pval[0] | (v1 << 8); ++ pval[0] = (v ^ v1) >> 8; ++ v = *--src32; ++ v1 = v & mask; ++ *--dst32 = pval[1] | (v1 << 8); ++ pval[1] = (v ^ v1) >> 8; ++ v = *--src32; ++ v1 = v & mask; ++ *--dst32 = pval[2] | (v1 << 8); ++ pval[2] = (v ^ v1) >> 8; ++ v = *--src32; ++ v1 = v & mask; ++ *--dst32 = pval[3] | (v1 << 8); ++ pval[3] = (v ^ v1) >> 8; ++ } ++ ++ if (!(f & 2)) { ++ dst32[-1] = (dst32[-1] & mask) | pval[0]; ++ dst32[-2] = (dst32[-2] & mask) | pval[1]; ++ dst32[-3] = (dst32[-3] & mask) | pval[2]; ++ dst32[-4] = (dst32[-4] & mask) | pval[3]; ++ } ++ ++ src -= next_line; ++ dst -= next_line; ++ } ++ } ++ } ++} ++ ++void atafb_iplan2p8_fillrect(struct fb_info *info, u_long next_line, u32 color, ++ int sy, int sx, int height, int width) ++{ ++ u32 *dest; ++ int rows, i; ++ u32 cval[4]; ++ ++ dest = (u32 *)(info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL)); ++ if (sx & 15) { ++ u8 *dest8 = (u8 *)dest + 1; ++ ++ expand8_col2mask(color, cval); ++ ++ for (i = height; i; i--) { ++ fill8_col(dest8, cval); ++ dest8 += next_line; ++ } ++ dest += BPL / 2; ++ width -= 8; ++ } ++ ++ expand16_col2mask(color, cval); ++ rows = width >> 4; ++ if (rows) { ++ u32 *d = dest; ++ u32 off = next_line - rows * BPL * 2; ++ for (i = height; i; i--) { ++ d = fill16_col(d, rows, cval); ++ d = (u32 *)((long)d + off); ++ } ++ dest += rows * BPL / 2; ++ width &= 15; ++ } ++ ++ if (width) { ++ u8 *dest8 = (u8 *)dest; ++ ++ expand8_col2mask(color, cval); ++ ++ for (i = height; i; i--) { ++ fill8_col(dest8, cval); ++ dest8 += next_line; ++ } ++ } ++} ++ ++void atafb_iplan2p8_linefill(struct fb_info *info, u_long next_line, ++ int dy, int dx, u32 width, ++ const u8 *data, u32 bgcolor, u32 fgcolor) ++{ ++ u32 *dest; ++ const u16 *data16; ++ int rows; ++ u32 fgm[4], bgm[4], m; ++ ++ dest = (u32 *)(info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL)); ++ if (dx & 15) { ++ fill8_2col((u8 *)dest + 1, fgcolor, bgcolor, *data++); ++ dest += BPL / 2; ++ width -= 8; ++ } ++ ++ if (width >= 16) { ++ data16 = (const u16 *)data; ++ expand16_2col2mask(fgcolor, bgcolor, fgm, bgm); ++ ++ for (rows = width / 16; rows; rows--) { ++ u16 d = *data16++; ++ m = d | ((u32)d << 16); ++ *dest++ = (m & fgm[0]) ^ bgm[0]; ++ *dest++ = (m & fgm[1]) ^ bgm[1]; ++ *dest++ = (m & fgm[2]) ^ bgm[2]; ++ *dest++ = (m & fgm[3]) ^ bgm[3]; ++ } ++ ++ data = (const u8 *)data16; ++ width &= 15; ++ } ++ ++ if (width) ++ fill8_2col((u8 *)dest, fgcolor, bgcolor, *data); ++} ++ ++#ifdef MODULE ++MODULE_LICENSE("GPL"); ++ ++int init_module(void) ++{ ++ return 0; ++} ++ ++void cleanup_module(void) ++{ ++} ++#endif /* MODULE */ ++ ++ ++ /* ++ * Visible symbols for modules ++ */ ++ ++EXPORT_SYMBOL(atafb_iplan2p8_copyarea); ++EXPORT_SYMBOL(atafb_iplan2p8_fillrect); ++EXPORT_SYMBOL(atafb_iplan2p8_linefill); +--- /dev/null ++++ linux-m68k-2.6.21/drivers/video/atafb_mfb.c +@@ -0,0 +1,112 @@ ++/* ++ * linux/drivers/video/mfb.c -- Low level frame buffer operations for ++ * monochrome ++ * ++ * Created 5 Apr 1997 by Geert Uytterhoeven ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ */ ++ ++#include <linux/module.h> ++#include <linux/string.h> ++#include <linux/fb.h> ++ ++#include "atafb.h" ++#include "atafb_utils.h" ++ ++ ++ /* ++ * Monochrome ++ */ ++ ++void atafb_mfb_copyarea(struct fb_info *info, u_long next_line, ++ int sy, int sx, int dy, int dx, ++ int height, int width) ++{ ++ u8 *src, *dest; ++ u_int rows; ++ ++ if (sx == 0 && dx == 0 && width == next_line) { ++ src = (u8 *)info->screen_base + sy * (width >> 3); ++ dest = (u8 *)info->screen_base + dy * (width >> 3); ++ fb_memmove(dest, src, height * (width >> 3)); ++ } else if (dy <= sy) { ++ src = (u8 *)info->screen_base + sy * next_line + (sx >> 3); ++ dest = (u8 *)info->screen_base + dy * next_line + (dx >> 3); ++ for (rows = height; rows--;) { ++ fb_memmove(dest, src, width >> 3); ++ src += next_line; ++ dest += next_line; ++ } ++ } else { ++ src = (u8 *)info->screen_base + (sy + height - 1) * next_line + (sx >> 3); ++ dest = (u8 *)info->screen_base + (dy + height - 1) * next_line + (dx >> 3); ++ for (rows = height; rows--;) { ++ fb_memmove(dest, src, width >> 3); ++ src -= next_line; ++ dest -= next_line; ++ } ++ } ++} ++ ++void atafb_mfb_fillrect(struct fb_info *info, u_long next_line, u32 color, ++ int sy, int sx, int height, int width) ++{ ++ u8 *dest; ++ u_int rows; ++ ++ dest = (u8 *)info->screen_base + sy * next_line + (sx >> 3); ++ ++ if (sx == 0 && width == next_line) { ++ if (color) ++ fb_memset255(dest, height * (width >> 3)); ++ else ++ fb_memclear(dest, height * (width >> 3)); ++ } else { ++ for (rows = height; rows--; dest += next_line) { ++ if (color) ++ fb_memset255(dest, width >> 3); ++ else ++ fb_memclear_small(dest, width >> 3); ++ } ++ } ++} ++ ++void atafb_mfb_linefill(struct fb_info *info, u_long next_line, ++ int dy, int dx, u32 width, ++ const u8 *data, u32 bgcolor, u32 fgcolor) ++{ ++ u8 *dest; ++ u_int rows; ++ ++ dest = (u8 *)info->screen_base + dy * next_line + (dx >> 3); ++ ++ for (rows = width / 8; rows--; /* check margins */ ) { ++ // use fast_memmove or fb_memmove ++ *dest++ = *data++; ++ } ++} ++ ++#ifdef MODULE ++MODULE_LICENSE("GPL"); ++ ++int init_module(void) ++{ ++ return 0; ++} ++ ++void cleanup_module(void) ++{ ++} ++#endif /* MODULE */ ++ ++ ++ /* ++ * Visible symbols for modules ++ */ ++ ++EXPORT_SYMBOL(atafb_mfb_copyarea); ++EXPORT_SYMBOL(atafb_mfb_fillrect); ++EXPORT_SYMBOL(atafb_mfb_linefill); +--- /dev/null ++++ linux-m68k-2.6.21/drivers/video/atafb_utils.h +@@ -0,0 +1,400 @@ ++#ifndef _VIDEO_ATAFB_UTILS_H ++#define _VIDEO_ATAFB_UTILS_H ++ ++/* ================================================================= */ ++/* Utility Assembler Functions */ ++/* ================================================================= */ ++ ++/* ====================================================================== */ ++ ++/* Those of a delicate disposition might like to skip the next couple of ++ * pages. ++ * ++ * These functions are drop in replacements for memmove and ++ * memset(_, 0, _). However their five instances add at least a kilobyte ++ * to the object file. You have been warned. ++ * ++ * Not a great fan of assembler for the sake of it, but I think ++ * that these routines are at least 10 times faster than their C ++ * equivalents for large blits, and that's important to the lowest level of ++ * a graphics driver. Question is whether some scheme with the blitter ++ * would be faster. I suspect not for simple text system - not much ++ * asynchrony. ++ * ++ * Code is very simple, just gruesome expansion. Basic strategy is to ++ * increase data moved/cleared at each step to 16 bytes to reduce ++ * instruction per data move overhead. movem might be faster still ++ * For more than 15 bytes, we try to align the write direction on a ++ * longword boundary to get maximum speed. This is even more gruesome. ++ * Unaligned read/write used requires 68020+ - think this is a problem? ++ * ++ * Sorry! ++ */ ++ ++ ++/* ++roman: I've optimized Robert's original versions in some minor ++ * aspects, e.g. moveq instead of movel, let gcc choose the registers, ++ * use movem in some places... ++ * For other modes than 1 plane, lots of more such assembler functions ++ * were needed (e.g. the ones using movep or expanding color values). ++ */ ++ ++/* ++andreas: more optimizations: ++ subl #65536,d0 replaced by clrw d0; subql #1,d0 for dbcc ++ addal is faster than addaw ++ movep is rather expensive compared to ordinary move's ++ some functions rewritten in C for clarity, no speed loss */ ++ ++static inline void *fb_memclear_small(void *s, size_t count) ++{ ++ if (!count) ++ return 0; ++ ++ asm volatile ("\n" ++ " lsr.l #1,%1 ; jcc 1f ; move.b %2,-(%0)\n" ++ "1: lsr.l #1,%1 ; jcc 1f ; move.w %2,-(%0)\n" ++ "1: lsr.l #1,%1 ; jcc 1f ; move.l %2,-(%0)\n" ++ "1: lsr.l #1,%1 ; jcc 1f ; move.l %2,-(%0) ; move.l %2,-(%0)\n" ++ "1:" ++ : "=a" (s), "=d" (count) ++ : "d" (0), "0" ((char *)s + count), "1" (count)); ++ asm volatile ("\n" ++ " subq.l #1,%1\n" ++ " jcs 3f\n" ++ " move.l %2,%%d4; move.l %2,%%d5; move.l %2,%%d6\n" ++ "2: movem.l %2/%%d4/%%d5/%%d6,-(%0)\n" ++ " dbra %1,2b\n" ++ "3:" ++ : "=a" (s), "=d" (count) ++ : "d" (0), "0" (s), "1" (count) ++ : "d4", "d5", "d6" ++ ); ++ ++ return 0; ++} ++ ++ ++static inline void *fb_memclear(void *s, size_t count) ++{ ++ if (!count) ++ return 0; ++ ++ if (count < 16) { ++ asm volatile ("\n" ++ " lsr.l #1,%1 ; jcc 1f ; clr.b (%0)+\n" ++ "1: lsr.l #1,%1 ; jcc 1f ; clr.w (%0)+\n" ++ "1: lsr.l #1,%1 ; jcc 1f ; clr.l (%0)+\n" ++ "1: lsr.l #1,%1 ; jcc 1f ; clr.l (%0)+ ; clr.l (%0)+\n" ++ "1:" ++ : "=a" (s), "=d" (count) ++ : "0" (s), "1" (count)); ++ } else { ++ long tmp; ++ asm volatile ("\n" ++ " move.l %1,%2\n" ++ " lsr.l #1,%2 ; jcc 1f ; clr.b (%0)+ ; subq.w #1,%1\n" ++ " lsr.l #1,%2 ; jcs 2f\n" /* %0 increased=>bit 2 switched*/ ++ " clr.w (%0)+ ; subq.w #2,%1 ; jra 2f\n" ++ "1: lsr.l #1,%2 ; jcc 2f\n" ++ " clr.w (%0)+ ; subq.w #2,%1\n" ++ "2: move.w %1,%2; lsr.l #2,%1 ; jeq 6f\n" ++ " lsr.l #1,%1 ; jcc 3f ; clr.l (%0)+\n" ++ "3: lsr.l #1,%1 ; jcc 4f ; clr.l (%0)+ ; clr.l (%0)+\n" ++ "4: subq.l #1,%1 ; jcs 6f\n" ++ "5: clr.l (%0)+; clr.l (%0)+ ; clr.l (%0)+ ; clr.l (%0)+\n" ++ " dbra %1,5b ; clr.w %1; subq.l #1,%1; jcc 5b\n" ++ "6: move.w %2,%1; btst #1,%1 ; jeq 7f ; clr.w (%0)+\n" ++ "7: btst #0,%1 ; jeq 8f ; clr.b (%0)+\n" ++ "8:" ++ : "=a" (s), "=d" (count), "=d" (tmp) ++ : "0" (s), "1" (count)); ++ } ++ ++ return 0; ++} ++ ++ ++static inline void *fb_memset255(void *s, size_t count) ++{ ++ if (!count) ++ return 0; ++ ++ asm volatile ("\n" ++ " lsr.l #1,%1 ; jcc 1f ; move.b %2,-(%0)\n" ++ "1: lsr.l #1,%1 ; jcc 1f ; move.w %2,-(%0)\n" ++ "1: lsr.l #1,%1 ; jcc 1f ; move.l %2,-(%0)\n" ++ "1: lsr.l #1,%1 ; jcc 1f ; move.l %2,-(%0) ; move.l %2,-(%0)\n" ++ "1:" ++ : "=a" (s), "=d" (count) ++ : "d" (-1), "0" ((char *)s+count), "1" (count)); ++ asm volatile ("\n" ++ " subq.l #1,%1 ; jcs 3f\n" ++ " move.l %2,%%d4; move.l %2,%%d5; move.l %2,%%d6\n" ++ "2: movem.l %2/%%d4/%%d5/%%d6,-(%0)\n" ++ " dbra %1,2b\n" ++ "3:" ++ : "=a" (s), "=d" (count) ++ : "d" (-1), "0" (s), "1" (count) ++ : "d4", "d5", "d6"); ++ ++ return 0; ++} ++ ++ ++static inline void *fb_memmove(void *d, const void *s, size_t count) ++{ ++ if (d < s) { ++ if (count < 16) { ++ asm volatile ("\n" ++ " lsr.l #1,%2 ; jcc 1f ; move.b (%1)+,(%0)+\n" ++ "1: lsr.l #1,%2 ; jcc 1f ; move.w (%1)+,(%0)+\n" ++ "1: lsr.l #1,%2 ; jcc 1f ; move.l (%1)+,(%0)+\n" ++ "1: lsr.l #1,%2 ; jcc 1f ; move.l (%1)+,(%0)+ ; move.l (%1)+,(%0)+\n" ++ "1:" ++ : "=a" (d), "=a" (s), "=d" (count) ++ : "0" (d), "1" (s), "2" (count)); ++ } else { ++ long tmp; ++ asm volatile ("\n" ++ " move.l %0,%3\n" ++ " lsr.l #1,%3 ; jcc 1f ; move.b (%1)+,(%0)+ ; subqw #1,%2\n" ++ " lsr.l #1,%3 ; jcs 2f\n" /* %0 increased=>bit 2 switched*/ ++ " move.w (%1)+,(%0)+ ; subqw #2,%2 ; jra 2f\n" ++ "1: lsr.l #1,%3 ; jcc 2f\n" ++ " move.w (%1)+,(%0)+ ; subqw #2,%2\n" ++ "2: move.w %2,%-; lsr.l #2,%2 ; jeq 6f\n" ++ " lsr.l #1,%2 ; jcc 3f ; move.l (%1)+,(%0)+\n" ++ "3: lsr.l #1,%2 ; jcc 4f ; move.l (%1)+,(%0)+ ; move.l (%1)+,(%0)+\n" ++ "4: subq.l #1,%2 ; jcs 6f\n" ++ "5: move.l (%1)+,(%0)+; move.l (%1)+,(%0)+\n" ++ " move.l (%1)+,(%0)+; move.l (%1)+,(%0)+\n" ++ " dbra %2,5b ; clr.w %2; subq.l #1,%2; jcc 5b\n" ++ "6: move.w %+,%2; btst #1,%2 ; jeq 7f ; move.w (%1)+,(%0)+\n" ++ "7: btst #0,%2 ; jeq 8f ; move.b (%1)+,(%0)+\n" ++ "8:" ++ : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp) ++ : "0" (d), "1" (s), "2" (count)); ++ } ++ } else { ++ if (count < 16) { ++ asm volatile ("\n" ++ " lsr.l #1,%2 ; jcc 1f ; move.b -(%1),-(%0)\n" ++ "1: lsr.l #1,%2 ; jcc 1f ; move.w -(%1),-(%0)\n" ++ "1: lsr.l #1,%2 ; jcc 1f ; move.l -(%1),-(%0)\n" ++ "1: lsr.l #1,%2 ; jcc 1f ; move.l -(%1),-(%0) ; move.l -(%1),-(%0)\n" ++ "1:" ++ : "=a" (d), "=a" (s), "=d" (count) ++ : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count)); ++ } else { ++ long tmp; ++ ++ asm volatile ("\n" ++ " move.l %0,%3\n" ++ " lsr.l #1,%3 ; jcc 1f ; move.b -(%1),-(%0) ; subqw #1,%2\n" ++ " lsr.l #1,%3 ; jcs 2f\n" /* %0 increased=>bit 2 switched*/ ++ " move.w -(%1),-(%0) ; subqw #2,%2 ; jra 2f\n" ++ "1: lsr.l #1,%3 ; jcc 2f\n" ++ " move.w -(%1),-(%0) ; subqw #2,%2\n" ++ "2: move.w %2,%-; lsr.l #2,%2 ; jeq 6f\n" ++ " lsr.l #1,%2 ; jcc 3f ; move.l -(%1),-(%0)\n" ++ "3: lsr.l #1,%2 ; jcc 4f ; move.l -(%1),-(%0) ; move.l -(%1),-(%0)\n" ++ "4: subq.l #1,%2 ; jcs 6f\n" ++ "5: move.l -(%1),-(%0); move.l -(%1),-(%0)\n" ++ " move.l -(%1),-(%0); move.l -(%1),-(%0)\n" ++ " dbra %2,5b ; clr.w %2; subq.l #1,%2; jcc 5b\n" ++ "6: move.w %+,%2; btst #1,%2 ; jeq 7f ; move.w -(%1),-(%0)\n" ++ "7: btst #0,%2 ; jeq 8f ; move.b -(%1),-(%0)\n" ++ "8:" ++ : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp) ++ : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count)); ++ } ++ } ++ ++ return 0; ++} ++ ++ ++/* ++andreas: Simple and fast version of memmove, assumes size is ++ divisible by 16, suitable for moving the whole screen bitplane */ ++static inline void fast_memmove(char *dst, const char *src, size_t size) ++{ ++ if (!size) ++ return; ++ if (dst < src) ++ asm volatile ("\n" ++ "1: movem.l (%0)+,%%d0/%%d1/%%a0/%%a1\n" ++ " movem.l %%d0/%%d1/%%a0/%%a1,%1@\n" ++ " addq.l #8,%1; addq.l #8,%1\n" ++ " dbra %2,1b\n" ++ " clr.w %2; subq.l #1,%2\n" ++ " jcc 1b" ++ : "=a" (src), "=a" (dst), "=d" (size) ++ : "0" (src), "1" (dst), "2" (size / 16 - 1) ++ : "d0", "d1", "a0", "a1", "memory"); ++ else ++ asm volatile ("\n" ++ "1: subq.l #8,%0; subq.l #8,%0\n" ++ " movem.l %0@,%%d0/%%d1/%%a0/%%a1\n" ++ " movem.l %%d0/%%d1/%%a0/%%a1,-(%1)\n" ++ " dbra %2,1b\n" ++ " clr.w %2; subq.l #1,%2\n" ++ " jcc 1b" ++ : "=a" (src), "=a" (dst), "=d" (size) ++ : "0" (src + size), "1" (dst + size), "2" (size / 16 - 1) ++ : "d0", "d1", "a0", "a1", "memory"); ++} ++ ++#ifdef BPL ++ ++/* ++ * This expands a up to 8 bit color into two longs ++ * for movel operations. ++ */ ++static const u32 four2long[] = { ++ 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff, ++ 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff, ++ 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff, ++ 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff, ++}; ++ ++static inline void expand8_col2mask(u8 c, u32 m[]) ++{ ++ m[0] = four2long[c & 15]; ++#if BPL > 4 ++ m[1] = four2long[c >> 4]; ++#endif ++} ++ ++static inline void expand8_2col2mask(u8 fg, u8 bg, u32 fgm[], u32 bgm[]) ++{ ++ fgm[0] = four2long[fg & 15] ^ (bgm[0] = four2long[bg & 15]); ++#if BPL > 4 ++ fgm[1] = four2long[fg >> 4] ^ (bgm[1] = four2long[bg >> 4]); ++#endif ++} ++ ++/* ++ * set an 8bit value to a color ++ */ ++static inline void fill8_col(u8 *dst, u32 m[]) ++{ ++ u32 tmp = m[0]; ++ dst[0] = tmp; ++ dst[2] = (tmp >>= 8); ++#if BPL > 2 ++ dst[4] = (tmp >>= 8); ++ dst[6] = tmp >> 8; ++#endif ++#if BPL > 4 ++ tmp = m[1]; ++ dst[8] = tmp; ++ dst[10] = (tmp >>= 8); ++ dst[12] = (tmp >>= 8); ++ dst[14] = tmp >> 8; ++#endif ++} ++ ++/* ++ * set an 8bit value according to foreground/background color ++ */ ++static inline void fill8_2col(u8 *dst, u8 fg, u8 bg, u32 mask) ++{ ++ u32 fgm[2], bgm[2], tmp; ++ ++ expand8_2col2mask(fg, bg, fgm, bgm); ++ ++ mask |= mask << 8; ++#if BPL > 2 ++ mask |= mask << 16; ++#endif ++ tmp = (mask & fgm[0]) ^ bgm[0]; ++ dst[0] = tmp; ++ dst[2] = (tmp >>= 8); ++#if BPL > 2 ++ dst[4] = (tmp >>= 8); ++ dst[6] = tmp >> 8; ++#endif ++#if BPL > 4 ++ tmp = (mask & fgm[1]) ^ bgm[1]; ++ dst[8] = tmp; ++ dst[10] = (tmp >>= 8); ++ dst[12] = (tmp >>= 8); ++ dst[14] = tmp >> 8; ++#endif ++} ++ ++static const u32 two2word[] = { ++ 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff ++}; ++ ++static inline void expand16_col2mask(u8 c, u32 m[]) ++{ ++ m[0] = two2word[c & 3]; ++#if BPL > 2 ++ m[1] = two2word[(c >> 2) & 3]; ++#endif ++#if BPL > 4 ++ m[2] = two2word[(c >> 4) & 3]; ++ m[3] = two2word[c >> 6]; ++#endif ++} ++ ++static inline void expand16_2col2mask(u8 fg, u8 bg, u32 fgm[], u32 bgm[]) ++{ ++ bgm[0] = two2word[bg & 3]; ++ fgm[0] = two2word[fg & 3] ^ bgm[0]; ++#if BPL > 2 ++ bgm[1] = two2word[(bg >> 2) & 3]; ++ fgm[1] = two2word[(fg >> 2) & 3] ^ bgm[1]; ++#endif ++#if BPL > 4 ++ bgm[2] = two2word[(bg >> 4) & 3]; ++ fgm[2] = two2word[(fg >> 4) & 3] ^ bgm[2]; ++ bgm[3] = two2word[bg >> 6]; ++ fgm[3] = two2word[fg >> 6] ^ bgm[3]; ++#endif ++} ++ ++static inline u32 *fill16_col(u32 *dst, int rows, u32 m[]) ++{ ++ while (rows) { ++ *dst++ = m[0]; ++#if BPL > 2 ++ *dst++ = m[1]; ++#endif ++#if BPL > 4 ++ *dst++ = m[2]; ++ *dst++ = m[3]; ++#endif ++ rows--; ++ } ++ return dst; ++} ++ ++static inline void memmove32_col(void *dst, void *src, u32 mask, u32 h, u32 bytes) ++{ ++ u32 *s, *d, v; ++ ++ s = src; ++ d = dst; ++ do { ++ v = (*s++ & mask) | (*d & ~mask); ++ *d++ = v; ++#if BPL > 2 ++ v = (*s++ & mask) | (*d & ~mask); ++ *d++ = v; ++#endif ++#if BPL > 4 ++ v = (*s++ & mask) | (*d & ~mask); ++ *d++ = v; ++ v = (*s++ & mask) | (*d & ~mask); ++ *d++ = v; ++#endif ++ d = (u32 *)((u8 *)d + bytes); ++ s = (u32 *)((u8 *)s + bytes); ++ } while (--h); ++} ++ ++#endif ++ ++#endif /* _VIDEO_ATAFB_UTILS_H */ diff --git a/debian/patches/bugfix/m68k/amiga-a2065-ariadne-stats.diff b/debian/patches/bugfix/m68k/amiga-a2065-ariadne-stats.diff new file mode 100644 index 000000000000..d6cd97977ec4 --- /dev/null +++ b/debian/patches/bugfix/m68k/amiga-a2065-ariadne-stats.diff @@ -0,0 +1,42 @@ +Subject: [PATCH] m68k: Amiga A2065 and Ariadne TX statistics +Cc: Jeff Garzik <jgarzik@pobox.com>, netdev@vger.kernel.org + +Add missing code to the Amiga A2065 and Ariadne drivers to update +net_device_stats.tx_bytes. + +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + drivers/net/a2065.c | 4 +--- + drivers/net/ariadne.c | 1 + + 2 files changed, 2 insertions(+), 3 deletions(-) + +--- linux-m68k-2.6.21.orig/drivers/net/a2065.c ++++ linux-m68k-2.6.21/drivers/net/a2065.c +@@ -563,7 +563,6 @@ static int lance_start_xmit (struct sk_b + volatile struct lance_init_block *ib = lp->init_block; + int entry, skblen, len; + int status = 0; +- static int outs; + unsigned long flags; + + skblen = skb->len; +@@ -608,8 +607,7 @@ static int lance_start_xmit (struct sk_b + /* Now, give the packet to the lance */ + ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN); + lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask; +- +- outs++; ++ lp->stats.tx_bytes += skblen; + + if (TX_BUFFS_AVAIL <= 0) + netif_stop_queue(dev); +--- linux-m68k-2.6.21.orig/drivers/net/ariadne.c ++++ linux-m68k-2.6.21/drivers/net/ariadne.c +@@ -677,6 +677,7 @@ static int ariadne_start_xmit(struct sk_ + priv->cur_tx -= TX_RING_SIZE; + priv->dirty_tx -= TX_RING_SIZE; + } ++ priv->stats.tx_bytes += len; + + /* Trigger an immediate send poll. */ + lance->RAP = CSR0; /* PCnet-ISA Controller Status */ diff --git a/debian/patches/bugfix/m68k/atari-aranym.diff b/debian/patches/bugfix/m68k/atari-aranym.diff new file mode 100644 index 000000000000..b0579c114107 --- /dev/null +++ b/debian/patches/bugfix/m68k/atari-aranym.diff @@ -0,0 +1,542 @@ +Subject: [PATCH] m68k: Atari ARAnyM support + +From: Michael Schmitz <schmitz@opal.biophys.uni-duesseldorf.de> + +This isn't really my kettle of fish, but I post it anyway unless Petr +complains :-) + +This is what makes it possible for me to test 2.6 builds on the +emulator... + +Should be signed off by Petr, really. + +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + arch/m68k/Kconfig | 15 ++ + arch/m68k/Makefile | 1 + arch/m68k/emu/Makefile | 7 + + arch/m68k/emu/natfeat.c | 113 +++++++++++++++++ + arch/m68k/emu/nfeth.c | 292 +++++++++++++++++++++++++++++++++++++++++++++ + arch/m68k/kernel/setup.c | 5 + drivers/net/Kconfig | 8 + + include/asm-m68k/natfeat.h | 22 +++ + 8 files changed, 463 insertions(+) + +--- linux-m68k-2.6.21.orig/arch/m68k/Kconfig ++++ linux-m68k-2.6.21/arch/m68k/Kconfig +@@ -260,6 +260,21 @@ config Q40 + Q60. Select your CPU below. For 68LC060 don't forget to enable FPU + emulation. + ++config NATFEAT ++ bool "ARAnyM emulator support" ++ depends on ATARI ++ help ++ This option enables support for ARAnyM native features, such as ++ access to a disk image as /dev/hda. Useful with the ARANYM option. ++ ++config NFETH ++ tristate "NatFeat Ethernet support" ++ depends on NET_ETHERNET && NATFEAT ++ help ++ Say Y to include support for the ARAnyM NatFeat network device ++ which will emulate a regular ethernet device while presenting an ++ ethertap device to the host system. ++ + comment "Processor type" + + config M68020 +--- linux-m68k-2.6.21.orig/arch/m68k/Makefile ++++ linux-m68k-2.6.21/arch/m68k/Makefile +@@ -75,6 +75,7 @@ core-$(CONFIG_MVME16x) += arch/m68k/mvm + core-$(CONFIG_BVME6000) += arch/m68k/bvme6000/ + core-$(CONFIG_SUN3X) += arch/m68k/sun3x/ arch/m68k/sun3/ + core-$(CONFIG_SUN3) += arch/m68k/sun3/ arch/m68k/sun3/prom/ ++core-$(CONFIG_NATFEAT) += arch/m68k/emu/ + core-$(CONFIG_M68040) += arch/m68k/fpsp040/ + core-$(CONFIG_M68060) += arch/m68k/ifpsp060/ + core-$(CONFIG_M68KFPU_EMU) += arch/m68k/math-emu/ +--- /dev/null ++++ linux-m68k-2.6.21/arch/m68k/emu/Makefile +@@ -0,0 +1,7 @@ ++# ++# Makefile for Linux arch/m68k/emu source directory ++# ++ ++obj-y += natfeat.o ++ ++obj-$(CONFIG_NFETH) += nfeth.o +--- /dev/null ++++ linux-m68k-2.6.21/arch/m68k/emu/natfeat.c +@@ -0,0 +1,113 @@ ++/* ++ * natfeat.c - ARAnyM hardware support via Native Features (natfeats) ++ * ++ * Copyright (c) 2005 Petr Stehlik of ARAnyM dev team ++ * ++ * Reworked for Linux by Roman Zippel <zippel@linux-m68k.org> ++ * ++ * This software may be used and distributed according to the terms of ++ * the GNU General Public License (GPL), incorporated herein by reference. ++ */ ++ ++#include <linux/types.h> ++#include <linux/console.h> ++#include <linux/string.h> ++#include <linux/kernel.h> ++#include <asm/io.h> ++#include <asm/machdep.h> ++#include <asm/natfeat.h> ++ ++asm ("\n" ++" .global nf_get_id,nf_call\n" ++"nf_get_id:\n" ++" .short 0x7300\n" ++" rts\n" ++"nf_call:\n" ++" .short 0x7301\n" ++" rts\n" ++"1: moveq.l #0,%d0\n" ++" rts\n" ++" .section __ex_table,\"a\"\n" ++" .long nf_get_id,1b\n" ++" .long nf_call,1b\n" ++" .previous"); ++ ++static int stderr_id; ++ ++static void nf_write(struct console *co, const char *str, unsigned int count) ++{ ++ char buf[68]; ++ ++ buf[64] = 0; ++ while (count > 64) { ++ memcpy(buf, str, 64); ++ nf_call(stderr_id, buf); ++ str += 64; ++ count -= 64; ++ } ++ memcpy(buf, str, count); ++ buf[count] = 0; ++ nf_call(stderr_id, buf); ++} ++ ++void nfprint(const char *fmt, ...) ++{ ++ static char buf[256]; ++ va_list ap; ++ int n; ++ ++ va_start(ap, fmt); ++ n = vsnprintf(buf, 256, fmt, ap); ++ nf_call(nf_get_id("NF_STDERR"), buf); ++ va_end(ap); ++} ++ ++static struct console nf_console_driver = { ++ .name = "debug", ++ .write = nf_write, ++ .flags = CON_PRINTBUFFER, ++ .index = -1, ++}; ++ ++static int __init nf_debug_setup(char *arg) ++{ ++ if (strcmp(arg, "emu")) ++ return 0; ++ ++ stderr_id = nf_get_id("NF_STDERR"); ++ if (stderr_id) ++ register_console(&nf_console_driver); ++ return 0; ++} ++ ++early_param("debug", nf_debug_setup); ++ ++static void nf_poweroff(void) ++{ ++ long id = nf_get_id("NF_SHUTDOWN"); ++ ++ if (id) ++ nf_call(id); ++} ++ ++void nf_init(void) ++{ ++ unsigned long id, version; ++ char buf[256]; ++ ++ id = nf_get_id("NF_VERSION"); ++ if (!id) ++ return; ++ version = nf_call(id); ++ ++ id = nf_get_id("NF_NAME"); ++ if (!id) ++ return; ++ nf_call(id, buf, 256); ++ buf[255] = 0; ++ ++ printk("NatFeats found (%s, %lu.%lu)\n", buf, ++ version >> 16, version & 0xffff); ++ ++ mach_power_off = nf_poweroff; ++} +--- /dev/null ++++ linux-m68k-2.6.21/arch/m68k/emu/nfeth.c +@@ -0,0 +1,292 @@ ++/* ++ * atari_nfeth.c - ARAnyM ethernet card driver for GNU/Linux ++ * ++ * Copyright (c) 2005 Milan Jurik, Petr Stehlik of ARAnyM dev team ++ * ++ * Based on ARAnyM driver for FreeMiNT written by Standa Opichal ++ * ++ * This software may be used and distributed according to the terms of ++ * the GNU General Public License (GPL), incorporated herein by reference. ++ */ ++ ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/module.h> ++#include <net/ieee80211.h> ++#include <asm/natfeat.h> ++ ++enum { ++ GET_VERSION = 0, /* no parameters, return NFAPI_VERSION in d0 */ ++ XIF_INTLEVEL, /* no parameters, return Interrupt Level in d0 */ ++ XIF_IRQ, /* acknowledge interrupt from host */ ++ XIF_START, /* (ethX), called on 'ifup', start receiver thread */ ++ XIF_STOP, /* (ethX), called on 'ifdown', stop the thread */ ++ XIF_READLENGTH, /* (ethX), return size of network data block to read */ ++ XIF_READBLOCK, /* (ethX, buffer, size), read block of network data */ ++ XIF_WRITEBLOCK, /* (ethX, buffer, size), write block of network data */ ++ XIF_GET_MAC, /* (ethX, buffer, size), return MAC HW addr in buffer */ ++ XIF_GET_IPHOST, /* (ethX, buffer, size), return IP address of host */ ++ XIF_GET_IPATARI, /* (ethX, buffer, size), return IP address of atari */ ++ XIF_GET_NETMASK /* (ethX, buffer, size), return IP netmask */ ++}; ++ ++#define DRV_NAME "nfeth" ++#define DRV_VERSION "0.3" ++#define DRV_RELDATE "10/12/2005" ++ ++#define MAX_UNIT 8 ++ ++/* These identify the driver base version and may not be removed. */ ++static char version[] __devinitdata = ++KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " S.Opichal, M.Jurik, P.Stehlik\n" ++KERN_INFO " http://aranym.atari.org/\n"; ++ ++MODULE_AUTHOR("Milan Jurik"); ++MODULE_DESCRIPTION("Atari NFeth driver"); ++MODULE_LICENSE("GPL"); ++/* ++MODULE_PARM(nfeth_debug, "i"); ++MODULE_PARM_DESC(nfeth_debug, "nfeth_debug level (1-2)"); ++*/ ++ ++#undef DEBUG ++ ++static long nfEtherID; ++static int nfEtherIRQ; ++ ++struct nfeth_private { ++ int ethX; ++ struct net_device_stats stats; ++ spinlock_t lock; ++}; ++ ++static struct net_device *nfeth_dev[MAX_UNIT]; ++ ++int nfeth_open(struct net_device *dev); ++int nfeth_stop(struct net_device *dev); ++irqreturn_t nfeth_interrupt(int irq, void *dev_id); ++int nfeth_xmit(struct sk_buff *skb, struct net_device *dev); ++ ++int nfeth_open(struct net_device *dev) ++{ ++ struct nfeth_private *priv = netdev_priv(dev); ++ int res; ++ ++ res = nf_call(nfEtherID + XIF_START, priv->ethX); ++ ++ /* Clean statistics */ ++ memset(&priv->stats, 0, sizeof(struct net_device_stats)); ++ spin_lock_init(&priv->lock); ++ ++#ifdef DEBUG ++ printk(DRV_NAME ": open %d\n", res); ++#endif ++ ++ /* Ready for data */ ++ netif_start_queue(dev); ++ ++ return 0; ++} ++ ++int nfeth_stop(struct net_device *dev) ++{ ++ struct nfeth_private *priv = netdev_priv(dev); ++ ++ /* No more data */ ++ netif_stop_queue(dev); ++ ++ nf_call(nfEtherID + XIF_STOP, priv->ethX); ++ ++ return 0; ++} ++ ++/* ++ * Read a packet out of the adapter and pass it to the upper layers ++ */ ++static inline void recv_packet(struct net_device *dev) ++{ ++ struct nfeth_private *priv = netdev_priv(dev); ++ int handled = 0; ++ unsigned short pktlen; ++ struct sk_buff *skb; ++ ++ /* read packet length (excluding 32 bit crc) */ ++ pktlen = nf_call(nfEtherID + XIF_READLENGTH, priv->ethX); ++ ++#ifdef DEBUG ++ printk(DRV_NAME ": recv_packet: %i\n", pktlen); ++#endif ++ ++ if (!pktlen) { ++#ifdef DEBUG ++ printk(DRV_NAME ": recv_packet: pktlen == 0\n"); ++#endif ++ priv->stats.rx_errors++; ++ return; ++ } ++ ++ skb = dev_alloc_skb(pktlen + 2); ++ if (!skb) { ++#ifdef DEBUG ++ printk(DRV_NAME ": recv_packet: out of mem (buf_alloc failed)\n"); ++#endif ++ priv->stats.rx_dropped++; ++ return; ++ } ++ ++ skb->dev = dev; ++ skb_reserve(skb, 2); /* 16 Byte align */ ++ skb_put(skb, pktlen); /* make room */ ++ nf_call(nfEtherID + XIF_READBLOCK, priv->ethX, virt_to_phys(skb->data), pktlen); ++ ++ skb->protocol = eth_type_trans(skb, dev); ++ netif_rx(skb); ++ dev->last_rx = jiffies; ++ priv->stats.rx_packets++; ++ priv->stats.rx_bytes += pktlen; ++ ++ /* and enqueue packet */ ++ handled = 1; ++ return; ++} ++ ++irqreturn_t nfeth_interrupt(int irq, void *dev_id) ++{ ++ int i, m, mask; ++ ++ mask = nf_call(nfEtherID + XIF_IRQ, 0); ++ for (i = 0, m = 1; i < MAX_UNIT; m <<= 1, i++) { ++ if (mask & m && nfeth_dev[i]) { ++ recv_packet(nfeth_dev[i]); ++ nf_call(nfEtherID + XIF_IRQ, m); ++ } ++ } ++ return IRQ_HANDLED; ++} ++ ++int nfeth_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ int len; ++ char *data, shortpkt[ETH_ZLEN]; ++ struct nfeth_private *priv = netdev_priv(dev); ++ ++ data = skb->data; ++ len = skb->len; ++ if (len < ETH_ZLEN) { ++ memset(shortpkt, 0, ETH_ZLEN); ++ memcpy(shortpkt, data, len); ++ data = shortpkt; ++ len = ETH_ZLEN; ++ } ++ ++ dev->trans_start = jiffies; ++ ++#ifdef DEBUG ++ printk(DRV_NAME ": send %d bytes\n", len); ++#endif ++ nf_call(nfEtherID + XIF_WRITEBLOCK, priv->ethX, virt_to_phys(data), len); ++ ++ priv->stats.tx_packets++; ++ priv->stats.tx_bytes += len; ++ ++ dev_kfree_skb(skb); ++ return 0; ++} ++ ++static void nfeth_tx_timeout(struct net_device *dev) ++{ ++ struct nfeth_private *priv = netdev_priv(dev); ++ priv->stats.tx_errors++; ++ netif_wake_queue(dev); ++} ++ ++static struct net_device_stats *nfeth_get_stats(struct net_device *dev) ++{ ++ struct nfeth_private *priv = netdev_priv(dev); ++ return &priv->stats; ++} ++ ++struct net_device * __init nfeth_probe(int unit) ++{ ++ struct net_device *dev; ++ struct nfeth_private *priv; ++ char mac[ETH_ALEN], host_ip[32], local_ip[32]; ++ int err; ++ ++ if (!nf_call(nfEtherID + XIF_GET_MAC, unit, mac, ETH_ALEN)) ++ return NULL; ++ ++ dev = alloc_etherdev(sizeof(struct nfeth_private)); ++ if (!dev) ++ return NULL; ++ ++ SET_MODULE_OWNER(dev); ++ dev->irq = nfEtherIRQ; ++ dev->open = nfeth_open; ++ dev->stop = nfeth_stop; ++ dev->hard_start_xmit = nfeth_xmit; ++ dev->tx_timeout = nfeth_tx_timeout; ++ dev->get_stats = nfeth_get_stats; ++ dev->flags |= NETIF_F_NO_CSUM; ++ memcpy(dev->dev_addr, mac, ETH_ALEN); ++ ++ priv = netdev_priv(dev); ++ priv->ethX = unit; ++ ++ err = register_netdev(dev); ++ if (err) { ++ free_netdev(dev); ++ return NULL; ++ } ++ ++ nf_call(nfEtherID + XIF_GET_IPHOST, unit, ++ host_ip, sizeof(host_ip)); ++ nf_call(nfEtherID + XIF_GET_IPATARI, unit, ++ local_ip, sizeof(local_ip)); ++ ++ printk(KERN_INFO "%s: nfeth addr:%s (%s) HWaddr:" MAC_FMT "\n", ++ dev->name, host_ip, local_ip, MAC_ARG(mac)); ++ ++ return dev; ++} ++ ++int __init nfeth_init(void) ++{ ++ long ver; ++ int i; ++ ++ nfEtherID = nf_get_id("ETHERNET"); ++ if (!nfEtherID) ++ return -ENODEV; ++ ++ ver = nf_call(nfEtherID + GET_VERSION); ++ printk("nfeth API %lu\n", ver); ++ ++ nfEtherIRQ = nf_call(nfEtherID + XIF_INTLEVEL); ++ if (request_irq(nfEtherIRQ, nfeth_interrupt, IRQF_SHARED, ++ "eth emu", nfeth_interrupt)) { ++ printk("nfeth: request for irq %d failed", nfEtherIRQ); ++ return -ENODEV; ++ } ++ ++ for (i = 0; i < MAX_UNIT; i++) ++ nfeth_dev[i] = nfeth_probe(i); ++ ++ return 0; ++} ++ ++void __exit nfeth_cleanup(void) ++{ ++ int i; ++ ++ for (i = 0; i < MAX_UNIT; i++) { ++ if (nfeth_dev[i]) { ++ unregister_netdev(nfeth_dev[0]); ++ free_netdev(nfeth_dev[0]); ++ } ++ } ++ free_irq(nfEtherIRQ, nfeth_interrupt); ++} ++ ++module_init(nfeth_init); ++module_exit(nfeth_cleanup); +--- linux-m68k-2.6.21.orig/arch/m68k/kernel/setup.c ++++ linux-m68k-2.6.21/arch/m68k/kernel/setup.c +@@ -39,6 +39,7 @@ + #ifdef CONFIG_SUN3X + #include <asm/dvma.h> + #endif ++#include <asm/natfeat.h> + + unsigned long m68k_machtype; + unsigned long m68k_cputype; +@@ -313,6 +314,10 @@ void __init setup_arch(char **cmdline_p) + panic("No configuration setup"); + } + ++#ifdef CONFIG_NATFEAT ++ nf_init(); ++#endif ++ + paging_init(); + + #ifndef CONFIG_SUN3 +--- linux-m68k-2.6.21.orig/drivers/net/Kconfig ++++ linux-m68k-2.6.21/drivers/net/Kconfig +@@ -398,6 +398,14 @@ config ATARI_PAMSNET + ACSI port ("ACSI node"). The driver works (has to work...) with a + polled I/O scheme, so it's rather slow :-( + ++config ATARI_ETHERNEC ++ tristate "Atari EtherNEC Ethernet support" ++ depends on NET_ETHERNET && ATARI && ATARI_ROM_ISA ++ help ++ Say Y to include support for the EtherNEC network adapter for the ++ ROM port. The driver works by polling instead of interrupts, so it ++ is quite slow. ++ + config SUN3LANCE + tristate "Sun3/Sun3x on-board LANCE support" + depends on NET_ETHERNET && (SUN3 || SUN3X) +--- /dev/null ++++ linux-m68k-2.6.21/include/asm-m68k/natfeat.h +@@ -0,0 +1,22 @@ ++/* ++ * ARAnyM hardware support via Native Features (natfeats) ++ * ++ * Copyright (c) 2005 Petr Stehlik of ARAnyM dev team ++ * ++ * This software may be used and distributed according to the terms of ++ * the GNU General Public License (GPL), incorporated herein by reference. ++ */ ++ ++#ifndef _NATFEAT_H ++#define _NATFEAT_H ++ ++long nf_get_id(const char *feature_name); ++long nf_call(long id, ...); ++ ++void nf_init(void); ++void nf_shutdown(void); ++ ++void nfprint(const char *fmt, ...) ++ __attribute__ ((format (printf, 1, 2))); ++ ++# endif /* _NATFEAT_H */ diff --git a/debian/patches/bugfix/m68k/atari-ethernec.diff b/debian/patches/bugfix/m68k/atari-ethernec.diff new file mode 100644 index 000000000000..9ddd4570479a --- /dev/null +++ b/debian/patches/bugfix/m68k/atari-ethernec.diff @@ -0,0 +1,1106 @@ +Subject: [PATCH] m68k: Atari EtherNEC driver +Cc: Jeff Garzik <jgarzik@pobox.com>, netdev@vger.kernel.org + +From: Michael Schmitz <schmitz@opal.biophys.uni-duesseldorf.de> + +Atari EtherNEC driver + +Signed-off-by: Michael Schmitz <schmitz@debian.org> +Signed-off-by: Roman Zippel <zippel@linux-m68k.org> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + drivers/net/Makefile | 1 + drivers/net/Space.c | 4 + drivers/net/atari_ethernec.c | 1057 +++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 1062 insertions(+) + +--- linux-m68k-2.6.21.orig/drivers/net/Makefile ++++ linux-m68k-2.6.21/drivers/net/Makefile +@@ -177,6 +177,7 @@ obj-$(CONFIG_DECLANCE) += declance.o + obj-$(CONFIG_ATARILANCE) += atarilance.o + obj-$(CONFIG_ATARI_BIONET) += atari_bionet.o + obj-$(CONFIG_ATARI_PAMSNET) += atari_pamsnet.o ++obj-$(CONFIG_ATARI_ETHERNEC) += atari_ethernec.o 8390.o + obj-$(CONFIG_A2065) += a2065.o + obj-$(CONFIG_HYDRA) += hydra.o + obj-$(CONFIG_ARIADNE) += ariadne.o +--- linux-m68k-2.6.21.orig/drivers/net/Space.c ++++ linux-m68k-2.6.21/drivers/net/Space.c +@@ -72,6 +72,7 @@ extern struct net_device *SK_init(int un + extern struct net_device *seeq8005_probe(int unit); + extern struct net_device *smc_init(int unit); + extern struct net_device *atarilance_probe(int unit); ++extern struct net_device *atari_ethernec_probe(int unit); + extern struct net_device *sun3lance_probe(int unit); + extern struct net_device *sun3_82586_probe(int unit); + extern struct net_device *apne_probe(int unit); +@@ -255,6 +256,9 @@ static struct devprobe2 m68k_probes[] __ + #ifdef CONFIG_ATARILANCE /* Lance-based Atari ethernet boards */ + {atarilance_probe, 0}, + #endif ++#ifdef CONFIG_ATARI_ETHERNEC /* NE2000 based ROM port ethernet cards */ ++ {atari_ethernec_probe, 0}, ++#endif + #ifdef CONFIG_SUN3LANCE /* sun3 onboard Lance chip */ + {sun3lance_probe, 0}, + #endif +--- /dev/null ++++ linux-m68k-2.6.21/drivers/net/atari_ethernec.c +@@ -0,0 +1,1057 @@ ++/* ++ * atari_ethernec.c: Atari cartridge port ethernet adapter ++ * (C) 2006 Michael Schmitz ++ * ++ * Modified after: ++ */ ++ ++/* ne.c: A general non-shared-memory NS8390 ethernet driver for linux. */ ++/* ++ Written 1992-94 by Donald Becker. ++ ++ Copyright 1993 United States Government as represented by the ++ Director, National Security Agency. ++ ++ This software may be used and distributed according to the terms ++ of the GNU General Public License, incorporated herein by reference. ++ ++ The author may be reached as becker@scyld.com, or C/O ++ Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403 ++ ++ This driver should work with many programmed-I/O 8390-based ethernet ++ boards. Currently it supports the NE1000, NE2000, many clones, ++ and some Cabletron products. ++ ++ Changelog: ++ ++ Paul Gortmaker : use ENISR_RDC to monitor Tx PIO uploads, made ++ sanity checks and bad clone support optional. ++ Paul Gortmaker : new reset code, reset card after probe at boot. ++ Paul Gortmaker : multiple card support for module users. ++ Paul Gortmaker : Support for PCI ne2k clones, similar to lance.c ++ Paul Gortmaker : Allow users with bad cards to avoid full probe. ++ Paul Gortmaker : PCI probe changes, more PCI cards supported. ++ rjohnson@analogic.com : Changed init order so an interrupt will only ++ occur after memory is allocated for dev->priv. Deallocated memory ++ last in cleanup_modue() ++ Richard Guenther : Added support for ISAPnP cards ++ Paul Gortmaker : Discontinued PCI support - use ne2k-pci.c instead. ++ Hayato Fujiwara : Add m32r support. ++ ++*/ ++ ++/* ++ * From the driver distribution kit by Thomas Redelberger: ++ * ++ * Hardware circuit description (see directory ETHERNEC for schematics) ++ * ++ * As there is no reset line on the CP, a resistor and a capacitor are ++ * used to reset the NE card on power up. ++ * ++ * Reading from the NE card is done by a read cycle on the CP at address ++ * /ROM4 + 512*ISA address as the ISA address lines A0-A4 are connected ++ * to CP A9-A13. /ROM4 going low will start the ISA read cycle, enable ++ * the ISA bus buffers of the NE card and start decoding of the ISA IO ++ * address by the NE card. /ROM4 going high ends the cycle and the ++ * processor latches the data. ++ * ++ * Because the CP is read only writing to the NE card must be done with ++ * the trick to read from addresses that stand for the data. Dummy reads ++ * at /ROM3 base address + data*2 + ISA address*512 effect this. You ++ * might wonder why everything appears to be shifted up one bit. There is ++ * no CP "A0" address line. There are the signals /UDS and /LDS instead ++ * typical for the 68000 family. The original design which generated an ++ * "A0" worked on an ST and an STE but did not on a Falcon. ++ * ++ * The falling edge of /ROM3 enables the CP address lines A1-A8 onto the ++ * data bus and starts the ISA write cycle. The rising edge will end the ++ * ISA write cycle and the NE latches the data. The processor will also ++ * see and just read this same data but that is harmless. ++ * Elmar Hilgart reported that the bus buffer IC shall be an TTL F-type ++ * to keep up with the fast cycles on the Falcon. ++ * ++ * Base addresses: ++ * rom4 EQU $00fa0000 ; ROM4 base address ++ * rom3 EQU $00fb0000 ; ROM3 base address ++ * ++ */ ++ ++/* Routines for the NatSemi-based designs (NE[12]000). */ ++ ++static const char version1[] = ++"ne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com)\n"; ++static const char version2[] = ++"atari_ethernec.c 11/10/06 Michael Schmitz (schmitz@debian.org)\n"; ++ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/wait.h> ++#include <linux/sched.h> ++#include <linux/errno.h> ++#include <linux/isapnp.h> ++#include <linux/init.h> ++#include <linux/interrupt.h> ++#include <linux/delay.h> ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/jiffies.h> ++ ++#include <asm/system.h> ++#include <asm/atarihw.h> ++#include <asm/atariints.h> ++#include <asm/io.h> ++ ++#include "8390.h" ++ ++#define DRV_NAME "ethernec" ++ ++/* Some defines that people can play with if so inclined. */ ++ ++/* Do we support clones that don't adhere to 14,15 of the SAprom ? */ ++#define SUPPORT_NE_BAD_CLONES ++ ++/* Do we perform extra sanity checks on stuff ? */ ++/* #define NE_SANITY_CHECK */ ++ ++/* Do we implement the read before write bugfix ? */ ++/* #define NE_RW_BUGFIX */ ++ ++/* Do we have a non std. amount of memory? (in units of 256 byte pages) */ ++/* #define PACKETBUF_MEMSIZE 0x40 */ ++ ++/* A zero-terminated list of I/O addresses to be probed at boot. */ ++#ifndef MODULE ++static unsigned int netcard_portlist[] __initdata = { ++ 0x300, 0x280, 0x320, 0x340, 0x360, 0x380, 0 ++}; ++#endif ++ ++static struct isapnp_device_id isapnp_clone_list[] __initdata = { ++ { ISAPNP_CARD_ID('A','X','E',0x2011), ++ ISAPNP_VENDOR('A','X','E'), ISAPNP_FUNCTION(0x2011), ++ (long) "NetGear EA201" }, ++ { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ++ ISAPNP_VENDOR('E','D','I'), ISAPNP_FUNCTION(0x0216), ++ (long) "NN NE2000" }, ++ { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ++ ISAPNP_VENDOR('P','N','P'), ISAPNP_FUNCTION(0x80d6), ++ (long) "Generic PNP" }, ++ { } /* terminate list */ ++}; ++ ++MODULE_DEVICE_TABLE(isapnp, isapnp_clone_list); ++ ++#ifdef SUPPORT_NE_BAD_CLONES ++/* A list of bad clones that we none-the-less recognize. */ ++static struct { const char *name8, *name16; unsigned char SAprefix[4];} ++bad_clone_list[] __initdata = { ++ {"DE100", "DE200", {0x00, 0xDE, 0x01,}}, ++ {"DE120", "DE220", {0x00, 0x80, 0xc8,}}, ++ {"DFI1000", "DFI2000", {'D', 'F', 'I',}}, /* Original, eh? */ ++ {"EtherNext UTP8", "EtherNext UTP16", {0x00, 0x00, 0x79}}, ++ {"NE1000","NE2000-invalid", {0x00, 0x00, 0xd8}}, /* Ancient real NE1000. */ ++ {"NN1000", "NN2000", {0x08, 0x03, 0x08}}, /* Outlaw no-name clone. */ ++ {"4-DIM8","4-DIM16", {0x00,0x00,0x4d,}}, /* Outlaw 4-Dimension cards. */ ++ {"Con-Intl_8", "Con-Intl_16", {0x00, 0x00, 0x24}}, /* Connect Int'nl */ ++ {"ET-100","ET-200", {0x00, 0x45, 0x54}}, /* YANG and YA clone */ ++ {"COMPEX","COMPEX16",{0x00,0x80,0x48}}, /* Broken ISA Compex cards */ ++ {"E-LAN100", "E-LAN200", {0x00, 0x00, 0x5d}}, /* Broken ne1000 clones */ ++ {"PCM-4823", "PCM-4823", {0x00, 0xc0, 0x6c}}, /* Broken Advantech MoBo */ ++ {"REALTEK", "RTL8019", {0x00, 0x00, 0xe8}}, /* no-name with Realtek chip */ ++#if defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938) ++ {"RBHMA4X00-RTL8019", "RBHMA4X00/RTL8019", {0x00, 0x60, 0x0a}}, /* Toshiba built-in */ ++#endif ++ {"LCS-8834", "LCS-8836", {0x04, 0x04, 0x37}}, /* ShinyNet (SET) */ ++ {NULL,} ++}; ++#endif ++ ++/* ---- No user-serviceable parts below ---- */ ++ ++#define NE_BASE (dev->base_addr) ++#define NE_CMD 0x00 ++#define NE_DATAPORT 0x10 /* NatSemi-defined port window offset. */ ++#define NE_RESET 0x1f /* Issue a read to reset, a write to clear. */ ++#define NE_IO_EXTENT 0x20 ++ ++#define NE1SM_START_PG 0x20 /* First page of TX buffer */ ++#define NE1SM_STOP_PG 0x40 /* Last page +1 of RX ring */ ++#define NESM_START_PG 0x40 /* First page of TX buffer */ ++#define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ ++ ++#if defined(CONFIG_PLAT_MAPPI) ++# define DCR_VAL 0x4b ++#elif defined(CONFIG_PLAT_OAKS32R) || \ ++ defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938) || \ ++ defined(CONFIG_ATARI_ETHERNEC) || defined(CONFIG_ATARI_ETHERNEC_MODULE) ++# define DCR_VAL 0x48 /* 8-bit mode */ ++#else ++# define DCR_VAL 0x49 ++#endif ++ ++#if defined(CONFIG_ATARI_ETHERNEC) || defined(CONFIG_ATARI_ETHERNEC_MODULE) ++# define ETHERNEC_RTL_8019_BASE 0x300 ++# define ETHERNEC_RTL_8019_IRQ IRQ_MFP_TIMD ++#endif ++ ++static int ne_probe1(struct net_device *dev, int ioaddr); ++static int ne_probe_isapnp(struct net_device *dev); ++ ++static int ne_open(struct net_device *dev); ++static int ne_close(struct net_device *dev); ++ ++static void ne_reset_8390(struct net_device *dev); ++static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, ++ int ring_page); ++static void ne_block_input(struct net_device *dev, int count, ++ struct sk_buff *skb, int ring_offset); ++static void ne_block_output(struct net_device *dev, const int count, ++ const unsigned char *buf, const int start_page); ++ ++ ++/* ++ * The Atari ROM port has no interrupt line, so we poll the card instead. ++ */ ++ ++static int use_poll; ++ ++/* ++ * This is used by cleanup, to prevent the module from being unloaded while ++ * intrpt_routine is still in the task queue ++ */ ++static wait_queue_head_t WaitQ; ++ ++static struct work_struct tqueue; ++ ++#ifdef ETHERNEC_USE_POLL ++static struct { ++ struct work_struct poll_queue; ++ struct timer_list poll_timer; ++ struct net_device *dev; ++} poll_ops; ++#endif ++ ++static struct net_device *poll_dev = NULL; ++ ++static void atari_ethernec_int(unsigned long dev_addr) ++{ ++ struct net_device *dev = poll_dev; ++ ++ if (!dev) { ++ /* If cleanup wants us to die */ ++ if (waitqueue_active(&WaitQ)) ++ wake_up(&WaitQ); /* Now cleanup_module can return */ ++ else ++ /* Put ourselves back in the task queue */ ++ schedule_delayed_work(&tqueue, 1); ++ return; ++ } ++ ++ if (netif_running(dev)) ++ ei_interrupt(dev->irq, dev); ++ ++ /* If cleanup wants us to die */ ++ if (waitqueue_active(&WaitQ)) ++ wake_up(&WaitQ); /* Now cleanup_module can return */ ++ else ++ /* Put ourselves back in the task queue */ ++ schedule_delayed_work(&tqueue, 0); /* reduced delay from 1 */ ++} ++ ++#ifdef ETHERNEC_USE_POLL ++static void atari_ethernec_poll_handler(unsigned long dev_addr) ++{ ++ struct net_device *dev = poll_dev; ++ ++ if (!dev || !dev->poll_controller) ++ return; ++ ++ if (netif_running(dev)) ++ dev->poll_controller(dev); ++ ++ schedule_work(&poll_ops.poll_queue); ++ mod_timer(&poll_ops.poll_timer, jiffies + HZ / 100); ++} ++#endif ++ ++static void atari_ethernec_start_poll(struct net_device *dev) ++{ ++ poll_dev = dev; ++ ++ init_waitqueue_head(&WaitQ); ++ ++ INIT_WORK(&tqueue, (void (*)(void *))atari_ethernec_int, dev); ++ schedule_delayed_work(&tqueue, 1); ++#ifdef ETHERNEC_USE_POLL ++ if (!poll_ops.poll_queue.func || ++ poll_ops.poll_queue.func == ei_interrupt) { ++ if (!poll_ops.poll_queue.func) ++ INIT_WORK(&poll_ops.poll_queue, ei_interrupt, dev); ++ ++ init_timer(&poll_ops.poll_timer); ++ poll_ops.poll_timer.function = atari_ethernec_poll_handler; ++ poll_ops.poll_timer.expires = jiffies + HZ / 5; ++ poll_ops.poll_timer.data = (unsigned long)dev; ++ add_timer(&poll_ops.poll_timer); ++ } ++#endif ++} ++ ++static void atari_ethernec_stop_poll(struct net_device *dev) ++{ ++ poll_dev = NULL; ++ ++ if (dev) ++ sleep_on(&WaitQ); ++ ++#ifdef ETHERNEC_USE_POLL ++ if (poll_ops.poll_queue.func == ei_interrupt) ++ del_timer_sync(&poll_ops.poll_timer); ++#endif ++} ++ ++ ++/* Probe for various non-shared-memory ethercards. ++ ++ NEx000-clone boards have a Station Address PROM (SAPROM) in the packet ++ buffer memory space. NE2000 clones have 0x57,0x57 in bytes 0x0e,0x0f of ++ the SAPROM, while other supposed NE2000 clones must be detected by their ++ SA prefix. ++ ++ Reading the SAPROM from a word-wide card with the 8390 set in byte-wide ++ mode results in doubled values, which can be detected and compensated for. ++ ++ The probe is also responsible for initializing the card and filling ++ in the 'dev' and 'ei_status' structures. ++ ++ We use the minimum memory size for some ethercard product lines, iff we can't ++ distinguish models. You can increase the packet buffer size by setting ++ PACKETBUF_MEMSIZE. Reported Cabletron packet buffer locations are: ++ E1010 starts at 0x100 and ends at 0x2000. ++ E1010-x starts at 0x100 and ends at 0x8000. ("-x" means "more memory") ++ E2010 starts at 0x100 and ends at 0x4000. ++ E2010-x starts at 0x100 and ends at 0xffff. ++*/ ++ ++static int __init do_ne_probe(struct net_device *dev) ++{ ++ unsigned int base_addr = dev->base_addr; ++ int rv; ++#ifndef MODULE ++ int orig_irq = dev->irq; ++#endif ++ ++ SET_MODULE_OWNER(dev); ++ ++ /* First check any supplied i/o locations. User knows best. <cough> */ ++ if (base_addr > 0x1ff) { /* Check a single specified location. */ ++ rv = ne_probe1(dev, base_addr); ++ if (!rv && use_poll) { ++ /* Seems we have a valid device here; set up polling routine */ ++ poll_dev = dev; ++ atari_ethernec_start_poll(dev); ++ } ++ return rv; ++ } else if (base_addr != 0) /* Don't probe at all. */ ++ return -ENXIO; ++ ++ /* Then look for any installed ISAPnP clones */ ++ if (isapnp_present() && (ne_probe_isapnp(dev) == 0)) ++ return 0; ++ ++#ifndef MODULE ++ /* Last resort. The semi-risky ISA auto-probe. */ ++ for (base_addr = 0; netcard_portlist[base_addr] != 0; base_addr++) { ++ int ioaddr = netcard_portlist[base_addr]; ++ dev->irq = orig_irq; ++ rv = ne_probe1(dev, ioaddr); ++ if (rv == 0) { ++ if (use_poll) { ++ poll_dev = dev; ++ atari_ethernec_start_poll(dev); ++ } ++ return 0; ++ } ++ } ++#endif ++ ++ return -ENODEV; ++} ++ ++#ifndef MODULE ++struct net_device * __init atari_ethernec_probe(int unit) ++{ ++ struct net_device *dev = alloc_ei_netdev(); ++ int err; ++ ++ if (!dev) ++ return ERR_PTR(-ENOMEM); ++ ++ sprintf(dev->name, "eth%d", unit); ++ netdev_boot_setup_check(dev); ++ ++#if defined(CONFIG_ATARI_ETHERNEC) ++ dev->base_addr = ETHERNEC_RTL_8019_BASE; ++ dev->irq = ETHERNEC_RTL_8019_IRQ; ++#endif ++ err = do_ne_probe(dev); ++ if (err) ++ goto out; ++ ++ /* Seems we have a valid device here; set up polling routine */ ++ return dev; ++out: ++ free_netdev(dev); ++ return ERR_PTR(err); ++} ++#endif ++ ++static int __init ne_probe_isapnp(struct net_device *dev) ++{ ++ int i; ++ ++ for (i = 0; isapnp_clone_list[i].vendor != 0; i++) { ++ struct pnp_dev *idev = NULL; ++ ++ while ((idev = pnp_find_dev(NULL, ++ isapnp_clone_list[i].vendor, ++ isapnp_clone_list[i].function, ++ idev))) { ++ /* Avoid already found cards from previous calls */ ++ if (pnp_device_attach(idev) < 0) ++ continue; ++ if (pnp_activate_dev(idev) < 0) { ++ pnp_device_detach(idev); ++ continue; ++ } ++ /* if no io and irq, search for next */ ++ if (!pnp_port_valid(idev, 0) || !pnp_irq_valid(idev, 0)) { ++ pnp_device_detach(idev); ++ continue; ++ } ++ /* found it */ ++ dev->base_addr = pnp_port_start(idev, 0); ++ dev->irq = pnp_irq(idev, 0); ++ printk(KERN_INFO "atari_ethernec.c: ISAPnP reports %s at i/o %#lx, irq %d.\n", ++ (char *) isapnp_clone_list[i].driver_data, ++ dev->base_addr, dev->irq); ++ if (ne_probe1(dev, dev->base_addr) != 0) { /* Shouldn't happen. */ ++ printk(KERN_ERR "atari_ethernec.c: Probe of ISAPnP card at %#lx failed.\n", ++ dev->base_addr); ++ pnp_device_detach(idev); ++ return -ENXIO; ++ } ++ ei_status.priv = (unsigned long)idev; ++ break; ++ } ++ if (!idev) ++ continue; ++ return 0; ++ } ++ ++ return -ENODEV; ++} ++ ++static int __init ne_probe1(struct net_device *dev, int ioaddr) ++{ ++ int i; ++ unsigned char SA_prom[32]; ++ int wordlength = 2; ++ const char *name = NULL; ++ int start_page, stop_page; ++ int neX000, ctron, copam, bad_card; ++ int reg0, ret; ++ static unsigned version_printed; ++ ++ if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME)) ++ return -EBUSY; ++ ++ reg0 = inb_p(ioaddr); ++ if (reg0 == 0xFF) { ++ ret = -ENODEV; ++ goto err_out; ++ } ++ ++ /* Do a preliminary verification that we have a 8390. */ ++ { ++ int regd; ++ outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD); ++ regd = inb_p(ioaddr + 0x0d); ++ outb_p(0xff, ioaddr + 0x0d); ++ outb_p(E8390_NODMA+E8390_PAGE0, ioaddr + E8390_CMD); ++ inb_p(ioaddr + EN0_COUNTER0); /* Clear the counter by reading. */ ++ if (inb_p(ioaddr + EN0_COUNTER0) != 0) { ++ outb_p(reg0, ioaddr); ++ outb_p(regd, ioaddr + 0x0d); /* Restore the old values. */ ++ ret = -ENODEV; ++ goto err_out; ++ } ++ } ++ ++ if (ei_debug && version_printed++ == 0) ++ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2); ++ ++ /* A user with a poor card that fails to ack the reset, or that ++ does not have a valid 0x57,0x57 signature can still use this ++ without having to recompile. Specifying an i/o address along ++ with an otherwise unused dev->mem_end value of "0xBAD" will ++ cause the driver to skip these parts of the probe. */ ++ ++ bad_card = ((dev->base_addr != 0) && (dev->mem_end == 0xbad)); ++ ++ /* Reset card. Who knows what dain-bramaged state it was left in. */ ++ ++ { ++ unsigned long reset_start_time = jiffies; ++ ++ /* DON'T change these to inb_p/outb_p or reset will fail on clones. */ ++ outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET); ++ ++ while ((inb_p(ioaddr + EN0_ISR) & ENISR_RESET) == 0) { ++ if (time_after(jiffies, reset_start_time + 2 * HZ / 100)) { ++ if (bad_card) { ++ printk(" (warning: no reset ack)"); ++ break; ++ } else { ++ // MSch: ARAnyM exits here ++ printk(" not found (no reset ack).\n"); ++ ret = -ENODEV; ++ goto err_out; ++ } ++ } ++ } ++ ++ outb_p(0xff, ioaddr + EN0_ISR); /* Ack all intr. */ ++ } ++ ++ /* Read the 16 bytes of station address PROM. ++ We must first initialize registers, similar to NS8390_init(eifdev, 0). ++ We can't reliably read the SAPROM address without this. ++ (I learned the hard way!). */ ++ { ++ struct {unsigned char value, offset; } program_seq[] = ++ { ++ {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/ ++ {0x48, EN0_DCFG}, /* Set byte-wide (0x48) access. */ ++ {0x00, EN0_RCNTLO}, /* Clear the count regs. */ ++ {0x00, EN0_RCNTHI}, ++ {0x00, EN0_IMR}, /* Mask completion irq. */ ++ {0xFF, EN0_ISR}, ++ {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */ ++ {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */ ++ {32, EN0_RCNTLO}, ++ {0x00, EN0_RCNTHI}, ++ {0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */ ++ {0x00, EN0_RSARHI}, ++ {E8390_RREAD+E8390_START, E8390_CMD}, ++ }; ++ ++ for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) ++ outb_p(program_seq[i].value, ioaddr + program_seq[i].offset); ++ ++ } ++ for (i = 0; i < 32 /*sizeof(SA_prom)*/; i += 2) { ++ SA_prom[i] = inb(ioaddr + NE_DATAPORT); ++ SA_prom[i+1] = inb(ioaddr + NE_DATAPORT); ++ if (SA_prom[i] != SA_prom[i+1]) ++ wordlength = 1; ++ } ++ ++ if (wordlength == 2) { ++ for (i = 0; i < 16; i++) ++ SA_prom[i] = SA_prom[i+i]; ++ /* We must set the 8390 for word mode. */ ++ outb_p(DCR_VAL, ioaddr + EN0_DCFG); ++ start_page = NESM_START_PG; ++ ++ /* ++ * Realtek RTL8019AS datasheet says that the PSTOP register ++ * shouldn't exceed 0x60 in 8-bit mode. ++ * This chip can be identified by reading the signature from ++ * the remote byte count registers (otherwise write-only)... ++ */ ++ if ((DCR_VAL & 0x01) == 0 && /* 8-bit mode */ ++ inb(ioaddr + EN0_RCNTLO) == 0x50 && ++ inb(ioaddr + EN0_RCNTHI) == 0x70) ++ stop_page = 0x60; ++ else ++ stop_page = NESM_STOP_PG; ++ } else { ++ start_page = NE1SM_START_PG; ++ stop_page = NE1SM_STOP_PG; ++ } ++ ++#if defined(CONFIG_PLAT_MAPPI) || defined(CONFIG_PLAT_OAKS32R) ++ neX000 = ((SA_prom[14] == 0x57 && SA_prom[15] == 0x57) ++ || (SA_prom[14] == 0x42 && SA_prom[15] == 0x42)); ++#else ++ neX000 = (SA_prom[14] == 0x57 && SA_prom[15] == 0x57); ++#endif ++ ctron = (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d); ++ copam = (SA_prom[14] == 0x49 && SA_prom[15] == 0x00); ++ ++ /* Set up the rest of the parameters. */ ++ if (neX000 || bad_card || copam) { ++ name = (wordlength == 2) ? "NE2000" : "NE1000"; ++ } else if (ctron) { ++ name = (wordlength == 2) ? "Ctron-8" : "Ctron-16"; ++ start_page = 0x01; ++ stop_page = (wordlength == 2) ? 0x40 : 0x20; ++ } else { ++#ifdef SUPPORT_NE_BAD_CLONES ++ /* Ack! Well, there might be a *bad* NE*000 clone there. ++ Check for total bogus addresses. */ ++ for (i = 0; bad_clone_list[i].name8; i++) { ++ if (SA_prom[0] == bad_clone_list[i].SAprefix[0] && ++ SA_prom[1] == bad_clone_list[i].SAprefix[1] && ++ SA_prom[2] == bad_clone_list[i].SAprefix[2]) { ++ if (wordlength == 2) { ++ name = bad_clone_list[i].name16; ++ } else { ++ name = bad_clone_list[i].name8; ++ } ++ break; ++ } ++ } ++ if (bad_clone_list[i].name8 == NULL) { ++ printk(" not found (invalid signature %2.2x %2.2x).\n", ++ SA_prom[14], SA_prom[15]); ++ ret = -ENXIO; ++ goto err_out; ++ } ++#else ++ printk(" not found.\n"); ++ ret = -ENXIO; ++ goto err_out; ++#endif ++ } ++ ++ if (dev->irq < 2) { ++ unsigned long cookie = probe_irq_on(); ++ outb_p(0x50, ioaddr + EN0_IMR); /* Enable one interrupt. */ ++ outb_p(0x00, ioaddr + EN0_RCNTLO); ++ outb_p(0x00, ioaddr + EN0_RCNTHI); ++ outb_p(E8390_RREAD+E8390_START, ioaddr); /* Trigger it... */ ++ mdelay(10); /* wait 10ms for interrupt to propagate */ ++ outb_p(0x00, ioaddr + EN0_IMR); /* Mask it again. */ ++ dev->irq = probe_irq_off(cookie); ++ if (ei_debug > 2) ++ printk(" autoirq is %d\n", dev->irq); ++ } else if (dev->irq == 2) ++ /* Fixup for users that don't know that IRQ 2 is really IRQ 9, ++ or don't know which one to set. */ ++ dev->irq = 9; ++ ++ /* ++ * use timer based polling! ++ */ ++ if (! dev->irq) { ++ printk(" failed to detect IRQ line. Assuming irq %d\n", ++ ETHERNEC_RTL_8019_IRQ); ++ dev->irq = ETHERNEC_RTL_8019_IRQ; ++ /* timer routine set up in atari_ethernec_probe() */ ++ if (dev->irq == IRQ_MFP_TIMD) { ++ /* set Timer D data Register */ ++ mfp.tim_dt_d = 123; /* 200 Hz */ ++ /* start timer D, div = 1:100 */ ++ mfp.tim_ct_cd = (mfp.tim_ct_cd & 0xf0) | 0x6; ++ } ++ ret = request_irq(dev->irq, ei_interrupt, 0, name, dev); ++ if (ret) { ++ printk(" unable to get IRQ %d (errno=%d), polling instead.\n", ++ dev->irq, ret); ++ use_poll = 1; ++ } ++ } else { ++ ++ /* Snarf the interrupt now. There's no point in waiting since we cannot ++ share and the board will usually be enabled. */ ++ ret = request_irq(dev->irq, ei_interrupt, 0, name, dev); ++ if (ret) { ++ printk(" unable to get IRQ %d (errno=%d).\n", dev->irq, ret); ++ goto err_out; ++ } ++ } ++ dev->base_addr = ioaddr; ++ ++#ifdef CONFIG_PLAT_MAPPI ++ outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, ++ ioaddr + E8390_CMD); /* 0x61 */ ++ for (i = 0; i < ETHER_ADDR_LEN; i++) { ++ dev->dev_addr[i] = SA_prom[i] = inb_p(ioaddr + EN1_PHYS_SHIFT(i)); ++ printk(" %2.2x", SA_prom[i]); ++ } ++#else ++ for (i = 0; i < ETHER_ADDR_LEN; i++) { ++ printk(" %2.2x", SA_prom[i]); ++ dev->dev_addr[i] = SA_prom[i]; ++ } ++#endif ++ ++ printk("\n%s: %s found at %#x, using IRQ %d.\n", ++ dev->name, name, ioaddr, dev->irq); ++ ++ ei_status.name = name; ++ ei_status.tx_start_page = start_page; ++ ei_status.stop_page = stop_page; ++ ++ /* Use 16-bit mode only if this wasn't overridden by DCR_VAL */ ++ ei_status.word16 = (wordlength == 2 && (DCR_VAL & 0x01)); ++ ++ ei_status.rx_start_page = start_page + TX_PAGES; ++#ifdef PACKETBUF_MEMSIZE ++ /* Allow the packet buffer size to be overridden by know-it-alls. */ ++ ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE; ++#endif ++ ++ ei_status.reset_8390 = &ne_reset_8390; ++ ei_status.block_input = &ne_block_input; ++ ei_status.block_output = &ne_block_output; ++ ei_status.get_8390_hdr = &ne_get_8390_hdr; ++ ei_status.priv = 0; ++ dev->open = &ne_open; ++ dev->stop = &ne_close; ++#ifdef CONFIG_NET_POLL_CONTROLLER ++ dev->poll_controller = ei_poll; ++#endif ++ NS8390_init(dev, 0); ++ ++ ret = register_netdev(dev); ++ if (ret) ++ goto out_irq; ++ return 0; ++ ++out_irq: ++ free_irq(dev->irq, dev); ++err_out: ++ release_region(ioaddr, NE_IO_EXTENT); ++ return ret; ++} ++ ++static int ne_open(struct net_device *dev) ++{ ++ ei_open(dev); ++ return 0; ++} ++ ++static int ne_close(struct net_device *dev) ++{ ++ if (ei_debug > 1) ++ printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name); ++ ei_close(dev); ++ return 0; ++} ++ ++/* Hard reset the card. This used to pause for the same period that a ++ 8390 reset command required, but that shouldn't be necessary. */ ++ ++static void ne_reset_8390(struct net_device *dev) ++{ ++ unsigned long reset_start_time = jiffies; ++ ++ if (ei_debug > 1) ++ printk(KERN_DEBUG "resetting the 8390 t=%ld...", jiffies); ++ ++ /* DON'T change these to inb_p/outb_p or reset will fail on clones. */ ++ outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET); ++ ++ ei_status.txing = 0; ++ ei_status.dmaing = 0; ++ ++ /* This check _should_not_ be necessary, omit eventually. */ ++ while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0) { ++ if (time_after(jiffies, reset_start_time + 2*HZ/100)) { ++ printk(KERN_WARNING "%s: ne_reset_8390() did not complete.\n", ++ dev->name); ++ break; ++ } ++ } ++ outb_p(ENISR_RESET, NE_BASE + EN0_ISR); /* Ack intr. */ ++} ++ ++/* Grab the 8390 specific header. Similar to the block_input routine, but ++ we don't need to be concerned with ring wrap as the header will be at ++ the start of a page, so we optimize accordingly. */ ++ ++static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) ++{ ++ int nic_base = dev->base_addr; ++ ++ /* This *shouldn't* happen. If it does, it's the last thing you'll see */ ++ ++ if (ei_status.dmaing) ++ { ++ printk(KERN_EMERG "%s: DMAing conflict in ne_get_8390_hdr " ++ "[DMAstat:%d][irqlock:%d].\n", ++ dev->name, ei_status.dmaing, ei_status.irqlock); ++ return; ++ } ++ ++ ei_status.dmaing |= 0x01; ++ outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); ++ outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO); ++ outb_p(0, nic_base + EN0_RCNTHI); ++ outb_p(0, nic_base + EN0_RSARLO); /* On page boundary */ ++ outb_p(ring_page, nic_base + EN0_RSARHI); ++ outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD); ++ ++ if (ei_status.word16) ++ insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1); ++ else ++ insb(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)); ++ ++ outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ ++ ei_status.dmaing &= ~0x01; ++ ++ le16_to_cpus(&hdr->count); ++} ++ ++/* Block input and output, similar to the Crynwr packet driver. If you ++ are porting to a new ethercard, look at the packet driver source for hints. ++ The NEx000 doesn't share the on-board packet memory -- you have to put ++ the packet out through the "remote DMA" dataport using outb. */ ++ ++static void ne_block_input(struct net_device *dev, int count, ++ struct sk_buff *skb, int ring_offset) ++{ ++#ifdef NE_SANITY_CHECK ++ int xfer_count = count; ++#endif ++ int nic_base = dev->base_addr; ++ char *buf = skb->data; ++ ++ /* This *shouldn't* happen. If it does, it's the last thing you'll see */ ++ if (ei_status.dmaing) { ++ printk(KERN_EMERG "%s: DMAing conflict in ne_block_input " ++ "[DMAstat:%d][irqlock:%d].\n", ++ dev->name, ei_status.dmaing, ei_status.irqlock); ++ return; ++ } ++ ei_status.dmaing |= 0x01; ++ outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); ++ outb_p(count & 0xff, nic_base + EN0_RCNTLO); ++ outb_p(count >> 8, nic_base + EN0_RCNTHI); ++ outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO); ++ outb_p(ring_offset >> 8, nic_base + EN0_RSARHI); ++ outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD); ++ ++ if (ei_status.word16) { ++ insw(NE_BASE + NE_DATAPORT,buf,count>>1); ++ if (count & 0x01) { ++ buf[count-1] = inb(NE_BASE + NE_DATAPORT); ++#ifdef NE_SANITY_CHECK ++ xfer_count++; ++#endif ++ } ++ } else { ++ insb(NE_BASE + NE_DATAPORT, buf, count); ++ } ++ ++#ifdef NE_SANITY_CHECK ++ /* This was for the ALPHA version only, but enough people have ++ been encountering problems so it is still here. If you see ++ this message you either 1) have a slightly incompatible clone ++ or 2) have noise/speed problems with your bus. */ ++ ++ if (ei_debug > 1) { ++ /* DMA termination address check... */ ++ int addr, tries = 20; ++ do { ++ /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here ++ -- it's broken for Rx on some cards! */ ++ int high = inb_p(nic_base + EN0_RSARHI); ++ int low = inb_p(nic_base + EN0_RSARLO); ++ addr = (high << 8) + low; ++ if (((ring_offset + xfer_count) & 0xff) == low) ++ break; ++ } while (--tries > 0); ++ if (tries <= 0) ++ printk(KERN_WARNING "%s: RX transfer address mismatch," ++ "%#4.4x (expected) vs. %#4.4x (actual).\n", ++ dev->name, ring_offset + xfer_count, addr); ++ } ++#endif ++ outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ ++ ei_status.dmaing &= ~0x01; ++} ++ ++static void ne_block_output(struct net_device *dev, int count, ++ const unsigned char *buf, const int start_page) ++{ ++ int nic_base = NE_BASE; ++ unsigned long dma_start; ++#ifdef NE_SANITY_CHECK ++ int retries = 0; ++#endif ++ ++ /* Round the count up for word writes. Do we need to do this? ++ What effect will an odd byte count have on the 8390? ++ I should check someday. */ ++ ++ if (ei_status.word16 && (count & 0x01)) ++ count++; ++ ++ /* This *shouldn't* happen. If it does, it's the last thing you'll see */ ++ if (ei_status.dmaing) { ++ printk(KERN_EMERG "%s: DMAing conflict in ne_block_output." ++ "[DMAstat:%d][irqlock:%d]\n", ++ dev->name, ei_status.dmaing, ei_status.irqlock); ++ return; ++ } ++ ei_status.dmaing |= 0x01; ++ /* We should already be in page 0, but to be safe... */ ++ outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD); ++ ++#ifdef NE_SANITY_CHECK ++retry: ++#endif ++ ++#ifdef NE8390_RW_BUGFIX ++ /* Handle the read-before-write bug the same way as the ++ Crynwr packet driver -- the NatSemi method doesn't work. ++ Actually this doesn't always work either, but if you have ++ problems with your NEx000 this is better than nothing! */ ++ ++ outb_p(0x42, nic_base + EN0_RCNTLO); ++ outb_p(0x00, nic_base + EN0_RCNTHI); ++ outb_p(0x42, nic_base + EN0_RSARLO); ++ outb_p(0x00, nic_base + EN0_RSARHI); ++ outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD); ++ /* Make certain that the dummy read has occurred. */ ++ udelay(6); ++#endif ++ ++ outb_p(ENISR_RDC, nic_base + EN0_ISR); ++ ++ /* Now the normal output. */ ++ outb_p(count & 0xff, nic_base + EN0_RCNTLO); ++ outb_p(count >> 8, nic_base + EN0_RCNTHI); ++ outb_p(0x00, nic_base + EN0_RSARLO); ++ outb_p(start_page, nic_base + EN0_RSARHI); ++ ++ outb_p(E8390_RWRITE+E8390_START, nic_base + NE_CMD); ++ if (ei_status.word16) ++ outsw(NE_BASE + NE_DATAPORT, buf, count>>1); ++ else ++ outsb(NE_BASE + NE_DATAPORT, buf, count); ++ ++ dma_start = jiffies; ++ ++#ifdef NE_SANITY_CHECK ++ /* This was for the ALPHA version only, but enough people have ++ been encountering problems so it is still here. */ ++ ++ if (ei_debug > 1) { ++ /* DMA termination address check... */ ++ int addr, tries = 20; ++ do { ++ int high = inb_p(nic_base + EN0_RSARHI); ++ int low = inb_p(nic_base + EN0_RSARLO); ++ addr = (high << 8) + low; ++ if ((start_page << 8) + count == addr) ++ break; ++ } while (--tries > 0); ++ ++ if (tries <= 0) { ++ printk(KERN_WARNING "%s: Tx packet transfer address mismatch," ++ "%#4.4x (expected) vs. %#4.4x (actual).\n", ++ dev->name, (start_page << 8) + count, addr); ++ if (retries++ == 0) ++ goto retry; ++ } ++ } ++#endif ++ ++ while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0) { ++ if (time_after(jiffies, dma_start + 2*HZ/100)) { /* 20ms */ ++ printk(KERN_WARNING "%s: timeout waiting for Tx RDC.\n", dev->name); ++ ne_reset_8390(dev); ++ NS8390_init(dev, 1); ++ break; ++ } ++ } ++ ++ outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ ++ ei_status.dmaing &= ~0x01; ++ return; ++} ++ ++ ++#ifdef MODULE ++#define MAX_NE_CARDS 4 /* Max number of NE cards per module */ ++static struct net_device *dev_ne[MAX_NE_CARDS]; ++static int io[MAX_NE_CARDS]; ++static int irq[MAX_NE_CARDS]; ++static int bad[MAX_NE_CARDS]; /* 0xbad = bad sig or no reset ack */ ++ ++module_param_array(io, int, NULL, 0); ++module_param_array(irq, int, NULL, 0); ++module_param_array(bad, int, NULL, 0); ++module_param(use_poll, int, 0); ++MODULE_PARM_DESC(io, "I/O base address(es),required"); ++MODULE_PARM_DESC(irq, "IRQ number(s)"); ++MODULE_PARM_DESC(bad, "Accept card(s) with bad signatures"); ++MODULE_PARM_DESC(use_poll, "Use timer interrupt to poll driver"); ++MODULE_DESCRIPTION("NE1000/NE2000 ISA/PnP Ethernet driver"); ++MODULE_LICENSE("GPL"); ++ ++/* This is set up so that no ISA autoprobe takes place. We can't guarantee ++that the ne2k probe is the last 8390 based probe to take place (as it ++is at boot) and so the probe will get confused by any other 8390 cards. ++ISA device autoprobes on a running machine are not recommended anyway. */ ++ ++int __init init_module(void) ++{ ++ int this_dev, found = 0; ++ ++ for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { ++ struct net_device *dev = alloc_ei_netdev(); ++ if (!dev) ++ break; ++ dev->irq = irq[this_dev]; ++ dev->mem_end = bad[this_dev]; ++ dev->base_addr = io[this_dev]; ++ if (do_ne_probe(dev) == 0) { ++ dev_ne[found++] = dev; ++ continue; ++ } ++ free_netdev(dev); ++ if (found) ++ break; ++ if (io[this_dev] != 0) ++ printk(KERN_WARNING "atari_ethernec.c: No NE*000 card found at i/o = %#x\n", io[this_dev]); ++ else ++ printk(KERN_NOTICE "atari_ethernec.c: You must supply \"io=0xNNN\" value(s) for ISA cards.\n"); ++ return -ENXIO; ++ } ++ if (found) ++ return 0; ++ return -ENODEV; ++} ++ ++static void cleanup_card(struct net_device *dev) ++{ ++ struct pnp_dev *idev = (struct pnp_dev *)ei_status.priv; ++ if (idev) ++ pnp_device_detach(idev); ++ free_irq(dev->irq, dev); ++ release_region(dev->base_addr, NE_IO_EXTENT); ++} ++ ++void cleanup_module(void) ++{ ++ int this_dev; ++ ++ for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { ++ struct net_device *dev = dev_ne[this_dev]; ++ if (dev) { ++ if (use_poll) ++ atari_ethernec_stop_poll(dev); ++ unregister_netdev(dev); ++ cleanup_card(dev); ++ free_netdev(dev); ++ } ++ } ++} ++#endif /* MODULE */ diff --git a/debian/patches/bugfix/m68k/atari-rom-isa.diff b/debian/patches/bugfix/m68k/atari-rom-isa.diff new file mode 100644 index 000000000000..ce5fdffd6fef --- /dev/null +++ b/debian/patches/bugfix/m68k/atari-rom-isa.diff @@ -0,0 +1,340 @@ +Subject: [PATCH] m68k: Atari ROM port ISA adapter support + +From: Michael Schmitz <schmitz@opal.biophys.uni-duesseldorf.de> + +Atari ROM port ISA adapter support + +Signed-off-by: Michael Schmitz <schmitz@debian.org> +Signed-off-by: Roman Zippel <zippel@linux-m68k.org> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + arch/m68k/Kconfig | 10 ++++ + include/asm-m68k/io.h | 101 ++++++++++++++++++++++++++++++++++++++++++++-- + include/asm-m68k/raw_io.h | 98 ++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 205 insertions(+), 4 deletions(-) + +--- linux-m68k-2.6.21.orig/arch/m68k/Kconfig ++++ linux-m68k-2.6.21/arch/m68k/Kconfig +@@ -143,6 +143,16 @@ config PCI + information about which PCI hardware does work under Linux and which + doesn't. + ++config ATARI_ROM_ISA ++ bool "Atari ROM port ISA adapter support" ++ depends on ATARI ++ help ++ This option enables support for the ROM port ISA adapter used to ++ operate ISA cards on Atari. Only 8 bit cards are supported, and ++ no interrupt lines are connected. ++ The only driver currently using this adapter is the EtherNEC ++ driver for RTL8019AS based NE2000 compatible network cards. ++ + config MAC + bool "Macintosh support" + depends on !MMU_SUN3 +--- linux-m68k-2.6.21.orig/include/asm-m68k/io.h ++++ linux-m68k-2.6.21/include/asm-m68k/io.h +@@ -82,9 +82,21 @@ extern unsigned long gg2_isa_base; + #endif + #endif /* AMIGA_PCMCIA */ + ++#ifdef CONFIG_ATARI_ROM_ISA + ++#define enec_isa_read_base 0xfffa0000 ++#define enec_isa_write_base 0xfffb0000 + +-#ifdef CONFIG_ISA ++#define ENEC_ISA_IO_B(ioaddr) (enec_isa_read_base+((((unsigned long)(ioaddr))&0x1F)<<9)) ++#define ENEC_ISA_IO_W(ioaddr) (enec_isa_read_base+((((unsigned long)(ioaddr))&0x1F)<<9)) ++#define ENEC_ISA_MEM_B(madr) (enec_isa_read_base+((((unsigned long)(madr))&0x1F)<<9)) ++#define ENEC_ISA_MEM_W(madr) (enec_isa_read_base+((((unsigned long)(madr))&0x1F)<<9)) ++ ++#define MULTI_ISA 0 ++#endif /* ATARI */ ++ ++ ++#if defined(CONFIG_ISA) || defined(CONFIG_ATARI_ROM_ISA) + + #if MULTI_ISA == 0 + #undef MULTI_ISA +@@ -93,6 +105,7 @@ extern unsigned long gg2_isa_base; + #define Q40_ISA (1) + #define GG2_ISA (2) + #define AG_ISA (3) ++#define ENEC_ISA (4) + + #if defined(CONFIG_Q40) && !defined(MULTI_ISA) + #define ISA_TYPE Q40_ISA +@@ -106,6 +119,10 @@ extern unsigned long gg2_isa_base; + #define ISA_TYPE GG2_ISA + #define ISA_SEX 0 + #endif ++#if defined(CONFIG_ATARI_ROM_ISA) && !defined(MULTI_ISA) ++#define ISA_TYPE ENEC_ISA ++#define ISA_SEX 0 ++#endif + + #ifdef MULTI_ISA + extern int isa_type; +@@ -133,6 +150,9 @@ static inline u8 __iomem *isa_itb(unsign + #ifdef CONFIG_AMIGA_PCMCIA + case AG_ISA: return (u8 __iomem *)AG_ISA_IO_B(addr); + #endif ++#ifdef CONFIG_ATARI_ROM_ISA ++ case ENEC_ISA: return (u8 __iomem *)ENEC_ISA_IO_B(addr); ++#endif + default: return NULL; /* avoid warnings, just in case */ + } + } +@@ -149,6 +169,9 @@ static inline u16 __iomem *isa_itw(unsig + #ifdef CONFIG_AMIGA_PCMCIA + case AG_ISA: return (u16 __iomem *)AG_ISA_IO_W(addr); + #endif ++#ifdef CONFIG_ATARI_ROM_ISA ++ case ENEC_ISA: return (u16 __iomem *)ENEC_ISA_IO_W(addr); ++#endif + default: return NULL; /* avoid warnings, just in case */ + } + } +@@ -165,6 +188,9 @@ static inline u8 __iomem *isa_mtb(unsign + #ifdef CONFIG_AMIGA_PCMCIA + case AG_ISA: return (u8 __iomem *)addr; + #endif ++#ifdef CONFIG_ATARI_ROM_ISA ++ case ENEC_ISA: return (u8 __iomem *)ENEC_ISA_MEM_B(addr); ++#endif + default: return NULL; /* avoid warnings, just in case */ + } + } +@@ -181,6 +207,9 @@ static inline u16 __iomem *isa_mtw(unsig + #ifdef CONFIG_AMIGA_PCMCIA + case AG_ISA: return (u16 __iomem *)addr; + #endif ++#ifdef CONFIG_ATARI_ROM_ISA ++ case ENEC_ISA: return (u16 __iomem *)ENEC_ISA_MEM_W(addr); ++#endif + default: return NULL; /* avoid warnings, just in case */ + } + } +@@ -200,6 +229,19 @@ static inline u16 __iomem *isa_mtw(unsig + (ISA_SEX ? out_be16(isa_mtw((unsigned long)(p)),(val)) \ + : out_le16(isa_mtw((unsigned long)(p)),(val))) + ++#if defined(CONFIG_ATARI_ROM_ISA) ++#define isa_rom_inb(port) rom_in_8(isa_itb(port)) ++#define isa_rom_inw(port) (ISA_SEX ? rom_in_be16(isa_itw(port)) : rom_in_le16(isa_itw(port))) ++ ++#define isa_rom_outb(val,port) rom_out_8(isa_itb(port),(val)) ++#define isa_rom_outw(val,port) (ISA_SEX ? rom_out_be16(isa_itw(port),(val)) : rom_out_le16(isa_itw(port),(val))) ++ ++#define isa_rom_writeb(val,p) rom_out_8(isa_mtb((unsigned long)(p)),(val)) ++#define isa_rom_writew(val,p) \ ++ (ISA_SEX ? rom_out_be16(isa_mtw((unsigned long)(p)),(val)) \ ++ : rom_out_le16(isa_mtw((unsigned long)(p)),(val))) ++#endif ++ + static inline void isa_delay(void) + { + switch(ISA_TYPE) +@@ -213,6 +255,9 @@ static inline void isa_delay(void) + #ifdef CONFIG_AMIGA_PCMCIA + case AG_ISA: break; + #endif ++#ifdef CONFIG_ATARI_ROM_ISA ++ case ENEC_ISA: break; ++#endif + default: break; /* avoid warnings */ + } + } +@@ -234,10 +279,33 @@ static inline void isa_delay(void) + #define isa_outsw(port, buf, nr) \ + (ISA_SEX ? raw_outsw(isa_itw(port), (u16 *)(buf), (nr)) : \ + raw_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr))) ++ ++#if defined(CONFIG_ATARI_ROM_ISA) ++#define isa_rom_inb_p(p) ({ u8 _v = isa_rom_inb(p); isa_delay(); _v; }) ++#define isa_rom_inw_p(p) ({ u16 _v = isa_rom_inw(p); isa_delay(); _v; }) ++#define isa_rom_inl_p(p) ({ u32 _v = isa_rom_inl(p) ;isa_delay(); _v; }) ++#define isa_rom_outb_p(v,p) ({ isa_rom_outb((v), (p)); isa_delay(); }) ++#define isa_rom_outw_p(v,p) ({ isa_rom_outw((v), (p)); isa_delay(); }) ++#define isa_rom_outl_p(v,p) ({ isa_rom_outl((v), (p)); isa_delay(); }) ++ ++#define isa_rom_insb(port, buf, nr) raw_rom_insb(isa_itb(port), (u8 *)(buf), (nr)) ++ ++#define isa_rom_insw(port, buf, nr) \ ++ (ISA_SEX ? raw_rom_insw(isa_itw(port), (u16 *)(buf), (nr)) : \ ++ raw_rom_insw_swapw(isa_itw(port), (u16 *)(buf), (nr))) ++ ++#define isa_rom_outsb(port, buf, nr) raw_rom_outsb(isa_itb(port), (u8 *)(buf), (nr)) ++ ++#define isa_rom_outsw(port, buf, nr) \ ++ (ISA_SEX ? raw_rom_outsw(isa_itw(port), (u16 *)(buf), (nr)) : \ ++ raw_rom_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr))) ++ ++#endif ++ + #endif /* CONFIG_ISA */ + + +-#if defined(CONFIG_ISA) && !defined(CONFIG_PCI) ++#if defined(CONFIG_ISA) && !defined(CONFIG_PCI) && !defined(CONFIG_ATARI_ROM_ISA) + #define inb isa_inb + #define inb_p isa_inb_p + #define outb isa_outb +@@ -306,7 +374,34 @@ static inline void isa_delay(void) + #endif + #endif /* CONFIG_PCI */ + +-#if !defined(CONFIG_ISA) && !defined(CONFIG_PCI) && defined(CONFIG_HP300) ++#if defined(CONFIG_ATARI_ROM_ISA) ++/* ++ * kernel with both ROM port ISA and IDE compiled in, those have ++ * conflicting defs for in/out. Simply consider port < 1024 ++ * ROM port ISA and everything else regular ISA for IDE. read,write not defined ++ * in this case ++ */ ++#define inb(port) ((port) < 1024 ? isa_rom_inb(port) : in_8(port)) ++#define inb_p(port) ((port) < 1024 ? isa_rom_inb_p(port) : in_8(port)) ++#define inw(port) ((port) < 1024 ? isa_rom_inw(port) : in_le16(port)) ++#define inw_p(port) ((port) < 1024 ? isa_rom_inw_p(port) : in_le16(port)) ++#define inl(port) ((port) < 1024 ? isa_rom_inl(port) : in_le32(port)) ++#define inl_p(port) ((port) < 1024 ? isa_rom_inl_p(port) : in_le32(port)) ++ ++#define outb(val,port) ((port) < 1024 ? isa_rom_outb((val), (port)) : out_8((port), (val))) ++#define outb_p(val,port) ((port) < 1024 ? isa_rom_outb_p((val), (port)) : out_8((port), (val))) ++#define outw(val,port) ((port) < 1024 ? isa_rom_outw((val), (port)) : out_le16((port), (val))) ++#define outw_p(val,port) ((port) < 1024 ? isa_rom_outw_p((val), (port)) : out_le16((port), (val))) ++#define outl(val,port) ((port) < 1024 ? isa_rom_outl((val), (port)) : out_le32((port), (val))) ++#define outl_p(val,port) ((port) < 1024 ? isa_rom_outl_p((val), (port)) : out_le32((port), (val))) ++ ++#define insb isa_rom_insb ++#define insw isa_rom_insw ++#define outsb isa_rom_outsb ++#define outsw isa_rom_outsw ++#endif ++ ++#if !defined(CONFIG_ISA) && !defined(CONFIG_PCI) && !defined(CONFIG_ATARI_ROM_ISA) && defined(CONFIG_HP300) + /* + * We need to define dummy functions otherwise drivers/serial/8250.c doesn't link + */ +--- linux-m68k-2.6.21.orig/include/asm-m68k/raw_io.h ++++ linux-m68k-2.6.21/include/asm-m68k/raw_io.h +@@ -10,7 +10,7 @@ + + #ifdef __KERNEL__ + +-#include <asm/types.h> ++#include <asm/byteorder.h> + + + /* Values for nocacheflag and cmode */ +@@ -54,6 +54,46 @@ extern void __iounmap(void *addr, unsign + #define raw_outw(val,port) out_be16((port),(val)) + #define raw_outl(val,port) out_be32((port),(val)) + ++/* ++ * Atari ROM port (cartridge port) ISA adapter, used for the EtherNEC NE2000 ++ * network card driver. ++ * The ISA adapter connects address lines A9-A13 to ISA address lines A0-A4, ++ * and hardwires the rest of the ISA addresses for a base address of 0x300. ++ * ++ * Data lines D8-D15 are connected to ISA data lines D0-D7 for reading. ++ * For writes, address lines A1-A8 are latched to ISA data lines D0-D7 ++ * (meaning the bit pattern on A1-A8 can be read back as byte). ++ * ++ * Reads and writes are byte only. ++ */ ++ ++#if defined(CONFIG_ATARI_ROM_ISA) ++#define rom_in_8(addr) \ ++ ({ u16 __v = (*(__force volatile u16 *) (addr)); __v >>= 8; __v; }) ++#define rom_in_be16(addr) \ ++ ({ u16 __v = (*(__force volatile u16 *) (addr)); __v >>= 8; __v; }) ++#define rom_in_be32(addr) \ ++ ({ u32 __v = (*(__force volatile u32 *) (addr)); __v >>= 8; __v; }) ++#define rom_in_le16(addr) \ ++ ({ u16 __v = le16_to_cpu(*(__force volatile u16 *) (addr)); __v >>= 8; __v; }) ++#define rom_in_le32(addr) \ ++ ({ u32 __v = le32_to_cpu(*(__force volatile u32 *) (addr)); __v >>= 8; __v; }) ++ ++#define rom_out_8(addr,b) ({u8 __w, __v = (b); __w = ((*(__force volatile u8 *) ((addr) + 0x10000 + (__v<<1)))); }) ++#define rom_out_be16(addr,w) ({u16 __w, __v = (w); __w = ((*(__force volatile u16 *) ((addr) + 0x10000 + (__v<<1)))); }) ++#define rom_out_be32(addr,l) ({u32 __w, __v = (l); __w = ((*(__force volatile u32 *) ((addr) + 0x10000 + (__v<<1)))); }) ++#define rom_out_le16(addr,w) ({u16 __w, __v = cpu_to_le16(w); __w = ((*(__force volatile u16 *) ((addr) + 0x10000 + (__v<<1)))); }) ++#define rom_out_le32(addr,l) ({u32 __w, __v = cpu_to_le32(l); __w = ((*(__force volatile u32 *) ((addr) + 0x10000 + (__v<<1)))); }) ++ ++#define raw_rom_inb rom_in_8 ++#define raw_rom_inw rom_in_be16 ++#define raw_rom_inl rom_in_be32 ++ ++#define raw_rom_outb(val,port) rom_out_8((port),(val)) ++#define raw_rom_outw(val,port) rom_out_be16((port),(val)) ++#define raw_rom_outl(val,port) rom_out_be32((port),(val)) ++#endif /* CONFIG_ATARI_ROM_ISA */ ++ + static inline void raw_insb(volatile u8 __iomem *port, u8 *buf, unsigned int len) + { + unsigned int i; +@@ -336,6 +376,62 @@ static inline void raw_outsw_swapw(volat + : "d0", "a0", "a1", "d6"); + } + ++ ++#if defined(CONFIG_ATARI_ROM_ISA) ++static inline void raw_rom_insb(volatile u8 __iomem *port, u8 *buf, unsigned int len) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < len; i++) ++ *buf++ = rom_in_8(port); ++} ++ ++static inline void raw_rom_outsb(volatile u8 __iomem *port, const u8 *buf, ++ unsigned int len) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < len; i++) ++ rom_out_8(port, *buf++); ++} ++ ++static inline void raw_rom_insw(volatile u16 __iomem *port, u16 *buf, ++ unsigned int nr) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < nr; i++) ++ *buf++ = rom_in_be16(port); ++} ++ ++static inline void raw_rom_outsw(volatile u16 __iomem *port, const u16 *buf, ++ unsigned int nr) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < nr; i++) ++ rom_out_be16(port, *buf++); ++} ++ ++static inline void raw_rom_insw_swapw(volatile u16 __iomem *port, u16 *buf, ++ unsigned int nr) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < nr; i++) ++ *buf++ = rom_in_le16(port); ++} ++ ++static inline void raw_rom_outsw_swapw(volatile u16 __iomem *port, const u16 *buf, ++ unsigned int nr) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < nr; i++) ++ rom_out_le16(port, *buf++); ++} ++#endif /* CONFIG_ATARI_ROM_ISA */ ++ + #define __raw_writel raw_outl + + #endif /* __KERNEL__ */ diff --git a/debian/patches/bugfix/m68k/atari-scsi-compile-fixes.diff b/debian/patches/bugfix/m68k/atari-scsi-compile-fixes.diff new file mode 100644 index 000000000000..3aa6f7bfb40f --- /dev/null +++ b/debian/patches/bugfix/m68k/atari-scsi-compile-fixes.diff @@ -0,0 +1,340 @@ +Cc: James E.J. Bottomley <James.Bottomley@SteelEye.com>, + linux-scsi@vger.kernel.org +Subject: [PATCH] m68k: Atari SCSI driver compile fixes + +From: Roman Zippel <zippel@linux-m68k.org> + +Atari SCSI driver compile fixes + +Signed-off-by: Roman Zippel <zippel@linux-m68k.org> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + drivers/scsi/atari_NCR5380.c | 33 +++++---- + drivers/scsi/atari_scsi.c | 6 - + drivers/scsi/atari_scsi.h | 144 ++++++++----------------------------------- + 3 files changed, 49 insertions(+), 134 deletions(-) + +--- linux-m68k-2.6.21.orig/drivers/scsi/atari_NCR5380.c ++++ linux-m68k-2.6.21/drivers/scsi/atari_NCR5380.c +@@ -272,8 +272,9 @@ static struct scsi_host_template *the_te + (struct NCR5380_hostdata *)(in)->hostdata + #define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata) + +-#define NEXT(cmd) ((cmd)->host_scribble) +-#define NEXTADDR(cmd) ((Scsi_Cmnd **)&((cmd)->host_scribble)) ++#define NEXT(cmd) ((Scsi_Cmnd *)(cmd)->host_scribble) ++#define SET_NEXT(cmd,next) ((cmd)->host_scribble = (void *)(next)) ++#define NEXTADDR(cmd) ((Scsi_Cmnd **)&(cmd)->host_scribble) + + #define HOSTNO instance->host_no + #define H_NO(cmd) (cmd)->device->host->host_no +@@ -479,7 +480,7 @@ static void merge_contiguous_buffers(Scs + virt_to_phys(page_address(cmd->SCp.buffer[1].page) + + cmd->SCp.buffer[1].offset) == endaddr;) { + MER_PRINTK("VTOP(%p) == %08lx -> merging\n", +- cmd->SCp.buffer[1].address, endaddr); ++ page_address(cmd->SCp.buffer[1].page), endaddr); + #if (NDEBUG & NDEBUG_MERGING) + ++cnt; + #endif +@@ -1002,7 +1003,7 @@ static int NCR5380_queue_command(Scsi_Cm + * in a queue + */ + +- NEXT(cmd) = NULL; ++ SET_NEXT(cmd, NULL); + cmd->scsi_done = done; + + cmd->result = 0; +@@ -1034,14 +1035,14 @@ static int NCR5380_queue_command(Scsi_Cm + } + if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) { + LIST(cmd, hostdata->issue_queue); +- NEXT(cmd) = hostdata->issue_queue; ++ SET_NEXT(cmd, hostdata->issue_queue); + hostdata->issue_queue = cmd; + } else { + for (tmp = (Scsi_Cmnd *)hostdata->issue_queue; + NEXT(tmp); tmp = NEXT(tmp)) + ; + LIST(cmd, tmp); +- NEXT(tmp) = cmd; ++ SET_NEXT(tmp, cmd); + } + local_irq_restore(flags); + +@@ -1149,12 +1150,12 @@ static void NCR5380_main(void *bl) + local_irq_disable(); + if (prev) { + REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); +- NEXT(prev) = NEXT(tmp); ++ SET_NEXT(prev, NEXT(tmp)); + } else { + REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp)); + hostdata->issue_queue = NEXT(tmp); + } +- NEXT(tmp) = NULL; ++ SET_NEXT(tmp, NULL); + falcon_dont_release++; + + /* reenable interrupts after finding one */ +@@ -1192,7 +1193,7 @@ static void NCR5380_main(void *bl) + } else { + local_irq_disable(); + LIST(tmp, hostdata->issue_queue); +- NEXT(tmp) = hostdata->issue_queue; ++ SET_NEXT(tmp, hostdata->issue_queue); + hostdata->issue_queue = tmp; + #ifdef SUPPORT_TAGS + cmd_free_tag(tmp); +@@ -2295,7 +2296,7 @@ static void NCR5380_information_transfer + + local_irq_save(flags); + LIST(cmd,hostdata->issue_queue); +- NEXT(cmd) = hostdata->issue_queue; ++ SET_NEXT(cmd, hostdata->issue_queue); + hostdata->issue_queue = (Scsi_Cmnd *) cmd; + local_irq_restore(flags); + QU_PRINTK("scsi%d: REQUEST SENSE added to head of " +@@ -2357,7 +2358,7 @@ static void NCR5380_information_transfer + local_irq_save(flags); + cmd->device->disconnect = 1; + LIST(cmd,hostdata->disconnected_queue); +- NEXT(cmd) = hostdata->disconnected_queue; ++ SET_NEXT(cmd, hostdata->disconnected_queue); + hostdata->connected = NULL; + hostdata->disconnected_queue = cmd; + local_irq_restore(flags); +@@ -2632,12 +2633,12 @@ static void NCR5380_reselect(struct Scsi + falcon_dont_release++; + if (prev) { + REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); +- NEXT(prev) = NEXT(tmp); ++ SET_NEXT(prev, NEXT(tmp)); + } else { + REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp)); + hostdata->disconnected_queue = NEXT(tmp); + } +- NEXT(tmp) = NULL; ++ SET_NEXT(tmp, NULL); + break; + } + } +@@ -2769,7 +2770,7 @@ int NCR5380_abort(Scsi_Cmnd *cmd) + if (cmd == tmp) { + REMOVE(5, *prev, tmp, NEXT(tmp)); + (*prev) = NEXT(tmp); +- NEXT(tmp) = NULL; ++ SET_NEXT(tmp, NULL); + tmp->result = DID_ABORT << 16; + local_irq_restore(flags); + ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n", +@@ -2844,7 +2845,7 @@ int NCR5380_abort(Scsi_Cmnd *cmd) + if (cmd == tmp) { + REMOVE(5, *prev, tmp, NEXT(tmp)); + *prev = NEXT(tmp); +- NEXT(tmp) = NULL; ++ SET_NEXT(tmp, NULL); + tmp->result = DID_ABORT << 16; + /* We must unlock the tag/LUN immediately here, since the + * target goes to BUS FREE and doesn't send us another +@@ -2965,7 +2966,7 @@ static int NCR5380_bus_reset(Scsi_Cmnd * + + for (i = 0; (cmd = disconnected_queue); ++i) { + disconnected_queue = NEXT(cmd); +- NEXT(cmd) = NULL; ++ SET_NEXT(cmd, NULL); + cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16); + cmd->scsi_done(cmd); + } +--- linux-m68k-2.6.21.orig/drivers/scsi/atari_scsi.c ++++ linux-m68k-2.6.21/drivers/scsi/atari_scsi.c +@@ -69,9 +69,9 @@ + + #define NDEBUG (0) + +-#define NDEBUG_ABORT 0x800000 +-#define NDEBUG_TAGS 0x1000000 +-#define NDEBUG_MERGING 0x2000000 ++#define NDEBUG_ABORT 0x00100000 ++#define NDEBUG_TAGS 0x00200000 ++#define NDEBUG_MERGING 0x00400000 + + #define AUTOSENSE + /* For the Atari version, use only polled IO or REAL_DMA */ +--- linux-m68k-2.6.21.orig/drivers/scsi/atari_scsi.h ++++ linux-m68k-2.6.21/drivers/scsi/atari_scsi.h +@@ -113,144 +113,58 @@ int atari_scsi_release (struct Scsi_Host + * + */ + +-#if NDEBUG & NDEBUG_ARBITRATION ++#define dprint(flg, format...) \ ++({ \ ++ if (NDEBUG & (flg)) \ ++ printk(KERN_DEBUG format); \ ++}) ++ + #define ARB_PRINTK(format, args...) \ +- printk(KERN_DEBUG format , ## args) +-#else +-#define ARB_PRINTK(format, args...) +-#endif +-#if NDEBUG & NDEBUG_AUTOSENSE ++ dprint(NDEBUG_ARBITRATION, format , ## args) + #define ASEN_PRINTK(format, args...) \ +- printk(KERN_DEBUG format , ## args) +-#else +-#define ASEN_PRINTK(format, args...) +-#endif +-#if NDEBUG & NDEBUG_DMA ++ dprint(NDEBUG_AUTOSENSE, format , ## args) + #define DMA_PRINTK(format, args...) \ +- printk(KERN_DEBUG format , ## args) +-#else +-#define DMA_PRINTK(format, args...) +-#endif +-#if NDEBUG & NDEBUG_HANDSHAKE ++ dprint(NDEBUG_DMA, format , ## args) + #define HSH_PRINTK(format, args...) \ +- printk(KERN_DEBUG format , ## args) +-#else +-#define HSH_PRINTK(format, args...) +-#endif +-#if NDEBUG & NDEBUG_INFORMATION ++ dprint(NDEBUG_HANDSHAKE, format , ## args) + #define INF_PRINTK(format, args...) \ +- printk(KERN_DEBUG format , ## args) +-#else +-#define INF_PRINTK(format, args...) +-#endif +-#if NDEBUG & NDEBUG_INIT ++ dprint(NDEBUG_INFORMATION, format , ## args) + #define INI_PRINTK(format, args...) \ +- printk(KERN_DEBUG format , ## args) +-#else +-#define INI_PRINTK(format, args...) +-#endif +-#if NDEBUG & NDEBUG_INTR ++ dprint(NDEBUG_INIT, format , ## args) + #define INT_PRINTK(format, args...) \ +- printk(KERN_DEBUG format , ## args) +-#else +-#define INT_PRINTK(format, args...) +-#endif +-#if NDEBUG & NDEBUG_LINKED ++ dprint(NDEBUG_INTR, format , ## args) + #define LNK_PRINTK(format, args...) \ +- printk(KERN_DEBUG format , ## args) +-#else +-#define LNK_PRINTK(format, args...) +-#endif +-#if NDEBUG & NDEBUG_MAIN ++ dprint(NDEBUG_LINKED, format , ## args) + #define MAIN_PRINTK(format, args...) \ +- printk(KERN_DEBUG format , ## args) +-#else +-#define MAIN_PRINTK(format, args...) +-#endif +-#if NDEBUG & NDEBUG_NO_DATAOUT ++ dprint(NDEBUG_MAIN, format , ## args) + #define NDAT_PRINTK(format, args...) \ +- printk(KERN_DEBUG format , ## args) +-#else +-#define NDAT_PRINTK(format, args...) +-#endif +-#if NDEBUG & NDEBUG_NO_WRITE ++ dprint(NDEBUG_NO_DATAOUT, format , ## args) + #define NWR_PRINTK(format, args...) \ +- printk(KERN_DEBUG format , ## args) +-#else +-#define NWR_PRINTK(format, args...) +-#endif +-#if NDEBUG & NDEBUG_PIO ++ dprint(NDEBUG_NO_WRITE, format , ## args) + #define PIO_PRINTK(format, args...) \ +- printk(KERN_DEBUG format , ## args) +-#else +-#define PIO_PRINTK(format, args...) +-#endif +-#if NDEBUG & NDEBUG_PSEUDO_DMA ++ dprint(NDEBUG_PIO, format , ## args) + #define PDMA_PRINTK(format, args...) \ +- printk(KERN_DEBUG format , ## args) +-#else +-#define PDMA_PRINTK(format, args...) +-#endif +-#if NDEBUG & NDEBUG_QUEUES ++ dprint(NDEBUG_PSEUDO_DMA, format , ## args) + #define QU_PRINTK(format, args...) \ +- printk(KERN_DEBUG format , ## args) +-#else +-#define QU_PRINTK(format, args...) +-#endif +-#if NDEBUG & NDEBUG_RESELECTION ++ dprint(NDEBUG_QUEUES, format , ## args) + #define RSL_PRINTK(format, args...) \ +- printk(KERN_DEBUG format , ## args) +-#else +-#define RSL_PRINTK(format, args...) +-#endif +-#if NDEBUG & NDEBUG_SELECTION ++ dprint(NDEBUG_RESELECTION, format , ## args) + #define SEL_PRINTK(format, args...) \ +- printk(KERN_DEBUG format , ## args) +-#else +-#define SEL_PRINTK(format, args...) +-#endif +-#if NDEBUG & NDEBUG_USLEEP ++ dprint(NDEBUG_SELECTION, format , ## args) + #define USL_PRINTK(format, args...) \ +- printk(KERN_DEBUG format , ## args) +-#else +-#define USL_PRINTK(format, args...) +-#endif +-#if NDEBUG & NDEBUG_LAST_BYTE_SENT ++ dprint(NDEBUG_USLEEP, format , ## args) + #define LBS_PRINTK(format, args...) \ +- printk(KERN_DEBUG format , ## args) +-#else +-#define LBS_PRINTK(format, args...) +-#endif +-#if NDEBUG & NDEBUG_RESTART_SELECT ++ dprint(NDEBUG_LAST_BYTE_SENT, format , ## args) + #define RSS_PRINTK(format, args...) \ +- printk(KERN_DEBUG format , ## args) +-#else +-#define RSS_PRINTK(format, args...) +-#endif +-#if NDEBUG & NDEBUG_EXTENDED ++ dprint(NDEBUG_RESTART_SELECT, format , ## args) + #define EXT_PRINTK(format, args...) \ +- printk(KERN_DEBUG format , ## args) +-#else +-#define EXT_PRINTK(format, args...) +-#endif +-#if NDEBUG & NDEBUG_ABORT ++ dprint(NDEBUG_EXTENDED, format , ## args) + #define ABRT_PRINTK(format, args...) \ +- printk(KERN_DEBUG format , ## args) +-#else +-#define ABRT_PRINTK(format, args...) +-#endif +-#if NDEBUG & NDEBUG_TAGS ++ dprint(NDEBUG_ABORT, format , ## args) + #define TAG_PRINTK(format, args...) \ +- printk(KERN_DEBUG format , ## args) +-#else +-#define TAG_PRINTK(format, args...) +-#endif +-#if NDEBUG & NDEBUG_MERGING ++ dprint(NDEBUG_TAGS, format , ## args) + #define MER_PRINTK(format, args...) \ +- printk(KERN_DEBUG format , ## args) +-#else +-#define MER_PRINTK(format, args...) +-#endif ++ dprint(NDEBUG_MERGING, format , ## args) + + /* conditional macros for NCR5380_print_{,phase,status} */ + diff --git a/debian/patches/bugfix/m68k/atari-scsi-reformat.diff b/debian/patches/bugfix/m68k/atari-scsi-reformat.diff new file mode 100644 index 000000000000..09afca506ae0 --- /dev/null +++ b/debian/patches/bugfix/m68k/atari-scsi-reformat.diff @@ -0,0 +1,5903 @@ +Cc: James E.J. Bottomley <James.Bottomley@SteelEye.com>, + linux-scsi@vger.kernel.org +Subject: [PATCH] m68k: Reformat the Atari SCSI driver + +From: Roman Zippel <zippel@linux-m68k.org> + +Reformat the Atari SCSI driver + +Signed-off-by: Roman Zippel <zippel@linux-m68k.org> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + drivers/scsi/atari_NCR5380.c | 4433 +++++++++++++++++++++---------------------- + drivers/scsi/atari_scsi.c | 363 +-- + 2 files changed, 2397 insertions(+), 2399 deletions(-) + +--- linux-m68k-2.6.21.orig/drivers/scsi/atari_NCR5380.c ++++ linux-m68k-2.6.21/drivers/scsi/atari_NCR5380.c +@@ -1,19 +1,19 @@ +-/* ++/* + * NCR 5380 generic driver routines. These should make it *trivial* +- * to implement 5380 SCSI drivers under Linux with a non-trantor ++ * to implement 5380 SCSI drivers under Linux with a non-trantor + * architecture. + * + * Note that these routines also work with NR53c400 family chips. + * + * Copyright 1993, Drew Eckhardt +- * Visionary Computing ++ * Visionary Computing + * (Unix and Linux consulting and custom programming) +- * drew@colorado.edu ++ * drew@colorado.edu + * +1 (303) 666-5836 + * +- * DISTRIBUTION RELEASE 6. ++ * DISTRIBUTION RELEASE 6. + * +- * For more information, please consult ++ * For more information, please consult + * + * NCR 5380 Family + * SCSI Protocol Controller +@@ -57,7 +57,7 @@ + * - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA + * and USLEEP, because these were messing up readability and will never be + * needed for Atari SCSI. +- * ++ * + * - I've revised the NCR5380_main() calling scheme (relax the 'main_running' + * stuff), and 'main' is executed in a bottom half if awoken by an + * interrupt. +@@ -69,21 +69,29 @@ + */ + + /* +- * Further development / testing that should be done : +- * 1. Test linked command handling code after Eric is ready with ++ * Further development / testing that should be done : ++ * 1. Test linked command handling code after Eric is ready with + * the high level code. + */ + #include <scsi/scsi_dbg.h> + #include <scsi/scsi_transport_spi.h> + + #if (NDEBUG & NDEBUG_LISTS) +-#define LIST(x,y) \ +- { printk("LINE:%d Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); \ +- if ((x)==(y)) udelay(5); } +-#define REMOVE(w,x,y,z) \ +- { printk("LINE:%d Removing: %p->%p %p->%p \n", __LINE__, \ +- (void*)(w), (void*)(x), (void*)(y), (void*)(z)); \ +- if ((x)==(y)) udelay(5); } ++#define LIST(x, y) \ ++ do { \ ++ printk("LINE:%d Adding %p to %p\n", \ ++ __LINE__, (void*)(x), (void*)(y)); \ ++ if ((x) == (y)) \ ++ udelay(5); \ ++ } while (0) ++#define REMOVE(w, x, y, z) \ ++ do { \ ++ printk("LINE:%d Removing: %p->%p %p->%p \n", \ ++ __LINE__, (void*)(w), (void*)(x), \ ++ (void*)(y), (void*)(z)); \ ++ if ((x) == (y)) \ ++ udelay(5); \ ++ } while (0) + #else + #define LIST(x,y) + #define REMOVE(w,x,y,z) +@@ -103,62 +111,62 @@ + * more difficult than it has to be. + * + * Also, many of the SCSI drivers were written before the command queuing +- * routines were implemented, meaning their implementations of queued ++ * routines were implemented, meaning their implementations of queued + * commands were hacked on rather than designed in from the start. + * +- * When I designed the Linux SCSI drivers I figured that ++ * When I designed the Linux SCSI drivers I figured that + * while having two different SCSI boards in a system might be useful + * for debugging things, two of the same type wouldn't be used. + * Well, I was wrong and a number of users have mailed me about running + * multiple high-performance SCSI boards in a server. + * +- * Finally, when I get questions from users, I have no idea what ++ * Finally, when I get questions from users, I have no idea what + * revision of my driver they are running. + * + * This driver attempts to address these problems : +- * This is a generic 5380 driver. To use it on a different platform, ++ * This is a generic 5380 driver. To use it on a different platform, + * one simply writes appropriate system specific macros (ie, data +- * transfer - some PC's will use the I/O bus, 68K's must use ++ * transfer - some PC's will use the I/O bus, 68K's must use + * memory mapped) and drops this file in their 'C' wrapper. + * +- * As far as command queueing, two queues are maintained for ++ * As far as command queueing, two queues are maintained for + * each 5380 in the system - commands that haven't been issued yet, +- * and commands that are currently executing. This means that an +- * unlimited number of commands may be queued, letting +- * more commands propagate from the higher driver levels giving higher +- * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported, +- * allowing multiple commands to propagate all the way to a SCSI-II device ++ * and commands that are currently executing. This means that an ++ * unlimited number of commands may be queued, letting ++ * more commands propagate from the higher driver levels giving higher ++ * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported, ++ * allowing multiple commands to propagate all the way to a SCSI-II device + * while a command is already executing. + * +- * To solve the multiple-boards-in-the-same-system problem, ++ * To solve the multiple-boards-in-the-same-system problem, + * there is a separate instance structure for each instance + * of a 5380 in the system. So, multiple NCR5380 drivers will + * be able to coexist with appropriate changes to the high level +- * SCSI code. ++ * SCSI code. + * + * A NCR5380_PUBLIC_REVISION macro is provided, with the release +- * number (updated for each public release) printed by the +- * NCR5380_print_options command, which should be called from the ++ * number (updated for each public release) printed by the ++ * NCR5380_print_options command, which should be called from the + * wrapper detect function, so that I know what release of the driver + * users are using. + * +- * Issues specific to the NCR5380 : ++ * Issues specific to the NCR5380 : + * +- * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead +- * piece of hardware that requires you to sit in a loop polling for +- * the REQ signal as long as you are connected. Some devices are +- * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect ++ * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead ++ * piece of hardware that requires you to sit in a loop polling for ++ * the REQ signal as long as you are connected. Some devices are ++ * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect + * while doing long seek operations. +- * ++ * + * The workaround for this is to keep track of devices that have + * disconnected. If the device hasn't disconnected, for commands that +- * should disconnect, we do something like ++ * should disconnect, we do something like + * + * while (!REQ is asserted) { sleep for N usecs; poll for M usecs } +- * +- * Some tweaking of N and M needs to be done. An algorithm based ++ * ++ * Some tweaking of N and M needs to be done. An algorithm based + * on "time to data" would give the best results as long as short time +- * to datas (ie, on the same track) were considered, however these ++ * to datas (ie, on the same track) were considered, however these + * broken devices are the exception rather than the rule and I'd rather + * spend my time optimizing for the normal case. + * +@@ -167,9 +175,9 @@ + * At the heart of the design is a coroutine, NCR5380_main, + * which is started when not running by the interrupt handler, + * timer, and queue command function. It attempts to establish +- * I_T_L or I_T_L_Q nexuses by removing the commands from the +- * issue queue and calling NCR5380_select() if a nexus +- * is not established. ++ * I_T_L or I_T_L_Q nexuses by removing the commands from the ++ * issue queue and calling NCR5380_select() if a nexus ++ * is not established. + * + * Once a nexus is established, the NCR5380_information_transfer() + * phase goes through the various phases as instructed by the target. +@@ -183,10 +191,10 @@ + * calling NCR5380_intr() which will in turn call NCR5380_reselect + * to reestablish a nexus. This will run main if necessary. + * +- * On command termination, the done function will be called as ++ * On command termination, the done function will be called as + * appropriate. + * +- * SCSI pointers are maintained in the SCp field of SCSI command ++ * SCSI pointers are maintained in the SCp field of SCSI command + * structures, being initialized after the command is connected + * in NCR5380_select, and set as appropriate in NCR5380_information_transfer. + * Note that in violation of the standard, an implicit SAVE POINTERS operation +@@ -196,12 +204,12 @@ + /* + * Using this file : + * This file a skeleton Linux SCSI driver for the NCR 5380 series +- * of chips. To use it, you write an architecture specific functions ++ * of chips. To use it, you write an architecture specific functions + * and macros and include this file in your driver. + * +- * These macros control options : ++ * These macros control options : + * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically +- * for commands that return with a CHECK CONDITION status. ++ * for commands that return with a CHECK CONDITION status. + * + * LINKED - if defined, linked commands are supported. + * +@@ -210,18 +218,18 @@ + * SUPPORT_TAGS - if defined, SCSI-2 tagged queuing is used where possible + * + * These macros MUST be defined : +- * ++ * + * NCR5380_read(register) - read from the specified register + * +- * NCR5380_write(register, value) - write to the specific register ++ * NCR5380_write(register, value) - write to the specific register + * + * Either real DMA *or* pseudo DMA may be implemented +- * REAL functions : ++ * REAL functions : + * NCR5380_REAL_DMA should be defined if real DMA is to be used. +- * Note that the DMA setup functions should return the number of bytes ++ * Note that the DMA setup functions should return the number of bytes + * that they were able to program the controller for. + * +- * Also note that generic i386/PC versions of these macros are ++ * Also note that generic i386/PC versions of these macros are + * available as NCR5380_i386_dma_write_setup, + * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual. + * +@@ -234,14 +242,14 @@ + * NCR5380_pread(instance, dst, count); + * + * If nothing specific to this implementation needs doing (ie, with external +- * hardware), you must also define +- * ++ * hardware), you must also define ++ * + * NCR5380_queue_command + * NCR5380_reset + * NCR5380_abort + * NCR5380_proc_info + * +- * to be the global entry points into the specific driver, ie ++ * to be the global entry points into the specific driver, ie + * #define NCR5380_queue_command t128_queue_command. + * + * If this is not done, the routines will be defined as static functions +@@ -249,7 +257,7 @@ + * accessible wrapper function. + * + * The generic driver is initialized by calling NCR5380_init(instance), +- * after setting the appropriate host specific fields and ID. If the ++ * after setting the appropriate host specific fields and ID. If the + * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance, + * possible) function may be used. Before the specific driver initialization + * code finishes, NCR5380_print_options should be called. +@@ -312,34 +320,34 @@ static struct scsi_host_template *the_te + #define TAG_NONE 0xff + + typedef struct { +- DECLARE_BITMAP(allocated, MAX_TAGS); +- int nr_allocated; +- int queue_size; ++ DECLARE_BITMAP(allocated, MAX_TAGS); ++ int nr_allocated; ++ int queue_size; + } TAG_ALLOC; + +-static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */ ++static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */ + + +-static void __init init_tags( void ) ++static void __init init_tags(void) + { +- int target, lun; +- TAG_ALLOC *ta; +- +- if (!setup_use_tagged_queuing) +- return; +- +- for( target = 0; target < 8; ++target ) { +- for( lun = 0; lun < 8; ++lun ) { +- ta = &TagAlloc[target][lun]; +- bitmap_zero(ta->allocated, MAX_TAGS); +- ta->nr_allocated = 0; +- /* At the beginning, assume the maximum queue size we could +- * support (MAX_TAGS). This value will be decreased if the target +- * returns QUEUE_FULL status. +- */ +- ta->queue_size = MAX_TAGS; ++ int target, lun; ++ TAG_ALLOC *ta; ++ ++ if (!setup_use_tagged_queuing) ++ return; ++ ++ for (target = 0; target < 8; ++target) { ++ for (lun = 0; lun < 8; ++lun) { ++ ta = &TagAlloc[target][lun]; ++ bitmap_zero(ta->allocated, MAX_TAGS); ++ ta->nr_allocated = 0; ++ /* At the beginning, assume the maximum queue size we could ++ * support (MAX_TAGS). This value will be decreased if the target ++ * returns QUEUE_FULL status. ++ */ ++ ta->queue_size = MAX_TAGS; ++ } + } +- } + } + + +@@ -348,24 +356,24 @@ static void __init init_tags( void ) + * check that there is a free tag and the target's queue won't overflow. This + * function should be called with interrupts disabled to avoid race + * conditions. +- */ ++ */ + +-static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged ) ++static int is_lun_busy(Scsi_Cmnd *cmd, int should_be_tagged) + { +- SETUP_HOSTDATA(cmd->device->host); ++ SETUP_HOSTDATA(cmd->device->host); + +- if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun)) +- return( 1 ); +- if (!should_be_tagged || +- !setup_use_tagged_queuing || !cmd->device->tagged_supported) +- return( 0 ); +- if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >= +- TagAlloc[cmd->device->id][cmd->device->lun].queue_size ) { +- TAG_PRINTK( "scsi%d: target %d lun %d: no free tags\n", +- H_NO(cmd), cmd->device->id, cmd->device->lun ); +- return( 1 ); +- } +- return( 0 ); ++ if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun)) ++ return 1; ++ if (!should_be_tagged || ++ !setup_use_tagged_queuing || !cmd->device->tagged_supported) ++ return 0; ++ if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >= ++ TagAlloc[cmd->device->id][cmd->device->lun].queue_size) { ++ TAG_PRINTK("scsi%d: target %d lun %d: no free tags\n", ++ H_NO(cmd), cmd->device->id, cmd->device->lun); ++ return 1; ++ } ++ return 0; + } + + +@@ -374,31 +382,30 @@ static int is_lun_busy( Scsi_Cmnd *cmd, + * untagged. + */ + +-static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged ) ++static void cmd_get_tag(Scsi_Cmnd *cmd, int should_be_tagged) + { +- SETUP_HOSTDATA(cmd->device->host); ++ SETUP_HOSTDATA(cmd->device->host); + +- /* If we or the target don't support tagged queuing, allocate the LUN for +- * an untagged command. +- */ +- if (!should_be_tagged || +- !setup_use_tagged_queuing || !cmd->device->tagged_supported) { +- cmd->tag = TAG_NONE; +- hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); +- TAG_PRINTK( "scsi%d: target %d lun %d now allocated by untagged " +- "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun ); +- } +- else { +- TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; +- +- cmd->tag = find_first_zero_bit( ta->allocated, MAX_TAGS ); +- set_bit( cmd->tag, ta->allocated ); +- ta->nr_allocated++; +- TAG_PRINTK( "scsi%d: using tag %d for target %d lun %d " +- "(now %d tags in use)\n", +- H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun, +- ta->nr_allocated ); +- } ++ /* If we or the target don't support tagged queuing, allocate the LUN for ++ * an untagged command. ++ */ ++ if (!should_be_tagged || ++ !setup_use_tagged_queuing || !cmd->device->tagged_supported) { ++ cmd->tag = TAG_NONE; ++ hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); ++ TAG_PRINTK("scsi%d: target %d lun %d now allocated by untagged " ++ "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun); ++ } else { ++ TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; ++ ++ cmd->tag = find_first_zero_bit(ta->allocated, MAX_TAGS); ++ set_bit(cmd->tag, ta->allocated); ++ ta->nr_allocated++; ++ TAG_PRINTK("scsi%d: using tag %d for target %d lun %d " ++ "(now %d tags in use)\n", ++ H_NO(cmd), cmd->tag, cmd->device->id, ++ cmd->device->lun, ta->nr_allocated); ++ } + } + + +@@ -406,44 +413,42 @@ static void cmd_get_tag( Scsi_Cmnd *cmd, + * unlock the LUN. + */ + +-static void cmd_free_tag( Scsi_Cmnd *cmd ) ++static void cmd_free_tag(Scsi_Cmnd *cmd) + { +- SETUP_HOSTDATA(cmd->device->host); ++ SETUP_HOSTDATA(cmd->device->host); + +- if (cmd->tag == TAG_NONE) { +- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); +- TAG_PRINTK( "scsi%d: target %d lun %d untagged cmd finished\n", +- H_NO(cmd), cmd->device->id, cmd->device->lun ); +- } +- else if (cmd->tag >= MAX_TAGS) { +- printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n", +- H_NO(cmd), cmd->tag ); +- } +- else { +- TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; +- clear_bit( cmd->tag, ta->allocated ); +- ta->nr_allocated--; +- TAG_PRINTK( "scsi%d: freed tag %d for target %d lun %d\n", +- H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun ); +- } ++ if (cmd->tag == TAG_NONE) { ++ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); ++ TAG_PRINTK("scsi%d: target %d lun %d untagged cmd finished\n", ++ H_NO(cmd), cmd->device->id, cmd->device->lun); ++ } else if (cmd->tag >= MAX_TAGS) { ++ printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n", ++ H_NO(cmd), cmd->tag); ++ } else { ++ TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; ++ clear_bit(cmd->tag, ta->allocated); ++ ta->nr_allocated--; ++ TAG_PRINTK("scsi%d: freed tag %d for target %d lun %d\n", ++ H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun); ++ } + } + + +-static void free_all_tags( void ) +-{ +- int target, lun; +- TAG_ALLOC *ta; +- +- if (!setup_use_tagged_queuing) +- return; +- +- for( target = 0; target < 8; ++target ) { +- for( lun = 0; lun < 8; ++lun ) { +- ta = &TagAlloc[target][lun]; +- bitmap_zero(ta->allocated, MAX_TAGS); +- ta->nr_allocated = 0; ++static void free_all_tags(void) ++{ ++ int target, lun; ++ TAG_ALLOC *ta; ++ ++ if (!setup_use_tagged_queuing) ++ return; ++ ++ for (target = 0; target < 8; ++target) { ++ for (lun = 0; lun < 8; ++lun) { ++ ta = &TagAlloc[target][lun]; ++ bitmap_zero(ta->allocated, MAX_TAGS); ++ ta->nr_allocated = 0; ++ } + } +- } + } + + #endif /* SUPPORT_TAGS */ +@@ -461,89 +466,94 @@ static void free_all_tags( void ) + * assumed to be already transfered into ptr/this_residual. + */ + +-static void merge_contiguous_buffers( Scsi_Cmnd *cmd ) ++static void merge_contiguous_buffers(Scsi_Cmnd *cmd) + { +- unsigned long endaddr; ++ unsigned long endaddr; + #if (NDEBUG & NDEBUG_MERGING) +- unsigned long oldlen = cmd->SCp.this_residual; +- int cnt = 1; ++ unsigned long oldlen = cmd->SCp.this_residual; ++ int cnt = 1; + #endif + +- for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1; +- cmd->SCp.buffers_residual && +- virt_to_phys(page_address(cmd->SCp.buffer[1].page)+ +- cmd->SCp.buffer[1].offset) == endaddr; ) { +- MER_PRINTK("VTOP(%p) == %08lx -> merging\n", +- cmd->SCp.buffer[1].address, endaddr); ++ for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1; ++ cmd->SCp.buffers_residual && ++ virt_to_phys(page_address(cmd->SCp.buffer[1].page) + ++ cmd->SCp.buffer[1].offset) == endaddr;) { ++ MER_PRINTK("VTOP(%p) == %08lx -> merging\n", ++ cmd->SCp.buffer[1].address, endaddr); + #if (NDEBUG & NDEBUG_MERGING) +- ++cnt; ++ ++cnt; + #endif +- ++cmd->SCp.buffer; +- --cmd->SCp.buffers_residual; +- cmd->SCp.this_residual += cmd->SCp.buffer->length; +- endaddr += cmd->SCp.buffer->length; +- } ++ ++cmd->SCp.buffer; ++ --cmd->SCp.buffers_residual; ++ cmd->SCp.this_residual += cmd->SCp.buffer->length; ++ endaddr += cmd->SCp.buffer->length; ++ } + #if (NDEBUG & NDEBUG_MERGING) +- if (oldlen != cmd->SCp.this_residual) +- MER_PRINTK("merged %d buffers from %p, new length %08x\n", +- cnt, cmd->SCp.ptr, cmd->SCp.this_residual); ++ if (oldlen != cmd->SCp.this_residual) ++ MER_PRINTK("merged %d buffers from %p, new length %08x\n", ++ cnt, cmd->SCp.ptr, cmd->SCp.this_residual); + #endif + } + + /* + * Function : void initialize_SCp(Scsi_Cmnd *cmd) + * +- * Purpose : initialize the saved data pointers for cmd to point to the ++ * Purpose : initialize the saved data pointers for cmd to point to the + * start of the buffer. + * + * Inputs : cmd - Scsi_Cmnd structure to have pointers reset. + */ + +-static __inline__ void initialize_SCp(Scsi_Cmnd *cmd) ++static inline void initialize_SCp(Scsi_Cmnd *cmd) + { +- /* +- * Initialize the Scsi Pointer field so that all of the commands in the +- * various queues are valid. +- */ +- +- if (cmd->use_sg) { +- cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; +- cmd->SCp.buffers_residual = cmd->use_sg - 1; +- cmd->SCp.ptr = (char *)page_address(cmd->SCp.buffer->page)+ +- cmd->SCp.buffer->offset; +- cmd->SCp.this_residual = cmd->SCp.buffer->length; +- /* ++roman: Try to merge some scatter-buffers if they are at +- * contiguous physical addresses. +- */ +- merge_contiguous_buffers( cmd ); +- } else { +- cmd->SCp.buffer = NULL; +- cmd->SCp.buffers_residual = 0; +- cmd->SCp.ptr = (char *) cmd->request_buffer; +- cmd->SCp.this_residual = cmd->request_bufflen; +- } ++ /* ++ * Initialize the Scsi Pointer field so that all of the commands in the ++ * various queues are valid. ++ */ ++ ++ if (cmd->use_sg) { ++ cmd->SCp.buffer = (struct scatterlist *)cmd->request_buffer; ++ cmd->SCp.buffers_residual = cmd->use_sg - 1; ++ cmd->SCp.ptr = (char *)page_address(cmd->SCp.buffer->page) + ++ cmd->SCp.buffer->offset; ++ cmd->SCp.this_residual = cmd->SCp.buffer->length; ++ /* ++roman: Try to merge some scatter-buffers if they are at ++ * contiguous physical addresses. ++ */ ++ merge_contiguous_buffers(cmd); ++ } else { ++ cmd->SCp.buffer = NULL; ++ cmd->SCp.buffers_residual = 0; ++ cmd->SCp.ptr = (char *)cmd->request_buffer; ++ cmd->SCp.this_residual = cmd->request_bufflen; ++ } + } + + #include <linux/delay.h> + + #if NDEBUG + static struct { +- unsigned char mask; +- const char * name;} +-signals[] = {{ SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" }, +- { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD, "CD" }, { SR_IO, "IO" }, +- { SR_SEL, "SEL" }, {0, NULL}}, +-basrs[] = {{BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}}, +-icrs[] = {{ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"}, +- {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"}, +- {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"}, +- {0, NULL}}, +-mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"}, +- {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR, +- "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"}, +- {MR_MONITOR_BSY, "MODE MONITOR BSY"}, +- {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"}, +- {0, NULL}}; ++ unsigned char mask; ++ const char *name; ++} signals[] = { ++ { SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" }, ++ { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD, "CD" }, { SR_IO, "IO" }, ++ { SR_SEL, "SEL" }, {0, NULL} ++}, basrs[] = { ++ {BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL} ++}, icrs[] = { ++ {ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"}, ++ {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"}, ++ {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"}, ++ {0, NULL} ++}, mrs[] = { ++ {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"}, ++ {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR, ++ "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"}, ++ {MR_MONITOR_BSY, "MODE MONITOR BSY"}, ++ {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"}, ++ {0, NULL} ++}; + + /* + * Function : void NCR5380_print(struct Scsi_Host *instance) +@@ -553,45 +563,47 @@ mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK + * Input : instance - which NCR5380 + */ + +-static void NCR5380_print(struct Scsi_Host *instance) { +- unsigned char status, data, basr, mr, icr, i; +- unsigned long flags; +- +- local_irq_save(flags); +- data = NCR5380_read(CURRENT_SCSI_DATA_REG); +- status = NCR5380_read(STATUS_REG); +- mr = NCR5380_read(MODE_REG); +- icr = NCR5380_read(INITIATOR_COMMAND_REG); +- basr = NCR5380_read(BUS_AND_STATUS_REG); +- local_irq_restore(flags); +- printk("STATUS_REG: %02x ", status); +- for (i = 0; signals[i].mask ; ++i) +- if (status & signals[i].mask) +- printk(",%s", signals[i].name); +- printk("\nBASR: %02x ", basr); +- for (i = 0; basrs[i].mask ; ++i) +- if (basr & basrs[i].mask) +- printk(",%s", basrs[i].name); +- printk("\nICR: %02x ", icr); +- for (i = 0; icrs[i].mask; ++i) +- if (icr & icrs[i].mask) +- printk(",%s", icrs[i].name); +- printk("\nMODE: %02x ", mr); +- for (i = 0; mrs[i].mask; ++i) +- if (mr & mrs[i].mask) +- printk(",%s", mrs[i].name); +- printk("\n"); ++static void NCR5380_print(struct Scsi_Host *instance) ++{ ++ unsigned char status, data, basr, mr, icr, i; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ data = NCR5380_read(CURRENT_SCSI_DATA_REG); ++ status = NCR5380_read(STATUS_REG); ++ mr = NCR5380_read(MODE_REG); ++ icr = NCR5380_read(INITIATOR_COMMAND_REG); ++ basr = NCR5380_read(BUS_AND_STATUS_REG); ++ local_irq_restore(flags); ++ printk("STATUS_REG: %02x ", status); ++ for (i = 0; signals[i].mask; ++i) ++ if (status & signals[i].mask) ++ printk(",%s", signals[i].name); ++ printk("\nBASR: %02x ", basr); ++ for (i = 0; basrs[i].mask; ++i) ++ if (basr & basrs[i].mask) ++ printk(",%s", basrs[i].name); ++ printk("\nICR: %02x ", icr); ++ for (i = 0; icrs[i].mask; ++i) ++ if (icr & icrs[i].mask) ++ printk(",%s", icrs[i].name); ++ printk("\nMODE: %02x ", mr); ++ for (i = 0; mrs[i].mask; ++i) ++ if (mr & mrs[i].mask) ++ printk(",%s", mrs[i].name); ++ printk("\n"); + } + + static struct { +- unsigned char value; +- const char *name; ++ unsigned char value; ++ const char *name; + } phases[] = { +- {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"}, +- {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"}, +- {PHASE_UNKNOWN, "UNKNOWN"}}; ++ {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"}, ++ {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"}, ++ {PHASE_UNKNOWN, "UNKNOWN"} ++}; + +-/* ++/* + * Function : void NCR5380_print_phase(struct Scsi_Host *instance) + * + * Purpose : print the current SCSI phase for debugging purposes +@@ -601,30 +613,35 @@ static struct { + + static void NCR5380_print_phase(struct Scsi_Host *instance) + { +- unsigned char status; +- int i; ++ unsigned char status; ++ int i; + +- status = NCR5380_read(STATUS_REG); +- if (!(status & SR_REQ)) +- printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO); +- else { +- for (i = 0; (phases[i].value != PHASE_UNKNOWN) && +- (phases[i].value != (status & PHASE_MASK)); ++i); +- printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name); +- } ++ status = NCR5380_read(STATUS_REG); ++ if (!(status & SR_REQ)) ++ printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO); ++ else { ++ for (i = 0; (phases[i].value != PHASE_UNKNOWN) && ++ (phases[i].value != (status & PHASE_MASK)); ++i) ++ ; ++ printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name); ++ } + } + + #else /* !NDEBUG */ + + /* dummies... */ +-__inline__ void NCR5380_print(struct Scsi_Host *instance) { }; +-__inline__ void NCR5380_print_phase(struct Scsi_Host *instance) { }; ++static inline void NCR5380_print(struct Scsi_Host *instance) ++{ ++}; ++static inline void NCR5380_print_phase(struct Scsi_Host *instance) ++{ ++}; + + #endif + + /* + * ++roman: New scheme of calling NCR5380_main() +- * ++ * + * If we're not in an interrupt, we can call our main directly, it cannot be + * already running. Else, we queue it on a task queue, if not 'main_running' + * tells us that a lower level is already executing it. This way, +@@ -638,33 +655,33 @@ __inline__ void NCR5380_print_phase(stru + #include <linux/workqueue.h> + #include <linux/interrupt.h> + +-static volatile int main_running = 0; +-static DECLARE_WORK(NCR5380_tqueue, (void (*)(void*))NCR5380_main, NULL); ++static volatile int main_running; ++static DECLARE_WORK(NCR5380_tqueue, (void (*)(void *))NCR5380_main, NULL); + +-static __inline__ void queue_main(void) ++static inline void queue_main(void) + { +- if (!main_running) { +- /* If in interrupt and NCR5380_main() not already running, +- queue it on the 'immediate' task queue, to be processed +- immediately after the current interrupt processing has +- finished. */ +- schedule_work(&NCR5380_tqueue); +- } +- /* else: nothing to do: the running NCR5380_main() will pick up +- any newly queued command. */ ++ if (!main_running) { ++ /* If in interrupt and NCR5380_main() not already running, ++ queue it on the 'immediate' task queue, to be processed ++ immediately after the current interrupt processing has ++ finished. */ ++ schedule_work(&NCR5380_tqueue); ++ } ++ /* else: nothing to do: the running NCR5380_main() will pick up ++ any newly queued command. */ + } + + +-static inline void NCR5380_all_init (void) ++static inline void NCR5380_all_init(void) + { +- static int done = 0; +- if (!done) { +- INI_PRINTK("scsi : NCR5380_all_init()\n"); +- done = 1; +- } ++ static int done = 0; ++ if (!done) { ++ INI_PRINTK("scsi : NCR5380_all_init()\n"); ++ done = 1; ++ } + } + +- ++ + /* + * Function : void NCR58380_print_options (struct Scsi_Host *instance) + * +@@ -674,23 +691,23 @@ static inline void NCR5380_all_init (voi + * Inputs : instance, pointer to this instance. Unused. + */ + +-static void __init NCR5380_print_options (struct Scsi_Host *instance) ++static void __init NCR5380_print_options(struct Scsi_Host *instance) + { +- printk(" generic options" +-#ifdef AUTOSENSE +- " AUTOSENSE" ++ printk(" generic options" ++#ifdef AUTOSENSE ++ " AUTOSENSE" + #endif + #ifdef REAL_DMA +- " REAL DMA" ++ " REAL DMA" + #endif + #ifdef PARITY +- " PARITY" ++ " PARITY" + #endif + #ifdef SUPPORT_TAGS +- " SCSI-2 TAGGED QUEUING" ++ " SCSI-2 TAGGED QUEUING" + #endif +- ); +- printk(" generic release=%d", NCR5380_PUBLIC_RELEASE); ++ ); ++ printk(" generic release=%d", NCR5380_PUBLIC_RELEASE); + } + + /* +@@ -699,27 +716,27 @@ static void __init NCR5380_print_options + * Purpose : print commands in the various queues, called from + * NCR5380_abort and NCR5380_debug to aid debugging. + * +- * Inputs : instance, pointer to this instance. ++ * Inputs : instance, pointer to this instance. + */ + +-static void NCR5380_print_status (struct Scsi_Host *instance) ++static void NCR5380_print_status(struct Scsi_Host *instance) + { +- char *pr_bfr; +- char *start; +- int len; +- +- NCR_PRINT(NDEBUG_ANY); +- NCR_PRINT_PHASE(NDEBUG_ANY); +- +- pr_bfr = (char *) __get_free_page(GFP_ATOMIC); +- if (!pr_bfr) { +- printk("NCR5380_print_status: no memory for print buffer\n"); +- return; +- } +- len = NCR5380_proc_info(instance, pr_bfr, &start, 0, PAGE_SIZE, 0); +- pr_bfr[len] = 0; +- printk("\n%s\n", pr_bfr); +- free_page((unsigned long) pr_bfr); ++ char *pr_bfr; ++ char *start; ++ int len; ++ ++ NCR_PRINT(NDEBUG_ANY); ++ NCR_PRINT_PHASE(NDEBUG_ANY); ++ ++ pr_bfr = (char *)__get_free_page(GFP_ATOMIC); ++ if (!pr_bfr) { ++ printk("NCR5380_print_status: no memory for print buffer\n"); ++ return; ++ } ++ len = NCR5380_proc_info(instance, pr_bfr, &start, 0, PAGE_SIZE, 0); ++ pr_bfr[len] = 0; ++ printk("\n%s\n", pr_bfr); ++ free_page((unsigned long)pr_bfr); + } + + +@@ -738,146 +755,144 @@ static void NCR5380_print_status (struct + */ + + #undef SPRINTF +-#define SPRINTF(fmt,args...) \ +- do { if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \ +- pos += sprintf(pos, fmt , ## args); } while(0) +-static +-char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length); +- +-static +-int NCR5380_proc_info (struct Scsi_Host *instance, char *buffer, char **start, off_t offset, +- int length, int inout) +-{ +- char *pos = buffer; +- struct NCR5380_hostdata *hostdata; +- Scsi_Cmnd *ptr; +- unsigned long flags; +- off_t begin = 0; +-#define check_offset() \ +- do { \ +- if (pos - buffer < offset - begin) { \ +- begin += pos - buffer; \ +- pos = buffer; \ +- } \ +- } while (0) +- +- hostdata = (struct NCR5380_hostdata *)instance->hostdata; +- +- if (inout) { /* Has data been written to the file ? */ +- return(-ENOSYS); /* Currently this is a no-op */ +- } +- SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE); +- check_offset(); +- local_irq_save(flags); +- SPRINTF("NCR5380: coroutine is%s running.\n", main_running ? "" : "n't"); +- check_offset(); +- if (!hostdata->connected) +- SPRINTF("scsi%d: no currently connected command\n", HOSTNO); +- else +- pos = lprint_Scsi_Cmnd ((Scsi_Cmnd *) hostdata->connected, +- pos, buffer, length); +- SPRINTF("scsi%d: issue_queue\n", HOSTNO); +- check_offset(); +- for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = NEXT(ptr)) { +- pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length); ++#define SPRINTF(fmt,args...) \ ++ do { \ ++ if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \ ++ pos += sprintf(pos, fmt , ## args); \ ++ } while(0) ++static char *lprint_Scsi_Cmnd(Scsi_Cmnd *cmd, char *pos, char *buffer, int length); ++ ++static int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer, ++ char **start, off_t offset, int length, int inout) ++{ ++ char *pos = buffer; ++ struct NCR5380_hostdata *hostdata; ++ Scsi_Cmnd *ptr; ++ unsigned long flags; ++ off_t begin = 0; ++#define check_offset() \ ++ do { \ ++ if (pos - buffer < offset - begin) { \ ++ begin += pos - buffer; \ ++ pos = buffer; \ ++ } \ ++ } while (0) ++ ++ hostdata = (struct NCR5380_hostdata *)instance->hostdata; ++ ++ if (inout) /* Has data been written to the file ? */ ++ return -ENOSYS; /* Currently this is a no-op */ ++ SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE); + check_offset(); +- } +- +- SPRINTF("scsi%d: disconnected_queue\n", HOSTNO); +- check_offset(); +- for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; +- ptr = NEXT(ptr)) { +- pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length); ++ local_irq_save(flags); ++ SPRINTF("NCR5380: coroutine is%s running.\n", ++ main_running ? "" : "n't"); + check_offset(); +- } ++ if (!hostdata->connected) ++ SPRINTF("scsi%d: no currently connected command\n", HOSTNO); ++ else ++ pos = lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected, ++ pos, buffer, length); ++ SPRINTF("scsi%d: issue_queue\n", HOSTNO); ++ check_offset(); ++ for (ptr = (Scsi_Cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr)) { ++ pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length); ++ check_offset(); ++ } + +- local_irq_restore(flags); +- *start = buffer + (offset - begin); +- if (pos - buffer < offset - begin) +- return 0; +- else if (pos - buffer - (offset - begin) < length) +- return pos - buffer - (offset - begin); +- return length; +-} ++ SPRINTF("scsi%d: disconnected_queue\n", HOSTNO); ++ check_offset(); ++ for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ++ ptr = NEXT(ptr)) { ++ pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length); ++ check_offset(); ++ } + +-static char * +-lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length) +-{ +- int i, s; +- unsigned char *command; +- SPRINTF("scsi%d: destination target %d, lun %d\n", +- H_NO(cmd), cmd->device->id, cmd->device->lun); +- SPRINTF(" command = "); +- command = cmd->cmnd; +- SPRINTF("%2d (0x%02x)", command[0], command[0]); +- for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) +- SPRINTF(" %02x", command[i]); +- SPRINTF("\n"); +- return pos; ++ local_irq_restore(flags); ++ *start = buffer + (offset - begin); ++ if (pos - buffer < offset - begin) ++ return 0; ++ else if (pos - buffer - (offset - begin) < length) ++ return pos - buffer - (offset - begin); ++ return length; ++} ++ ++static char *lprint_Scsi_Cmnd(Scsi_Cmnd *cmd, char *pos, char *buffer, int length) ++{ ++ int i, s; ++ unsigned char *command; ++ SPRINTF("scsi%d: destination target %d, lun %d\n", ++ H_NO(cmd), cmd->device->id, cmd->device->lun); ++ SPRINTF(" command = "); ++ command = cmd->cmnd; ++ SPRINTF("%2d (0x%02x)", command[0], command[0]); ++ for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) ++ SPRINTF(" %02x", command[i]); ++ SPRINTF("\n"); ++ return pos; + } + + +-/* ++/* + * Function : void NCR5380_init (struct Scsi_Host *instance) + * + * Purpose : initializes *instance and corresponding 5380 chip. + * +- * Inputs : instance - instantiation of the 5380 driver. ++ * Inputs : instance - instantiation of the 5380 driver. + * + * Notes : I assume that the host, hostno, and id bits have been +- * set correctly. I don't care about the irq and other fields. +- * ++ * set correctly. I don't care about the irq and other fields. ++ * + */ + +-static int NCR5380_init (struct Scsi_Host *instance, int flags) ++static int NCR5380_init(struct Scsi_Host *instance, int flags) + { +- int i; +- SETUP_HOSTDATA(instance); ++ int i; ++ SETUP_HOSTDATA(instance); + +- NCR5380_all_init(); ++ NCR5380_all_init(); + +- hostdata->aborted = 0; +- hostdata->id_mask = 1 << instance->this_id; +- hostdata->id_higher_mask = 0; +- for (i = hostdata->id_mask; i <= 0x80; i <<= 1) +- if (i > hostdata->id_mask) +- hostdata->id_higher_mask |= i; +- for (i = 0; i < 8; ++i) +- hostdata->busy[i] = 0; ++ hostdata->aborted = 0; ++ hostdata->id_mask = 1 << instance->this_id; ++ hostdata->id_higher_mask = 0; ++ for (i = hostdata->id_mask; i <= 0x80; i <<= 1) ++ if (i > hostdata->id_mask) ++ hostdata->id_higher_mask |= i; ++ for (i = 0; i < 8; ++i) ++ hostdata->busy[i] = 0; + #ifdef SUPPORT_TAGS +- init_tags(); ++ init_tags(); + #endif + #if defined (REAL_DMA) +- hostdata->dma_len = 0; ++ hostdata->dma_len = 0; + #endif +- hostdata->targets_present = 0; +- hostdata->connected = NULL; +- hostdata->issue_queue = NULL; +- hostdata->disconnected_queue = NULL; +- hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT; +- +- if (!the_template) { +- the_template = instance->hostt; +- first_instance = instance; +- } +- ++ hostdata->targets_present = 0; ++ hostdata->connected = NULL; ++ hostdata->issue_queue = NULL; ++ hostdata->disconnected_queue = NULL; ++ hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT; ++ ++ if (!the_template) { ++ the_template = instance->hostt; ++ first_instance = instance; ++ } + + #ifndef AUTOSENSE +- if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1)) +- printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n" +- " without AUTOSENSE option, contingent allegiance conditions may\n" +- " be incorrectly cleared.\n", HOSTNO); ++ if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1)) ++ printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n" ++ " without AUTOSENSE option, contingent allegiance conditions may\n" ++ " be incorrectly cleared.\n", HOSTNO); + #endif /* def AUTOSENSE */ + +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +- NCR5380_write(MODE_REG, MR_BASE); +- NCR5380_write(TARGET_COMMAND_REG, 0); +- NCR5380_write(SELECT_ENABLE_REG, 0); ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); ++ NCR5380_write(MODE_REG, MR_BASE); ++ NCR5380_write(TARGET_COMMAND_REG, 0); ++ NCR5380_write(SELECT_ENABLE_REG, 0); + +- return 0; ++ return 0; + } + +-/* ++/* + * our own old-style timeout update + */ + /* +@@ -890,331 +905,328 @@ static int NCR5380_init (struct Scsi_Hos + + int atari_scsi_update_timeout(Scsi_Cmnd * SCset, int timeout) + { +- int rtn; ++ int rtn; + +- /* +- * We are using the new error handling code to actually register/deregister +- * timers for timeout. +- */ +- +- if (!timer_pending(&SCset->eh_timeout)) { +- rtn = 0; +- } else { +- rtn = SCset->eh_timeout.expires - jiffies; +- } +- +- if (timeout == 0) { +- del_timer(&SCset->eh_timeout); +- SCset->eh_timeout.data = (unsigned long) NULL; +- SCset->eh_timeout.expires = 0; +- } else { +- if (SCset->eh_timeout.data != (unsigned long) NULL) +- del_timer(&SCset->eh_timeout); +- SCset->eh_timeout.data = (unsigned long) SCset; +- SCset->eh_timeout.expires = jiffies + timeout; +- add_timer(&SCset->eh_timeout); +- } ++ /* ++ * We are using the new error handling code to actually register/deregister ++ * timers for timeout. ++ */ ++ ++ if (!timer_pending(&SCset->eh_timeout)) ++ rtn = 0; ++ else ++ rtn = SCset->eh_timeout.expires - jiffies; ++ ++ if (timeout == 0) { ++ del_timer(&SCset->eh_timeout); ++ SCset->eh_timeout.data = (unsigned long)NULL; ++ SCset->eh_timeout.expires = 0; ++ } else { ++ if (SCset->eh_timeout.data != (unsigned long)NULL) ++ del_timer(&SCset->eh_timeout); ++ SCset->eh_timeout.data = (unsigned long)SCset; ++ SCset->eh_timeout.expires = jiffies + timeout; ++ add_timer(&SCset->eh_timeout); ++ } + return rtn; + } + +-/* +- * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, +- * void (*done)(Scsi_Cmnd *)) ++/* ++ * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, ++ * void (*done)(Scsi_Cmnd *)) + * + * Purpose : enqueues a SCSI command + * + * Inputs : cmd - SCSI command, done - function called on completion, with + * a pointer to the command descriptor. +- * ++ * + * Returns : 0 + * +- * Side effects : +- * cmd is added to the per instance issue_queue, with minor +- * twiddling done to the host specific fields of cmd. If the ++ * Side effects : ++ * cmd is added to the per instance issue_queue, with minor ++ * twiddling done to the host specific fields of cmd. If the + * main coroutine is not running, it is restarted. + * + */ + +-static +-int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) ++static int NCR5380_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) + { +- SETUP_HOSTDATA(cmd->device->host); +- Scsi_Cmnd *tmp; +- int oldto; +- unsigned long flags; +- // extern int update_timeout(Scsi_Cmnd * SCset, int timeout); ++ SETUP_HOSTDATA(cmd->device->host); ++ Scsi_Cmnd *tmp; ++ int oldto; ++ unsigned long flags; ++ // extern int update_timeout(Scsi_Cmnd * SCset, int timeout); + + #if (NDEBUG & NDEBUG_NO_WRITE) +- switch (cmd->cmnd[0]) { +- case WRITE_6: +- case WRITE_10: +- printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n", +- H_NO(cmd)); +- cmd->result = (DID_ERROR << 16); +- done(cmd); +- return 0; +- } ++ switch (cmd->cmnd[0]) { ++ case WRITE_6: ++ case WRITE_10: ++ printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n", ++ H_NO(cmd)); ++ cmd->result = (DID_ERROR << 16); ++ done(cmd); ++ return 0; ++ } + #endif /* (NDEBUG & NDEBUG_NO_WRITE) */ + +- + #ifdef NCR5380_STATS + # if 0 +- if (!hostdata->connected && !hostdata->issue_queue && +- !hostdata->disconnected_queue) { +- hostdata->timebase = jiffies; +- } ++ if (!hostdata->connected && !hostdata->issue_queue && ++ !hostdata->disconnected_queue) { ++ hostdata->timebase = jiffies; ++ } + # endif + # ifdef NCR5380_STAT_LIMIT +- if (cmd->request_bufflen > NCR5380_STAT_LIMIT) ++ if (cmd->request_bufflen > NCR5380_STAT_LIMIT) + # endif +- switch (cmd->cmnd[0]) +- { +- case WRITE: +- case WRITE_6: +- case WRITE_10: +- hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase); +- hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen; +- hostdata->pendingw++; +- break; +- case READ: +- case READ_6: +- case READ_10: +- hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase); +- hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen; +- hostdata->pendingr++; +- break; +- } +-#endif +- +- /* +- * We use the host_scribble field as a pointer to the next command +- * in a queue +- */ +- +- NEXT(cmd) = NULL; +- cmd->scsi_done = done; +- +- cmd->result = 0; +- +- +- /* +- * Insert the cmd into the issue queue. Note that REQUEST SENSE +- * commands are added to the head of the queue since any command will +- * clear the contingent allegiance condition that exists and the +- * sense data is only guaranteed to be valid while the condition exists. +- */ +- +- local_irq_save(flags); +- /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA. +- * Otherwise a running NCR5380_main may steal the lock. +- * Lock before actually inserting due to fairness reasons explained in +- * atari_scsi.c. If we insert first, then it's impossible for this driver +- * to release the lock. +- * Stop timer for this command while waiting for the lock, or timeouts +- * may happen (and they really do), and it's no good if the command doesn't +- * appear in any of the queues. +- * ++roman: Just disabling the NCR interrupt isn't sufficient here, +- * because also a timer int can trigger an abort or reset, which would +- * alter queues and touch the lock. +- */ +- if (!IS_A_TT()) { +- oldto = atari_scsi_update_timeout(cmd, 0); +- falcon_get_lock(); +- atari_scsi_update_timeout(cmd, oldto); +- } +- if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) { +- LIST(cmd, hostdata->issue_queue); +- NEXT(cmd) = hostdata->issue_queue; +- hostdata->issue_queue = cmd; +- } else { +- for (tmp = (Scsi_Cmnd *)hostdata->issue_queue; +- NEXT(tmp); tmp = NEXT(tmp)) +- ; +- LIST(cmd, tmp); +- NEXT(tmp) = cmd; +- } +- local_irq_restore(flags); +- +- QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd), +- (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"); +- +- /* If queue_command() is called from an interrupt (real one or bottom +- * half), we let queue_main() do the job of taking care about main. If it +- * is already running, this is a no-op, else main will be queued. +- * +- * If we're not in an interrupt, we can call NCR5380_main() +- * unconditionally, because it cannot be already running. +- */ +- if (in_interrupt() || ((flags >> 8) & 7) >= 6) +- queue_main(); +- else +- NCR5380_main(NULL); +- return 0; +-} +- +-/* +- * Function : NCR5380_main (void) +- * +- * Purpose : NCR5380_main is a coroutine that runs as long as more work can +- * be done on the NCR5380 host adapters in a system. Both +- * NCR5380_queue_command() and NCR5380_intr() will try to start it ++ switch (cmd->cmnd[0]) { ++ case WRITE: ++ case WRITE_6: ++ case WRITE_10: ++ hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase); ++ hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen; ++ hostdata->pendingw++; ++ break; ++ case READ: ++ case READ_6: ++ case READ_10: ++ hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase); ++ hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen; ++ hostdata->pendingr++; ++ break; ++ } ++#endif ++ ++ /* ++ * We use the host_scribble field as a pointer to the next command ++ * in a queue ++ */ ++ ++ NEXT(cmd) = NULL; ++ cmd->scsi_done = done; ++ ++ cmd->result = 0; ++ ++ /* ++ * Insert the cmd into the issue queue. Note that REQUEST SENSE ++ * commands are added to the head of the queue since any command will ++ * clear the contingent allegiance condition that exists and the ++ * sense data is only guaranteed to be valid while the condition exists. ++ */ ++ ++ local_irq_save(flags); ++ /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA. ++ * Otherwise a running NCR5380_main may steal the lock. ++ * Lock before actually inserting due to fairness reasons explained in ++ * atari_scsi.c. If we insert first, then it's impossible for this driver ++ * to release the lock. ++ * Stop timer for this command while waiting for the lock, or timeouts ++ * may happen (and they really do), and it's no good if the command doesn't ++ * appear in any of the queues. ++ * ++roman: Just disabling the NCR interrupt isn't sufficient here, ++ * because also a timer int can trigger an abort or reset, which would ++ * alter queues and touch the lock. ++ */ ++ if (!IS_A_TT()) { ++ oldto = atari_scsi_update_timeout(cmd, 0); ++ falcon_get_lock(); ++ atari_scsi_update_timeout(cmd, oldto); ++ } ++ if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) { ++ LIST(cmd, hostdata->issue_queue); ++ NEXT(cmd) = hostdata->issue_queue; ++ hostdata->issue_queue = cmd; ++ } else { ++ for (tmp = (Scsi_Cmnd *)hostdata->issue_queue; ++ NEXT(tmp); tmp = NEXT(tmp)) ++ ; ++ LIST(cmd, tmp); ++ NEXT(tmp) = cmd; ++ } ++ local_irq_restore(flags); ++ ++ QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd), ++ (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"); ++ ++ /* If queue_command() is called from an interrupt (real one or bottom ++ * half), we let queue_main() do the job of taking care about main. If it ++ * is already running, this is a no-op, else main will be queued. ++ * ++ * If we're not in an interrupt, we can call NCR5380_main() ++ * unconditionally, because it cannot be already running. ++ */ ++ if (in_interrupt() || ((flags >> 8) & 7) >= 6) ++ queue_main(); ++ else ++ NCR5380_main(NULL); ++ return 0; ++} ++ ++/* ++ * Function : NCR5380_main (void) ++ * ++ * Purpose : NCR5380_main is a coroutine that runs as long as more work can ++ * be done on the NCR5380 host adapters in a system. Both ++ * NCR5380_queue_command() and NCR5380_intr() will try to start it + * in case it is not running. +- * +- * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should ++ * ++ * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should + * reenable them. This prevents reentrancy and kernel stack overflow. +- */ +- +-static void NCR5380_main (void *bl) +-{ +- Scsi_Cmnd *tmp, *prev; +- struct Scsi_Host *instance = first_instance; +- struct NCR5380_hostdata *hostdata = HOSTDATA(instance); +- int done; +- unsigned long flags; +- +- /* +- * We run (with interrupts disabled) until we're sure that none of +- * the host adapters have anything that can be done, at which point +- * we set main_running to 0 and exit. +- * +- * Interrupts are enabled before doing various other internal +- * instructions, after we've decided that we need to run through +- * the loop again. +- * +- * this should prevent any race conditions. +- * +- * ++roman: Just disabling the NCR interrupt isn't sufficient here, +- * because also a timer int can trigger an abort or reset, which can +- * alter queues and touch the Falcon lock. +- */ +- +- /* Tell int handlers main() is now already executing. Note that +- no races are possible here. If an int comes in before +- 'main_running' is set here, and queues/executes main via the +- task queue, it doesn't do any harm, just this instance of main +- won't find any work left to do. */ +- if (main_running) +- return; +- main_running = 1; +- +- local_save_flags(flags); +- do { +- local_irq_disable(); /* Freeze request queues */ +- done = 1; +- +- if (!hostdata->connected) { +- MAIN_PRINTK( "scsi%d: not connected\n", HOSTNO ); +- /* +- * Search through the issue_queue for a command destined +- * for a target that's not busy. +- */ ++ */ ++ ++static void NCR5380_main(void *bl) ++{ ++ Scsi_Cmnd *tmp, *prev; ++ struct Scsi_Host *instance = first_instance; ++ struct NCR5380_hostdata *hostdata = HOSTDATA(instance); ++ int done; ++ unsigned long flags; ++ ++ /* ++ * We run (with interrupts disabled) until we're sure that none of ++ * the host adapters have anything that can be done, at which point ++ * we set main_running to 0 and exit. ++ * ++ * Interrupts are enabled before doing various other internal ++ * instructions, after we've decided that we need to run through ++ * the loop again. ++ * ++ * this should prevent any race conditions. ++ * ++ * ++roman: Just disabling the NCR interrupt isn't sufficient here, ++ * because also a timer int can trigger an abort or reset, which can ++ * alter queues and touch the Falcon lock. ++ */ ++ ++ /* Tell int handlers main() is now already executing. Note that ++ no races are possible here. If an int comes in before ++ 'main_running' is set here, and queues/executes main via the ++ task queue, it doesn't do any harm, just this instance of main ++ won't find any work left to do. */ ++ if (main_running) ++ return; ++ main_running = 1; ++ ++ local_save_flags(flags); ++ do { ++ local_irq_disable(); /* Freeze request queues */ ++ done = 1; ++ ++ if (!hostdata->connected) { ++ MAIN_PRINTK("scsi%d: not connected\n", HOSTNO); ++ /* ++ * Search through the issue_queue for a command destined ++ * for a target that's not busy. ++ */ + #if (NDEBUG & NDEBUG_LISTS) +- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; +- tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp)) +- ; +- /*printk("%p ", tmp);*/ +- if ((tmp == prev) && tmp) printk(" LOOP\n");/* else printk("\n");*/ ++ for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; ++ tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp)) ++ ; ++ /*printk("%p ", tmp);*/ ++ if ((tmp == prev) && tmp) ++ printk(" LOOP\n"); ++ /* else printk("\n"); */ + #endif +- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, +- prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp) ) { ++ for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, ++ prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp)) { + + #if (NDEBUG & NDEBUG_LISTS) +- if (prev != tmp) +- printk("MAIN tmp=%p target=%d busy=%d lun=%d\n", +- tmp, tmp->device->id, hostdata->busy[tmp->device->id], +- tmp->device->lun); +-#endif +- /* When we find one, remove it from the issue queue. */ +- /* ++guenther: possible race with Falcon locking */ +- if ( ++ if (prev != tmp) ++ printk("MAIN tmp=%p target=%d busy=%d lun=%d\n", ++ tmp, tmp->device->id, hostdata->busy[tmp->device->id], ++ tmp->device->lun); ++#endif ++ /* When we find one, remove it from the issue queue. */ ++ /* ++guenther: possible race with Falcon locking */ ++ if ( + #ifdef SUPPORT_TAGS +- !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE) ++ !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE) + #else +- !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun)) ++ !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun)) + #endif +- ) { +- /* ++guenther: just to be sure, this must be atomic */ +- local_irq_disable(); +- if (prev) { +- REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); +- NEXT(prev) = NEXT(tmp); +- } else { +- REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp)); +- hostdata->issue_queue = NEXT(tmp); +- } +- NEXT(tmp) = NULL; +- falcon_dont_release++; +- +- /* reenable interrupts after finding one */ +- local_irq_restore(flags); +- +- /* +- * Attempt to establish an I_T_L nexus here. +- * On success, instance->hostdata->connected is set. +- * On failure, we must add the command back to the +- * issue queue so we can keep trying. +- */ +- MAIN_PRINTK("scsi%d: main(): command for target %d " +- "lun %d removed from issue_queue\n", +- HOSTNO, tmp->device->id, tmp->device->lun); +- /* +- * REQUEST SENSE commands are issued without tagged +- * queueing, even on SCSI-II devices because the +- * contingent allegiance condition exists for the +- * entire unit. +- */ +- /* ++roman: ...and the standard also requires that +- * REQUEST SENSE command are untagged. +- */ +- ++ ) { ++ /* ++guenther: just to be sure, this must be atomic */ ++ local_irq_disable(); ++ if (prev) { ++ REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); ++ NEXT(prev) = NEXT(tmp); ++ } else { ++ REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp)); ++ hostdata->issue_queue = NEXT(tmp); ++ } ++ NEXT(tmp) = NULL; ++ falcon_dont_release++; ++ ++ /* reenable interrupts after finding one */ ++ local_irq_restore(flags); ++ ++ /* ++ * Attempt to establish an I_T_L nexus here. ++ * On success, instance->hostdata->connected is set. ++ * On failure, we must add the command back to the ++ * issue queue so we can keep trying. ++ */ ++ MAIN_PRINTK("scsi%d: main(): command for target %d " ++ "lun %d removed from issue_queue\n", ++ HOSTNO, tmp->device->id, tmp->device->lun); ++ /* ++ * REQUEST SENSE commands are issued without tagged ++ * queueing, even on SCSI-II devices because the ++ * contingent allegiance condition exists for the ++ * entire unit. ++ */ ++ /* ++roman: ...and the standard also requires that ++ * REQUEST SENSE command are untagged. ++ */ ++ + #ifdef SUPPORT_TAGS +- cmd_get_tag( tmp, tmp->cmnd[0] != REQUEST_SENSE ); ++ cmd_get_tag(tmp, tmp->cmnd[0] != REQUEST_SENSE); + #endif +- if (!NCR5380_select(instance, tmp, +- (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : +- TAG_NEXT)) { +- falcon_dont_release--; +- /* release if target did not response! */ +- falcon_release_lock_if_possible( hostdata ); +- break; +- } else { +- local_irq_disable(); +- LIST(tmp, hostdata->issue_queue); +- NEXT(tmp) = hostdata->issue_queue; +- hostdata->issue_queue = tmp; ++ if (!NCR5380_select(instance, tmp, ++ (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : ++ TAG_NEXT)) { ++ falcon_dont_release--; ++ /* release if target did not response! */ ++ falcon_release_lock_if_possible(hostdata); ++ break; ++ } else { ++ local_irq_disable(); ++ LIST(tmp, hostdata->issue_queue); ++ NEXT(tmp) = hostdata->issue_queue; ++ hostdata->issue_queue = tmp; + #ifdef SUPPORT_TAGS +- cmd_free_tag( tmp ); ++ cmd_free_tag(tmp); + #endif +- falcon_dont_release--; +- local_irq_restore(flags); +- MAIN_PRINTK("scsi%d: main(): select() failed, " +- "returned to issue_queue\n", HOSTNO); +- if (hostdata->connected) +- break; +- } +- } /* if target/lun/target queue is not busy */ +- } /* for issue_queue */ +- } /* if (!hostdata->connected) */ +- +- if (hostdata->connected ++ falcon_dont_release--; ++ local_irq_restore(flags); ++ MAIN_PRINTK("scsi%d: main(): select() failed, " ++ "returned to issue_queue\n", HOSTNO); ++ if (hostdata->connected) ++ break; ++ } ++ } /* if target/lun/target queue is not busy */ ++ } /* for issue_queue */ ++ } /* if (!hostdata->connected) */ ++ ++ if (hostdata->connected + #ifdef REAL_DMA +- && !hostdata->dma_len ++ && !hostdata->dma_len + #endif +- ) { +- local_irq_restore(flags); +- MAIN_PRINTK("scsi%d: main: performing information transfer\n", +- HOSTNO); +- NCR5380_information_transfer(instance); +- MAIN_PRINTK("scsi%d: main: done set false\n", HOSTNO); +- done = 0; +- } +- } while (!done); +- +- /* Better allow ints _after_ 'main_running' has been cleared, else +- an interrupt could believe we'll pick up the work it left for +- us, but we won't see it anymore here... */ +- main_running = 0; +- local_irq_restore(flags); ++ ) { ++ local_irq_restore(flags); ++ MAIN_PRINTK("scsi%d: main: performing information transfer\n", ++ HOSTNO); ++ NCR5380_information_transfer(instance); ++ MAIN_PRINTK("scsi%d: main: done set false\n", HOSTNO); ++ done = 0; ++ } ++ } while (!done); ++ ++ /* Better allow ints _after_ 'main_running' has been cleared, else ++ an interrupt could believe we'll pick up the work it left for ++ us, but we won't see it anymore here... */ ++ main_running = 0; ++ local_irq_restore(flags); + } + + +@@ -1223,1441 +1235,1439 @@ static void NCR5380_main (void *bl) + * Function : void NCR5380_dma_complete (struct Scsi_Host *instance) + * + * Purpose : Called by interrupt handler when DMA finishes or a phase +- * mismatch occurs (which would finish the DMA transfer). ++ * mismatch occurs (which would finish the DMA transfer). + * + * Inputs : instance - this instance of the NCR5380. + * + */ + +-static void NCR5380_dma_complete( struct Scsi_Host *instance ) ++static void NCR5380_dma_complete(struct Scsi_Host *instance) + { +- SETUP_HOSTDATA(instance); +- int transfered, saved_data = 0, overrun = 0, cnt, toPIO; +- unsigned char **data, p; +- volatile int *count; +- +- if (!hostdata->connected) { +- printk(KERN_WARNING "scsi%d: received end of DMA interrupt with " +- "no connected cmd\n", HOSTNO); +- return; +- } +- +- if (atari_read_overruns) { +- p = hostdata->connected->SCp.phase; +- if (p & SR_IO) { +- udelay(10); +- if ((((NCR5380_read(BUS_AND_STATUS_REG)) & +- (BASR_PHASE_MATCH|BASR_ACK)) == +- (BASR_PHASE_MATCH|BASR_ACK))) { +- saved_data = NCR5380_read(INPUT_DATA_REG); +- overrun = 1; +- DMA_PRINTK("scsi%d: read overrun handled\n", HOSTNO); +- } +- } +- } +- +- DMA_PRINTK("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n", +- HOSTNO, NCR5380_read(BUS_AND_STATUS_REG), +- NCR5380_read(STATUS_REG)); +- +- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); +- NCR5380_write(MODE_REG, MR_BASE); +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +- +- transfered = hostdata->dma_len - NCR5380_dma_residual(instance); +- hostdata->dma_len = 0; +- +- data = (unsigned char **) &(hostdata->connected->SCp.ptr); +- count = &(hostdata->connected->SCp.this_residual); +- *data += transfered; +- *count -= transfered; +- +- if (atari_read_overruns) { +- if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) { +- cnt = toPIO = atari_read_overruns; +- if (overrun) { +- DMA_PRINTK("Got an input overrun, using saved byte\n"); +- *(*data)++ = saved_data; +- (*count)--; +- cnt--; +- toPIO--; +- } +- DMA_PRINTK("Doing %d-byte PIO to 0x%08lx\n", cnt, (long)*data); +- NCR5380_transfer_pio(instance, &p, &cnt, data); +- *count -= toPIO - cnt; ++ SETUP_HOSTDATA(instance); ++ int transfered, saved_data = 0, overrun = 0, cnt, toPIO; ++ unsigned char **data, p; ++ volatile int *count; ++ ++ if (!hostdata->connected) { ++ printk(KERN_WARNING "scsi%d: received end of DMA interrupt with " ++ "no connected cmd\n", HOSTNO); ++ return; ++ } ++ ++ if (atari_read_overruns) { ++ p = hostdata->connected->SCp.phase; ++ if (p & SR_IO) { ++ udelay(10); ++ if ((NCR5380_read(BUS_AND_STATUS_REG) & ++ (BASR_PHASE_MATCH|BASR_ACK)) == ++ (BASR_PHASE_MATCH|BASR_ACK)) { ++ saved_data = NCR5380_read(INPUT_DATA_REG); ++ overrun = 1; ++ DMA_PRINTK("scsi%d: read overrun handled\n", HOSTNO); ++ } ++ } ++ } ++ ++ DMA_PRINTK("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n", ++ HOSTNO, NCR5380_read(BUS_AND_STATUS_REG), ++ NCR5380_read(STATUS_REG)); ++ ++ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); ++ NCR5380_write(MODE_REG, MR_BASE); ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); ++ ++ transfered = hostdata->dma_len - NCR5380_dma_residual(instance); ++ hostdata->dma_len = 0; ++ ++ data = (unsigned char **)&hostdata->connected->SCp.ptr; ++ count = &hostdata->connected->SCp.this_residual; ++ *data += transfered; ++ *count -= transfered; ++ ++ if (atari_read_overruns) { ++ if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) { ++ cnt = toPIO = atari_read_overruns; ++ if (overrun) { ++ DMA_PRINTK("Got an input overrun, using saved byte\n"); ++ *(*data)++ = saved_data; ++ (*count)--; ++ cnt--; ++ toPIO--; ++ } ++ DMA_PRINTK("Doing %d-byte PIO to 0x%08lx\n", cnt, (long)*data); ++ NCR5380_transfer_pio(instance, &p, &cnt, data); ++ *count -= toPIO - cnt; ++ } + } +- } + } + #endif /* REAL_DMA */ + + + /* + * Function : void NCR5380_intr (int irq) +- * ++ * + * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses +- * from the disconnected queue, and restarting NCR5380_main() ++ * from the disconnected queue, and restarting NCR5380_main() + * as required. + * + * Inputs : int irq, irq that caused this interrupt. + * + */ + +-static irqreturn_t NCR5380_intr (int irq, void *dev_id) ++static irqreturn_t NCR5380_intr(int irq, void *dev_id) + { +- struct Scsi_Host *instance = first_instance; +- int done = 1, handled = 0; +- unsigned char basr; +- +- INT_PRINTK("scsi%d: NCR5380 irq triggered\n", HOSTNO); +- +- /* Look for pending interrupts */ +- basr = NCR5380_read(BUS_AND_STATUS_REG); +- INT_PRINTK("scsi%d: BASR=%02x\n", HOSTNO, basr); +- /* dispatch to appropriate routine if found and done=0 */ +- if (basr & BASR_IRQ) { +- NCR_PRINT(NDEBUG_INTR); +- if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) { +- done = 0; +- ENABLE_IRQ(); +- INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO); +- NCR5380_reselect(instance); +- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); +- } +- else if (basr & BASR_PARITY_ERROR) { +- INT_PRINTK("scsi%d: PARITY interrupt\n", HOSTNO); +- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); +- } +- else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) { +- INT_PRINTK("scsi%d: RESET interrupt\n", HOSTNO); +- (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); +- } +- else { +- /* +- * The rest of the interrupt conditions can occur only during a +- * DMA transfer +- */ ++ struct Scsi_Host *instance = first_instance; ++ int done = 1, handled = 0; ++ unsigned char basr; ++ ++ INT_PRINTK("scsi%d: NCR5380 irq triggered\n", HOSTNO); ++ ++ /* Look for pending interrupts */ ++ basr = NCR5380_read(BUS_AND_STATUS_REG); ++ INT_PRINTK("scsi%d: BASR=%02x\n", HOSTNO, basr); ++ /* dispatch to appropriate routine if found and done=0 */ ++ if (basr & BASR_IRQ) { ++ NCR_PRINT(NDEBUG_INTR); ++ if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) { ++ done = 0; ++ ENABLE_IRQ(); ++ INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO); ++ NCR5380_reselect(instance); ++ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); ++ } else if (basr & BASR_PARITY_ERROR) { ++ INT_PRINTK("scsi%d: PARITY interrupt\n", HOSTNO); ++ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); ++ } else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) { ++ INT_PRINTK("scsi%d: RESET interrupt\n", HOSTNO); ++ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); ++ } else { ++ /* ++ * The rest of the interrupt conditions can occur only during a ++ * DMA transfer ++ */ + + #if defined(REAL_DMA) +- /* +- * We should only get PHASE MISMATCH and EOP interrupts if we have +- * DMA enabled, so do a sanity check based on the current setting +- * of the MODE register. +- */ +- +- if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) && +- ((basr & BASR_END_DMA_TRANSFER) || +- !(basr & BASR_PHASE_MATCH))) { +- +- INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO); +- NCR5380_dma_complete( instance ); +- done = 0; +- ENABLE_IRQ(); +- } else ++ /* ++ * We should only get PHASE MISMATCH and EOP interrupts if we have ++ * DMA enabled, so do a sanity check based on the current setting ++ * of the MODE register. ++ */ ++ ++ if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) && ++ ((basr & BASR_END_DMA_TRANSFER) || ++ !(basr & BASR_PHASE_MATCH))) { ++ ++ INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO); ++ NCR5380_dma_complete( instance ); ++ done = 0; ++ ENABLE_IRQ(); ++ } else + #endif /* REAL_DMA */ +- { ++ { + /* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */ +- if (basr & BASR_PHASE_MATCH) +- printk(KERN_NOTICE "scsi%d: unknown interrupt, " +- "BASR 0x%x, MR 0x%x, SR 0x%x\n", +- HOSTNO, basr, NCR5380_read(MODE_REG), +- NCR5380_read(STATUS_REG)); +- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); +- } +- } /* if !(SELECTION || PARITY) */ +- handled = 1; +- } /* BASR & IRQ */ +- else { +- printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, " +- "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr, +- NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG)); +- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); +- } +- +- if (!done) { +- INT_PRINTK("scsi%d: in int routine, calling main\n", HOSTNO); +- /* Put a call to NCR5380_main() on the queue... */ +- queue_main(); +- } +- return IRQ_RETVAL(handled); ++ if (basr & BASR_PHASE_MATCH) ++ printk(KERN_NOTICE "scsi%d: unknown interrupt, " ++ "BASR 0x%x, MR 0x%x, SR 0x%x\n", ++ HOSTNO, basr, NCR5380_read(MODE_REG), ++ NCR5380_read(STATUS_REG)); ++ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); ++ } ++ } /* if !(SELECTION || PARITY) */ ++ handled = 1; ++ } /* BASR & IRQ */ else { ++ printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, " ++ "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr, ++ NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG)); ++ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); ++ } ++ ++ if (!done) { ++ INT_PRINTK("scsi%d: in int routine, calling main\n", HOSTNO); ++ /* Put a call to NCR5380_main() on the queue... */ ++ queue_main(); ++ } ++ return IRQ_RETVAL(handled); + } + + #ifdef NCR5380_STATS +-static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd) ++static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd *cmd) + { + # ifdef NCR5380_STAT_LIMIT +- if (cmd->request_bufflen > NCR5380_STAT_LIMIT) ++ if (cmd->request_bufflen > NCR5380_STAT_LIMIT) + # endif +- switch (cmd->cmnd[0]) +- { +- case WRITE: +- case WRITE_6: +- case WRITE_10: +- hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase); +- /*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/ +- hostdata->pendingw--; +- break; +- case READ: +- case READ_6: +- case READ_10: +- hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase); +- /*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/ +- hostdata->pendingr--; +- break; +- } ++ switch (cmd->cmnd[0]) { ++ case WRITE: ++ case WRITE_6: ++ case WRITE_10: ++ hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase); ++ /*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/ ++ hostdata->pendingw--; ++ break; ++ case READ: ++ case READ_6: ++ case READ_10: ++ hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase); ++ /*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/ ++ hostdata->pendingr--; ++ break; ++ } + } + #endif + +-/* +- * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, ++/* ++ * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, + * int tag); + * + * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command, +- * including ARBITRATION, SELECTION, and initial message out for +- * IDENTIFY and queue messages. ++ * including ARBITRATION, SELECTION, and initial message out for ++ * IDENTIFY and queue messages. + * +- * Inputs : instance - instantiation of the 5380 driver on which this +- * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for +- * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for ++ * Inputs : instance - instantiation of the 5380 driver on which this ++ * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for ++ * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for + * the command that is presently connected. +- * ++ * + * Returns : -1 if selection could not execute for some reason, +- * 0 if selection succeeded or failed because the target +- * did not respond. ++ * 0 if selection succeeded or failed because the target ++ * did not respond. + * +- * Side effects : +- * If bus busy, arbitration failed, etc, NCR5380_select() will exit ++ * Side effects : ++ * If bus busy, arbitration failed, etc, NCR5380_select() will exit + * with registers as they should have been on entry - ie + * SELECT_ENABLE will be set appropriately, the NCR5380 + * will cease to drive any SCSI bus signals. + * +- * If successful : I_T_L or I_T_L_Q nexus will be established, +- * instance->connected will be set to cmd. +- * SELECT interrupt will be disabled. ++ * If successful : I_T_L or I_T_L_Q nexus will be established, ++ * instance->connected will be set to cmd. ++ * SELECT interrupt will be disabled. + * +- * If failed (no target) : cmd->scsi_done() will be called, and the ++ * If failed (no target) : cmd->scsi_done() will be called, and the + * cmd->result host byte set to DID_BAD_TARGET. + */ + +-static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) ++static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) + { +- SETUP_HOSTDATA(instance); +- unsigned char tmp[3], phase; +- unsigned char *data; +- int len; +- unsigned long timeout; +- unsigned long flags; +- +- hostdata->restart_select = 0; +- NCR_PRINT(NDEBUG_ARBITRATION); +- ARB_PRINTK("scsi%d: starting arbitration, id = %d\n", HOSTNO, +- instance->this_id); +- +- /* +- * Set the phase bits to 0, otherwise the NCR5380 won't drive the +- * data bus during SELECTION. +- */ ++ SETUP_HOSTDATA(instance); ++ unsigned char tmp[3], phase; ++ unsigned char *data; ++ int len; ++ unsigned long timeout; ++ unsigned long flags; ++ ++ hostdata->restart_select = 0; ++ NCR_PRINT(NDEBUG_ARBITRATION); ++ ARB_PRINTK("scsi%d: starting arbitration, id = %d\n", HOSTNO, ++ instance->this_id); ++ ++ /* ++ * Set the phase bits to 0, otherwise the NCR5380 won't drive the ++ * data bus during SELECTION. ++ */ + +- local_irq_save(flags); +- if (hostdata->connected) { +- local_irq_restore(flags); +- return -1; +- } +- NCR5380_write(TARGET_COMMAND_REG, 0); ++ local_irq_save(flags); ++ if (hostdata->connected) { ++ local_irq_restore(flags); ++ return -1; ++ } ++ NCR5380_write(TARGET_COMMAND_REG, 0); + ++ /* ++ * Start arbitration. ++ */ + +- /* +- * Start arbitration. +- */ +- +- NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); +- NCR5380_write(MODE_REG, MR_ARBITRATE); ++ NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); ++ NCR5380_write(MODE_REG, MR_ARBITRATE); + +- local_irq_restore(flags); ++ local_irq_restore(flags); + +- /* Wait for arbitration logic to complete */ ++ /* Wait for arbitration logic to complete */ + #if defined(NCR_TIMEOUT) +- { +- unsigned long timeout = jiffies + 2*NCR_TIMEOUT; ++ { ++ unsigned long timeout = jiffies + 2*NCR_TIMEOUT; + +- while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) +- && time_before(jiffies, timeout) && !hostdata->connected) +- ; +- if (time_after_eq(jiffies, timeout)) +- { +- printk("scsi : arbitration timeout at %d\n", __LINE__); +- NCR5380_write(MODE_REG, MR_BASE); +- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); +- return -1; +- } +- } ++ while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) && ++ time_before(jiffies, timeout) && !hostdata->connected) ++ ; ++ if (time_after_eq(jiffies, timeout)) { ++ printk("scsi : arbitration timeout at %d\n", __LINE__); ++ NCR5380_write(MODE_REG, MR_BASE); ++ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); ++ return -1; ++ } ++ } + #else /* NCR_TIMEOUT */ +- while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) +- && !hostdata->connected); ++ while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) && ++ !hostdata->connected) ++ ; + #endif + +- ARB_PRINTK("scsi%d: arbitration complete\n", HOSTNO); ++ ARB_PRINTK("scsi%d: arbitration complete\n", HOSTNO); + +- if (hostdata->connected) { +- NCR5380_write(MODE_REG, MR_BASE); +- return -1; +- } +- /* +- * The arbitration delay is 2.2us, but this is a minimum and there is +- * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate +- * the integral nature of udelay(). +- * +- */ +- +- udelay(3); +- +- /* Check for lost arbitration */ +- if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || +- (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || +- (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || +- hostdata->connected) { +- NCR5380_write(MODE_REG, MR_BASE); +- ARB_PRINTK("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n", +- HOSTNO); +- return -1; +- } +- +- /* after/during arbitration, BSY should be asserted. +- IBM DPES-31080 Version S31Q works now */ +- /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */ +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL | +- ICR_ASSERT_BSY ) ; +- +- if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || +- hostdata->connected) { +- NCR5380_write(MODE_REG, MR_BASE); +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +- ARB_PRINTK("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n", +- HOSTNO); +- return -1; +- } +- +- /* +- * Again, bus clear + bus settle time is 1.2us, however, this is +- * a minimum so we'll udelay ceil(1.2) +- */ ++ if (hostdata->connected) { ++ NCR5380_write(MODE_REG, MR_BASE); ++ return -1; ++ } ++ /* ++ * The arbitration delay is 2.2us, but this is a minimum and there is ++ * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate ++ * the integral nature of udelay(). ++ * ++ */ ++ ++ udelay(3); ++ ++ /* Check for lost arbitration */ ++ if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || ++ (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || ++ (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || ++ hostdata->connected) { ++ NCR5380_write(MODE_REG, MR_BASE); ++ ARB_PRINTK("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n", ++ HOSTNO); ++ return -1; ++ } ++ ++ /* after/during arbitration, BSY should be asserted. ++ IBM DPES-31080 Version S31Q works now */ ++ /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */ ++ NCR5380_write(INITIATOR_COMMAND_REG, ++ ICR_BASE | ICR_ASSERT_SEL | ICR_ASSERT_BSY); ++ ++ if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || ++ hostdata->connected) { ++ NCR5380_write(MODE_REG, MR_BASE); ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); ++ ARB_PRINTK("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n", ++ HOSTNO); ++ return -1; ++ } ++ ++ /* ++ * Again, bus clear + bus settle time is 1.2us, however, this is ++ * a minimum so we'll udelay ceil(1.2) ++ */ + + #ifdef CONFIG_ATARI_SCSI_TOSHIBA_DELAY +- /* ++roman: But some targets (see above :-) seem to need a bit more... */ +- udelay(15); ++ /* ++roman: But some targets (see above :-) seem to need a bit more... */ ++ udelay(15); + #else +- udelay(2); ++ udelay(2); + #endif +- +- if (hostdata->connected) { ++ ++ if (hostdata->connected) { ++ NCR5380_write(MODE_REG, MR_BASE); ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); ++ return -1; ++ } ++ ++ ARB_PRINTK("scsi%d: won arbitration\n", HOSTNO); ++ ++ /* ++ * Now that we have won arbitration, start Selection process, asserting ++ * the host and target ID's on the SCSI bus. ++ */ ++ ++ NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id))); ++ ++ /* ++ * Raise ATN while SEL is true before BSY goes false from arbitration, ++ * since this is the only way to guarantee that we'll get a MESSAGE OUT ++ * phase immediately after selection. ++ */ ++ ++ NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | ++ ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL )); + NCR5380_write(MODE_REG, MR_BASE); +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +- return -1; +- } + +- ARB_PRINTK("scsi%d: won arbitration\n", HOSTNO); ++ /* ++ * Reselect interrupts must be turned off prior to the dropping of BSY, ++ * otherwise we will trigger an interrupt. ++ */ ++ ++ if (hostdata->connected) { ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); ++ return -1; ++ } ++ ++ NCR5380_write(SELECT_ENABLE_REG, 0); + +- /* +- * Now that we have won arbitration, start Selection process, asserting +- * the host and target ID's on the SCSI bus. +- */ +- +- NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id))); +- +- /* +- * Raise ATN while SEL is true before BSY goes false from arbitration, +- * since this is the only way to guarantee that we'll get a MESSAGE OUT +- * phase immediately after selection. +- */ +- +- NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | +- ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL )); +- NCR5380_write(MODE_REG, MR_BASE); +- +- /* +- * Reselect interrupts must be turned off prior to the dropping of BSY, +- * otherwise we will trigger an interrupt. +- */ ++ /* ++ * The initiator shall then wait at least two deskew delays and release ++ * the BSY signal. ++ */ ++ udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */ + +- if (hostdata->connected) { +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +- return -1; +- } ++ /* Reset BSY */ ++ NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | ++ ICR_ASSERT_ATN | ICR_ASSERT_SEL)); ++ ++ /* ++ * Something weird happens when we cease to drive BSY - looks ++ * like the board/chip is letting us do another read before the ++ * appropriate propagation delay has expired, and we're confusing ++ * a BSY signal from ourselves as the target's response to SELECTION. ++ * ++ * A small delay (the 'C++' frontend breaks the pipeline with an ++ * unnecessary jump, making it work on my 386-33/Trantor T128, the ++ * tighter 'C' code breaks and requires this) solves the problem - ++ * the 1 us delay is arbitrary, and only used because this delay will ++ * be the same on other platforms and since it works here, it should ++ * work there. ++ * ++ * wingel suggests that this could be due to failing to wait ++ * one deskew delay. ++ */ ++ ++ udelay(1); + +- NCR5380_write(SELECT_ENABLE_REG, 0); ++ SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->device->id); ++ ++ /* ++ * The SCSI specification calls for a 250 ms timeout for the actual ++ * selection. ++ */ + +- /* +- * The initiator shall then wait at least two deskew delays and release +- * the BSY signal. +- */ +- udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */ +- +- /* Reset BSY */ +- NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | +- ICR_ASSERT_ATN | ICR_ASSERT_SEL)); +- +- /* +- * Something weird happens when we cease to drive BSY - looks +- * like the board/chip is letting us do another read before the +- * appropriate propagation delay has expired, and we're confusing +- * a BSY signal from ourselves as the target's response to SELECTION. +- * +- * A small delay (the 'C++' frontend breaks the pipeline with an +- * unnecessary jump, making it work on my 386-33/Trantor T128, the +- * tighter 'C' code breaks and requires this) solves the problem - +- * the 1 us delay is arbitrary, and only used because this delay will +- * be the same on other platforms and since it works here, it should +- * work there. +- * +- * wingel suggests that this could be due to failing to wait +- * one deskew delay. +- */ +- +- udelay(1); +- +- SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->device->id); +- +- /* +- * The SCSI specification calls for a 250 ms timeout for the actual +- * selection. +- */ +- +- timeout = jiffies + 25; +- +- /* +- * XXX very interesting - we're seeing a bounce where the BSY we +- * asserted is being reflected / still asserted (propagation delay?) +- * and it's detecting as true. Sigh. +- */ ++ timeout = jiffies + 25; ++ ++ /* ++ * XXX very interesting - we're seeing a bounce where the BSY we ++ * asserted is being reflected / still asserted (propagation delay?) ++ * and it's detecting as true. Sigh. ++ */ + + #if 0 +- /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert +- * IO while SEL is true. But again, there are some disks out the in the +- * world that do that nevertheless. (Somebody claimed that this announces +- * reselection capability of the target.) So we better skip that test and +- * only wait for BSY... (Famous german words: Der Klügere gibt nach :-) +- */ +- +- while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & +- (SR_BSY | SR_IO))); +- +- if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == +- (SR_SEL | SR_IO)) { +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +- NCR5380_reselect(instance); +- printk (KERN_ERR "scsi%d: reselection after won arbitration?\n", +- HOSTNO); +- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); +- return -1; +- } ++ /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert ++ * IO while SEL is true. But again, there are some disks out the in the ++ * world that do that nevertheless. (Somebody claimed that this announces ++ * reselection capability of the target.) So we better skip that test and ++ * only wait for BSY... (Famous german words: Der Klügere gibt nach :-) ++ */ ++ ++ while (time_before(jiffies, timeout) && ++ !(NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO))) ++ ; ++ ++ if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) { ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); ++ NCR5380_reselect(instance); ++ printk(KERN_ERR "scsi%d: reselection after won arbitration?\n", ++ HOSTNO); ++ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); ++ return -1; ++ } + #else +- while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY)); ++ while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY)) ++ ; + #endif + +- /* +- * No less than two deskew delays after the initiator detects the +- * BSY signal is true, it shall release the SEL signal and may +- * change the DATA BUS. -wingel +- */ ++ /* ++ * No less than two deskew delays after the initiator detects the ++ * BSY signal is true, it shall release the SEL signal and may ++ * change the DATA BUS. -wingel ++ */ + +- udelay(1); ++ udelay(1); + +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); + +- if (!(NCR5380_read(STATUS_REG) & SR_BSY)) { +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +- if (hostdata->targets_present & (1 << cmd->device->id)) { +- printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO); +- if (hostdata->restart_select) +- printk(KERN_NOTICE "\trestart select\n"); +- NCR_PRINT(NDEBUG_ANY); +- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); +- return -1; +- } +- cmd->result = DID_BAD_TARGET << 16; ++ if (!(NCR5380_read(STATUS_REG) & SR_BSY)) { ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); ++ if (hostdata->targets_present & (1 << cmd->device->id)) { ++ printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO); ++ if (hostdata->restart_select) ++ printk(KERN_NOTICE "\trestart select\n"); ++ NCR_PRINT(NDEBUG_ANY); ++ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); ++ return -1; ++ } ++ cmd->result = DID_BAD_TARGET << 16; + #ifdef NCR5380_STATS +- collect_stats(hostdata, cmd); ++ collect_stats(hostdata, cmd); + #endif + #ifdef SUPPORT_TAGS +- cmd_free_tag( cmd ); ++ cmd_free_tag(cmd); + #endif +- cmd->scsi_done(cmd); +- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); +- SEL_PRINTK("scsi%d: target did not respond within 250ms\n", HOSTNO); +- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); +- return 0; +- } ++ cmd->scsi_done(cmd); ++ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); ++ SEL_PRINTK("scsi%d: target did not respond within 250ms\n", HOSTNO); ++ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); ++ return 0; ++ } ++ ++ hostdata->targets_present |= (1 << cmd->device->id); + +- hostdata->targets_present |= (1 << cmd->device->id); ++ /* ++ * Since we followed the SCSI spec, and raised ATN while SEL ++ * was true but before BSY was false during selection, the information ++ * transfer phase should be a MESSAGE OUT phase so that we can send the ++ * IDENTIFY message. ++ * ++ * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG ++ * message (2 bytes) with a tag ID that we increment with every command ++ * until it wraps back to 0. ++ * ++ * XXX - it turns out that there are some broken SCSI-II devices, ++ * which claim to support tagged queuing but fail when more than ++ * some number of commands are issued at once. ++ */ ++ ++ /* Wait for start of REQ/ACK handshake */ ++ while (!(NCR5380_read(STATUS_REG) & SR_REQ)) ++ ; + +- /* +- * Since we followed the SCSI spec, and raised ATN while SEL +- * was true but before BSY was false during selection, the information +- * transfer phase should be a MESSAGE OUT phase so that we can send the +- * IDENTIFY message. +- * +- * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG +- * message (2 bytes) with a tag ID that we increment with every command +- * until it wraps back to 0. +- * +- * XXX - it turns out that there are some broken SCSI-II devices, +- * which claim to support tagged queuing but fail when more than +- * some number of commands are issued at once. +- */ +- +- /* Wait for start of REQ/ACK handshake */ +- while (!(NCR5380_read(STATUS_REG) & SR_REQ)); +- +- SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n", +- HOSTNO, cmd->device->id); +- tmp[0] = IDENTIFY(1, cmd->device->lun); ++ SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n", ++ HOSTNO, cmd->device->id); ++ tmp[0] = IDENTIFY(1, cmd->device->lun); + + #ifdef SUPPORT_TAGS +- if (cmd->tag != TAG_NONE) { +- tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG; +- tmp[2] = cmd->tag; +- len = 3; +- } else +- len = 1; ++ if (cmd->tag != TAG_NONE) { ++ tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG; ++ tmp[2] = cmd->tag; ++ len = 3; ++ } else ++ len = 1; + #else +- len = 1; +- cmd->tag=0; ++ len = 1; ++ cmd->tag = 0; + #endif /* SUPPORT_TAGS */ + +- /* Send message(s) */ +- data = tmp; +- phase = PHASE_MSGOUT; +- NCR5380_transfer_pio(instance, &phase, &len, &data); +- SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO); +- /* XXX need to handle errors here */ +- hostdata->connected = cmd; ++ /* Send message(s) */ ++ data = tmp; ++ phase = PHASE_MSGOUT; ++ NCR5380_transfer_pio(instance, &phase, &len, &data); ++ SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO); ++ /* XXX need to handle errors here */ ++ hostdata->connected = cmd; + #ifndef SUPPORT_TAGS +- hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); +-#endif +- +- initialize_SCp(cmd); ++ hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); ++#endif + ++ initialize_SCp(cmd); + +- return 0; ++ return 0; + } + +-/* +- * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, ++/* ++ * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, + * unsigned char *phase, int *count, unsigned char **data) + * + * Purpose : transfers data in given phase using polled I/O + * +- * Inputs : instance - instance of driver, *phase - pointer to +- * what phase is expected, *count - pointer to number of ++ * Inputs : instance - instance of driver, *phase - pointer to ++ * what phase is expected, *count - pointer to number of + * bytes to transfer, **data - pointer to data pointer. +- * ++ * + * Returns : -1 when different phase is entered without transferring + * maximum number of bytes, 0 if all bytes are transfered or exit + * is in same phase. + * +- * Also, *phase, *count, *data are modified in place. ++ * Also, *phase, *count, *data are modified in place. + * + * XXX Note : handling for bus free may be useful. + */ + + /* +- * Note : this code is not as quick as it could be, however it ++ * Note : this code is not as quick as it could be, however it + * IS 100% reliable, and for the actual data transfer where speed + * counts, we will always do a pseudo DMA or DMA transfer. + */ + +-static int NCR5380_transfer_pio( struct Scsi_Host *instance, +- unsigned char *phase, int *count, +- unsigned char **data) +-{ +- register unsigned char p = *phase, tmp; +- register int c = *count; +- register unsigned char *d = *data; +- +- /* +- * The NCR5380 chip will only drive the SCSI bus when the +- * phase specified in the appropriate bits of the TARGET COMMAND +- * REGISTER match the STATUS REGISTER +- */ +- +- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); +- +- do { +- /* +- * Wait for assertion of REQ, after which the phase bits will be +- * valid +- */ +- while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ)); +- +- HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO); +- +- /* Check for phase mismatch */ +- if ((tmp & PHASE_MASK) != p) { +- PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO); +- NCR_PRINT_PHASE(NDEBUG_PIO); +- break; +- } +- +- /* Do actual transfer from SCSI bus to / from memory */ +- if (!(p & SR_IO)) +- NCR5380_write(OUTPUT_DATA_REG, *d); +- else +- *d = NCR5380_read(CURRENT_SCSI_DATA_REG); +- +- ++d; +- +- /* +- * The SCSI standard suggests that in MSGOUT phase, the initiator +- * should drop ATN on the last byte of the message phase +- * after REQ has been asserted for the handshake but before +- * the initiator raises ACK. +- */ +- +- if (!(p & SR_IO)) { +- if (!((p & SR_MSG) && c > 1)) { +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | +- ICR_ASSERT_DATA); +- NCR_PRINT(NDEBUG_PIO); +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | +- ICR_ASSERT_DATA | ICR_ASSERT_ACK); +- } else { +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | +- ICR_ASSERT_DATA | ICR_ASSERT_ATN); +- NCR_PRINT(NDEBUG_PIO); +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | +- ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); +- } +- } else { +- NCR_PRINT(NDEBUG_PIO); +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); +- } ++static int NCR5380_transfer_pio(struct Scsi_Host *instance, ++ unsigned char *phase, int *count, ++ unsigned char **data) ++{ ++ register unsigned char p = *phase, tmp; ++ register int c = *count; ++ register unsigned char *d = *data; ++ ++ /* ++ * The NCR5380 chip will only drive the SCSI bus when the ++ * phase specified in the appropriate bits of the TARGET COMMAND ++ * REGISTER match the STATUS REGISTER ++ */ + +- while (NCR5380_read(STATUS_REG) & SR_REQ); ++ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); + +- HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO); ++ do { ++ /* ++ * Wait for assertion of REQ, after which the phase bits will be ++ * valid ++ */ ++ while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ)) ++ ; + +-/* +- * We have several special cases to consider during REQ/ACK handshaking : +- * 1. We were in MSGOUT phase, and we are on the last byte of the +- * message. ATN must be dropped as ACK is dropped. +- * +- * 2. We are in a MSGIN phase, and we are on the last byte of the +- * message. We must exit with ACK asserted, so that the calling +- * code may raise ATN before dropping ACK to reject the message. +- * +- * 3. ACK and ATN are clear and the target may proceed as normal. +- */ +- if (!(p == PHASE_MSGIN && c == 1)) { +- if (p == PHASE_MSGOUT && c > 1) +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); +- else +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +- } +- } while (--c); ++ HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO); + +- PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c); ++ /* Check for phase mismatch */ ++ if ((tmp & PHASE_MASK) != p) { ++ PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO); ++ NCR_PRINT_PHASE(NDEBUG_PIO); ++ break; ++ } + +- *count = c; +- *data = d; +- tmp = NCR5380_read(STATUS_REG); +- /* The phase read from the bus is valid if either REQ is (already) +- * asserted or if ACK hasn't been released yet. The latter is the case if +- * we're in MSGIN and all wanted bytes have been received. */ +- if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0)) +- *phase = tmp & PHASE_MASK; +- else +- *phase = PHASE_UNKNOWN; ++ /* Do actual transfer from SCSI bus to / from memory */ ++ if (!(p & SR_IO)) ++ NCR5380_write(OUTPUT_DATA_REG, *d); ++ else ++ *d = NCR5380_read(CURRENT_SCSI_DATA_REG); + +- if (!c || (*phase == p)) +- return 0; +- else +- return -1; ++ ++d; ++ ++ /* ++ * The SCSI standard suggests that in MSGOUT phase, the initiator ++ * should drop ATN on the last byte of the message phase ++ * after REQ has been asserted for the handshake but before ++ * the initiator raises ACK. ++ */ ++ ++ if (!(p & SR_IO)) { ++ if (!((p & SR_MSG) && c > 1)) { ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); ++ NCR_PRINT(NDEBUG_PIO); ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ++ ICR_ASSERT_DATA | ICR_ASSERT_ACK); ++ } else { ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ++ ICR_ASSERT_DATA | ICR_ASSERT_ATN); ++ NCR_PRINT(NDEBUG_PIO); ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ++ ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); ++ } ++ } else { ++ NCR_PRINT(NDEBUG_PIO); ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); ++ } ++ ++ while (NCR5380_read(STATUS_REG) & SR_REQ) ++ ; ++ ++ HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO); ++ ++ /* ++ * We have several special cases to consider during REQ/ACK handshaking : ++ * 1. We were in MSGOUT phase, and we are on the last byte of the ++ * message. ATN must be dropped as ACK is dropped. ++ * ++ * 2. We are in a MSGIN phase, and we are on the last byte of the ++ * message. We must exit with ACK asserted, so that the calling ++ * code may raise ATN before dropping ACK to reject the message. ++ * ++ * 3. ACK and ATN are clear and the target may proceed as normal. ++ */ ++ if (!(p == PHASE_MSGIN && c == 1)) { ++ if (p == PHASE_MSGOUT && c > 1) ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); ++ else ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); ++ } ++ } while (--c); ++ ++ PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c); ++ ++ *count = c; ++ *data = d; ++ tmp = NCR5380_read(STATUS_REG); ++ /* The phase read from the bus is valid if either REQ is (already) ++ * asserted or if ACK hasn't been released yet. The latter is the case if ++ * we're in MSGIN and all wanted bytes have been received. ++ */ ++ if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0)) ++ *phase = tmp & PHASE_MASK; ++ else ++ *phase = PHASE_UNKNOWN; ++ ++ if (!c || (*phase == p)) ++ return 0; ++ else ++ return -1; + } + + /* + * Function : do_abort (Scsi_Host *host) +- * +- * Purpose : abort the currently established nexus. Should only be +- * called from a routine which can drop into a +- * ++ * ++ * Purpose : abort the currently established nexus. Should only be ++ * called from a routine which can drop into a ++ * + * Returns : 0 on success, -1 on failure. + */ + +-static int do_abort (struct Scsi_Host *host) ++static int do_abort(struct Scsi_Host *host) + { +- unsigned char tmp, *msgptr, phase; +- int len; +- +- /* Request message out phase */ +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); ++ unsigned char tmp, *msgptr, phase; ++ int len; + +- /* +- * Wait for the target to indicate a valid phase by asserting +- * REQ. Once this happens, we'll have either a MSGOUT phase +- * and can immediately send the ABORT message, or we'll have some +- * other phase and will have to source/sink data. +- * +- * We really don't care what value was on the bus or what value +- * the target sees, so we just handshake. +- */ +- +- while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ); +- +- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); +- +- if ((tmp & PHASE_MASK) != PHASE_MSGOUT) { +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | +- ICR_ASSERT_ACK); +- while (NCR5380_read(STATUS_REG) & SR_REQ); ++ /* Request message out phase */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); +- } +- +- tmp = ABORT; +- msgptr = &tmp; +- len = 1; +- phase = PHASE_MSGOUT; +- NCR5380_transfer_pio (host, &phase, &len, &msgptr); +- +- /* +- * If we got here, and the command completed successfully, +- * we're about to go into bus free state. +- */ + +- return len ? -1 : 0; ++ /* ++ * Wait for the target to indicate a valid phase by asserting ++ * REQ. Once this happens, we'll have either a MSGOUT phase ++ * and can immediately send the ABORT message, or we'll have some ++ * other phase and will have to source/sink data. ++ * ++ * We really don't care what value was on the bus or what value ++ * the target sees, so we just handshake. ++ */ ++ ++ while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ) ++ ; ++ ++ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); ++ ++ if ((tmp & PHASE_MASK) != PHASE_MSGOUT) { ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ++ ICR_ASSERT_ACK); ++ while (NCR5380_read(STATUS_REG) & SR_REQ) ++ ; ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); ++ } ++ ++ tmp = ABORT; ++ msgptr = &tmp; ++ len = 1; ++ phase = PHASE_MSGOUT; ++ NCR5380_transfer_pio(host, &phase, &len, &msgptr); ++ ++ /* ++ * If we got here, and the command completed successfully, ++ * we're about to go into bus free state. ++ */ ++ ++ return len ? -1 : 0; + } + + #if defined(REAL_DMA) +-/* +- * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, ++/* ++ * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, + * unsigned char *phase, int *count, unsigned char **data) + * + * Purpose : transfers data in given phase using either real + * or pseudo DMA. + * +- * Inputs : instance - instance of driver, *phase - pointer to +- * what phase is expected, *count - pointer to number of ++ * Inputs : instance - instance of driver, *phase - pointer to ++ * what phase is expected, *count - pointer to number of + * bytes to transfer, **data - pointer to data pointer. +- * ++ * + * Returns : -1 when different phase is entered without transferring + * maximum number of bytes, 0 if all bytes or transfered or exit + * is in same phase. + * +- * Also, *phase, *count, *data are modified in place. ++ * Also, *phase, *count, *data are modified in place. + * + */ + + +-static int NCR5380_transfer_dma( struct Scsi_Host *instance, +- unsigned char *phase, int *count, +- unsigned char **data) ++static int NCR5380_transfer_dma(struct Scsi_Host *instance, ++ unsigned char *phase, int *count, ++ unsigned char **data) + { +- SETUP_HOSTDATA(instance); +- register int c = *count; +- register unsigned char p = *phase; +- register unsigned char *d = *data; +- unsigned char tmp; +- unsigned long flags; ++ SETUP_HOSTDATA(instance); ++ register int c = *count; ++ register unsigned char p = *phase; ++ register unsigned char *d = *data; ++ unsigned char tmp; ++ unsigned long flags; + +- if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { +- *phase = tmp; +- return -1; +- } ++ if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { ++ *phase = tmp; ++ return -1; ++ } + +- if (atari_read_overruns && (p & SR_IO)) { +- c -= atari_read_overruns; +- } ++ if (atari_read_overruns && (p & SR_IO)) ++ c -= atari_read_overruns; + +- DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n", +- HOSTNO, (p & SR_IO) ? "reading" : "writing", +- c, (p & SR_IO) ? "to" : "from", d); ++ DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n", ++ HOSTNO, (p & SR_IO) ? "reading" : "writing", ++ c, (p & SR_IO) ? "to" : "from", d); + +- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); ++ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); + + #ifdef REAL_DMA +- NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY); ++ NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY); + #endif /* def REAL_DMA */ + +- if (IS_A_TT()) { +- /* On the Medusa, it is a must to initialize the DMA before +- * starting the NCR. This is also the cleaner way for the TT. +- */ +- local_irq_save(flags); +- hostdata->dma_len = (p & SR_IO) ? +- NCR5380_dma_read_setup(instance, d, c) : +- NCR5380_dma_write_setup(instance, d, c); +- local_irq_restore(flags); +- } +- +- if (p & SR_IO) +- NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); +- else { +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); +- NCR5380_write(START_DMA_SEND_REG, 0); +- } +- +- if (!IS_A_TT()) { +- /* On the Falcon, the DMA setup must be done after the last */ +- /* NCR access, else the DMA setup gets trashed! +- */ +- local_irq_save(flags); +- hostdata->dma_len = (p & SR_IO) ? +- NCR5380_dma_read_setup(instance, d, c) : +- NCR5380_dma_write_setup(instance, d, c); +- local_irq_restore(flags); +- } +- return 0; ++ if (IS_A_TT()) { ++ /* On the Medusa, it is a must to initialize the DMA before ++ * starting the NCR. This is also the cleaner way for the TT. ++ */ ++ local_irq_save(flags); ++ hostdata->dma_len = (p & SR_IO) ? ++ NCR5380_dma_read_setup(instance, d, c) : ++ NCR5380_dma_write_setup(instance, d, c); ++ local_irq_restore(flags); ++ } ++ ++ if (p & SR_IO) ++ NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); ++ else { ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); ++ NCR5380_write(START_DMA_SEND_REG, 0); ++ } ++ ++ if (!IS_A_TT()) { ++ /* On the Falcon, the DMA setup must be done after the last */ ++ /* NCR access, else the DMA setup gets trashed! ++ */ ++ local_irq_save(flags); ++ hostdata->dma_len = (p & SR_IO) ? ++ NCR5380_dma_read_setup(instance, d, c) : ++ NCR5380_dma_write_setup(instance, d, c); ++ local_irq_restore(flags); ++ } ++ return 0; + } + #endif /* defined(REAL_DMA) */ + + /* + * Function : NCR5380_information_transfer (struct Scsi_Host *instance) + * +- * Purpose : run through the various SCSI phases and do as the target +- * directs us to. Operates on the currently connected command, ++ * Purpose : run through the various SCSI phases and do as the target ++ * directs us to. Operates on the currently connected command, + * instance->connected. + * + * Inputs : instance, instance for which we are doing commands + * +- * Side effects : SCSI things happen, the disconnected queue will be ++ * Side effects : SCSI things happen, the disconnected queue will be + * modified if a command disconnects, *instance->connected will + * change. + * +- * XXX Note : we need to watch for bus free or a reset condition here +- * to recover from an unexpected bus free condition. ++ * XXX Note : we need to watch for bus free or a reset condition here ++ * to recover from an unexpected bus free condition. + */ +- +-static void NCR5380_information_transfer (struct Scsi_Host *instance) ++ ++static void NCR5380_information_transfer(struct Scsi_Host *instance) + { +- SETUP_HOSTDATA(instance); +- unsigned long flags; +- unsigned char msgout = NOP; +- int sink = 0; +- int len; ++ SETUP_HOSTDATA(instance); ++ unsigned long flags; ++ unsigned char msgout = NOP; ++ int sink = 0; ++ int len; + #if defined(REAL_DMA) +- int transfersize; +-#endif +- unsigned char *data; +- unsigned char phase, tmp, extended_msg[10], old_phase=0xff; +- Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected; +- +- while (1) { +- tmp = NCR5380_read(STATUS_REG); +- /* We only have a valid SCSI phase when REQ is asserted */ +- if (tmp & SR_REQ) { +- phase = (tmp & PHASE_MASK); +- if (phase != old_phase) { +- old_phase = phase; +- NCR_PRINT_PHASE(NDEBUG_INFORMATION); +- } +- +- if (sink && (phase != PHASE_MSGOUT)) { +- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); +- +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | +- ICR_ASSERT_ACK); +- while (NCR5380_read(STATUS_REG) & SR_REQ); +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | +- ICR_ASSERT_ATN); +- sink = 0; +- continue; +- } +- +- switch (phase) { +- case PHASE_DATAOUT: +-#if (NDEBUG & NDEBUG_NO_DATAOUT) +- printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT " +- "aborted\n", HOSTNO); +- sink = 1; +- do_abort(instance); +- cmd->result = DID_ERROR << 16; +- cmd->done(cmd); +- return; ++ int transfersize; + #endif +- case PHASE_DATAIN: +- /* +- * If there is no room left in the current buffer in the +- * scatter-gather list, move onto the next one. +- */ ++ unsigned char *data; ++ unsigned char phase, tmp, extended_msg[10], old_phase = 0xff; ++ Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected; ++ ++ while (1) { ++ tmp = NCR5380_read(STATUS_REG); ++ /* We only have a valid SCSI phase when REQ is asserted */ ++ if (tmp & SR_REQ) { ++ phase = (tmp & PHASE_MASK); ++ if (phase != old_phase) { ++ old_phase = phase; ++ NCR_PRINT_PHASE(NDEBUG_INFORMATION); ++ } + +- if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { +- ++cmd->SCp.buffer; +- --cmd->SCp.buffers_residual; +- cmd->SCp.this_residual = cmd->SCp.buffer->length; +- cmd->SCp.ptr = page_address(cmd->SCp.buffer->page)+ +- cmd->SCp.buffer->offset; +- /* ++roman: Try to merge some scatter-buffers if +- * they are at contiguous physical addresses. +- */ +- merge_contiguous_buffers( cmd ); +- INF_PRINTK("scsi%d: %d bytes and %d buffers left\n", +- HOSTNO, cmd->SCp.this_residual, +- cmd->SCp.buffers_residual); +- } ++ if (sink && (phase != PHASE_MSGOUT)) { ++ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); + +- /* +- * The preferred transfer method is going to be +- * PSEUDO-DMA for systems that are strictly PIO, +- * since we can let the hardware do the handshaking. +- * +- * For this to work, we need to know the transfersize +- * ahead of time, since the pseudo-DMA code will sit +- * in an unconditional loop. +- */ ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ++ ICR_ASSERT_ACK); ++ while (NCR5380_read(STATUS_REG) & SR_REQ) ++ ; ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ++ ICR_ASSERT_ATN); ++ sink = 0; ++ continue; ++ } + +-/* ++roman: I suggest, this should be +- * #if def(REAL_DMA) +- * instead of leaving REAL_DMA out. +- */ ++ switch (phase) { ++ case PHASE_DATAOUT: ++#if (NDEBUG & NDEBUG_NO_DATAOUT) ++ printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT " ++ "aborted\n", HOSTNO); ++ sink = 1; ++ do_abort(instance); ++ cmd->result = DID_ERROR << 16; ++ cmd->done(cmd); ++ return; ++#endif ++ case PHASE_DATAIN: ++ /* ++ * If there is no room left in the current buffer in the ++ * scatter-gather list, move onto the next one. ++ */ ++ ++ if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { ++ ++cmd->SCp.buffer; ++ --cmd->SCp.buffers_residual; ++ cmd->SCp.this_residual = cmd->SCp.buffer->length; ++ cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + ++ cmd->SCp.buffer->offset; ++ /* ++roman: Try to merge some scatter-buffers if ++ * they are at contiguous physical addresses. ++ */ ++ merge_contiguous_buffers(cmd); ++ INF_PRINTK("scsi%d: %d bytes and %d buffers left\n", ++ HOSTNO, cmd->SCp.this_residual, ++ cmd->SCp.buffers_residual); ++ } ++ ++ /* ++ * The preferred transfer method is going to be ++ * PSEUDO-DMA for systems that are strictly PIO, ++ * since we can let the hardware do the handshaking. ++ * ++ * For this to work, we need to know the transfersize ++ * ahead of time, since the pseudo-DMA code will sit ++ * in an unconditional loop. ++ */ ++ ++ /* ++roman: I suggest, this should be ++ * #if def(REAL_DMA) ++ * instead of leaving REAL_DMA out. ++ */ + + #if defined(REAL_DMA) +- if (!cmd->device->borken && +- (transfersize = NCR5380_dma_xfer_len(instance,cmd,phase)) > 31) { +- len = transfersize; +- cmd->SCp.phase = phase; +- if (NCR5380_transfer_dma(instance, &phase, +- &len, (unsigned char **) &cmd->SCp.ptr)) { +- /* +- * If the watchdog timer fires, all future +- * accesses to this device will use the +- * polled-IO. */ +- printk(KERN_NOTICE "scsi%d: switching target %d " +- "lun %d to slow handshake\n", HOSTNO, +- cmd->device->id, cmd->device->lun); +- cmd->device->borken = 1; +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | +- ICR_ASSERT_ATN); +- sink = 1; +- do_abort(instance); +- cmd->result = DID_ERROR << 16; +- cmd->done(cmd); +- /* XXX - need to source or sink data here, as appropriate */ +- } else { ++ if (!cmd->device->borken && ++ (transfersize = NCR5380_dma_xfer_len(instance,cmd,phase)) > 31) { ++ len = transfersize; ++ cmd->SCp.phase = phase; ++ if (NCR5380_transfer_dma(instance, &phase, ++ &len, (unsigned char **)&cmd->SCp.ptr)) { ++ /* ++ * If the watchdog timer fires, all future ++ * accesses to this device will use the ++ * polled-IO. */ ++ printk(KERN_NOTICE "scsi%d: switching target %d " ++ "lun %d to slow handshake\n", HOSTNO, ++ cmd->device->id, cmd->device->lun); ++ cmd->device->borken = 1; ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ++ ICR_ASSERT_ATN); ++ sink = 1; ++ do_abort(instance); ++ cmd->result = DID_ERROR << 16; ++ cmd->done(cmd); ++ /* XXX - need to source or sink data here, as appropriate */ ++ } else { + #ifdef REAL_DMA +- /* ++roman: When using real DMA, +- * information_transfer() should return after +- * starting DMA since it has nothing more to +- * do. +- */ +- return; +-#else +- cmd->SCp.this_residual -= transfersize - len; ++ /* ++roman: When using real DMA, ++ * information_transfer() should return after ++ * starting DMA since it has nothing more to ++ * do. ++ */ ++ return; ++#else ++ cmd->SCp.this_residual -= transfersize - len; + #endif +- } +- } else ++ } ++ } else + #endif /* defined(REAL_DMA) */ +- NCR5380_transfer_pio(instance, &phase, +- (int *) &cmd->SCp.this_residual, (unsigned char **) +- &cmd->SCp.ptr); +- break; +- case PHASE_MSGIN: +- len = 1; +- data = &tmp; +- NCR5380_write(SELECT_ENABLE_REG, 0); /* disable reselects */ +- NCR5380_transfer_pio(instance, &phase, &len, &data); +- cmd->SCp.Message = tmp; +- +- switch (tmp) { +- /* +- * Linking lets us reduce the time required to get the +- * next command out to the device, hopefully this will +- * mean we don't waste another revolution due to the delays +- * required by ARBITRATION and another SELECTION. +- * +- * In the current implementation proposal, low level drivers +- * merely have to start the next command, pointed to by +- * next_link, done() is called as with unlinked commands. +- */ ++ NCR5380_transfer_pio(instance, &phase, ++ (int *)&cmd->SCp.this_residual, ++ (unsigned char **)&cmd->SCp.ptr); ++ break; ++ case PHASE_MSGIN: ++ len = 1; ++ data = &tmp; ++ NCR5380_write(SELECT_ENABLE_REG, 0); /* disable reselects */ ++ NCR5380_transfer_pio(instance, &phase, &len, &data); ++ cmd->SCp.Message = tmp; ++ ++ switch (tmp) { ++ /* ++ * Linking lets us reduce the time required to get the ++ * next command out to the device, hopefully this will ++ * mean we don't waste another revolution due to the delays ++ * required by ARBITRATION and another SELECTION. ++ * ++ * In the current implementation proposal, low level drivers ++ * merely have to start the next command, pointed to by ++ * next_link, done() is called as with unlinked commands. ++ */ + #ifdef LINKED +- case LINKED_CMD_COMPLETE: +- case LINKED_FLG_CMD_COMPLETE: +- /* Accept message by clearing ACK */ +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +- +- LNK_PRINTK("scsi%d: target %d lun %d linked command " +- "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun); +- +- /* Enable reselect interrupts */ +- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); +- /* +- * Sanity check : A linked command should only terminate +- * with one of these messages if there are more linked +- * commands available. +- */ +- +- if (!cmd->next_link) { +- printk(KERN_NOTICE "scsi%d: target %d lun %d " +- "linked command complete, no next_link\n", +- HOSTNO, cmd->device->id, cmd->device->lun); +- sink = 1; +- do_abort (instance); +- return; +- } +- +- initialize_SCp(cmd->next_link); +- /* The next command is still part of this process; copy it +- * and don't free it! */ +- cmd->next_link->tag = cmd->tag; +- cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); +- LNK_PRINTK("scsi%d: target %d lun %d linked request " +- "done, calling scsi_done().\n", +- HOSTNO, cmd->device->id, cmd->device->lun); ++ case LINKED_CMD_COMPLETE: ++ case LINKED_FLG_CMD_COMPLETE: ++ /* Accept message by clearing ACK */ ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); ++ ++ LNK_PRINTK("scsi%d: target %d lun %d linked command " ++ "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun); ++ ++ /* Enable reselect interrupts */ ++ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); ++ /* ++ * Sanity check : A linked command should only terminate ++ * with one of these messages if there are more linked ++ * commands available. ++ */ ++ ++ if (!cmd->next_link) { ++ printk(KERN_NOTICE "scsi%d: target %d lun %d " ++ "linked command complete, no next_link\n", ++ HOSTNO, cmd->device->id, cmd->device->lun); ++ sink = 1; ++ do_abort(instance); ++ return; ++ } ++ ++ initialize_SCp(cmd->next_link); ++ /* The next command is still part of this process; copy it ++ * and don't free it! */ ++ cmd->next_link->tag = cmd->tag; ++ cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); ++ LNK_PRINTK("scsi%d: target %d lun %d linked request " ++ "done, calling scsi_done().\n", ++ HOSTNO, cmd->device->id, cmd->device->lun); + #ifdef NCR5380_STATS +- collect_stats(hostdata, cmd); ++ collect_stats(hostdata, cmd); + #endif +- cmd->scsi_done(cmd); +- cmd = hostdata->connected; +- break; ++ cmd->scsi_done(cmd); ++ cmd = hostdata->connected; ++ break; + #endif /* def LINKED */ +- case ABORT: +- case COMMAND_COMPLETE: +- /* Accept message by clearing ACK */ +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +- /* ++guenther: possible race with Falcon locking */ +- falcon_dont_release++; +- hostdata->connected = NULL; +- QU_PRINTK("scsi%d: command for target %d, lun %d " +- "completed\n", HOSTNO, cmd->device->id, cmd->device->lun); ++ case ABORT: ++ case COMMAND_COMPLETE: ++ /* Accept message by clearing ACK */ ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); ++ /* ++guenther: possible race with Falcon locking */ ++ falcon_dont_release++; ++ hostdata->connected = NULL; ++ QU_PRINTK("scsi%d: command for target %d, lun %d " ++ "completed\n", HOSTNO, cmd->device->id, cmd->device->lun); + #ifdef SUPPORT_TAGS +- cmd_free_tag( cmd ); +- if (status_byte(cmd->SCp.Status) == QUEUE_FULL) { +- /* Turn a QUEUE FULL status into BUSY, I think the +- * mid level cannot handle QUEUE FULL :-( (The +- * command is retried after BUSY). Also update our +- * queue size to the number of currently issued +- * commands now. +- */ +- /* ++Andreas: the mid level code knows about +- QUEUE_FULL now. */ +- TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; +- TAG_PRINTK("scsi%d: target %d lun %d returned " +- "QUEUE_FULL after %d commands\n", +- HOSTNO, cmd->device->id, cmd->device->lun, +- ta->nr_allocated); +- if (ta->queue_size > ta->nr_allocated) +- ta->nr_allocated = ta->queue_size; +- } ++ cmd_free_tag(cmd); ++ if (status_byte(cmd->SCp.Status) == QUEUE_FULL) { ++ /* Turn a QUEUE FULL status into BUSY, I think the ++ * mid level cannot handle QUEUE FULL :-( (The ++ * command is retried after BUSY). Also update our ++ * queue size to the number of currently issued ++ * commands now. ++ */ ++ /* ++Andreas: the mid level code knows about ++ QUEUE_FULL now. */ ++ TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; ++ TAG_PRINTK("scsi%d: target %d lun %d returned " ++ "QUEUE_FULL after %d commands\n", ++ HOSTNO, cmd->device->id, cmd->device->lun, ++ ta->nr_allocated); ++ if (ta->queue_size > ta->nr_allocated) ++ ta->nr_allocated = ta->queue_size; ++ } + #else +- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); ++ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); + #endif +- /* Enable reselect interrupts */ +- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); ++ /* Enable reselect interrupts */ ++ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + +- /* +- * I'm not sure what the correct thing to do here is : +- * +- * If the command that just executed is NOT a request +- * sense, the obvious thing to do is to set the result +- * code to the values of the stored parameters. +- * +- * If it was a REQUEST SENSE command, we need some way to +- * differentiate between the failure code of the original +- * and the failure code of the REQUEST sense - the obvious +- * case is success, where we fall through and leave the +- * result code unchanged. +- * +- * The non-obvious place is where the REQUEST SENSE failed +- */ +- +- if (cmd->cmnd[0] != REQUEST_SENSE) +- cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); +- else if (status_byte(cmd->SCp.Status) != GOOD) +- cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); +- +-#ifdef AUTOSENSE +- if ((cmd->cmnd[0] != REQUEST_SENSE) && +- (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) { +- ASEN_PRINTK("scsi%d: performing request sense\n", +- HOSTNO); +- cmd->cmnd[0] = REQUEST_SENSE; +- cmd->cmnd[1] &= 0xe0; +- cmd->cmnd[2] = 0; +- cmd->cmnd[3] = 0; +- cmd->cmnd[4] = sizeof(cmd->sense_buffer); +- cmd->cmnd[5] = 0; +- cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]); +- +- cmd->use_sg = 0; +- /* this is initialized from initialize_SCp +- cmd->SCp.buffer = NULL; +- cmd->SCp.buffers_residual = 0; +- */ +- cmd->request_buffer = (char *) cmd->sense_buffer; +- cmd->request_bufflen = sizeof(cmd->sense_buffer); ++ /* ++ * I'm not sure what the correct thing to do here is : ++ * ++ * If the command that just executed is NOT a request ++ * sense, the obvious thing to do is to set the result ++ * code to the values of the stored parameters. ++ * ++ * If it was a REQUEST SENSE command, we need some way to ++ * differentiate between the failure code of the original ++ * and the failure code of the REQUEST sense - the obvious ++ * case is success, where we fall through and leave the ++ * result code unchanged. ++ * ++ * The non-obvious place is where the REQUEST SENSE failed ++ */ ++ ++ if (cmd->cmnd[0] != REQUEST_SENSE) ++ cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); ++ else if (status_byte(cmd->SCp.Status) != GOOD) ++ cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); + +- local_irq_save(flags); +- LIST(cmd,hostdata->issue_queue); +- NEXT(cmd) = hostdata->issue_queue; +- hostdata->issue_queue = (Scsi_Cmnd *) cmd; +- local_irq_restore(flags); +- QU_PRINTK("scsi%d: REQUEST SENSE added to head of " +- "issue queue\n", H_NO(cmd)); +- } else ++#ifdef AUTOSENSE ++ if ((cmd->cmnd[0] != REQUEST_SENSE) && ++ (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) { ++ ASEN_PRINTK("scsi%d: performing request sense\n", HOSTNO); ++ cmd->cmnd[0] = REQUEST_SENSE; ++ cmd->cmnd[1] &= 0xe0; ++ cmd->cmnd[2] = 0; ++ cmd->cmnd[3] = 0; ++ cmd->cmnd[4] = sizeof(cmd->sense_buffer); ++ cmd->cmnd[5] = 0; ++ cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]); ++ ++ cmd->use_sg = 0; ++ /* this is initialized from initialize_SCp ++ cmd->SCp.buffer = NULL; ++ cmd->SCp.buffers_residual = 0; ++ */ ++ cmd->request_buffer = (char *) cmd->sense_buffer; ++ cmd->request_bufflen = sizeof(cmd->sense_buffer); ++ ++ local_irq_save(flags); ++ LIST(cmd,hostdata->issue_queue); ++ NEXT(cmd) = hostdata->issue_queue; ++ hostdata->issue_queue = (Scsi_Cmnd *) cmd; ++ local_irq_restore(flags); ++ QU_PRINTK("scsi%d: REQUEST SENSE added to head of " ++ "issue queue\n", H_NO(cmd)); ++ } else + #endif /* def AUTOSENSE */ +- { ++ { + #ifdef NCR5380_STATS +- collect_stats(hostdata, cmd); ++ collect_stats(hostdata, cmd); + #endif +- cmd->scsi_done(cmd); +- } ++ cmd->scsi_done(cmd); ++ } + +- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); +- /* +- * Restore phase bits to 0 so an interrupted selection, +- * arbitration can resume. +- */ +- NCR5380_write(TARGET_COMMAND_REG, 0); +- +- while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) +- barrier(); +- +- falcon_dont_release--; +- /* ++roman: For Falcon SCSI, release the lock on the +- * ST-DMA here if no other commands are waiting on the +- * disconnected queue. +- */ +- falcon_release_lock_if_possible( hostdata ); +- return; +- case MESSAGE_REJECT: +- /* Accept message by clearing ACK */ +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +- /* Enable reselect interrupts */ +- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); +- switch (hostdata->last_message) { +- case HEAD_OF_QUEUE_TAG: +- case ORDERED_QUEUE_TAG: +- case SIMPLE_QUEUE_TAG: +- /* The target obviously doesn't support tagged +- * queuing, even though it announced this ability in +- * its INQUIRY data ?!? (maybe only this LUN?) Ok, +- * clear 'tagged_supported' and lock the LUN, since +- * the command is treated as untagged further on. +- */ +- cmd->device->tagged_supported = 0; +- hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); +- cmd->tag = TAG_NONE; +- TAG_PRINTK("scsi%d: target %d lun %d rejected " +- "QUEUE_TAG message; tagged queuing " +- "disabled\n", +- HOSTNO, cmd->device->id, cmd->device->lun); +- break; +- } +- break; +- case DISCONNECT: +- /* Accept message by clearing ACK */ +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +- local_irq_save(flags); +- cmd->device->disconnect = 1; +- LIST(cmd,hostdata->disconnected_queue); +- NEXT(cmd) = hostdata->disconnected_queue; +- hostdata->connected = NULL; +- hostdata->disconnected_queue = cmd; +- local_irq_restore(flags); +- QU_PRINTK("scsi%d: command for target %d lun %d was " +- "moved from connected to the " +- "disconnected_queue\n", HOSTNO, +- cmd->device->id, cmd->device->lun); +- /* +- * Restore phase bits to 0 so an interrupted selection, +- * arbitration can resume. +- */ +- NCR5380_write(TARGET_COMMAND_REG, 0); +- +- /* Enable reselect interrupts */ +- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); +- /* Wait for bus free to avoid nasty timeouts */ +- while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) +- barrier(); +- return; +- /* +- * The SCSI data pointer is *IMPLICITLY* saved on a disconnect +- * operation, in violation of the SCSI spec so we can safely +- * ignore SAVE/RESTORE pointers calls. +- * +- * Unfortunately, some disks violate the SCSI spec and +- * don't issue the required SAVE_POINTERS message before +- * disconnecting, and we have to break spec to remain +- * compatible. +- */ +- case SAVE_POINTERS: +- case RESTORE_POINTERS: +- /* Accept message by clearing ACK */ +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +- /* Enable reselect interrupts */ +- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); +- break; +- case EXTENDED_MESSAGE: +-/* +- * Extended messages are sent in the following format : +- * Byte +- * 0 EXTENDED_MESSAGE == 1 +- * 1 length (includes one byte for code, doesn't +- * include first two bytes) +- * 2 code +- * 3..length+1 arguments +- * +- * Start the extended message buffer with the EXTENDED_MESSAGE +- * byte, since spi_print_msg() wants the whole thing. +- */ +- extended_msg[0] = EXTENDED_MESSAGE; +- /* Accept first byte by clearing ACK */ +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +- +- EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO); +- +- len = 2; +- data = extended_msg + 1; +- phase = PHASE_MSGIN; +- NCR5380_transfer_pio(instance, &phase, &len, &data); +- EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO, +- (int)extended_msg[1], (int)extended_msg[2]); +- +- if (!len && extended_msg[1] <= +- (sizeof (extended_msg) - 1)) { +- /* Accept third byte by clearing ACK */ +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +- len = extended_msg[1] - 1; +- data = extended_msg + 3; +- phase = PHASE_MSGIN; +- +- NCR5380_transfer_pio(instance, &phase, &len, &data); +- EXT_PRINTK("scsi%d: message received, residual %d\n", +- HOSTNO, len); +- +- switch (extended_msg[2]) { +- case EXTENDED_SDTR: +- case EXTENDED_WDTR: +- case EXTENDED_MODIFY_DATA_POINTER: +- case EXTENDED_EXTENDED_IDENTIFY: +- tmp = 0; +- } +- } else if (len) { +- printk(KERN_NOTICE "scsi%d: error receiving " +- "extended message\n", HOSTNO); +- tmp = 0; +- } else { +- printk(KERN_NOTICE "scsi%d: extended message " +- "code %02x length %d is too long\n", +- HOSTNO, extended_msg[2], extended_msg[1]); +- tmp = 0; +- } +- /* Fall through to reject message */ +- +- /* +- * If we get something weird that we aren't expecting, +- * reject it. +- */ +- default: +- if (!tmp) { +- printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO); +- spi_print_msg(extended_msg); +- printk("\n"); +- } else if (tmp != EXTENDED_MESSAGE) +- printk(KERN_DEBUG "scsi%d: rejecting unknown " +- "message %02x from target %d, lun %d\n", +- HOSTNO, tmp, cmd->device->id, cmd->device->lun); +- else +- printk(KERN_DEBUG "scsi%d: rejecting unknown " +- "extended message " +- "code %02x, length %d from target %d, lun %d\n", +- HOSTNO, extended_msg[1], extended_msg[0], +- cmd->device->id, cmd->device->lun); +- +- +- msgout = MESSAGE_REJECT; +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | +- ICR_ASSERT_ATN); +- break; +- } /* switch (tmp) */ +- break; +- case PHASE_MSGOUT: +- len = 1; +- data = &msgout; +- hostdata->last_message = msgout; +- NCR5380_transfer_pio(instance, &phase, &len, &data); +- if (msgout == ABORT) { ++ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); ++ /* ++ * Restore phase bits to 0 so an interrupted selection, ++ * arbitration can resume. ++ */ ++ NCR5380_write(TARGET_COMMAND_REG, 0); ++ ++ while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) ++ barrier(); ++ ++ falcon_dont_release--; ++ /* ++roman: For Falcon SCSI, release the lock on the ++ * ST-DMA here if no other commands are waiting on the ++ * disconnected queue. ++ */ ++ falcon_release_lock_if_possible(hostdata); ++ return; ++ case MESSAGE_REJECT: ++ /* Accept message by clearing ACK */ ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); ++ /* Enable reselect interrupts */ ++ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); ++ switch (hostdata->last_message) { ++ case HEAD_OF_QUEUE_TAG: ++ case ORDERED_QUEUE_TAG: ++ case SIMPLE_QUEUE_TAG: ++ /* The target obviously doesn't support tagged ++ * queuing, even though it announced this ability in ++ * its INQUIRY data ?!? (maybe only this LUN?) Ok, ++ * clear 'tagged_supported' and lock the LUN, since ++ * the command is treated as untagged further on. ++ */ ++ cmd->device->tagged_supported = 0; ++ hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); ++ cmd->tag = TAG_NONE; ++ TAG_PRINTK("scsi%d: target %d lun %d rejected " ++ "QUEUE_TAG message; tagged queuing " ++ "disabled\n", ++ HOSTNO, cmd->device->id, cmd->device->lun); ++ break; ++ } ++ break; ++ case DISCONNECT: ++ /* Accept message by clearing ACK */ ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); ++ local_irq_save(flags); ++ cmd->device->disconnect = 1; ++ LIST(cmd,hostdata->disconnected_queue); ++ NEXT(cmd) = hostdata->disconnected_queue; ++ hostdata->connected = NULL; ++ hostdata->disconnected_queue = cmd; ++ local_irq_restore(flags); ++ QU_PRINTK("scsi%d: command for target %d lun %d was " ++ "moved from connected to the " ++ "disconnected_queue\n", HOSTNO, ++ cmd->device->id, cmd->device->lun); ++ /* ++ * Restore phase bits to 0 so an interrupted selection, ++ * arbitration can resume. ++ */ ++ NCR5380_write(TARGET_COMMAND_REG, 0); ++ ++ /* Enable reselect interrupts */ ++ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); ++ /* Wait for bus free to avoid nasty timeouts */ ++ while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) ++ barrier(); ++ return; ++ /* ++ * The SCSI data pointer is *IMPLICITLY* saved on a disconnect ++ * operation, in violation of the SCSI spec so we can safely ++ * ignore SAVE/RESTORE pointers calls. ++ * ++ * Unfortunately, some disks violate the SCSI spec and ++ * don't issue the required SAVE_POINTERS message before ++ * disconnecting, and we have to break spec to remain ++ * compatible. ++ */ ++ case SAVE_POINTERS: ++ case RESTORE_POINTERS: ++ /* Accept message by clearing ACK */ ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); ++ /* Enable reselect interrupts */ ++ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); ++ break; ++ case EXTENDED_MESSAGE: ++ /* ++ * Extended messages are sent in the following format : ++ * Byte ++ * 0 EXTENDED_MESSAGE == 1 ++ * 1 length (includes one byte for code, doesn't ++ * include first two bytes) ++ * 2 code ++ * 3..length+1 arguments ++ * ++ * Start the extended message buffer with the EXTENDED_MESSAGE ++ * byte, since spi_print_msg() wants the whole thing. ++ */ ++ extended_msg[0] = EXTENDED_MESSAGE; ++ /* Accept first byte by clearing ACK */ ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); ++ ++ EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO); ++ ++ len = 2; ++ data = extended_msg + 1; ++ phase = PHASE_MSGIN; ++ NCR5380_transfer_pio(instance, &phase, &len, &data); ++ EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO, ++ (int)extended_msg[1], (int)extended_msg[2]); ++ ++ if (!len && extended_msg[1] <= ++ (sizeof(extended_msg) - 1)) { ++ /* Accept third byte by clearing ACK */ ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); ++ len = extended_msg[1] - 1; ++ data = extended_msg + 3; ++ phase = PHASE_MSGIN; ++ ++ NCR5380_transfer_pio(instance, &phase, &len, &data); ++ EXT_PRINTK("scsi%d: message received, residual %d\n", ++ HOSTNO, len); ++ ++ switch (extended_msg[2]) { ++ case EXTENDED_SDTR: ++ case EXTENDED_WDTR: ++ case EXTENDED_MODIFY_DATA_POINTER: ++ case EXTENDED_EXTENDED_IDENTIFY: ++ tmp = 0; ++ } ++ } else if (len) { ++ printk(KERN_NOTICE "scsi%d: error receiving " ++ "extended message\n", HOSTNO); ++ tmp = 0; ++ } else { ++ printk(KERN_NOTICE "scsi%d: extended message " ++ "code %02x length %d is too long\n", ++ HOSTNO, extended_msg[2], extended_msg[1]); ++ tmp = 0; ++ } ++ /* Fall through to reject message */ ++ ++ /* ++ * If we get something weird that we aren't expecting, ++ * reject it. ++ */ ++ default: ++ if (!tmp) { ++ printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO); ++ spi_print_msg(extended_msg); ++ printk("\n"); ++ } else if (tmp != EXTENDED_MESSAGE) ++ printk(KERN_DEBUG "scsi%d: rejecting unknown " ++ "message %02x from target %d, lun %d\n", ++ HOSTNO, tmp, cmd->device->id, cmd->device->lun); ++ else ++ printk(KERN_DEBUG "scsi%d: rejecting unknown " ++ "extended message " ++ "code %02x, length %d from target %d, lun %d\n", ++ HOSTNO, extended_msg[1], extended_msg[0], ++ cmd->device->id, cmd->device->lun); ++ ++ ++ msgout = MESSAGE_REJECT; ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); ++ break; ++ } /* switch (tmp) */ ++ break; ++ case PHASE_MSGOUT: ++ len = 1; ++ data = &msgout; ++ hostdata->last_message = msgout; ++ NCR5380_transfer_pio(instance, &phase, &len, &data); ++ if (msgout == ABORT) { + #ifdef SUPPORT_TAGS +- cmd_free_tag( cmd ); ++ cmd_free_tag(cmd); + #else +- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); ++ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); + #endif +- hostdata->connected = NULL; +- cmd->result = DID_ERROR << 16; ++ hostdata->connected = NULL; ++ cmd->result = DID_ERROR << 16; + #ifdef NCR5380_STATS +- collect_stats(hostdata, cmd); ++ collect_stats(hostdata, cmd); + #endif +- cmd->scsi_done(cmd); +- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); +- falcon_release_lock_if_possible( hostdata ); +- return; +- } +- msgout = NOP; +- break; +- case PHASE_CMDOUT: +- len = cmd->cmd_len; +- data = cmd->cmnd; +- /* +- * XXX for performance reasons, on machines with a +- * PSEUDO-DMA architecture we should probably +- * use the dma transfer function. +- */ +- NCR5380_transfer_pio(instance, &phase, &len, +- &data); +- break; +- case PHASE_STATIN: +- len = 1; +- data = &tmp; +- NCR5380_transfer_pio(instance, &phase, &len, &data); +- cmd->SCp.Status = tmp; +- break; +- default: +- printk("scsi%d: unknown phase\n", HOSTNO); +- NCR_PRINT(NDEBUG_ANY); +- } /* switch(phase) */ +- } /* if (tmp * SR_REQ) */ +- } /* while (1) */ ++ cmd->scsi_done(cmd); ++ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); ++ falcon_release_lock_if_possible(hostdata); ++ return; ++ } ++ msgout = NOP; ++ break; ++ case PHASE_CMDOUT: ++ len = cmd->cmd_len; ++ data = cmd->cmnd; ++ /* ++ * XXX for performance reasons, on machines with a ++ * PSEUDO-DMA architecture we should probably ++ * use the dma transfer function. ++ */ ++ NCR5380_transfer_pio(instance, &phase, &len, &data); ++ break; ++ case PHASE_STATIN: ++ len = 1; ++ data = &tmp; ++ NCR5380_transfer_pio(instance, &phase, &len, &data); ++ cmd->SCp.Status = tmp; ++ break; ++ default: ++ printk("scsi%d: unknown phase\n", HOSTNO); ++ NCR_PRINT(NDEBUG_ANY); ++ } /* switch(phase) */ ++ } /* if (tmp * SR_REQ) */ ++ } /* while (1) */ + } + + /* + * Function : void NCR5380_reselect (struct Scsi_Host *instance) + * +- * Purpose : does reselection, initializing the instance->connected +- * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q ++ * Purpose : does reselection, initializing the instance->connected ++ * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q + * nexus has been reestablished, +- * ++ * + * Inputs : instance - this instance of the NCR5380. + * + */ + + +-static void NCR5380_reselect (struct Scsi_Host *instance) ++static void NCR5380_reselect(struct Scsi_Host *instance) + { +- SETUP_HOSTDATA(instance); +- unsigned char target_mask; +- unsigned char lun, phase; +- int len; ++ SETUP_HOSTDATA(instance); ++ unsigned char target_mask; ++ unsigned char lun, phase; ++ int len; + #ifdef SUPPORT_TAGS +- unsigned char tag; ++ unsigned char tag; + #endif +- unsigned char msg[3]; +- unsigned char *data; +- Scsi_Cmnd *tmp = NULL, *prev; +-/* unsigned long flags; */ +- +- /* +- * Disable arbitration, etc. since the host adapter obviously +- * lost, and tell an interrupted NCR5380_select() to restart. +- */ +- +- NCR5380_write(MODE_REG, MR_BASE); +- hostdata->restart_select = 1; +- +- target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); +- +- RSL_PRINTK("scsi%d: reselect\n", HOSTNO); +- +- /* +- * At this point, we have detected that our SCSI ID is on the bus, +- * SEL is true and BSY was false for at least one bus settle delay +- * (400 ns). +- * +- * We must assert BSY ourselves, until the target drops the SEL +- * signal. +- */ +- +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); +- +- while (NCR5380_read(STATUS_REG) & SR_SEL); +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +- +- /* +- * Wait for target to go into MSGIN. +- */ +- +- while (!(NCR5380_read(STATUS_REG) & SR_REQ)); +- +- len = 1; +- data = msg; +- phase = PHASE_MSGIN; +- NCR5380_transfer_pio(instance, &phase, &len, &data); +- +- if (!(msg[0] & 0x80)) { +- printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO); +- spi_print_msg(msg); +- do_abort(instance); +- return; +- } +- lun = (msg[0] & 0x07); ++ unsigned char msg[3]; ++ unsigned char *data; ++ Scsi_Cmnd *tmp = NULL, *prev; ++/* unsigned long flags; */ ++ ++ /* ++ * Disable arbitration, etc. since the host adapter obviously ++ * lost, and tell an interrupted NCR5380_select() to restart. ++ */ ++ ++ NCR5380_write(MODE_REG, MR_BASE); ++ hostdata->restart_select = 1; ++ ++ target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); ++ ++ RSL_PRINTK("scsi%d: reselect\n", HOSTNO); ++ ++ /* ++ * At this point, we have detected that our SCSI ID is on the bus, ++ * SEL is true and BSY was false for at least one bus settle delay ++ * (400 ns). ++ * ++ * We must assert BSY ourselves, until the target drops the SEL ++ * signal. ++ */ ++ ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); ++ ++ while (NCR5380_read(STATUS_REG) & SR_SEL) ++ ; ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); ++ ++ /* ++ * Wait for target to go into MSGIN. ++ */ ++ ++ while (!(NCR5380_read(STATUS_REG) & SR_REQ)) ++ ; ++ ++ len = 1; ++ data = msg; ++ phase = PHASE_MSGIN; ++ NCR5380_transfer_pio(instance, &phase, &len, &data); ++ ++ if (!(msg[0] & 0x80)) { ++ printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO); ++ spi_print_msg(msg); ++ do_abort(instance); ++ return; ++ } ++ lun = (msg[0] & 0x07); + + #ifdef SUPPORT_TAGS +- /* If the phase is still MSGIN, the target wants to send some more +- * messages. In case it supports tagged queuing, this is probably a +- * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus. +- */ +- tag = TAG_NONE; +- if (phase == PHASE_MSGIN && setup_use_tagged_queuing) { +- /* Accept previous IDENTIFY message by clearing ACK */ +- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); +- len = 2; +- data = msg+1; +- if (!NCR5380_transfer_pio(instance, &phase, &len, &data) && +- msg[1] == SIMPLE_QUEUE_TAG) +- tag = msg[2]; +- TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at " +- "reselection\n", HOSTNO, target_mask, lun, tag); +- } +-#endif +- +- /* +- * Find the command corresponding to the I_T_L or I_T_L_Q nexus we +- * just reestablished, and remove it from the disconnected queue. +- */ +- +- for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; +- tmp; prev = tmp, tmp = NEXT(tmp) ) { +- if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun) ++ /* If the phase is still MSGIN, the target wants to send some more ++ * messages. In case it supports tagged queuing, this is probably a ++ * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus. ++ */ ++ tag = TAG_NONE; ++ if (phase == PHASE_MSGIN && setup_use_tagged_queuing) { ++ /* Accept previous IDENTIFY message by clearing ACK */ ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); ++ len = 2; ++ data = msg + 1; ++ if (!NCR5380_transfer_pio(instance, &phase, &len, &data) && ++ msg[1] == SIMPLE_QUEUE_TAG) ++ tag = msg[2]; ++ TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at " ++ "reselection\n", HOSTNO, target_mask, lun, tag); ++ } ++#endif ++ ++ /* ++ * Find the command corresponding to the I_T_L or I_T_L_Q nexus we ++ * just reestablished, and remove it from the disconnected queue. ++ */ ++ ++ for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; ++ tmp; prev = tmp, tmp = NEXT(tmp)) { ++ if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun) + #ifdef SUPPORT_TAGS +- && (tag == tmp->tag) ++ && (tag == tmp->tag) + #endif +- ) { +- /* ++guenther: prevent race with falcon_release_lock */ +- falcon_dont_release++; +- if (prev) { +- REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); +- NEXT(prev) = NEXT(tmp); +- } else { +- REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp)); +- hostdata->disconnected_queue = NEXT(tmp); +- } +- NEXT(tmp) = NULL; +- break; +- } +- } +- +- if (!tmp) { +- printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d " ++ ) { ++ /* ++guenther: prevent race with falcon_release_lock */ ++ falcon_dont_release++; ++ if (prev) { ++ REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); ++ NEXT(prev) = NEXT(tmp); ++ } else { ++ REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp)); ++ hostdata->disconnected_queue = NEXT(tmp); ++ } ++ NEXT(tmp) = NULL; ++ break; ++ } ++ } ++ ++ if (!tmp) { ++ printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d " + #ifdef SUPPORT_TAGS +- "tag %d " ++ "tag %d " + #endif +- "not in disconnected_queue.\n", +- HOSTNO, target_mask, lun ++ "not in disconnected_queue.\n", ++ HOSTNO, target_mask, lun + #ifdef SUPPORT_TAGS +- , tag ++ , tag + #endif +- ); +- /* +- * Since we have an established nexus that we can't do anything +- * with, we must abort it. +- */ +- do_abort(instance); +- return; +- } +- +- /* Accept message by clearing ACK */ +- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +- +- hostdata->connected = tmp; +- RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n", +- HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag); +- falcon_dont_release--; ++ ); ++ /* ++ * Since we have an established nexus that we can't do anything ++ * with, we must abort it. ++ */ ++ do_abort(instance); ++ return; ++ } ++ ++ /* Accept message by clearing ACK */ ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); ++ ++ hostdata->connected = tmp; ++ RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n", ++ HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag); ++ falcon_dont_release--; + } + + +@@ -2666,362 +2676,361 @@ static void NCR5380_reselect (struct Scs + * + * Purpose : abort a command + * +- * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the +- * host byte of the result field to, if zero DID_ABORTED is ++ * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the ++ * host byte of the result field to, if zero DID_ABORTED is + * used. + * + * Returns : 0 - success, -1 on failure. + * +- * XXX - there is no way to abort the command that is currently +- * connected, you have to wait for it to complete. If this is ++ * XXX - there is no way to abort the command that is currently ++ * connected, you have to wait for it to complete. If this is + * a problem, we could implement longjmp() / setjmp(), setjmp() +- * called where the loop started in NCR5380_main(). ++ * called where the loop started in NCR5380_main(). + */ + + static +-int NCR5380_abort (Scsi_Cmnd *cmd) ++int NCR5380_abort(Scsi_Cmnd *cmd) + { +- struct Scsi_Host *instance = cmd->device->host; +- SETUP_HOSTDATA(instance); +- Scsi_Cmnd *tmp, **prev; +- unsigned long flags; +- +- printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO); +- scsi_print_command(cmd); +- +- NCR5380_print_status (instance); +- +- local_irq_save(flags); +- +- if (!IS_A_TT() && !falcon_got_lock) +- printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n", +- HOSTNO); +- +- ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO, +- NCR5380_read(BUS_AND_STATUS_REG), +- NCR5380_read(STATUS_REG)); ++ struct Scsi_Host *instance = cmd->device->host; ++ SETUP_HOSTDATA(instance); ++ Scsi_Cmnd *tmp, **prev; ++ unsigned long flags; ++ ++ printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO); ++ scsi_print_command(cmd); ++ ++ NCR5380_print_status(instance); ++ ++ local_irq_save(flags); ++ ++ if (!IS_A_TT() && !falcon_got_lock) ++ printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n", ++ HOSTNO); ++ ++ ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO, ++ NCR5380_read(BUS_AND_STATUS_REG), ++ NCR5380_read(STATUS_REG)); + + #if 1 +-/* +- * Case 1 : If the command is the currently executing command, +- * we'll set the aborted flag and return control so that +- * information transfer routine can exit cleanly. +- */ ++ /* ++ * Case 1 : If the command is the currently executing command, ++ * we'll set the aborted flag and return control so that ++ * information transfer routine can exit cleanly. ++ */ + +- if (hostdata->connected == cmd) { ++ if (hostdata->connected == cmd) { + +- ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO); +-/* +- * We should perform BSY checking, and make sure we haven't slipped +- * into BUS FREE. +- */ ++ ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO); ++ /* ++ * We should perform BSY checking, and make sure we haven't slipped ++ * into BUS FREE. ++ */ + +-/* NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */ +-/* +- * Since we can't change phases until we've completed the current +- * handshake, we have to source or sink a byte of data if the current +- * phase is not MSGOUT. +- */ ++ /* NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */ ++ /* ++ * Since we can't change phases until we've completed the current ++ * handshake, we have to source or sink a byte of data if the current ++ * phase is not MSGOUT. ++ */ + +-/* +- * Return control to the executing NCR drive so we can clear the +- * aborted flag and get back into our main loop. +- */ ++ /* ++ * Return control to the executing NCR drive so we can clear the ++ * aborted flag and get back into our main loop. ++ */ + +- if (do_abort(instance) == 0) { +- hostdata->aborted = 1; +- hostdata->connected = NULL; +- cmd->result = DID_ABORT << 16; ++ if (do_abort(instance) == 0) { ++ hostdata->aborted = 1; ++ hostdata->connected = NULL; ++ cmd->result = DID_ABORT << 16; + #ifdef SUPPORT_TAGS +- cmd_free_tag( cmd ); ++ cmd_free_tag(cmd); + #else +- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); ++ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); ++#endif ++ local_irq_restore(flags); ++ cmd->scsi_done(cmd); ++ falcon_release_lock_if_possible(hostdata); ++ return SCSI_ABORT_SUCCESS; ++ } else { ++/* local_irq_restore(flags); */ ++ printk("scsi%d: abort of connected command failed!\n", HOSTNO); ++ return SCSI_ABORT_ERROR; ++ } ++ } + #endif +- local_irq_restore(flags); +- cmd->scsi_done(cmd); +- falcon_release_lock_if_possible( hostdata ); +- return SCSI_ABORT_SUCCESS; +- } else { +-/* local_irq_restore(flags); */ +- printk("scsi%d: abort of connected command failed!\n", HOSTNO); +- return SCSI_ABORT_ERROR; +- } +- } +-#endif +- +-/* +- * Case 2 : If the command hasn't been issued yet, we simply remove it +- * from the issue queue. +- */ +- for (prev = (Scsi_Cmnd **) &(hostdata->issue_queue), +- tmp = (Scsi_Cmnd *) hostdata->issue_queue; +- tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) ) +- if (cmd == tmp) { +- REMOVE(5, *prev, tmp, NEXT(tmp)); +- (*prev) = NEXT(tmp); +- NEXT(tmp) = NULL; +- tmp->result = DID_ABORT << 16; +- local_irq_restore(flags); +- ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n", +- HOSTNO); +- /* Tagged queuing note: no tag to free here, hasn't been assigned +- * yet... */ +- tmp->scsi_done(tmp); +- falcon_release_lock_if_possible( hostdata ); +- return SCSI_ABORT_SUCCESS; +- } +- +-/* +- * Case 3 : If any commands are connected, we're going to fail the abort +- * and let the high level SCSI driver retry at a later time or +- * issue a reset. +- * +- * Timeouts, and therefore aborted commands, will be highly unlikely +- * and handling them cleanly in this situation would make the common +- * case of noresets less efficient, and would pollute our code. So, +- * we fail. +- */ + +- if (hostdata->connected) { +- local_irq_restore(flags); +- ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO); +- return SCSI_ABORT_SNOOZE; +- } +- +-/* +- * Case 4: If the command is currently disconnected from the bus, and +- * there are no connected commands, we reconnect the I_T_L or +- * I_T_L_Q nexus associated with it, go into message out, and send +- * an abort message. +- * +- * This case is especially ugly. In order to reestablish the nexus, we +- * need to call NCR5380_select(). The easiest way to implement this +- * function was to abort if the bus was busy, and let the interrupt +- * handler triggered on the SEL for reselect take care of lost arbitrations +- * where necessary, meaning interrupts need to be enabled. +- * +- * When interrupts are enabled, the queues may change - so we +- * can't remove it from the disconnected queue before selecting it +- * because that could cause a failure in hashing the nexus if that +- * device reselected. +- * +- * Since the queues may change, we can't use the pointers from when we +- * first locate it. +- * +- * So, we must first locate the command, and if NCR5380_select() +- * succeeds, then issue the abort, relocate the command and remove +- * it from the disconnected queue. +- */ +- +- for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; +- tmp = NEXT(tmp)) +- if (cmd == tmp) { +- local_irq_restore(flags); +- ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO); +- +- if (NCR5380_select (instance, cmd, (int) cmd->tag)) +- return SCSI_ABORT_BUSY; +- +- ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO); +- +- do_abort (instance); +- +- local_irq_save(flags); +- for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue), +- tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; +- tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) ) +- if (cmd == tmp) { +- REMOVE(5, *prev, tmp, NEXT(tmp)); +- *prev = NEXT(tmp); +- NEXT(tmp) = NULL; +- tmp->result = DID_ABORT << 16; +- /* We must unlock the tag/LUN immediately here, since the +- * target goes to BUS FREE and doesn't send us another +- * message (COMMAND_COMPLETE or the like) +- */ ++ /* ++ * Case 2 : If the command hasn't been issued yet, we simply remove it ++ * from the issue queue. ++ */ ++ for (prev = (Scsi_Cmnd **)&(hostdata->issue_queue), ++ tmp = (Scsi_Cmnd *)hostdata->issue_queue; ++ tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) { ++ if (cmd == tmp) { ++ REMOVE(5, *prev, tmp, NEXT(tmp)); ++ (*prev) = NEXT(tmp); ++ NEXT(tmp) = NULL; ++ tmp->result = DID_ABORT << 16; ++ local_irq_restore(flags); ++ ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n", ++ HOSTNO); ++ /* Tagged queuing note: no tag to free here, hasn't been assigned ++ * yet... */ ++ tmp->scsi_done(tmp); ++ falcon_release_lock_if_possible(hostdata); ++ return SCSI_ABORT_SUCCESS; ++ } ++ } ++ ++ /* ++ * Case 3 : If any commands are connected, we're going to fail the abort ++ * and let the high level SCSI driver retry at a later time or ++ * issue a reset. ++ * ++ * Timeouts, and therefore aborted commands, will be highly unlikely ++ * and handling them cleanly in this situation would make the common ++ * case of noresets less efficient, and would pollute our code. So, ++ * we fail. ++ */ ++ ++ if (hostdata->connected) { ++ local_irq_restore(flags); ++ ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO); ++ return SCSI_ABORT_SNOOZE; ++ } ++ ++ /* ++ * Case 4: If the command is currently disconnected from the bus, and ++ * there are no connected commands, we reconnect the I_T_L or ++ * I_T_L_Q nexus associated with it, go into message out, and send ++ * an abort message. ++ * ++ * This case is especially ugly. In order to reestablish the nexus, we ++ * need to call NCR5380_select(). The easiest way to implement this ++ * function was to abort if the bus was busy, and let the interrupt ++ * handler triggered on the SEL for reselect take care of lost arbitrations ++ * where necessary, meaning interrupts need to be enabled. ++ * ++ * When interrupts are enabled, the queues may change - so we ++ * can't remove it from the disconnected queue before selecting it ++ * because that could cause a failure in hashing the nexus if that ++ * device reselected. ++ * ++ * Since the queues may change, we can't use the pointers from when we ++ * first locate it. ++ * ++ * So, we must first locate the command, and if NCR5380_select() ++ * succeeds, then issue the abort, relocate the command and remove ++ * it from the disconnected queue. ++ */ ++ ++ for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; ++ tmp = NEXT(tmp)) { ++ if (cmd == tmp) { ++ local_irq_restore(flags); ++ ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO); ++ ++ if (NCR5380_select(instance, cmd, (int)cmd->tag)) ++ return SCSI_ABORT_BUSY; ++ ++ ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO); ++ ++ do_abort(instance); ++ ++ local_irq_save(flags); ++ for (prev = (Scsi_Cmnd **)&(hostdata->disconnected_queue), ++ tmp = (Scsi_Cmnd *)hostdata->disconnected_queue; ++ tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) { ++ if (cmd == tmp) { ++ REMOVE(5, *prev, tmp, NEXT(tmp)); ++ *prev = NEXT(tmp); ++ NEXT(tmp) = NULL; ++ tmp->result = DID_ABORT << 16; ++ /* We must unlock the tag/LUN immediately here, since the ++ * target goes to BUS FREE and doesn't send us another ++ * message (COMMAND_COMPLETE or the like) ++ */ + #ifdef SUPPORT_TAGS +- cmd_free_tag( tmp ); ++ cmd_free_tag(tmp); + #else +- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); ++ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); + #endif +- local_irq_restore(flags); +- tmp->scsi_done(tmp); +- falcon_release_lock_if_possible( hostdata ); +- return SCSI_ABORT_SUCCESS; ++ local_irq_restore(flags); ++ tmp->scsi_done(tmp); ++ falcon_release_lock_if_possible(hostdata); ++ return SCSI_ABORT_SUCCESS; ++ } ++ } + } + } + +-/* +- * Case 5 : If we reached this point, the command was not found in any of +- * the queues. +- * +- * We probably reached this point because of an unlikely race condition +- * between the command completing successfully and the abortion code, +- * so we won't panic, but we will notify the user in case something really +- * broke. +- */ ++ /* ++ * Case 5 : If we reached this point, the command was not found in any of ++ * the queues. ++ * ++ * We probably reached this point because of an unlikely race condition ++ * between the command completing successfully and the abortion code, ++ * so we won't panic, but we will notify the user in case something really ++ * broke. ++ */ + +- local_irq_restore(flags); +- printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n" +- KERN_INFO " before abortion\n", HOSTNO); ++ local_irq_restore(flags); ++ printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n" ++ KERN_INFO " before abortion\n", HOSTNO); + +-/* Maybe it is sufficient just to release the ST-DMA lock... (if +- * possible at all) At least, we should check if the lock could be +- * released after the abort, in case it is kept due to some bug. +- */ +- falcon_release_lock_if_possible( hostdata ); ++ /* Maybe it is sufficient just to release the ST-DMA lock... (if ++ * possible at all) At least, we should check if the lock could be ++ * released after the abort, in case it is kept due to some bug. ++ */ ++ falcon_release_lock_if_possible(hostdata); + +- return SCSI_ABORT_NOT_RUNNING; ++ return SCSI_ABORT_NOT_RUNNING; + } + + +-/* ++/* + * Function : int NCR5380_reset (Scsi_Cmnd *cmd) +- * ++ * + * Purpose : reset the SCSI bus. + * + * Returns : SCSI_RESET_WAKEUP + * +- */ ++ */ + +-static int NCR5380_bus_reset( Scsi_Cmnd *cmd) ++static int NCR5380_bus_reset(Scsi_Cmnd *cmd) + { +- SETUP_HOSTDATA(cmd->device->host); +- int i; +- unsigned long flags; ++ SETUP_HOSTDATA(cmd->device->host); ++ int i; ++ unsigned long flags; + #if 1 +- Scsi_Cmnd *connected, *disconnected_queue; ++ Scsi_Cmnd *connected, *disconnected_queue; + #endif + +- if (!IS_A_TT() && !falcon_got_lock) +- printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n", +- H_NO(cmd) ); +- +- NCR5380_print_status (cmd->device->host); +- +- /* get in phase */ +- NCR5380_write( TARGET_COMMAND_REG, +- PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) )); +- /* assert RST */ +- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST ); +- udelay (40); +- /* reset NCR registers */ +- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); +- NCR5380_write( MODE_REG, MR_BASE ); +- NCR5380_write( TARGET_COMMAND_REG, 0 ); +- NCR5380_write( SELECT_ENABLE_REG, 0 ); +- /* ++roman: reset interrupt condition! otherwise no interrupts don't get +- * through anymore ... */ +- (void)NCR5380_read( RESET_PARITY_INTERRUPT_REG ); +- +-#if 1 /* XXX Should now be done by midlevel code, but it's broken XXX */ +- /* XXX see below XXX */ +- +- /* MSch: old-style reset: actually abort all command processing here */ +- +- /* After the reset, there are no more connected or disconnected commands +- * and no busy units; to avoid problems with re-inserting the commands +- * into the issue_queue (via scsi_done()), the aborted commands are +- * remembered in local variables first. +- */ +- local_irq_save(flags); +- connected = (Scsi_Cmnd *)hostdata->connected; +- hostdata->connected = NULL; +- disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue; +- hostdata->disconnected_queue = NULL; ++ if (!IS_A_TT() && !falcon_got_lock) ++ printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n", ++ H_NO(cmd)); ++ ++ NCR5380_print_status(cmd->device->host); ++ ++ /* get in phase */ ++ NCR5380_write(TARGET_COMMAND_REG, ++ PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG))); ++ /* assert RST */ ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); ++ udelay(40); ++ /* reset NCR registers */ ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); ++ NCR5380_write(MODE_REG, MR_BASE); ++ NCR5380_write(TARGET_COMMAND_REG, 0); ++ NCR5380_write(SELECT_ENABLE_REG, 0); ++ /* ++roman: reset interrupt condition! otherwise no interrupts don't get ++ * through anymore ... */ ++ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); ++ ++#if 1 /* XXX Should now be done by midlevel code, but it's broken XXX */ ++ /* XXX see below XXX */ ++ ++ /* MSch: old-style reset: actually abort all command processing here */ ++ ++ /* After the reset, there are no more connected or disconnected commands ++ * and no busy units; to avoid problems with re-inserting the commands ++ * into the issue_queue (via scsi_done()), the aborted commands are ++ * remembered in local variables first. ++ */ ++ local_irq_save(flags); ++ connected = (Scsi_Cmnd *)hostdata->connected; ++ hostdata->connected = NULL; ++ disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue; ++ hostdata->disconnected_queue = NULL; + #ifdef SUPPORT_TAGS +- free_all_tags(); ++ free_all_tags(); + #endif +- for( i = 0; i < 8; ++i ) +- hostdata->busy[i] = 0; ++ for (i = 0; i < 8; ++i) ++ hostdata->busy[i] = 0; + #ifdef REAL_DMA +- hostdata->dma_len = 0; ++ hostdata->dma_len = 0; + #endif +- local_irq_restore(flags); ++ local_irq_restore(flags); + +- /* In order to tell the mid-level code which commands were aborted, +- * set the command status to DID_RESET and call scsi_done() !!! +- * This ultimately aborts processing of these commands in the mid-level. +- */ +- +- if ((cmd = connected)) { +- ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd)); +- cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16); +- cmd->scsi_done( cmd ); +- } ++ /* In order to tell the mid-level code which commands were aborted, ++ * set the command status to DID_RESET and call scsi_done() !!! ++ * This ultimately aborts processing of these commands in the mid-level. ++ */ + +- for (i = 0; (cmd = disconnected_queue); ++i) { +- disconnected_queue = NEXT(cmd); +- NEXT(cmd) = NULL; +- cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16); +- cmd->scsi_done( cmd ); +- } +- if (i > 0) +- ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i); +- +-/* The Falcon lock should be released after a reset... +- */ +-/* ++guenther: moved to atari_scsi_reset(), to prevent a race between +- * unlocking and enabling dma interrupt. +- */ +-/* falcon_release_lock_if_possible( hostdata );*/ +- +- /* since all commands have been explicitly terminated, we need to tell +- * the midlevel code that the reset was SUCCESSFUL, and there is no +- * need to 'wake up' the commands by a request_sense +- */ +- return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET; ++ if ((cmd = connected)) { ++ ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd)); ++ cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16); ++ cmd->scsi_done(cmd); ++ } ++ ++ for (i = 0; (cmd = disconnected_queue); ++i) { ++ disconnected_queue = NEXT(cmd); ++ NEXT(cmd) = NULL; ++ cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16); ++ cmd->scsi_done(cmd); ++ } ++ if (i > 0) ++ ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i); ++ ++ /* The Falcon lock should be released after a reset... ++ */ ++ /* ++guenther: moved to atari_scsi_reset(), to prevent a race between ++ * unlocking and enabling dma interrupt. ++ */ ++/* falcon_release_lock_if_possible( hostdata );*/ ++ ++ /* since all commands have been explicitly terminated, we need to tell ++ * the midlevel code that the reset was SUCCESSFUL, and there is no ++ * need to 'wake up' the commands by a request_sense ++ */ ++ return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET; + #else /* 1 */ + +- /* MSch: new-style reset handling: let the mid-level do what it can */ ++ /* MSch: new-style reset handling: let the mid-level do what it can */ ++ ++ /* ++guenther: MID-LEVEL IS STILL BROKEN. ++ * Mid-level is supposed to requeue all commands that were active on the ++ * various low-level queues. In fact it does this, but that's not enough ++ * because all these commands are subject to timeout. And if a timeout ++ * happens for any removed command, *_abort() is called but all queues ++ * are now empty. Abort then gives up the falcon lock, which is fatal, ++ * since the mid-level will queue more commands and must have the lock ++ * (it's all happening inside timer interrupt handler!!). ++ * Even worse, abort will return NOT_RUNNING for all those commands not ++ * on any queue, so they won't be retried ... ++ * ++ * Conclusion: either scsi.c disables timeout for all resetted commands ++ * immediately, or we lose! As of linux-2.0.20 it doesn't. ++ */ ++ ++ /* After the reset, there are no more connected or disconnected commands ++ * and no busy units; so clear the low-level status here to avoid ++ * conflicts when the mid-level code tries to wake up the affected ++ * commands! ++ */ ++ ++ if (hostdata->issue_queue) ++ ABRT_PRINTK("scsi%d: reset aborted issued command(s)\n", H_NO(cmd)); ++ if (hostdata->connected) ++ ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd)); ++ if (hostdata->disconnected_queue) ++ ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd)); + +- /* ++guenther: MID-LEVEL IS STILL BROKEN. +- * Mid-level is supposed to requeue all commands that were active on the +- * various low-level queues. In fact it does this, but that's not enough +- * because all these commands are subject to timeout. And if a timeout +- * happens for any removed command, *_abort() is called but all queues +- * are now empty. Abort then gives up the falcon lock, which is fatal, +- * since the mid-level will queue more commands and must have the lock +- * (it's all happening inside timer interrupt handler!!). +- * Even worse, abort will return NOT_RUNNING for all those commands not +- * on any queue, so they won't be retried ... +- * +- * Conclusion: either scsi.c disables timeout for all resetted commands +- * immediately, or we lose! As of linux-2.0.20 it doesn't. +- */ +- +- /* After the reset, there are no more connected or disconnected commands +- * and no busy units; so clear the low-level status here to avoid +- * conflicts when the mid-level code tries to wake up the affected +- * commands! +- */ +- +- if (hostdata->issue_queue) +- ABRT_PRINTK("scsi%d: reset aborted issued command(s)\n", H_NO(cmd)); +- if (hostdata->connected) +- ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd)); +- if (hostdata->disconnected_queue) +- ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd)); +- +- local_irq_save(flags); +- hostdata->issue_queue = NULL; +- hostdata->connected = NULL; +- hostdata->disconnected_queue = NULL; ++ local_irq_save(flags); ++ hostdata->issue_queue = NULL; ++ hostdata->connected = NULL; ++ hostdata->disconnected_queue = NULL; + #ifdef SUPPORT_TAGS +- free_all_tags(); ++ free_all_tags(); + #endif +- for( i = 0; i < 8; ++i ) +- hostdata->busy[i] = 0; ++ for (i = 0; i < 8; ++i) ++ hostdata->busy[i] = 0; + #ifdef REAL_DMA +- hostdata->dma_len = 0; ++ hostdata->dma_len = 0; + #endif +- local_irq_restore(flags); ++ local_irq_restore(flags); + +- /* we did no complete reset of all commands, so a wakeup is required */ +- return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET; ++ /* we did no complete reset of all commands, so a wakeup is required */ ++ return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET; + #endif /* 1 */ + } +- +-/* Local Variables: */ +-/* tab-width: 8 */ +-/* End: */ +--- linux-m68k-2.6.21.orig/drivers/scsi/atari_scsi.c ++++ linux-m68k-2.6.21/drivers/scsi/atari_scsi.c +@@ -186,38 +186,37 @@ static inline void DISABLE_IRQ(void) + /***************************** Prototypes *****************************/ + + #ifdef REAL_DMA +-static int scsi_dma_is_ignored_buserr( unsigned char dma_stat ); +-static void atari_scsi_fetch_restbytes( void ); +-static long atari_scsi_dma_residual( struct Scsi_Host *instance ); +-static int falcon_classify_cmd( Scsi_Cmnd *cmd ); +-static unsigned long atari_dma_xfer_len( unsigned long wanted_len, +- Scsi_Cmnd *cmd, int write_flag ); +-#endif +-static irqreturn_t scsi_tt_intr( int irq, void *dummy); +-static irqreturn_t scsi_falcon_intr( int irq, void *dummy); +-static void falcon_release_lock_if_possible( struct NCR5380_hostdata * +- hostdata ); +-static void falcon_get_lock( void ); ++static int scsi_dma_is_ignored_buserr(unsigned char dma_stat); ++static void atari_scsi_fetch_restbytes(void); ++static long atari_scsi_dma_residual(struct Scsi_Host *instance); ++static int falcon_classify_cmd(Scsi_Cmnd *cmd); ++static unsigned long atari_dma_xfer_len(unsigned long wanted_len, ++ Scsi_Cmnd *cmd, int write_flag); ++#endif ++static irqreturn_t scsi_tt_intr(int irq, void *dummy); ++static irqreturn_t scsi_falcon_intr(int irq, void *dummy); ++static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata); ++static void falcon_get_lock(void); + #ifdef CONFIG_ATARI_SCSI_RESET_BOOT +-static void atari_scsi_reset_boot( void ); ++static void atari_scsi_reset_boot(void); + #endif +-static unsigned char atari_scsi_tt_reg_read( unsigned char reg ); +-static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value); +-static unsigned char atari_scsi_falcon_reg_read( unsigned char reg ); +-static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value ); ++static unsigned char atari_scsi_tt_reg_read(unsigned char reg); ++static void atari_scsi_tt_reg_write(unsigned char reg, unsigned char value); ++static unsigned char atari_scsi_falcon_reg_read(unsigned char reg); ++static void atari_scsi_falcon_reg_write(unsigned char reg, unsigned char value); + + /************************* End of Prototypes **************************/ + + +-static struct Scsi_Host *atari_scsi_host = NULL; +-static unsigned char (*atari_scsi_reg_read)( unsigned char reg ); +-static void (*atari_scsi_reg_write)( unsigned char reg, unsigned char value ); ++static struct Scsi_Host *atari_scsi_host; ++static unsigned char (*atari_scsi_reg_read)(unsigned char reg); ++static void (*atari_scsi_reg_write)(unsigned char reg, unsigned char value); + + #ifdef REAL_DMA + static unsigned long atari_dma_residual, atari_dma_startaddr; + static short atari_dma_active; + /* pointer to the dribble buffer */ +-static char *atari_dma_buffer = NULL; ++static char *atari_dma_buffer; + /* precalculated physical address of the dribble buffer */ + static unsigned long atari_dma_phys_buffer; + /* != 0 tells the Falcon int handler to copy data from the dribble buffer */ +@@ -233,7 +232,7 @@ static char *atari_dma_orig_addr; + static unsigned long atari_dma_stram_mask; + #define STRAM_ADDR(a) (((a) & atari_dma_stram_mask) == 0) + /* number of bytes to cut from a transfer to handle NCR overruns */ +-static int atari_read_overruns = 0; ++static int atari_read_overruns; + #endif + + static int setup_can_queue = -1; +@@ -256,10 +255,10 @@ module_param(setup_hostid, int, 0); + + #if defined(REAL_DMA) + +-static int scsi_dma_is_ignored_buserr( unsigned char dma_stat ) ++static int scsi_dma_is_ignored_buserr(unsigned char dma_stat) + { + int i; +- unsigned long addr = SCSI_DMA_READ_P( dma_addr ), end_addr; ++ unsigned long addr = SCSI_DMA_READ_P(dma_addr), end_addr; + + if (dma_stat & 0x01) { + +@@ -267,15 +266,14 @@ static int scsi_dma_is_ignored_buserr( u + * physical memory chunk (DMA prefetch!), but that doesn't hurt. + * Check for this case: + */ +- +- for( i = 0; i < m68k_num_memory; ++i ) { +- end_addr = m68k_memory[i].addr + +- m68k_memory[i].size; ++ ++ for (i = 0; i < m68k_num_memory; ++i) { ++ end_addr = m68k_memory[i].addr + m68k_memory[i].size; + if (end_addr <= addr && addr <= end_addr + 4) +- return( 1 ); ++ return 1; + } + } +- return( 0 ); ++ return 0; + } + + +@@ -284,28 +282,27 @@ static int scsi_dma_is_ignored_buserr( u + * end-of-DMA, both SCSI ints are triggered simultaneously, so the NCR int has + * to clear the DMA int pending bit before it allows other level 6 interrupts. + */ +-static void scsi_dma_buserr (int irq, void *dummy) ++static void scsi_dma_buserr(int irq, void *dummy) + { +- unsigned char dma_stat = tt_scsi_dma.dma_ctrl; ++ unsigned char dma_stat = tt_scsi_dma.dma_ctrl; + + /* Don't do anything if a NCR interrupt is pending. Probably it's just + * masked... */ +- if (atari_irq_pending( IRQ_TT_MFP_SCSI )) ++ if (atari_irq_pending(IRQ_TT_MFP_SCSI)) + return; +- ++ + printk("Bad SCSI DMA interrupt! dma_addr=0x%08lx dma_stat=%02x dma_cnt=%08lx\n", + SCSI_DMA_READ_P(dma_addr), dma_stat, SCSI_DMA_READ_P(dma_cnt)); + if (dma_stat & 0x80) { +- if (!scsi_dma_is_ignored_buserr( dma_stat )) +- printk( "SCSI DMA bus error -- bad DMA programming!\n" ); +- } +- else { ++ if (!scsi_dma_is_ignored_buserr(dma_stat)) ++ printk("SCSI DMA bus error -- bad DMA programming!\n"); ++ } else { + /* Under normal circumstances we never should get to this point, + * since both interrupts are triggered simultaneously and the 5380 + * int has higher priority. When this irq is handled, that DMA + * interrupt is cleared. So a warning message is printed here. + */ +- printk( "SCSI DMA intr ?? -- this shouldn't happen!\n" ); ++ printk("SCSI DMA intr ?? -- this shouldn't happen!\n"); + } + } + #endif +@@ -313,7 +310,7 @@ static void scsi_dma_buserr (int irq, vo + #endif + + +-static irqreturn_t scsi_tt_intr (int irq, void *dummy) ++static irqreturn_t scsi_tt_intr(int irq, void *dummy) + { + #ifdef REAL_DMA + int dma_stat; +@@ -327,7 +324,7 @@ static irqreturn_t scsi_tt_intr (int irq + * is that a bus error occurred... + */ + if (dma_stat & 0x80) { +- if (!scsi_dma_is_ignored_buserr( dma_stat )) { ++ if (!scsi_dma_is_ignored_buserr(dma_stat)) { + printk(KERN_ERR "SCSI DMA caused bus error near 0x%08lx\n", + SCSI_DMA_READ_P(dma_addr)); + printk(KERN_CRIT "SCSI DMA bus error -- bad DMA programming!"); +@@ -344,8 +341,7 @@ static irqreturn_t scsi_tt_intr (int irq + * data reg! + */ + if ((dma_stat & 0x02) && !(dma_stat & 0x40)) { +- atari_dma_residual = HOSTDATA_DMALEN - (SCSI_DMA_READ_P( dma_addr ) - +- atari_dma_startaddr); ++ atari_dma_residual = HOSTDATA_DMALEN - (SCSI_DMA_READ_P(dma_addr) - atari_dma_startaddr); + + DMA_PRINTK("SCSI DMA: There are %ld residual bytes.\n", + atari_dma_residual); +@@ -353,28 +349,30 @@ static irqreturn_t scsi_tt_intr (int irq + if ((signed int)atari_dma_residual < 0) + atari_dma_residual = 0; + if ((dma_stat & 1) == 0) { +- /* After read operations, we maybe have to +- transport some rest bytes */ ++ /* ++ * After read operations, we maybe have to ++ * transport some rest bytes ++ */ + atari_scsi_fetch_restbytes(); +- } +- else { +- /* There seems to be a nasty bug in some SCSI-DMA/NCR +- combinations: If a target disconnects while a write +- operation is going on, the address register of the +- DMA may be a few bytes farer than it actually read. +- This is probably due to DMA prefetching and a delay +- between DMA and NCR. Experiments showed that the +- dma_addr is 9 bytes to high, but this could vary. +- The problem is, that the residual is thus calculated +- wrong and the next transfer will start behind where +- it should. So we round up the residual to the next +- multiple of a sector size, if it isn't already a +- multiple and the originally expected transfer size +- was. The latter condition is there to ensure that +- the correction is taken only for "real" data +- transfers and not for, e.g., the parameters of some +- other command. These shouldn't disconnect anyway. +- */ ++ } else { ++ /* ++ * There seems to be a nasty bug in some SCSI-DMA/NCR ++ * combinations: If a target disconnects while a write ++ * operation is going on, the address register of the ++ * DMA may be a few bytes farer than it actually read. ++ * This is probably due to DMA prefetching and a delay ++ * between DMA and NCR. Experiments showed that the ++ * dma_addr is 9 bytes to high, but this could vary. ++ * The problem is, that the residual is thus calculated ++ * wrong and the next transfer will start behind where ++ * it should. So we round up the residual to the next ++ * multiple of a sector size, if it isn't already a ++ * multiple and the originally expected transfer size ++ * was. The latter condition is there to ensure that ++ * the correction is taken only for "real" data ++ * transfers and not for, e.g., the parameters of some ++ * other command. These shouldn't disconnect anyway. ++ */ + if (atari_dma_residual & 0x1ff) { + DMA_PRINTK("SCSI DMA: DMA bug corrected, " + "difference %ld bytes\n", +@@ -394,18 +392,18 @@ static irqreturn_t scsi_tt_intr (int irq + } + + #endif /* REAL_DMA */ +- ++ + NCR5380_intr(0, 0); + + #if 0 + /* To be sure the int is not masked */ +- atari_enable_irq( IRQ_TT_MFP_SCSI ); ++ atari_enable_irq(IRQ_TT_MFP_SCSI); + #endif + return IRQ_HANDLED; + } + + +-static irqreturn_t scsi_falcon_intr (int irq, void *dummy) ++static irqreturn_t scsi_falcon_intr(int irq, void *dummy) + { + #ifdef REAL_DMA + int dma_stat; +@@ -430,7 +428,7 @@ static irqreturn_t scsi_falcon_intr (int + * bytes are stuck in the ST-DMA fifo (there's no way to reach them!) + */ + if (atari_dma_active && (dma_stat & 0x02)) { +- unsigned long transferred; ++ unsigned long transferred; + + transferred = SCSI_DMA_GETADR() - atari_dma_startaddr; + /* The ST-DMA address is incremented in 2-byte steps, but the +@@ -445,8 +443,7 @@ static irqreturn_t scsi_falcon_intr (int + atari_dma_residual = HOSTDATA_DMALEN - transferred; + DMA_PRINTK("SCSI DMA: There are %ld residual bytes.\n", + atari_dma_residual); +- } +- else ++ } else + atari_dma_residual = 0; + atari_dma_active = 0; + +@@ -467,7 +464,7 @@ static irqreturn_t scsi_falcon_intr (int + + + #ifdef REAL_DMA +-static void atari_scsi_fetch_restbytes( void ) ++static void atari_scsi_fetch_restbytes(void) + { + int nr; + char *src, *dst; +@@ -505,19 +502,17 @@ static int falcon_dont_release = 0; + * again (but others waiting longer more probably will win). + */ + +-static void +-falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata ) ++static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata) + { + unsigned long flags; +- +- if (IS_A_TT()) return; +- ++ ++ if (IS_A_TT()) ++ return; ++ + local_irq_save(flags); + +- if (falcon_got_lock && +- !hostdata->disconnected_queue && +- !hostdata->issue_queue && +- !hostdata->connected) { ++ if (falcon_got_lock && !hostdata->disconnected_queue && ++ !hostdata->issue_queue && !hostdata->connected) { + + if (falcon_dont_release) { + #if 0 +@@ -528,7 +523,7 @@ falcon_release_lock_if_possible( struct + } + falcon_got_lock = 0; + stdma_release(); +- wake_up( &falcon_fairness_wait ); ++ wake_up(&falcon_fairness_wait); + } + + local_irq_restore(flags); +@@ -549,31 +544,31 @@ falcon_release_lock_if_possible( struct + * Complicated, complicated.... Sigh... + */ + +-static void falcon_get_lock( void ) ++static void falcon_get_lock(void) + { + unsigned long flags; + +- if (IS_A_TT()) return; ++ if (IS_A_TT()) ++ return; + + local_irq_save(flags); + + while (!in_irq() && falcon_got_lock && stdma_others_waiting()) +- sleep_on( &falcon_fairness_wait ); ++ sleep_on(&falcon_fairness_wait); + + while (!falcon_got_lock) { + if (in_irq()) +- panic( "Falcon SCSI hasn't ST-DMA lock in interrupt" ); ++ panic("Falcon SCSI hasn't ST-DMA lock in interrupt"); + if (!falcon_trying_lock) { + falcon_trying_lock = 1; + stdma_lock(scsi_falcon_intr, NULL); + falcon_got_lock = 1; + falcon_trying_lock = 0; +- wake_up( &falcon_try_wait ); +- } +- else { +- sleep_on( &falcon_try_wait ); ++ wake_up(&falcon_try_wait); ++ } else { ++ sleep_on(&falcon_try_wait); + } +- } ++ } + + local_irq_restore(flags); + if (!falcon_got_lock) +@@ -587,18 +582,18 @@ static void falcon_get_lock( void ) + */ + + #if 0 +-int atari_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) ++int atari_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) + { + /* falcon_get_lock(); + * ++guenther: moved to NCR5380_queue_command() to prevent + * race condition, see there for an explanation. + */ +- return( NCR5380_queue_command( cmd, done ) ); ++ return NCR5380_queue_command(cmd, done); + } + #endif + + +-int atari_scsi_detect (struct scsi_host_template *host) ++int atari_scsi_detect(struct scsi_host_template *host) + { + static int called = 0; + struct Scsi_Host *instance; +@@ -606,7 +601,7 @@ int atari_scsi_detect (struct scsi_host_ + if (!MACH_IS_ATARI || + (!ATARIHW_PRESENT(ST_SCSI) && !ATARIHW_PRESENT(TT_SCSI)) || + called) +- return( 0 ); ++ return 0; + + host->proc_name = "Atari"; + +@@ -655,32 +650,33 @@ int atari_scsi_detect (struct scsi_host_ + !ATARIHW_PRESENT(EXTD_DMA) && m68k_num_memory > 1) { + atari_dma_buffer = atari_stram_alloc(STRAM_BUFFER_SIZE, "SCSI"); + if (!atari_dma_buffer) { +- printk( KERN_ERR "atari_scsi_detect: can't allocate ST-RAM " +- "double buffer\n" ); +- return( 0 ); ++ printk(KERN_ERR "atari_scsi_detect: can't allocate ST-RAM " ++ "double buffer\n"); ++ return 0; + } +- atari_dma_phys_buffer = virt_to_phys( atari_dma_buffer ); ++ atari_dma_phys_buffer = virt_to_phys(atari_dma_buffer); + atari_dma_orig_addr = 0; + } + #endif +- instance = scsi_register (host, sizeof (struct NCR5380_hostdata)); +- if(instance == NULL) +- { ++ instance = scsi_register(host, sizeof(struct NCR5380_hostdata)); ++ if (instance == NULL) { + atari_stram_free(atari_dma_buffer); + atari_dma_buffer = 0; + return 0; + } + atari_scsi_host = instance; +- /* Set irq to 0, to avoid that the mid-level code disables our interrupt +- * during queue_command calls. This is completely unnecessary, and even +- * worse causes bad problems on the Falcon, where the int is shared with +- * IDE and floppy! */ ++ /* ++ * Set irq to 0, to avoid that the mid-level code disables our interrupt ++ * during queue_command calls. This is completely unnecessary, and even ++ * worse causes bad problems on the Falcon, where the int is shared with ++ * IDE and floppy! ++ */ + instance->irq = 0; + + #ifdef CONFIG_ATARI_SCSI_RESET_BOOT + atari_scsi_reset_boot(); + #endif +- NCR5380_init (instance, 0); ++ NCR5380_init(instance, 0); + + if (IS_A_TT()) { + +@@ -727,11 +723,10 @@ int atari_scsi_detect (struct scsi_host_ + * the rest data bug is fixed, this can be lowered to 1. + */ + atari_read_overruns = 4; +- } ++ } + #endif /*REAL_DMA*/ +- } +- else { /* ! IS_A_TT */ +- ++ } else { /* ! IS_A_TT */ ++ + /* Nothing to do for the interrupt: the ST-DMA is initialized + * already by atari_init_INTS() + */ +@@ -756,19 +751,19 @@ int atari_scsi_detect (struct scsi_host_ + setup_use_tagged_queuing ? "yes" : "no", + #endif + instance->hostt->this_id ); +- NCR5380_print_options (instance); +- printk ("\n"); ++ NCR5380_print_options(instance); ++ printk("\n"); + + called = 1; +- return( 1 ); ++ return 1; + } + +-int atari_scsi_release (struct Scsi_Host *sh) ++int atari_scsi_release(struct Scsi_Host *sh) + { + if (IS_A_TT()) + free_irq(IRQ_TT_MFP_SCSI, scsi_tt_intr); + if (atari_dma_buffer) +- atari_stram_free (atari_dma_buffer); ++ atari_stram_free(atari_dma_buffer); + return 1; + } + +@@ -779,9 +774,9 @@ void __init atari_scsi_setup(char *str, + * Defaults depend on TT or Falcon, hostid determined at run time. + * Negative values mean don't change. + */ +- ++ + if (ints[0] < 1) { +- printk( "atari_scsi_setup: no arguments!\n" ); ++ printk("atari_scsi_setup: no arguments!\n"); + return; + } + +@@ -807,7 +802,7 @@ void __init atari_scsi_setup(char *str, + if (ints[4] >= 0 && ints[4] <= 7) + setup_hostid = ints[4]; + else if (ints[4] > 7) +- printk( "atari_scsi_setup: invalid host ID %d !\n", ints[4] ); ++ printk("atari_scsi_setup: invalid host ID %d !\n", ints[4]); + } + #ifdef SUPPORT_TAGS + if (ints[0] >= 5) { +@@ -819,7 +814,7 @@ void __init atari_scsi_setup(char *str, + + int atari_scsi_bus_reset(Scsi_Cmnd *cmd) + { +- int rv; ++ int rv; + struct NCR5380_hostdata *hostdata = + (struct NCR5380_hostdata *)cmd->device->host->hostdata; + +@@ -829,13 +824,12 @@ int atari_scsi_bus_reset(Scsi_Cmnd *cmd) + */ + /* And abort a maybe active DMA transfer */ + if (IS_A_TT()) { +- atari_turnoff_irq( IRQ_TT_MFP_SCSI ); ++ atari_turnoff_irq(IRQ_TT_MFP_SCSI); + #ifdef REAL_DMA + tt_scsi_dma.dma_ctrl = 0; + #endif /* REAL_DMA */ +- } +- else { +- atari_turnoff_irq( IRQ_MFP_FSCSI ); ++ } else { ++ atari_turnoff_irq(IRQ_MFP_FSCSI); + #ifdef REAL_DMA + st_dma.dma_mode_status = 0x90; + atari_dma_active = 0; +@@ -847,52 +841,51 @@ int atari_scsi_bus_reset(Scsi_Cmnd *cmd) + + /* Re-enable ints */ + if (IS_A_TT()) { +- atari_turnon_irq( IRQ_TT_MFP_SCSI ); +- } +- else { +- atari_turnon_irq( IRQ_MFP_FSCSI ); ++ atari_turnon_irq(IRQ_TT_MFP_SCSI); ++ } else { ++ atari_turnon_irq(IRQ_MFP_FSCSI); + } + if ((rv & SCSI_RESET_ACTION) == SCSI_RESET_SUCCESS) + falcon_release_lock_if_possible(hostdata); + +- return( rv ); ++ return rv; + } + +- ++ + #ifdef CONFIG_ATARI_SCSI_RESET_BOOT + static void __init atari_scsi_reset_boot(void) + { + unsigned long end; +- ++ + /* + * Do a SCSI reset to clean up the bus during initialization. No messing + * with the queues, interrupts, or locks necessary here. + */ + +- printk( "Atari SCSI: resetting the SCSI bus..." ); ++ printk("Atari SCSI: resetting the SCSI bus..."); + + /* get in phase */ +- NCR5380_write( TARGET_COMMAND_REG, +- PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) )); ++ NCR5380_write(TARGET_COMMAND_REG, ++ PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG))); + + /* assert RST */ +- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST ); ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); + /* The min. reset hold time is 25us, so 40us should be enough */ +- udelay( 50 ); ++ udelay(50); + /* reset RST and interrupt */ +- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); +- NCR5380_read( RESET_PARITY_INTERRUPT_REG ); ++ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); ++ NCR5380_read(RESET_PARITY_INTERRUPT_REG); + + end = jiffies + AFTER_RESET_DELAY; + while (time_before(jiffies, end)) + barrier(); + +- printk( " done\n" ); ++ printk(" done\n"); + } + #endif + + +-const char * atari_scsi_info (struct Scsi_Host *host) ++const char *atari_scsi_info(struct Scsi_Host *host) + { + /* atari_scsi_detect() is verbose enough... */ + static const char string[] = "Atari native SCSI"; +@@ -902,10 +895,10 @@ const char * atari_scsi_info (struct Scs + + #if defined(REAL_DMA) + +-unsigned long atari_scsi_dma_setup( struct Scsi_Host *instance, void *data, +- unsigned long count, int dir ) ++unsigned long atari_scsi_dma_setup(struct Scsi_Host *instance, void *data, ++ unsigned long count, int dir) + { +- unsigned long addr = virt_to_phys( data ); ++ unsigned long addr = virt_to_phys(data); + + DMA_PRINTK("scsi%d: setting up dma, data = %p, phys = %lx, count = %ld, " + "dir = %d\n", instance->host_no, data, addr, count, dir); +@@ -917,38 +910,37 @@ unsigned long atari_scsi_dma_setup( stru + * wanted address. + */ + if (dir) +- memcpy( atari_dma_buffer, data, count ); ++ memcpy(atari_dma_buffer, data, count); + else + atari_dma_orig_addr = data; + addr = atari_dma_phys_buffer; + } +- ++ + atari_dma_startaddr = addr; /* Needed for calculating residual later. */ +- ++ + /* Cache cleanup stuff: On writes, push any dirty cache out before sending + * it to the peripheral. (Must be done before DMA setup, since at least + * the ST-DMA begins to fill internal buffers right after setup. For + * reads, invalidate any cache, may be altered after DMA without CPU + * knowledge. +- * ++ * + * ++roman: For the Medusa, there's no need at all for that cache stuff, + * because the hardware does bus snooping (fine!). + */ +- dma_cache_maintenance( addr, count, dir ); ++ dma_cache_maintenance(addr, count, dir); + + if (count == 0) + printk(KERN_NOTICE "SCSI warning: DMA programmed for 0 bytes !\n"); + + if (IS_A_TT()) { + tt_scsi_dma.dma_ctrl = dir; +- SCSI_DMA_WRITE_P( dma_addr, addr ); +- SCSI_DMA_WRITE_P( dma_cnt, count ); ++ SCSI_DMA_WRITE_P(dma_addr, addr); ++ SCSI_DMA_WRITE_P(dma_cnt, count); + tt_scsi_dma.dma_ctrl = dir | 2; +- } +- else { /* ! IS_A_TT */ +- ++ } else { /* ! IS_A_TT */ ++ + /* set address */ +- SCSI_DMA_SETADR( addr ); ++ SCSI_DMA_SETADR(addr); + + /* toggle direction bit to clear FIFO and set DMA direction */ + dir <<= 8; +@@ -966,13 +958,13 @@ unsigned long atari_scsi_dma_setup( stru + atari_dma_active = 1; + } + +- return( count ); ++ return count; + } + + +-static long atari_scsi_dma_residual( struct Scsi_Host *instance ) ++static long atari_scsi_dma_residual(struct Scsi_Host *instance) + { +- return( atari_dma_residual ); ++ return atari_dma_residual; + } + + +@@ -980,13 +972,13 @@ static long atari_scsi_dma_residual( str + #define CMD_SURELY_BYTE_MODE 1 + #define CMD_MODE_UNKNOWN 2 + +-static int falcon_classify_cmd( Scsi_Cmnd *cmd ) ++static int falcon_classify_cmd(Scsi_Cmnd *cmd) + { + unsigned char opcode = cmd->cmnd[0]; +- ++ + if (opcode == READ_DEFECT_DATA || opcode == READ_LONG || +- opcode == READ_BUFFER) +- return( CMD_SURELY_BYTE_MODE ); ++ opcode == READ_BUFFER) ++ return CMD_SURELY_BYTE_MODE; + else if (opcode == READ_6 || opcode == READ_10 || + opcode == 0xa8 /* READ_12 */ || opcode == READ_REVERSE || + opcode == RECOVER_BUFFERED_DATA) { +@@ -994,12 +986,11 @@ static int falcon_classify_cmd( Scsi_Cmn + * needed here: The transfer is block-mode only if the 'fixed' bit is + * set! */ + if (cmd->device->type == TYPE_TAPE && !(cmd->cmnd[1] & 1)) +- return( CMD_SURELY_BYTE_MODE ); ++ return CMD_SURELY_BYTE_MODE; + else +- return( CMD_SURELY_BLOCK_MODE ); +- } +- else +- return( CMD_MODE_UNKNOWN ); ++ return CMD_SURELY_BLOCK_MODE; ++ } else ++ return CMD_MODE_UNKNOWN; + } + + +@@ -1012,19 +1003,18 @@ static int falcon_classify_cmd( Scsi_Cmn + * the overrun problem, so this question is academic :-) + */ + +-static unsigned long atari_dma_xfer_len( unsigned long wanted_len, +- Scsi_Cmnd *cmd, +- int write_flag ) ++static unsigned long atari_dma_xfer_len(unsigned long wanted_len, ++ Scsi_Cmnd *cmd, int write_flag) + { + unsigned long possible_len, limit; + #ifndef CONFIG_TT_DMA_EMUL + if (MACH_IS_HADES) + /* Hades has no SCSI DMA at all :-( Always force use of PIO */ +- return( 0 ); +-#endif ++ return 0; ++#endif + if (IS_A_TT()) + /* TT SCSI DMA can transfer arbitrary #bytes */ +- return( wanted_len ); ++ return wanted_len; + + /* ST DMA chip is stupid -- only multiples of 512 bytes! (and max. + * 255*512 bytes, but this should be enough) +@@ -1060,8 +1050,7 @@ static unsigned long atari_dma_xfer_len( + * this). + */ + possible_len = wanted_len; +- } +- else { ++ } else { + /* Read operations: if the wanted transfer length is not a multiple of + * 512, we cannot use DMA, since the ST-DMA cannot split transfers + * (no interrupt on DMA finished!) +@@ -1071,15 +1060,15 @@ static unsigned long atari_dma_xfer_len( + else { + /* Now classify the command (see above) and decide whether it is + * allowed to do DMA at all */ +- switch( falcon_classify_cmd( cmd )) { +- case CMD_SURELY_BLOCK_MODE: ++ switch (falcon_classify_cmd(cmd)) { ++ case CMD_SURELY_BLOCK_MODE: + possible_len = wanted_len; + break; +- case CMD_SURELY_BYTE_MODE: ++ case CMD_SURELY_BYTE_MODE: + possible_len = 0; /* DMA prohibited */ + break; +- case CMD_MODE_UNKNOWN: +- default: ++ case CMD_MODE_UNKNOWN: ++ default: + /* For unknown commands assume block transfers if the transfer + * size/allocation length is >= 1024 */ + possible_len = (wanted_len < 1024) ? 0 : wanted_len; +@@ -1087,9 +1076,9 @@ static unsigned long atari_dma_xfer_len( + } + } + } +- ++ + /* Last step: apply the hard limit on DMA transfers */ +- limit = (atari_dma_buffer && !STRAM_ADDR( virt_to_phys(cmd->SCp.ptr) )) ? ++ limit = (atari_dma_buffer && !STRAM_ADDR(virt_to_phys(cmd->SCp.ptr))) ? + STRAM_BUFFER_SIZE : 255*512; + if (possible_len > limit) + possible_len = limit; +@@ -1098,7 +1087,7 @@ static unsigned long atari_dma_xfer_len( + DMA_PRINTK("Sorry, must cut DMA transfer size to %ld bytes " + "instead of %ld\n", possible_len, wanted_len); + +- return( possible_len ); ++ return possible_len; + } + + +@@ -1112,23 +1101,23 @@ static unsigned long atari_dma_xfer_len( + * NCR5380_write call these functions via function pointers. + */ + +-static unsigned char atari_scsi_tt_reg_read( unsigned char reg ) ++static unsigned char atari_scsi_tt_reg_read(unsigned char reg) + { +- return( tt_scsi_regp[reg * 2] ); ++ return tt_scsi_regp[reg * 2]; + } + +-static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value ) ++static void atari_scsi_tt_reg_write(unsigned char reg, unsigned char value) + { + tt_scsi_regp[reg * 2] = value; + } + +-static unsigned char atari_scsi_falcon_reg_read( unsigned char reg ) ++static unsigned char atari_scsi_falcon_reg_read(unsigned char reg) + { + dma_wd.dma_mode_status= (u_short)(0x88 + reg); +- return( (u_char)dma_wd.fdc_acces_seccount ); ++ return (u_char)dma_wd.fdc_acces_seccount; + } + +-static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value ) ++static void atari_scsi_falcon_reg_write(unsigned char reg, unsigned char value) + { + dma_wd.dma_mode_status = (u_short)(0x88 + reg); + dma_wd.fdc_acces_seccount = (u_short)value; diff --git a/debian/patches/bugfix/m68k/atari_NCR5380-work.diff b/debian/patches/bugfix/m68k/atari_NCR5380-work.diff new file mode 100644 index 000000000000..d49bdfdcb786 --- /dev/null +++ b/debian/patches/bugfix/m68k/atari_NCR5380-work.diff @@ -0,0 +1,31 @@ +Cc: James E.J. Bottomley <James.Bottomley@SteelEye.com>, + linux-scsi@vger.kernel.org +Subject: [PATCH] m68k: Atari SCSI workqueue updates + +Workqueue updates for the Atari SCSI driver + +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + drivers/scsi/atari_NCR5380.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- linux-m68k-2.6.21.orig/drivers/scsi/atari_NCR5380.c ++++ linux-m68k-2.6.21/drivers/scsi/atari_NCR5380.c +@@ -657,7 +657,7 @@ static inline void NCR5380_print_phase(s + #include <linux/interrupt.h> + + static volatile int main_running; +-static DECLARE_WORK(NCR5380_tqueue, (void (*)(void *))NCR5380_main, NULL); ++static DECLARE_WORK(NCR5380_tqueue, NCR5380_main); + + static inline void queue_main(void) + { +@@ -1075,7 +1075,7 @@ static int NCR5380_queue_command(Scsi_Cm + * reenable them. This prevents reentrancy and kernel stack overflow. + */ + +-static void NCR5380_main(void *bl) ++static void NCR5380_main(struct work_struct *work) + { + Scsi_Cmnd *tmp, *prev; + struct Scsi_Host *instance = first_instance; diff --git a/debian/patches/bugfix/m68k/early-param.diff b/debian/patches/bugfix/m68k/early-param.diff new file mode 100644 index 000000000000..59d9f3768214 --- /dev/null +++ b/debian/patches/bugfix/m68k/early-param.diff @@ -0,0 +1,468 @@ +Subject: [PATCH] m68k: early parameter support + +From: Roman Zippel <zippel@linux-m68k.org> + +Add early parameter support and convert current users to it. + +Signed-off-by: Roman Zippel <zippel@linux-m68k.org> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + arch/m68k/amiga/config.c | 41 ++++++++++++++++++++++------------------- + arch/m68k/atari/config.c | 17 +++++++++-------- + arch/m68k/atari/debug.c | 24 ++++++++++++++---------- + arch/m68k/kernel/setup.c | 39 +-------------------------------------- + arch/m68k/mac/config.c | 8 -------- + arch/m68k/mac/debug.c | 20 ++++++++++---------- + arch/m68k/q40/config.c | 23 ++++++++++++++--------- + arch/m68k/sun3x/prom.c | 11 +++++++---- + 8 files changed, 77 insertions(+), 106 deletions(-) + +--- linux-m68k-2.6.21.orig/arch/m68k/amiga/config.c ++++ linux-m68k-2.6.21/arch/m68k/amiga/config.c +@@ -79,8 +79,6 @@ static char *amiga_models[] __initdata = + + static char amiga_model_name[13] = "Amiga "; + +-extern char m68k_debug_device[]; +- + static void amiga_sched_init(irq_handler_t handler); + /* amiga specific irq functions */ + extern void amiga_init_IRQ(void); +@@ -95,12 +93,10 @@ static unsigned int amiga_get_ss(void); + extern void amiga_mksound(unsigned int count, unsigned int ticks); + static void amiga_reset(void); + extern void amiga_init_sound(void); +-static void amiga_savekmsg_init(void); + static void amiga_mem_console_write(struct console *co, const char *b, + unsigned int count); + void amiga_serial_console_write(struct console *co, const char *s, + unsigned int count); +-static void amiga_debug_init(void); + #ifdef CONFIG_HEARTBEAT + static void amiga_heartbeat(int on); + #endif +@@ -370,7 +366,6 @@ void __init config_amiga(void) + { + int i; + +- amiga_debug_init(); + amiga_identify(); + + /* Yuk, we don't have PCI memory */ +@@ -458,17 +453,6 @@ void __init config_amiga(void) + /* initialize chipram allocator */ + amiga_chip_init(); + +- /* debugging using chipram */ +- if (!strcmp(m68k_debug_device, "mem")) { +- if (!AMIGAHW_PRESENT(CHIP_RAM)) +- printk("Warning: no chipram present for debugging\n"); +- else { +- amiga_savekmsg_init(); +- amiga_console_driver.write = amiga_mem_console_write; +- register_console(&amiga_console_driver); +- } +- } +- + /* our beloved beeper */ + if (AMIGAHW_PRESENT(AMI_AUDIO)) + amiga_init_sound(); +@@ -787,17 +771,33 @@ static void amiga_mem_console_write(stru + } + } + +-static void amiga_savekmsg_init(void) ++static int __init amiga_savekmsg_setup(char *arg) + { + static struct resource debug_res = { .name = "Debug" }; + ++ if (!MACH_IS_AMIGA || strcmp(arg, "mem")) ++ goto done; ++ ++ if (!AMIGAHW_PRESENT(CHIP_RAM)) { ++ printk("Warning: no chipram present for debugging\n"); ++ goto done; ++ } ++ + savekmsg = amiga_chip_alloc_res(SAVEKMSG_MAXMEM, &debug_res); + savekmsg->magic1 = SAVEKMSG_MAGIC1; + savekmsg->magic2 = SAVEKMSG_MAGIC2; + savekmsg->magicptr = ZTWO_PADDR(savekmsg); + savekmsg->size = 0; ++ ++ amiga_console_driver.write = amiga_mem_console_write; ++ register_console(&amiga_console_driver); ++ ++done: ++ return 0; + } + ++early_param("debug", amiga_savekmsg_setup); ++ + static void amiga_serial_putc(char c) + { + amiga_custom.serdat = (unsigned char)c | 0x100; +@@ -872,15 +872,18 @@ void amiga_serial_gets(struct console *c + } + #endif + +-static void __init amiga_debug_init(void) ++static int __init amiga_debug_setup(char *arg) + { +- if (!strcmp(m68k_debug_device, "ser" )) { ++ if (MACH_IS_AMIGA && !strcmp(arg, "ser")) { + /* no initialization required (?) */ + amiga_console_driver.write = amiga_serial_console_write; + register_console(&amiga_console_driver); + } ++ return 0; + } + ++early_param("debug", amiga_debug_setup); ++ + #ifdef CONFIG_HEARTBEAT + static void amiga_heartbeat(int on) + { +--- linux-m68k-2.6.21.orig/arch/m68k/atari/config.c ++++ linux-m68k-2.6.21/arch/m68k/atari/config.c +@@ -69,9 +69,6 @@ extern int atari_tt_hwclk (int, struct r + extern int atari_mste_set_clock_mmss (unsigned long); + extern int atari_tt_set_clock_mmss (unsigned long); + +-/* atari specific debug functions (in debug.c) */ +-extern void atari_debug_init(void); +- + + /* ++roman: This is a more elaborate test for an SCC chip, since the plain + * Medusa board generates DTACK at the SCC's standard addresses, but a SCC +@@ -137,15 +134,18 @@ int __init atari_parse_bootinfo(const st + + + /* Parse the Atari-specific switches= option. */ +-void __init atari_switches_setup(const char *str, unsigned len) ++static int __init atari_switches_setup(char *str) + { +- char switches[len+1]; ++ char switches[strlen(str) + 1]; + char *p; + int ovsc_shift; + char *args = switches; + ++ if (!MACH_IS_ATARI) ++ return 0; ++ + /* copy string to local array, strsep works destructively... */ +- strlcpy(switches, str, sizeof(switches)); ++ strcpy(switches, str); + atari_switches = 0; + + /* parse the options */ +@@ -170,8 +170,11 @@ void __init atari_switches_setup(const c + atari_switches |= ATARI_SWITCH_SND7 << ovsc_shift; + } + } ++ return 0; + } + ++early_param("switches", atari_switches_setup); ++ + + /* + * Setup the Atari configuration info +@@ -183,8 +186,6 @@ void __init config_atari(void) + + memset(&atari_hw_present, 0, sizeof(atari_hw_present)); + +- atari_debug_init(); +- + /* Change size of I/O space from 64KB to 4GB. */ + ioport_resource.end = 0xFFFFFFFF; + +--- linux-m68k-2.6.21.orig/arch/m68k/atari/debug.c ++++ linux-m68k-2.6.21/arch/m68k/atari/debug.c +@@ -19,8 +19,6 @@ + #include <asm/atarihw.h> + #include <asm/atariints.h> + +-extern char m68k_debug_device[]; +- + /* Flag that Modem1 port is already initialized and used */ + int atari_MFP_init_done; + /* Flag that Modem1 port is already initialized and used */ +@@ -305,26 +303,28 @@ void atari_init_midi_port(int cflag) + ACIA_RHTID : ACIA_RLTID); + } + +-void __init atari_debug_init(void) ++static int __init atari_debug_setup(char *arg) + { +- if (!strcmp(m68k_debug_device, "ser")) { ++ if (!MACH_IS_ATARI) ++ return 0; ++ ++ if (!strcmp(arg, "ser")) + /* defaults to ser2 for a Falcon and ser1 otherwise */ +- strcpy(m68k_debug_device, MACH_IS_FALCON ? "ser2" : "ser1"); +- } ++ arg = MACH_IS_FALCON ? "ser2" : "ser1"; + +- if (!strcmp(m68k_debug_device, "ser1")) { ++ if (!strcmp(arg, "ser1")) { + /* ST-MFP Modem1 serial port */ + atari_init_mfp_port(B9600|CS8); + atari_console_driver.write = atari_mfp_console_write; +- } else if (!strcmp(m68k_debug_device, "ser2")) { ++ } else if (!strcmp(arg, "ser2")) { + /* SCC Modem2 serial port */ + atari_init_scc_port(B9600|CS8); + atari_console_driver.write = atari_scc_console_write; +- } else if (!strcmp(m68k_debug_device, "midi")) { ++ } else if (!strcmp(arg, "midi")) { + /* MIDI port */ + atari_init_midi_port(B9600|CS8); + atari_console_driver.write = atari_midi_console_write; +- } else if (!strcmp(m68k_debug_device, "par")) { ++ } else if (!strcmp(arg, "par")) { + /* parallel printer */ + atari_turnoff_irq(IRQ_MFP_BUSY); /* avoid ints */ + sound_ym.rd_data_reg_sel = 7; /* select mixer control */ +@@ -337,4 +337,8 @@ void __init atari_debug_init(void) + } + if (atari_console_driver.write) + register_console(&atari_console_driver); ++ ++ return 0; + } ++ ++early_param("debug", atari_debug_setup); +--- linux-m68k-2.6.21.orig/arch/m68k/kernel/setup.c ++++ linux-m68k-2.6.21/arch/m68k/kernel/setup.c +@@ -71,9 +71,6 @@ static struct mem_info m68k_ramdisk; + + static char m68k_command_line[CL_SIZE]; + +-char m68k_debug_device[6] = ""; +-EXPORT_SYMBOL(m68k_debug_device); +- + void (*mach_sched_init) (irq_handler_t handler) __initdata = NULL; + /* machine dependent irq functions */ + void (*mach_init_IRQ) (void) __initdata = NULL; +@@ -215,7 +212,6 @@ void __init setup_arch(char **cmdline_p) + unsigned long endmem, startmem; + #endif + int i; +- char *p, *q; + + /* The bootinfo is located right after the kernel bss */ + m68k_parse_bootinfo((const struct bi_record *)&_end); +@@ -258,40 +254,7 @@ void __init setup_arch(char **cmdline_p) + *cmdline_p = m68k_command_line; + memcpy(boot_command_line, *cmdline_p, CL_SIZE); + +- /* Parse the command line for arch-specific options. +- * For the m68k, this is currently only "debug=xxx" to enable printing +- * certain kernel messages to some machine-specific device. +- */ +- for (p = *cmdline_p; p && *p;) { +- i = 0; +- if (!strncmp(p, "debug=", 6)) { +- strlcpy(m68k_debug_device, p+6, sizeof(m68k_debug_device)); +- q = strchr(m68k_debug_device, ' '); +- if (q) +- *q = 0; +- i = 1; +- } +-#ifdef CONFIG_ATARI +- /* This option must be parsed very early */ +- if (!strncmp(p, "switches=", 9)) { +- extern void atari_switches_setup(const char *, int); +- q = strchr(p + 9, ' '); +- atari_switches_setup(p + 9, q ? (q - (p + 9)) : strlen(p + 9)); +- i = 1; +- } +-#endif +- +- if (i) { +- /* option processed, delete it */ +- if ((q = strchr(p, ' '))) +- strcpy(p, q + 1); +- else +- *p = 0; +- } else { +- if ((p = strchr(p, ' '))) +- ++p; +- } +- } ++ parse_early_param(); + + #ifdef CONFIG_DUMMY_CONSOLE + conswitchp = &dummy_con; +--- linux-m68k-2.6.21.orig/arch/m68k/mac/config.c ++++ linux-m68k-2.6.21/arch/m68k/mac/config.c +@@ -82,10 +82,6 @@ extern void mac_mksound(unsigned int, un + + extern void nubus_sweep_video(void); + +-/* Mac specific debug functions (in debug.c) */ +-extern void mac_debug_init(void); +-extern void mac_debugging_long(int, long); +- + static void mac_get_model(char *str); + + static void mac_sched_init(irq_handler_t vector) +@@ -180,9 +176,6 @@ void __init config_mac(void) + mach_halt = mac_poweroff; + mach_power_off = mac_poweroff; + mach_max_dma_address = 0xffffffff; +-#if 0 +- mach_debug_init = mac_debug_init; +-#endif + #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE) + mach_beep = mac_mksound; + #endif +@@ -802,7 +795,6 @@ void mac_identify(void) + /* the serial ports set to "Faster" mode in MacOS. */ + + iop_preinit(); +- mac_debug_init(); + + printk(KERN_INFO "Detected Macintosh model: %d \n", model); + +--- linux-m68k-2.6.21.orig/arch/m68k/mac/debug.c ++++ linux-m68k-2.6.21/arch/m68k/mac/debug.c +@@ -27,10 +27,6 @@ + #include <asm/machw.h> + #include <asm/macints.h> + +-extern char m68k_debug_device[]; +- +-extern struct compat_bootinfo compat_boot_info; +- + extern unsigned long mac_videobase; + extern unsigned long mac_videodepth; + extern unsigned long mac_rowbytes; +@@ -360,16 +356,18 @@ void mac_init_sccb_port(int cflag) + mac_init_scc_port(cflag, 1); + } + +-void __init mac_debug_init(void) ++static int __init mac_debug_setup(char *arg) + { ++ if (!MACH_IS_MAC) ++ return 0; ++ + #ifdef DEBUG_SERIAL +- if (!strcmp(m68k_debug_device, "ser") || +- !strcmp(m68k_debug_device, "ser1")) { ++ if (!strcmp(arg, "ser") || !strcmp(arg, "ser1")) { + /* Mac modem port */ + mac_init_scc_port(B9600|CS8, 0); + mac_console_driver.write = mac_scca_console_write; + scc_port = 0; +- } else if (!strcmp(m68k_debug_device, "ser2")) { ++ } else if (!strcmp(arg, "ser2")) { + /* Mac printer port */ + mac_init_scc_port(B9600|CS8, 1); + mac_console_driver.write = mac_sccb_console_write; +@@ -377,12 +375,14 @@ void __init mac_debug_init(void) + } + #endif + #ifdef DEBUG_HEADS +- if (!strcmp(m68k_debug_device, "scn") || +- !strcmp(m68k_debug_device, "con")) { ++ if (!strcmp(arg, "scn") || !strcmp(arg, "con")) { + /* display, using head.S console routines */ + mac_console_driver.write = mac_debug_console_write; + } + #endif + if (mac_console_driver.write) + register_console(&mac_console_driver); ++ return 0; + } ++ ++early_param("debug", mac_debug_setup); +--- linux-m68k-2.6.21.orig/arch/m68k/q40/config.c ++++ linux-m68k-2.6.21/arch/m68k/q40/config.c +@@ -54,7 +54,6 @@ void q40_set_vectors(void); + + extern void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/); + +-extern char m68k_debug_device[]; + static void q40_mem_console_write(struct console *co, const char *b, + unsigned int count); + +@@ -62,6 +61,7 @@ extern int ql_ticks; + + static struct console q40_console_driver = { + .name = "debug", ++ .write = q40_mem_console_write, + .flags = CON_PRINTBUFFER, + .index = -1, + }; +@@ -85,6 +85,19 @@ static void q40_mem_console_write(struct + } + } + ++static int __init q40_debug_setup(char *arg) ++{ ++ /* useful for early debugging stages - writes kernel messages into SRAM */ ++ if (MACH_IS_Q40 && !strncmp(arg, "mem", 3)) { ++ /*printk("using NVRAM debug, q40_mem_cptr=%p\n",q40_mem_cptr);*/ ++ _cpleft = 2000 - ((long)q40_mem_cptr-0xff020000) / 4; ++ register_console(&q40_console_driver); ++ } ++ return 0; ++} ++ ++early_param("debug", q40_debug_setup); ++ + #if 0 + void printq40(char *str) + { +@@ -194,14 +207,6 @@ void __init config_q40(void) + * all physical RAM fits into the boundary - otherwise + * allocator may play costly and useless tricks */ + mach_max_dma_address = 1024*1024*1024; +- +- /* useful for early debugging stages - writes kernel messages into SRAM */ +- if (!strncmp( m68k_debug_device,"mem", 3)) { +- /*printk("using NVRAM debug, q40_mem_cptr=%p\n",q40_mem_cptr);*/ +- _cpleft = 2000 - ((long)q40_mem_cptr-0xff020000) / 4; +- q40_console_driver.write = q40_mem_console_write; +- register_console(&q40_console_driver); +- } + } + + +--- linux-m68k-2.6.21.orig/arch/m68k/sun3x/prom.c ++++ linux-m68k-2.6.21/arch/m68k/sun3x/prom.c +@@ -73,8 +73,6 @@ void sun3x_reboot(void) + (*romvec->pv_reboot)("vmlinux"); + } + +-extern char m68k_debug_device[]; +- + static void sun3x_prom_write(struct console *co, const char *s, + unsigned int count) + { +@@ -119,13 +117,18 @@ void sun3x_prom_init(void) + * XXX this is futile since we restore the vbr first - oops + */ + vectors[VEC_TRAP14] = sun3x_prom_abort; ++} + ++static int __init sun3x_debug_setup(char *arg) ++{ + /* If debug=prom was specified, start the debug console */ +- +- if (!strcmp(m68k_debug_device, "prom")) ++ if (MACH_IS_SUN3X && !strcmp(arg, "prom")) + register_console(&sun3x_debug); ++ return 0; + } + ++early_param("debug", sun3x_debug_setup); ++ + /* some prom functions to export */ + int prom_getintdefault(int node, char *property, int deflt) + { diff --git a/debian/patches/bugfix/m68k/ethernec-kill-ETHERNEC_USE_POLL.diff b/debian/patches/bugfix/m68k/ethernec-kill-ETHERNEC_USE_POLL.diff new file mode 100644 index 000000000000..763f24e83c58 --- /dev/null +++ b/debian/patches/bugfix/m68k/ethernec-kill-ETHERNEC_USE_POLL.diff @@ -0,0 +1,76 @@ +--- + drivers/net/atari_ethernec.c | 42 ------------------------------------------ + 1 file changed, 42 deletions(-) + +--- linux-m68k-2.6.21.orig/drivers/net/atari_ethernec.c ++++ linux-m68k-2.6.21/drivers/net/atari_ethernec.c +@@ -225,14 +225,6 @@ static wait_queue_head_t WaitQ; + + static struct delayed_work tqueue; + +-#ifdef ETHERNEC_USE_POLL +-static struct { +- struct work_struct poll_queue; +- struct timer_list poll_timer; +- struct net_device *dev; +-} poll_ops; +-#endif +- + static struct net_device *poll_dev = NULL; + + static void atari_ethernec_int(struct work_struct *work) +@@ -260,22 +252,6 @@ static void atari_ethernec_int(struct wo + schedule_delayed_work(&tqueue, 0); /* reduced delay from 1 */ + } + +-#ifdef ETHERNEC_USE_POLL +-static void atari_ethernec_poll_handler(unsigned long dev_addr) +-{ +- struct net_device *dev = poll_dev; +- +- if (!dev || !dev->poll_controller) +- return; +- +- if (netif_running(dev)) +- dev->poll_controller(dev); +- +- schedule_work(&poll_ops.poll_queue); +- mod_timer(&poll_ops.poll_timer, jiffies + HZ / 100); +-} +-#endif +- + static void atari_ethernec_start_poll(struct net_device *dev) + { + poll_dev = dev; +@@ -284,19 +260,6 @@ static void atari_ethernec_start_poll(st + + INIT_DELAYED_WORK(&tqueue, atari_ethernec_int); + schedule_delayed_work(&tqueue, 1); +-#ifdef ETHERNEC_USE_POLL +- if (!poll_ops.poll_queue.func || +- poll_ops.poll_queue.func == ei_interrupt) { +- if (!poll_ops.poll_queue.func) +- INIT_WORK(&poll_ops.poll_queue, ei_interrupt, dev); +- +- init_timer(&poll_ops.poll_timer); +- poll_ops.poll_timer.function = atari_ethernec_poll_handler; +- poll_ops.poll_timer.expires = jiffies + HZ / 5; +- poll_ops.poll_timer.data = (unsigned long)dev; +- add_timer(&poll_ops.poll_timer); +- } +-#endif + } + + static void atari_ethernec_stop_poll(struct net_device *dev) +@@ -305,11 +268,6 @@ static void atari_ethernec_stop_poll(str + + if (dev) + sleep_on(&WaitQ); +- +-#ifdef ETHERNEC_USE_POLL +- if (poll_ops.poll_queue.func == ei_interrupt) +- del_timer_sync(&poll_ops.poll_timer); +-#endif + } + + diff --git a/debian/patches/bugfix/m68k/ethernec-work.diff b/debian/patches/bugfix/m68k/ethernec-work.diff new file mode 100644 index 000000000000..d0a291f58c62 --- /dev/null +++ b/debian/patches/bugfix/m68k/ethernec-work.diff @@ -0,0 +1,46 @@ +Subject: [PATCH] m68k: Atari EtherNEC workqueue updates + +Workqueue updates for the Atari EtherNEC driver + +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + drivers/net/atari_ethernec.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +--- linux-m68k-2.6.21.orig/drivers/net/atari_ethernec.c ++++ linux-m68k-2.6.21/drivers/net/atari_ethernec.c +@@ -96,6 +96,7 @@ static const char version2[] = + #include <linux/netdevice.h> + #include <linux/etherdevice.h> + #include <linux/jiffies.h> ++#include <linux/workqueue.h> + + #include <asm/system.h> + #include <asm/atarihw.h> +@@ -222,7 +223,7 @@ static int use_poll; + */ + static wait_queue_head_t WaitQ; + +-static struct work_struct tqueue; ++static struct delayed_work tqueue; + + #ifdef ETHERNEC_USE_POLL + static struct { +@@ -234,7 +235,7 @@ static struct { + + static struct net_device *poll_dev = NULL; + +-static void atari_ethernec_int(unsigned long dev_addr) ++static void atari_ethernec_int(struct work_struct *work) + { + struct net_device *dev = poll_dev; + +@@ -281,7 +282,7 @@ static void atari_ethernec_start_poll(st + + init_waitqueue_head(&WaitQ); + +- INIT_WORK(&tqueue, (void (*)(void *))atari_ethernec_int, dev); ++ INIT_DELAYED_WORK(&tqueue, atari_ethernec_int); + schedule_delayed_work(&tqueue, 1); + #ifdef ETHERNEC_USE_POLL + if (!poll_ops.poll_queue.func || diff --git a/debian/patches/bugfix/m68k/falconide_intr_lock-reentrant.diff b/debian/patches/bugfix/m68k/falconide_intr_lock-reentrant.diff new file mode 100644 index 000000000000..f632f831f7f5 --- /dev/null +++ b/debian/patches/bugfix/m68k/falconide_intr_lock-reentrant.diff @@ -0,0 +1,41 @@ +Subject: [PATCH] m68k: make Atari IDE lock reentrant + +From Roman Zippel <zippel@linux-m68k.org> + +Make the Atari IDE lock reentrant, as the new request is started in the +interrupt before the last one is completely released. + +Signed-off-by: Roman Zippel <zippel@linux-m68k.org> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + include/asm-m68k/ide.h | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- linux-m68k-2.6.21.orig/include/asm-m68k/ide.h ++++ linux-m68k-2.6.21/include/asm-m68k/ide.h +@@ -117,8 +117,8 @@ static __inline__ void ide_release_lock + printk("ide_release_lock: bug\n"); + return; + } +- falconide_intr_lock = 0; +- stdma_release(); ++ if (!--falconide_intr_lock) ++ stdma_release(); + } + } + +@@ -126,12 +126,12 @@ static __inline__ void + ide_get_lock(irq_handler_t handler, void *data) + { + if (MACH_IS_ATARI) { +- if (falconide_intr_lock == 0) { ++ if (!falconide_intr_lock) { + if (in_interrupt() > 0) + panic( "Falcon IDE hasn't ST-DMA lock in interrupt" ); + stdma_lock(handler, data); +- falconide_intr_lock = 1; + } ++ falconide_intr_lock++; + } + } + #endif /* CONFIG_BLK_DEV_FALCON_IDE */ diff --git a/debian/patches/bugfix/m68k/hilkbd-warning.diff b/debian/patches/bugfix/m68k/hilkbd-warning.diff new file mode 100644 index 000000000000..caacc2c0dde8 --- /dev/null +++ b/debian/patches/bugfix/m68k/hilkbd-warning.diff @@ -0,0 +1,21 @@ +Cc: parisc-linux@parisc-linux.org +Subject: [PATCH] hilkbd: Kill compiler warning and fix comment dyslexia + +hilkbd: Kill compiler warning and fix comment dyslexia + +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + drivers/input/keyboard/hilkbd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- linux-m68k-2.6.21.orig/drivers/input/keyboard/hilkbd.c ++++ linux-m68k-2.6.21/drivers/input/keyboard/hilkbd.c +@@ -52,7 +52,7 @@ MODULE_LICENSE("GPL v2"); + + #elif defined(CONFIG_HP300) + +- #define HILBASE 0xf0428000 /* HP300 (m86k) port address */ ++ #define HILBASE 0xf0428000UL /* HP300 (m68k) port address */ + #define HIL_DATA 0x1 + #define HIL_CMD 0x3 + #define HIL_IRQ 2 diff --git a/debian/patches/bugfix/m68k/irq_lockdep.diff b/debian/patches/bugfix/m68k/irq_lockdep.diff new file mode 100644 index 000000000000..1d3542fa64c4 --- /dev/null +++ b/debian/patches/bugfix/m68k/irq_lockdep.diff @@ -0,0 +1,30 @@ +Subject: [PATCH] lockdep: Add missing disable/enable irq variant + +From: Roman Zippel <zippel@linux-m68k.org> + +Add missing disable/enable irq variant + +Signed-off-by: Roman Zippel <zippel@linux-m68k.org> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + include/linux/interrupt.h | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- linux-m68k-2.6.21.orig/include/linux/interrupt.h ++++ linux-m68k-2.6.21/include/linux/interrupt.h +@@ -185,10 +185,14 @@ static inline int disable_irq_wake(unsig + * validator need to define the methods below in their asm/irq.h + * files, under an #ifdef CONFIG_LOCKDEP section. + */ +-# ifndef CONFIG_LOCKDEP ++#ifndef CONFIG_LOCKDEP + # define disable_irq_nosync_lockdep(irq) disable_irq_nosync(irq) ++# define disable_irq_nosync_lockdep_irqsave(irq, flags) \ ++ disable_irq_nosync(irq) + # define disable_irq_lockdep(irq) disable_irq(irq) + # define enable_irq_lockdep(irq) enable_irq(irq) ++# define enable_irq_lockdep_irqrestore(irq, flags) \ ++ enable_irq(irq) + # endif + + #endif /* CONFIG_GENERIC_HARDIRQS */ diff --git a/debian/patches/bugfix/m68k/kmap_atomic-inline.diff b/debian/patches/bugfix/m68k/kmap_atomic-inline.diff new file mode 100644 index 000000000000..3f6c50f5e50b --- /dev/null +++ b/debian/patches/bugfix/m68k/kmap_atomic-inline.diff @@ -0,0 +1,30 @@ +Subject: [PATCH] Convert non-highmem kmap_atomic() to static inline function + +Convert kmap_atomic() in the non-highmem case from a macro to a static +inline function, for better type-checking and the ability to pass void +pointers instead of struct page pointers. + +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + include/linux/highmem.h | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +--- linux-m68k-2.6.21.orig/include/linux/highmem.h ++++ linux-m68k-2.6.21/include/linux/highmem.h +@@ -42,8 +42,14 @@ static inline void *kmap(struct page *pa + + #define kunmap(page) do { (void) (page); } while (0) + +-#define kmap_atomic(page, idx) \ +- ({ pagefault_disable(); page_address(page); }) ++#include <asm/kmap_types.h> ++ ++static inline void *kmap_atomic(struct page *page, enum km_type idx) ++{ ++ pagefault_disable(); ++ return page_address(page); ++} ++ + #define kunmap_atomic(addr, idx) do { pagefault_enable(); } while (0) + #define kmap_atomic_pfn(pfn, idx) kmap_atomic(pfn_to_page(pfn), (idx)) + #define kmap_atomic_to_page(ptr) virt_to_page(ptr) diff --git a/debian/patches/bugfix/m68k/m68k-53c700-scsi.diff b/debian/patches/bugfix/m68k/m68k-53c700-scsi.diff new file mode 100644 index 000000000000..29ad0e2d972a --- /dev/null +++ b/debian/patches/bugfix/m68k/m68k-53c700-scsi.diff @@ -0,0 +1,1155 @@ +From jongk@linux-m68k.org Tue Oct 31 22:46:33 2006 +Date: Tue, 31 Oct 2006 22:47:04 +0100 +From: Kars de Jong <jongk@linux-m68k.org> +To: Christoph Hellwig <hch@infradead.org> +Cc: Richard Hirst <rhirst@levanta.com>, Matthew Wilcox <matthew@wil.cx>, linux-scsi@vger.kernel.org, linux-m68k@vger.kernel.org, Geert Uytterhoeven <geert@linux-m68k.org> +Subject: [RFC PATCH] m68k: switch to 53c700 driver + +On ma, 2006-10-30 at 11:13 +0000, Christoph Hellwig wrote: +> Any updates? Honestly, I do not plan to touch the current 53c7xx/etc +> mess in the upoming request_buffer transition, and unless the m68k +> folks provide the new 53c700-based driver I'll just submit a patch to +> rip 53c7xx and users out without replacement. + +OK, here's the patch, without the m68k generic iomap changes. + +If there are no objections, I will commit it to our CVS repository so +Geert can send it upstream (with proper Signed-Off-By: headers and +everything). + +Kars. + +--- + arch/m68k/configs/amiga_defconfig | 2 + arch/m68k/configs/bvme6000_defconfig | 2 + arch/m68k/configs/mvme16x_defconfig | 2 + arch/m68k/defconfig | 2 + drivers/scsi/53c700.c | 20 +- + drivers/scsi/53c700.h | 5 + drivers/scsi/Kconfig | 26 +- + drivers/scsi/Makefile | 15 - + drivers/scsi/amiga7xx.c | 344 +++++++++++++++++++++++++---------- + drivers/scsi/amiga7xx.h | 23 -- + drivers/scsi/bvme6000.h | 24 -- + drivers/scsi/bvme6000_scsi.c | 158 ++++++++++------ + drivers/scsi/mvme16x.h | 24 -- + drivers/scsi/mvme16x_scsi.c | 183 +++++++++++++----- + 14 files changed, 525 insertions(+), 305 deletions(-) + +--- linux-m68k-2.6.21.orig/arch/m68k/configs/amiga_defconfig ++++ linux-m68k-2.6.21/arch/m68k/configs/amiga_defconfig +@@ -249,7 +249,9 @@ CONFIG_CYBERSTORMII_SCSI=y + CONFIG_BLZ2060_SCSI=y + CONFIG_BLZ1230_SCSI=y + CONFIG_FASTLANE_SCSI=y ++CONFIG_SCSI_AMIGA7XX=y + CONFIG_OKTAGON_SCSI=y ++CONFIG_SCSI_NCR53C7xx_FAST=y + + # + # Old CD-ROM drivers (not SCSI, not IDE) +--- linux-m68k-2.6.21.orig/arch/m68k/configs/bvme6000_defconfig ++++ linux-m68k-2.6.21/arch/m68k/configs/bvme6000_defconfig +@@ -185,6 +185,8 @@ CONFIG_SCSI_CONSTANTS=y + # + # CONFIG_SCSI_SATA is not set + # CONFIG_SCSI_DEBUG is not set ++CONFIG_BVME6000_SCSI=y ++CONFIG_SCSI_NCR53C7xx_FAST=y + + # + # Multi-device support (RAID and LVM) +--- linux-m68k-2.6.21.orig/arch/m68k/configs/mvme16x_defconfig ++++ linux-m68k-2.6.21/arch/m68k/configs/mvme16x_defconfig +@@ -185,6 +185,8 @@ CONFIG_SCSI_CONSTANTS=y + # + # CONFIG_SCSI_SATA is not set + # CONFIG_SCSI_DEBUG is not set ++CONFIG_MVME16x_SCSI=y ++CONFIG_SCSI_NCR53C7xx_FAST=y + + # + # Multi-device support (RAID and LVM) +--- linux-m68k-2.6.21.orig/arch/m68k/defconfig ++++ linux-m68k-2.6.21/arch/m68k/defconfig +@@ -186,7 +186,9 @@ CONFIG_GVP11_SCSI=y + # CONFIG_BLZ2060_SCSI is not set + # CONFIG_BLZ1230_SCSI is not set + # CONFIG_FASTLANE_SCSI is not set ++CONFIG_SCSI_AMIGA7XX=y + # CONFIG_OKTAGON_SCSI is not set ++CONFIG_SCSI_NCR53C7xx_FAST=y + + # + # Multi-device support (RAID and LVM) +--- linux-m68k-2.6.21.orig/drivers/scsi/53c700.c ++++ linux-m68k-2.6.21/drivers/scsi/53c700.c +@@ -661,7 +661,6 @@ NCR_700_chip_setup(struct Scsi_Host *hos + { + struct NCR_700_Host_Parameters *hostdata = + (struct NCR_700_Host_Parameters *)host->hostdata[0]; +- __u32 dcntl_extra = 0; + __u8 min_period; + __u8 min_xferp = (hostdata->chip710 ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP); + +@@ -686,13 +685,14 @@ NCR_700_chip_setup(struct Scsi_Host *hos + burst_disable = BURST_DISABLE; + break; + } +- dcntl_extra = COMPAT_700_MODE; ++ hostdata->dcntl_extra |= COMPAT_700_MODE; + +- NCR_700_writeb(dcntl_extra, host, DCNTL_REG); ++ NCR_700_writeb(hostdata->dcntl_extra, host, DCNTL_REG); + NCR_700_writeb(burst_length | hostdata->dmode_extra, + host, DMODE_710_REG); +- NCR_700_writeb(burst_disable | (hostdata->differential ? +- DIFF : 0), host, CTEST7_REG); ++ NCR_700_writeb(burst_disable | hostdata->ctest7_extra | ++ (hostdata->differential ? DIFF : 0), ++ host, CTEST7_REG); + NCR_700_writeb(BTB_TIMER_DISABLE, host, CTEST0_REG); + NCR_700_writeb(FULL_ARBITRATION | ENABLE_PARITY | PARITY + | AUTO_ATN, host, SCNTL0_REG); +@@ -727,13 +727,13 @@ NCR_700_chip_setup(struct Scsi_Host *hos + * of spec: sync divider 2, async divider 3 */ + DEBUG(("53c700: sync 2 async 3\n")); + NCR_700_writeb(SYNC_DIV_2_0, host, SBCL_REG); +- NCR_700_writeb(ASYNC_DIV_3_0 | dcntl_extra, host, DCNTL_REG); ++ NCR_700_writeb(ASYNC_DIV_3_0 | hostdata->dcntl_extra, host, DCNTL_REG); + hostdata->sync_clock = hostdata->clock/2; + } else if(hostdata->clock > 50 && hostdata->clock <= 75) { + /* sync divider 1.5, async divider 3 */ + DEBUG(("53c700: sync 1.5 async 3\n")); + NCR_700_writeb(SYNC_DIV_1_5, host, SBCL_REG); +- NCR_700_writeb(ASYNC_DIV_3_0 | dcntl_extra, host, DCNTL_REG); ++ NCR_700_writeb(ASYNC_DIV_3_0 | hostdata->dcntl_extra, host, DCNTL_REG); + hostdata->sync_clock = hostdata->clock*2; + hostdata->sync_clock /= 3; + +@@ -741,18 +741,18 @@ NCR_700_chip_setup(struct Scsi_Host *hos + /* sync divider 1, async divider 2 */ + DEBUG(("53c700: sync 1 async 2\n")); + NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG); +- NCR_700_writeb(ASYNC_DIV_2_0 | dcntl_extra, host, DCNTL_REG); ++ NCR_700_writeb(ASYNC_DIV_2_0 | hostdata->dcntl_extra, host, DCNTL_REG); + hostdata->sync_clock = hostdata->clock; + } else if(hostdata->clock > 25 && hostdata->clock <=37) { + /* sync divider 1, async divider 1.5 */ + DEBUG(("53c700: sync 1 async 1.5\n")); + NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG); +- NCR_700_writeb(ASYNC_DIV_1_5 | dcntl_extra, host, DCNTL_REG); ++ NCR_700_writeb(ASYNC_DIV_1_5 | hostdata->dcntl_extra, host, DCNTL_REG); + hostdata->sync_clock = hostdata->clock; + } else { + DEBUG(("53c700: sync 1 async 1\n")); + NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG); +- NCR_700_writeb(ASYNC_DIV_1_0 | dcntl_extra, host, DCNTL_REG); ++ NCR_700_writeb(ASYNC_DIV_1_0 | hostdata->dcntl_extra, host, DCNTL_REG); + /* sync divider 1, async divider 1 */ + hostdata->sync_clock = hostdata->clock; + } +--- linux-m68k-2.6.21.orig/drivers/scsi/53c700.h ++++ linux-m68k-2.6.21/drivers/scsi/53c700.h +@@ -177,6 +177,7 @@ struct NCR_700_command_slot { + __u8 state; + #define NCR_700_FLAG_AUTOSENSE 0x01 + __u8 flags; ++ __u8 pad1[2]; /* Needed for m68k where min alignment is 2 bytes */ + int tag; + __u32 resume_offset; + struct scsi_cmnd *cmnd; +@@ -196,6 +197,8 @@ struct NCR_700_Host_Parameters { + void __iomem *base; /* the base for the port (copied to host) */ + struct device *dev; + __u32 dmode_extra; /* adjustable bus settings */ ++ __u32 dcntl_extra; /* adjustable bus settings */ ++ __u32 ctest7_extra; /* adjustable bus settings */ + __u32 differential:1; /* if we are differential */ + #ifdef CONFIG_53C700_LE_ON_BE + /* This option is for HP only. Set it if your chip is wired for +@@ -352,6 +355,7 @@ struct NCR_700_Host_Parameters { + #define SEL_TIMEOUT_DISABLE 0x10 /* 710 only */ + #define DFP 0x08 + #define EVP 0x04 ++#define CTEST7_TT1 0x02 + #define DIFF 0x01 + #define CTEST6_REG 0x1A + #define TEMP_REG 0x1C +@@ -385,6 +389,7 @@ struct NCR_700_Host_Parameters { + #define SOFTWARE_RESET 0x01 + #define COMPAT_700_MODE 0x01 + #define SCRPTS_16BITS 0x20 ++#define EA_710 0x20 + #define ASYNC_DIV_2_0 0x00 + #define ASYNC_DIV_1_5 0x40 + #define ASYNC_DIV_1_0 0x80 +--- linux-m68k-2.6.21.orig/drivers/scsi/Kconfig ++++ linux-m68k-2.6.21/drivers/scsi/Kconfig +@@ -1000,6 +1000,11 @@ config SCSI_STEX + To compile this driver as a module, choose M here: the + module will be called stex. + ++config 53C700_BE_BUS ++ bool ++ depends on SCSI_AMIGA7XX || MVME16x_SCSI || BVME6000_SCSI ++ default y ++ + config SCSI_SYM53C8XX_2 + tristate "SYM53C8XX Version 2 SCSI support" + depends on PCI && SCSI +@@ -1620,8 +1625,9 @@ config FASTLANE_SCSI + one in the near future, say Y to this question. Otherwise, say N. + + config SCSI_AMIGA7XX +- bool "Amiga NCR53c710 SCSI support (EXPERIMENTAL)" +- depends on AMIGA && SCSI && EXPERIMENTAL && BROKEN ++ tristate "Amiga NCR53c710 SCSI support (EXPERIMENTAL)" ++ depends on AMIGA && SCSI && EXPERIMENTAL ++ select SCSI_SPI_ATTRS + help + Support for various NCR53c710-based SCSI controllers on the Amiga. + This includes: +@@ -1720,8 +1726,8 @@ config MVME147_SCSI + single-board computer. + + config MVME16x_SCSI +- bool "NCR53C710 SCSI driver for MVME16x" +- depends on MVME16x && SCSI && BROKEN ++ tristate "NCR53C710 SCSI driver for MVME16x" ++ depends on MVME16x && SCSI + select SCSI_SPI_ATTRS + help + The Motorola MVME162, 166, 167, 172 and 177 boards use the NCR53C710 +@@ -1729,22 +1735,14 @@ config MVME16x_SCSI + will want to say Y to this question. + + config BVME6000_SCSI +- bool "NCR53C710 SCSI driver for BVME6000" +- depends on BVME6000 && SCSI && BROKEN ++ tristate "NCR53C710 SCSI driver for BVME6000" ++ depends on BVME6000 && SCSI + select SCSI_SPI_ATTRS + help + The BVME4000 and BVME6000 boards from BVM Ltd use the NCR53C710 + SCSI controller chip. Almost everyone using one of these boards + will want to say Y to this question. + +-config SCSI_NCR53C7xx_FAST +- bool "allow FAST-SCSI [10MHz]" +- depends on SCSI_AMIGA7XX || MVME16x_SCSI || BVME6000_SCSI +- help +- This will enable 10MHz FAST-SCSI transfers with your host +- adapter. Some systems have problems with that speed, so it's safest +- to say N here. +- + config SUN3_SCSI + tristate "Sun3 NCR5380 SCSI" + depends on SUN3 && SCSI +--- linux-m68k-2.6.21.orig/drivers/scsi/Makefile ++++ linux-m68k-2.6.21/drivers/scsi/Makefile +@@ -37,7 +37,7 @@ obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas/ + + obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o + obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o +-obj-$(CONFIG_SCSI_AMIGA7XX) += amiga7xx.o 53c7xx.o ++obj-$(CONFIG_SCSI_AMIGA7XX) += 53c700.o amiga7xx.o + obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o + obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o + obj-$(CONFIG_GVP11_SCSI) += gvp11.o wd33c93.o +@@ -53,8 +53,8 @@ obj-$(CONFIG_ATARI_SCSI) += atari_scsi.o + obj-$(CONFIG_MAC_SCSI) += mac_scsi.o + obj-$(CONFIG_SCSI_MAC_ESP) += mac_esp.o NCR53C9x.o + obj-$(CONFIG_SUN3_SCSI) += sun3_scsi.o sun3_scsi_vme.o +-obj-$(CONFIG_MVME16x_SCSI) += mvme16x_scsi.o 53c7xx.o +-obj-$(CONFIG_BVME6000_SCSI) += bvme6000_scsi.o 53c7xx.o ++obj-$(CONFIG_MVME16x_SCSI) += 53c700.o mvme16x_scsi.o ++obj-$(CONFIG_BVME6000_SCSI) += 53c700.o bvme6000_scsi.o + obj-$(CONFIG_SCSI_SIM710) += 53c700.o sim710.o + obj-$(CONFIG_SCSI_ADVANSYS) += advansys.o + obj-$(CONFIG_SCSI_PSI240I) += psi240i.o +@@ -168,10 +168,8 @@ NCR_Q720_mod-objs := NCR_Q720.o ncr53c8x + oktagon_esp_mod-objs := oktagon_esp.o oktagon_io.o + + # Files generated that shall be removed upon make clean +-clean-files := 53c7xx_d.h 53c700_d.h \ +- 53c7xx_u.h 53c700_u.h ++clean-files := 53c700_d.h 53c700_u.h + +-$(obj)/53c7xx.o: $(obj)/53c7xx_d.h $(obj)/53c7xx_u.h + $(obj)/53c700.o $(MODVERDIR)/$(obj)/53c700.ver: $(obj)/53c700_d.h + + # If you want to play with the firmware, uncomment +@@ -179,11 +177,6 @@ $(obj)/53c700.o $(MODVERDIR)/$(obj)/53c7 + + ifdef GENERATE_FIRMWARE + +-$(obj)/53c7xx_d.h: $(src)/53c7xx.scr $(src)/script_asm.pl +- $(CPP) -traditional -DCHIP=710 - < $< | grep -v '^#' | $(PERL) -s $(src)/script_asm.pl -ncr7x0_family $@ $(@:_d.h=_u.h) +- +-$(obj)/53c7xx_u.h: $(obj)/53c7xx_d.h +- + $(obj)/53c700_d.h: $(src)/53c700.scr $(src)/script_asm.pl + $(PERL) -s $(src)/script_asm.pl -ncr7x0_family $@ $(@:_d.h=_u.h) < $< + +--- linux-m68k-2.6.21.orig/drivers/scsi/amiga7xx.c ++++ linux-m68k-2.6.21/drivers/scsi/amiga7xx.c +@@ -6,133 +6,287 @@ + * + * Written 1997 by Alan Hourihane <alanh@fairlite.demon.co.uk> + * plus modifications of the 53c7xx.c driver to support the Amiga. ++ * ++ * Rewritten to use 53c700.c by Kars de Jong <jongk@linux-m68k.org> + */ +-#include <linux/types.h> +-#include <linux/mm.h> ++ ++#include <linux/module.h> + #include <linux/blkdev.h> ++#include <linux/device.h> ++#include <linux/platform_device.h> ++#include <linux/init.h> ++#include <linux/interrupt.h> + #include <linux/zorro.h> +-#include <linux/stat.h> +- +-#include <asm/setup.h> +-#include <asm/page.h> +-#include <asm/pgtable.h> +-#include <asm/amigaints.h> + #include <asm/amigahw.h> +-#include <asm/dma.h> +-#include <asm/irq.h> +- +-#include "scsi.h" ++#include <asm/amigaints.h> + #include <scsi/scsi_host.h> +-#include "53c7xx.h" +-#include "amiga7xx.h" ++#include <scsi/scsi_device.h> ++#include <scsi/scsi_transport.h> ++#include <scsi/scsi_transport_spi.h> ++ ++#include "53c700.h" ++ ++MODULE_AUTHOR("Alan Hourihane <alanh@fairlite.demon.co.uk> / Kars de Jong <jongk@linux-m68k.org>"); ++MODULE_DESCRIPTION("Amiga NCR53C710 driver"); ++MODULE_LICENSE("GPL"); ++ ++static struct scsi_host_template amiga7xx_scsi_driver_template = { ++ .name = "A4000T builtin SCSI", ++ .proc_name = "Amiga7xx", ++ .this_id = 7, ++ .module = THIS_MODULE, ++}; ++ ++static struct platform_device *a4000t_scsi_device; ++ ++#ifdef CONFIG_ZORRO ++ ++static struct zorro_driver_data { ++ const char *name; ++ unsigned long offset; ++ int absolute; /* offset is absolute address */ ++} amiga7xx_driver_data[] __devinitdata = { ++ { .name = "PowerUP 603e+", .offset = 0xf40000, .absolute = 1 }, ++ { .name = "WarpEngine 40xx", .offset = 0x40000 }, ++ { .name = "A4091", .offset = 0x800000 }, ++ { .name = "GForce 040/060", .offset = 0x40000 }, ++ { 0 } ++}; + ++static struct zorro_device_id amiga7xx_zorro_tbl[] __devinitdata = { ++ { ++ .id = ZORRO_PROD_PHASE5_BLIZZARD_603E_PLUS, ++ .driver_data = (unsigned long)&amiga7xx_driver_data[0], ++ }, ++ { ++ .id = ZORRO_PROD_MACROSYSTEMS_WARP_ENGINE_40xx, ++ .driver_data = (unsigned long)&amiga7xx_driver_data[1], ++ }, ++ { ++ .id = ZORRO_PROD_CBM_A4091_1, ++ .driver_data = (unsigned long)&amiga7xx_driver_data[2], ++ }, ++ { ++ .id = ZORRO_PROD_CBM_A4091_2, ++ .driver_data = (unsigned long)&amiga7xx_driver_data[2], ++ }, ++ { ++ .id = ZORRO_PROD_GVP_GFORCE_040_060, ++ .driver_data = (unsigned long)&amiga7xx_driver_data[3], ++ }, ++ { 0 } ++}; + +-static int amiga7xx_register_one(struct scsi_host_template *tpnt, +- unsigned long address) ++static int __devinit amiga7xx_init_one(struct zorro_dev *z, ++ const struct zorro_device_id *ent) + { +- long long options; +- int clock; ++ struct Scsi_Host * host = NULL; ++ struct NCR_700_Host_Parameters *hostdata; ++ struct zorro_driver_data *zdd; ++ unsigned long board, ioaddr; ++ ++ board = zorro_resource_start(z); ++ zdd = (struct zorro_driver_data *)ent->driver_data; ++ ++ if (zdd->absolute) { ++ ioaddr = zdd->offset; ++ } else { ++ ioaddr = board + zdd->offset; ++ } ++ ++ if (!zorro_request_device(z, zdd->name)) { ++ printk(KERN_ERR "amiga7xx: cannot reserve region 0x%lx, abort\n", ++ board); ++ return -EBUSY; ++ } ++ ++ hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); ++ ++ if (hostdata == NULL) { ++ printk(KERN_ERR "amiga7xx: Failed to allocate host data\n"); ++ goto out_release; ++ } ++ ++ memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters)); ++ ++ /* Fill in the required pieces of hostdata */ ++ if (ioaddr > 0x01000000) ++ hostdata->base = ioremap(ioaddr, zorro_resource_len(z)); ++ else ++ hostdata->base = (void __iomem *)ZTWO_VADDR(ioaddr); + +- if (!request_mem_region(address, 0x1000, "ncr53c710")) +- return 0; ++ hostdata->clock = 50; ++ hostdata->chip710 = 1; + +- address = (unsigned long)z_ioremap(address, 0x1000); +- options = OPTION_MEMORY_MAPPED | OPTION_DEBUG_TEST1 | OPTION_INTFLY | +- OPTION_SYNCHRONOUS | OPTION_ALWAYS_SYNCHRONOUS | +- OPTION_DISCONNECT; +- clock = 50000000; /* 50 MHz SCSI Clock */ +- ncr53c7xx_init(tpnt, 0, 710, address, 0, IRQ_AMIGA_PORTS, DMA_NONE, +- options, clock); +- return 1; +-} ++ /* Settings for at least WarpEngine 40xx */ ++ hostdata->ctest7_extra = CTEST7_TT1; + ++ amiga7xx_scsi_driver_template.name = zdd->name; + +-#ifdef CONFIG_ZORRO ++ /* and register the chip */ ++ if ((host = NCR_700_detect(&amiga7xx_scsi_driver_template, hostdata, &z->dev)) ++ == NULL) { ++ printk(KERN_ERR "amiga7xx-scsi: No host detected; board configuration problem?\n"); ++ goto out_free; ++ } + +-static struct { +- zorro_id id; +- unsigned long offset; +- int absolute; /* offset is absolute address */ +-} amiga7xx_table[] = { +- { .id = ZORRO_PROD_PHASE5_BLIZZARD_603E_PLUS, .offset = 0xf40000, +- .absolute = 1 }, +- { .id = ZORRO_PROD_MACROSYSTEMS_WARP_ENGINE_40xx, .offset = 0x40000 }, +- { .id = ZORRO_PROD_CBM_A4091_1, .offset = 0x800000 }, +- { .id = ZORRO_PROD_CBM_A4091_2, .offset = 0x800000 }, +- { .id = ZORRO_PROD_GVP_GFORCE_040_060, .offset = 0x40000 }, +- { 0 } +-}; ++ host->this_id = 7; ++ host->base = ioaddr; ++ host->irq = IRQ_AMIGA_PORTS; ++ ++ if (request_irq(host->irq, NCR_700_intr, IRQF_SHARED, "amiga7xx-scsi", host)) { ++ printk(KERN_ERR "amiga7xx-scsi: request_irq failed\n"); ++ goto out_put_host; ++ } ++ ++ scsi_scan_host(host); ++ ++ return 0; ++ ++ out_put_host: ++ scsi_host_put(host); ++ out_free: ++ if (ioaddr > 0x01000000) ++ iounmap(hostdata->base); ++ kfree(hostdata); ++ out_release: ++ zorro_release_device(z); ++ ++ return -ENODEV; ++} + +-static int __init amiga7xx_zorro_detect(struct scsi_host_template *tpnt) ++static __devexit void amiga7xx_remove_one(struct zorro_dev *z) + { +- int num = 0, i; +- struct zorro_dev *z = NULL; +- unsigned long address; +- +- while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { +- for (i = 0; amiga7xx_table[i].id; i++) +- if (z->id == amiga7xx_table[i].id) +- break; +- if (!amiga7xx_table[i].id) +- continue; +- if (amiga7xx_table[i].absolute) +- address = amiga7xx_table[i].offset; +- else +- address = z->resource.start + amiga7xx_table[i].offset; +- num += amiga7xx_register_one(tpnt, address); +- } +- return num; ++ struct Scsi_Host *host = dev_to_shost(&z->dev); ++ struct NCR_700_Host_Parameters *hostdata = ++ (struct NCR_700_Host_Parameters *)host->hostdata[0]; ++ ++ scsi_remove_host(host); ++ ++ NCR_700_release(host); ++ kfree(hostdata); ++ free_irq(host->irq, host); ++ zorro_release_device(z); + } + ++static struct zorro_driver amiga7xx_driver = { ++ .name = "amiga7xx-scsi", ++ .id_table = amiga7xx_zorro_tbl, ++ .probe = amiga7xx_init_one, ++ .remove = __devexit_p(amiga7xx_remove_one), ++}; ++ + #endif /* CONFIG_ZORRO */ + ++#define A4000T_SCSI_ADDR 0xdd0040 + +-int __init amiga7xx_detect(struct scsi_host_template *tpnt) ++static int __devinit a4000t_probe(struct device *dev) + { +- static unsigned char called = 0; +- int num = 0; ++ struct Scsi_Host * host = NULL; ++ struct NCR_700_Host_Parameters *hostdata; + +- if (called || !MACH_IS_AMIGA) +- return 0; ++ if (!(MACH_IS_AMIGA && AMIGAHW_PRESENT(A4000_SCSI))) ++ goto out; + +- tpnt->proc_name = "Amiga7xx"; ++ if (!request_mem_region(A4000T_SCSI_ADDR, 0x1000, "A4000T builtin SCSI")) ++ goto out; + +- if (AMIGAHW_PRESENT(A4000_SCSI)) +- num += amiga7xx_register_one(tpnt, 0xdd0040); ++ hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); ++ if (hostdata == NULL) { ++ printk(KERN_ERR "a4000t-scsi: Failed to allocate host data\n"); ++ goto out_release; ++ } ++ memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters)); ++ ++ /* Fill in the required pieces of hostdata */ ++ hostdata->base = (void __iomem *)ZTWO_VADDR(A4000T_SCSI_ADDR); ++ hostdata->clock = 50; ++ hostdata->chip710 = 1; ++ hostdata->dmode_extra = DMODE_FC2; ++ hostdata->dcntl_extra = EA_710; ++ ++ /* and register the chip */ ++ if ((host = NCR_700_detect(&amiga7xx_scsi_driver_template, hostdata, dev)) ++ == NULL) { ++ printk(KERN_ERR "a4000t-scsi: No host detected; board configuration problem?\n"); ++ goto out_free; ++ } ++ ++ host->this_id = 7; ++ host->base = A4000T_SCSI_ADDR; ++ host->irq = IRQ_AMIGA_PORTS; ++ ++ if (request_irq(host->irq, NCR_700_intr, IRQF_SHARED, "a4000t-scsi", host)) { ++ printk(KERN_ERR "a4000t-scsi: request_irq failed\n"); ++ goto out_put_host; ++ } + +-#ifdef CONFIG_ZORRO +- num += amiga7xx_zorro_detect(tpnt); +-#endif ++ scsi_scan_host(host); ++ ++ return 0; + +- called = 1; +- return num; ++ out_put_host: ++ scsi_host_put(host); ++ out_free: ++ kfree(hostdata); ++ out_release: ++ release_mem_region(A4000T_SCSI_ADDR, 0x1000); ++ out: ++ return -ENODEV; + } + +-static int amiga7xx_release(struct Scsi_Host *shost) ++static __devexit int a4000t_device_remove(struct device *dev) + { +- if (shost->irq) +- free_irq(shost->irq, NULL); +- if (shost->dma_channel != 0xff) +- free_dma(shost->dma_channel); +- if (shost->io_port && shost->n_io_port) +- release_region(shost->io_port, shost->n_io_port); +- scsi_unregister(shost); ++ struct Scsi_Host *host = dev_to_shost(dev); ++ struct NCR_700_Host_Parameters *hostdata = ++ (struct NCR_700_Host_Parameters *)host->hostdata[0]; ++ ++ scsi_remove_host(host); ++ ++ NCR_700_release(host); ++ kfree(hostdata); ++ free_irq(host->irq, host); ++ release_mem_region(A4000T_SCSI_ADDR, 0x1000); ++ + return 0; + } + +-static struct scsi_host_template driver_template = { +- .name = "Amiga NCR53c710 SCSI", +- .detect = amiga7xx_detect, +- .release = amiga7xx_release, +- .queuecommand = NCR53c7xx_queue_command, +- .abort = NCR53c7xx_abort, +- .reset = NCR53c7xx_reset, +- .can_queue = 24, +- .this_id = 7, +- .sg_tablesize = 63, +- .cmd_per_lun = 3, +- .use_clustering = DISABLE_CLUSTERING ++static struct device_driver a4000t_scsi_driver = { ++ .name = "a4000t-scsi", ++ .bus = &platform_bus_type, ++ .probe = a4000t_probe, ++ .remove = __devexit_p(a4000t_device_remove), + }; + ++static int __init amiga7xx_scsi_init(void) ++{ ++ int err; ++ ++ if ((err = driver_register(&a4000t_scsi_driver))) ++ return err; ++ ++ a4000t_scsi_device = platform_device_register_simple("a4000t-scsi", -1, NULL, 0); ++ ++ if (IS_ERR(a4000t_scsi_device)) { ++ driver_unregister(&a4000t_scsi_driver); ++ return PTR_ERR(a4000t_scsi_device); ++ } ++ ++#ifdef CONFIG_ZORRO ++ err = zorro_register_driver(&amiga7xx_driver); ++#endif ++ ++ return err; ++} ++ ++static void __exit amiga7xx_scsi_exit(void) ++{ ++ platform_device_unregister(a4000t_scsi_device); ++ driver_unregister(&a4000t_scsi_driver); ++#ifdef CONFIG_ZORRO ++ zorro_unregister_driver(&amiga7xx_driver); ++#endif ++} + +-#include "scsi_module.c" ++module_init(amiga7xx_scsi_init); ++module_exit(amiga7xx_scsi_exit); +--- linux-m68k-2.6.21.orig/drivers/scsi/amiga7xx.h ++++ /dev/null +@@ -1,23 +0,0 @@ +-#ifndef AMIGA7XX_H +- +-#include <linux/types.h> +- +-int amiga7xx_detect(struct scsi_host_template *); +-const char *NCR53c7x0_info(void); +-int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +-int NCR53c7xx_abort(Scsi_Cmnd *); +-int NCR53c7x0_release (struct Scsi_Host *); +-int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int); +-void NCR53c7x0_intr(int irq, void *dev_id); +- +-#ifndef CMD_PER_LUN +-#define CMD_PER_LUN 3 +-#endif +- +-#ifndef CAN_QUEUE +-#define CAN_QUEUE 24 +-#endif +- +-#include <scsi/scsicam.h> +- +-#endif /* AMIGA7XX_H */ +--- linux-m68k-2.6.21.orig/drivers/scsi/bvme6000.h ++++ /dev/null +@@ -1,24 +0,0 @@ +-#ifndef BVME6000_SCSI_H +-#define BVME6000_SCSI_H +- +-#include <linux/types.h> +- +-int bvme6000_scsi_detect(struct scsi_host_template *); +-const char *NCR53c7x0_info(void); +-int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +-int NCR53c7xx_abort(Scsi_Cmnd *); +-int NCR53c7x0_release (struct Scsi_Host *); +-int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int); +-void NCR53c7x0_intr(int irq, void *dev_id); +- +-#ifndef CMD_PER_LUN +-#define CMD_PER_LUN 3 +-#endif +- +-#ifndef CAN_QUEUE +-#define CAN_QUEUE 24 +-#endif +- +-#include <scsi/scsicam.h> +- +-#endif /* BVME6000_SCSI_H */ +--- linux-m68k-2.6.21.orig/drivers/scsi/bvme6000_scsi.c ++++ linux-m68k-2.6.21/drivers/scsi/bvme6000_scsi.c +@@ -1,76 +1,132 @@ + /* + * Detection routine for the NCR53c710 based BVME6000 SCSI Controllers for Linux. + * +- * Based on work by Alan Hourihane ++ * Based on work by Alan Hourihane and Kars de Jong ++ * ++ * Rewritten to use 53c700.c by Richard Hirst <richard@sleepie.demon.co.uk> + */ +-#include <linux/types.h> +-#include <linux/mm.h> +-#include <linux/blkdev.h> +-#include <linux/zorro.h> + +-#include <asm/setup.h> +-#include <asm/page.h> +-#include <asm/pgtable.h> ++#include <linux/module.h> ++#include <linux/blkdev.h> ++#include <linux/device.h> ++#include <linux/platform_device.h> ++#include <linux/init.h> ++#include <linux/interrupt.h> + #include <asm/bvme6000hw.h> +-#include <asm/irq.h> +- +-#include "scsi.h" + #include <scsi/scsi_host.h> +-#include "53c7xx.h" +-#include "bvme6000.h" ++#include <scsi/scsi_device.h> ++#include <scsi/scsi_transport.h> ++#include <scsi/scsi_transport_spi.h> + +-#include<linux/stat.h> ++#include "53c700.h" + ++MODULE_AUTHOR("Richard Hirst <richard@sleepie.demon.co.uk>"); ++MODULE_DESCRIPTION("BVME6000 NCR53C710 driver"); ++MODULE_LICENSE("GPL"); + +-int bvme6000_scsi_detect(struct scsi_host_template *tpnt) ++static struct scsi_host_template bvme6000_scsi_driver_template = { ++ .name = "BVME6000 NCR53c710 SCSI", ++ .proc_name = "BVME6000", ++ .this_id = 7, ++ .module = THIS_MODULE, ++}; ++ ++static struct platform_device *bvme6000_scsi_device; ++ ++static __devinit int ++bvme6000_probe(struct device *dev) + { +- static unsigned char called = 0; +- int clock; +- long long options; ++ struct Scsi_Host * host = NULL; ++ struct NCR_700_Host_Parameters *hostdata; + +- if (called) +- return 0; +- if (!MACH_IS_BVME6000) +- return 0; ++ if (!MACH_IS_BVME6000) ++ goto out; + +- tpnt->proc_name = "BVME6000"; ++ hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); ++ if (hostdata == NULL) { ++ printk(KERN_ERR "bvme6000-scsi: Failed to allocate host data\n"); ++ goto out; ++ } ++ memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters)); ++ ++ /* Fill in the required pieces of hostdata */ ++ hostdata->base = (void __iomem *)BVME_NCR53C710_BASE; ++ hostdata->clock = 40; /* XXX - depends on the CPU clock! */ ++ hostdata->chip710 = 1; ++ hostdata->dmode_extra = DMODE_FC2; ++ hostdata->dcntl_extra = EA_710; ++ hostdata->ctest7_extra = CTEST7_TT1; ++ ++ /* and register the chip */ ++ if ((host = NCR_700_detect(&bvme6000_scsi_driver_template, hostdata, dev)) ++ == NULL) { ++ printk(KERN_ERR "bvme6000-scsi: No host detected; board configuration problem?\n"); ++ goto out_free; ++ } ++ host->base = BVME_NCR53C710_BASE; ++ host->this_id = 7; ++ host->irq = BVME_IRQ_SCSI; ++ if (request_irq(BVME_IRQ_SCSI, NCR_700_intr, 0, "bvme6000-scsi", host)) { ++ printk(KERN_ERR "bvme6000-scsi: request_irq failed\n"); ++ goto out_put_host; ++ } + +- options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT; ++ scsi_scan_host(host); + +- clock = 40000000; /* 66MHz SCSI Clock */ ++ return 0; + +- ncr53c7xx_init(tpnt, 0, 710, (unsigned long)BVME_NCR53C710_BASE, +- 0, BVME_IRQ_SCSI, DMA_NONE, +- options, clock); +- called = 1; +- return 1; ++ out_put_host: ++ scsi_host_put(host); ++ out_free: ++ kfree(hostdata); ++ out: ++ return -ENODEV; + } + +-static int bvme6000_scsi_release(struct Scsi_Host *shost) ++static __devexit int ++bvme6000_device_remove(struct device *dev) + { +- if (shost->irq) +- free_irq(shost->irq, NULL); +- if (shost->dma_channel != 0xff) +- free_dma(shost->dma_channel); +- if (shost->io_port && shost->n_io_port) +- release_region(shost->io_port, shost->n_io_port); +- scsi_unregister(shost); ++ struct Scsi_Host *host = dev_to_shost(dev); ++ struct NCR_700_Host_Parameters *hostdata = ++ (struct NCR_700_Host_Parameters *)host->hostdata[0]; ++ ++ scsi_remove_host(host); ++ NCR_700_release(host); ++ kfree(hostdata); ++ free_irq(host->irq, host); ++ + return 0; + } + +-static struct scsi_host_template driver_template = { +- .name = "BVME6000 NCR53c710 SCSI", +- .detect = bvme6000_scsi_detect, +- .release = bvme6000_scsi_release, +- .queuecommand = NCR53c7xx_queue_command, +- .abort = NCR53c7xx_abort, +- .reset = NCR53c7xx_reset, +- .can_queue = 24, +- .this_id = 7, +- .sg_tablesize = 63, +- .cmd_per_lun = 3, +- .use_clustering = DISABLE_CLUSTERING ++static struct device_driver bvme6000_scsi_driver = { ++ .name = "bvme6000-scsi", ++ .bus = &platform_bus_type, ++ .probe = bvme6000_probe, ++ .remove = __devexit_p(bvme6000_device_remove), + }; + ++static int __init bvme6000_scsi_init(void) ++{ ++ int err; ++ ++ if ((err = driver_register(&bvme6000_scsi_driver))) ++ return err; ++ ++ bvme6000_scsi_device = platform_device_register_simple("bvme6000-scsi", -1, NULL, 0); ++ ++ if (IS_ERR(bvme6000_scsi_device)) { ++ driver_unregister(&bvme6000_scsi_driver); ++ return PTR_ERR(bvme6000_scsi_device); ++ } ++ ++ return 0; ++} ++ ++static void __exit bvme6000_scsi_exit(void) ++{ ++ platform_device_unregister(bvme6000_scsi_device); ++ driver_unregister(&bvme6000_scsi_driver); ++} + +-#include "scsi_module.c" ++module_init(bvme6000_scsi_init); ++module_exit(bvme6000_scsi_exit); +--- linux-m68k-2.6.21.orig/drivers/scsi/mvme16x.h ++++ /dev/null +@@ -1,24 +0,0 @@ +-#ifndef MVME16x_SCSI_H +-#define MVME16x_SCSI_H +- +-#include <linux/types.h> +- +-int mvme16x_scsi_detect(struct scsi_host_template *); +-const char *NCR53c7x0_info(void); +-int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +-int NCR53c7xx_abort(Scsi_Cmnd *); +-int NCR53c7x0_release (struct Scsi_Host *); +-int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int); +-void NCR53c7x0_intr(int irq, void *dev_id); +- +-#ifndef CMD_PER_LUN +-#define CMD_PER_LUN 3 +-#endif +- +-#ifndef CAN_QUEUE +-#define CAN_QUEUE 24 +-#endif +- +-#include <scsi/scsicam.h> +- +-#endif /* MVME16x_SCSI_H */ +--- linux-m68k-2.6.21.orig/drivers/scsi/mvme16x_scsi.c ++++ linux-m68k-2.6.21/drivers/scsi/mvme16x_scsi.c +@@ -2,77 +2,154 @@ + * Detection routine for the NCR53c710 based MVME16x SCSI Controllers for Linux. + * + * Based on work by Alan Hourihane ++ * ++ * Rewritten to use 53c700.c by Kars de Jong <jongk@linux-m68k.org> + */ +-#include <linux/types.h> +-#include <linux/mm.h> +-#include <linux/blkdev.h> + +-#include <asm/page.h> +-#include <asm/pgtable.h> ++#include <linux/module.h> ++#include <linux/blkdev.h> ++#include <linux/device.h> ++#include <linux/platform_device.h> ++#include <linux/init.h> ++#include <linux/interrupt.h> + #include <asm/mvme16xhw.h> +-#include <asm/irq.h> +- +-#include "scsi.h" + #include <scsi/scsi_host.h> +-#include "53c7xx.h" +-#include "mvme16x.h" ++#include <scsi/scsi_device.h> ++#include <scsi/scsi_transport.h> ++#include <scsi/scsi_transport_spi.h> + +-#include<linux/stat.h> ++#include "53c700.h" + ++MODULE_AUTHOR("Kars de Jong <jongk@linux-m68k.org>"); ++MODULE_DESCRIPTION("MVME16x NCR53C710 driver"); ++MODULE_LICENSE("GPL"); + +-int mvme16x_scsi_detect(struct scsi_host_template *tpnt) ++static struct scsi_host_template mvme16x_scsi_driver_template = { ++ .name = "MVME16x NCR53c710 SCSI", ++ .proc_name = "MVME16x", ++ .this_id = 7, ++ .module = THIS_MODULE, ++}; ++ ++static struct platform_device *mvme16x_scsi_device; ++ ++static __devinit int ++mvme16x_probe(struct device *dev) + { +- static unsigned char called = 0; +- int clock; +- long long options; +- +- if (!MACH_IS_MVME16x) +- return 0; +- if (mvme16x_config & MVME16x_CONFIG_NO_SCSICHIP) { +- printk ("SCSI detection disabled, SCSI chip not present\n"); +- return 0; +- } +- if (called) +- return 0; ++ struct Scsi_Host * host = NULL; ++ struct NCR_700_Host_Parameters *hostdata; ++ ++ if (!MACH_IS_MVME16x) ++ goto out; + +- tpnt->proc_name = "MVME16x"; ++ if (mvme16x_config & MVME16x_CONFIG_NO_SCSICHIP) { ++ printk(KERN_INFO "mvme16x-scsi: detection disabled, SCSI chip not present\n"); ++ goto out; ++ } ++ ++ hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); ++ if (hostdata == NULL) { ++ printk(KERN_ERR "mvme16x-scsi: Failed to allocate host data\n"); ++ goto out; ++ } ++ memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters)); ++ ++ /* Fill in the required pieces of hostdata */ ++ hostdata->base = (void __iomem *)0xfff47000UL; ++ hostdata->clock = 50; /* XXX - depends on the CPU clock! */ ++ hostdata->chip710 = 1; ++ hostdata->dmode_extra = DMODE_FC2; ++ hostdata->dcntl_extra = EA_710; ++ hostdata->ctest7_extra = CTEST7_TT1; ++ ++ /* and register the chip */ ++ if ((host = NCR_700_detect(&mvme16x_scsi_driver_template, hostdata, dev)) ++ == NULL) { ++ printk(KERN_ERR "mvme16x-scsi: No host detected; board configuration problem?\n"); ++ goto out_free; ++ } ++ host->this_id = 7; ++ host->base = 0xfff47000UL; ++ host->irq = MVME16x_IRQ_SCSI; ++ if (request_irq(host->irq, NCR_700_intr, 0, "mvme16x-scsi", host)) { ++ printk(KERN_ERR "mvme16x-scsi: request_irq failed\n"); ++ goto out_put_host; ++ } ++ ++ /* Enable scsi chip ints */ ++ { ++ volatile unsigned long v; ++ ++ /* Enable scsi interrupts at level 4 in PCCchip2 */ ++ v = in_be32(0xfff4202c); ++ v = (v & ~0xff) | 0x10 | 4; ++ out_be32(0xfff4202c, v); ++ } + +- options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT; ++ scsi_scan_host(host); + +- clock = 66000000; /* 66MHz SCSI Clock */ ++ return 0; + +- ncr53c7xx_init(tpnt, 0, 710, (unsigned long)0xfff47000, +- 0, MVME16x_IRQ_SCSI, DMA_NONE, +- options, clock); +- called = 1; +- return 1; ++ out_put_host: ++ scsi_host_put(host); ++ out_free: ++ kfree(hostdata); ++ out: ++ return -ENODEV; + } + +-static int mvme16x_scsi_release(struct Scsi_Host *shost) ++static __devexit int ++mvme16x_device_remove(struct device *dev) + { +- if (shost->irq) +- free_irq(shost->irq, NULL); +- if (shost->dma_channel != 0xff) +- free_dma(shost->dma_channel); +- if (shost->io_port && shost->n_io_port) +- release_region(shost->io_port, shost->n_io_port); +- scsi_unregister(shost); ++ struct Scsi_Host *host = dev_to_shost(dev); ++ struct NCR_700_Host_Parameters *hostdata = ++ (struct NCR_700_Host_Parameters *)host->hostdata[0]; ++ ++ /* Disable scsi chip ints */ ++ { ++ volatile unsigned long v; ++ ++ v = in_be32(0xfff4202c); ++ v &= ~0x10; ++ out_be32(0xfff4202c, v); ++ } ++ scsi_remove_host(host); ++ NCR_700_release(host); ++ kfree(hostdata); ++ free_irq(host->irq, host); ++ + return 0; + } + +-static struct scsi_host_template driver_template = { +- .name = "MVME16x NCR53c710 SCSI", +- .detect = mvme16x_scsi_detect, +- .release = mvme16x_scsi_release, +- .queuecommand = NCR53c7xx_queue_command, +- .abort = NCR53c7xx_abort, +- .reset = NCR53c7xx_reset, +- .can_queue = 24, +- .this_id = 7, +- .sg_tablesize = 63, +- .cmd_per_lun = 3, +- .use_clustering = DISABLE_CLUSTERING ++static struct device_driver mvme16x_scsi_driver = { ++ .name = "mvme16x-scsi", ++ .bus = &platform_bus_type, ++ .probe = mvme16x_probe, ++ .remove = __devexit_p(mvme16x_device_remove), + }; + ++static int __init mvme16x_scsi_init(void) ++{ ++ int err; ++ ++ if ((err = driver_register(&mvme16x_scsi_driver))) ++ return err; ++ ++ mvme16x_scsi_device = platform_device_register_simple("mvme16x-scsi", -1, NULL, 0); ++ ++ if (IS_ERR(mvme16x_scsi_device)) { ++ driver_unregister(&mvme16x_scsi_driver); ++ return PTR_ERR(mvme16x_scsi_device); ++ } ++ ++ return 0; ++} ++ ++static void __exit mvme16x_scsi_exit(void) ++{ ++ platform_device_unregister(mvme16x_scsi_device); ++ driver_unregister(&mvme16x_scsi_driver); ++} + +-#include "scsi_module.c" ++module_init(mvme16x_scsi_init); ++module_exit(mvme16x_scsi_exit); diff --git a/debian/patches/bugfix/m68k/m68k-as.patch b/debian/patches/bugfix/m68k/m68k-as.patch new file mode 100644 index 000000000000..f228e6d3090b --- /dev/null +++ b/debian/patches/bugfix/m68k/m68k-as.patch @@ -0,0 +1,308 @@ +From: Al Viro <viro@zeniv.linux.org.uk> +Date: 1134413482 -0500 + +recent as(1) doesn't think that . terminates a macro name, so +getuser.l is _not_ treated as invoking getuser with .l as the +first argument. + +Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> + +--- + + arch/m68k/math-emu/fp_cond.S | 2 +- + arch/m68k/math-emu/fp_decode.h | 4 ++-- + arch/m68k/math-emu/fp_move.S | 14 +++++++------- + arch/m68k/math-emu/fp_movem.S | 16 ++++++++-------- + arch/m68k/math-emu/fp_scan.S | 22 +++++++++++----------- + arch/m68k/math-emu/fp_util.S | 16 ++++++++-------- + 6 files changed, 37 insertions(+), 37 deletions(-) + +3c4ab44571b5a46917ad28620995c326e386a909 +diff --git a/arch/m68k/math-emu/fp_cond.S b/arch/m68k/math-emu/fp_cond.S +index ddae8b1..1cddeb0 100644 +--- a/arch/m68k/math-emu/fp_cond.S ++++ b/arch/m68k/math-emu/fp_cond.S +@@ -163,7 +163,7 @@ fp_absolute_long: + + fp_do_scc: + swap %d1 +- putuser.b %d1,(%a0),fp_err_ua1,%a0 ++ putuser .b,%d1,(%a0),fp_err_ua1,%a0 + printf PDECODE,"\n" + jra fp_end + +diff --git a/arch/m68k/math-emu/fp_decode.h b/arch/m68k/math-emu/fp_decode.h +index 759679d..a2595d9 100644 +--- a/arch/m68k/math-emu/fp_decode.h ++++ b/arch/m68k/math-emu/fp_decode.h +@@ -311,7 +311,7 @@ debug move.l "(%sp)+,%d1" + btst #2,%d2 + jne 1f + printf PDECODE,")@(" +- getuser.l (%a1),%a1,fp_err_ua1,%a1 ++ getuser .l,(%a1),%a1,fp_err_ua1,%a1 + debug jra "2f" + 1: printf PDECODE,"," + 2: +@@ -322,7 +322,7 @@ debug jra "2f" + btst #2,%d2 + jeq 1f + printf PDECODE,")@(" +- getuser.l (%a1),%a1,fp_err_ua1,%a1 ++ getuser .l,(%a1),%a1,fp_err_ua1,%a1 + debug jra "2f" + 1: printf PDECODE,"," + 2: +diff --git a/arch/m68k/math-emu/fp_move.S b/arch/m68k/math-emu/fp_move.S +index 71bdf83..9bd0334 100644 +--- a/arch/m68k/math-emu/fp_move.S ++++ b/arch/m68k/math-emu/fp_move.S +@@ -200,12 +200,12 @@ fp_putdest: + + fp_format_long: + jsr fp_conv_ext2long +- putuser.l %d0,(%a1),fp_err_ua1,%a1 ++ putuser .l,%d0,(%a1),fp_err_ua1,%a1 + jra fp_finish_move + + fp_format_single: + jsr fp_conv_ext2single +- putuser.l %d0,(%a1),fp_err_ua1,%a1 ++ putuser .l,%d0,(%a1),fp_err_ua1,%a1 + jra fp_finish_move + + fp_format_extended: +@@ -213,11 +213,11 @@ fp_format_extended: + lsl.w #1,%d0 + lsl.l #7,%d0 + lsl.l #8,%d0 +- putuser.l %d0,(%a1)+,fp_err_ua1,%a1 ++ putuser .l,%d0,(%a1)+,fp_err_ua1,%a1 + move.l (%a0)+,%d0 +- putuser.l %d0,(%a1)+,fp_err_ua1,%a1 ++ putuser .l,%d0,(%a1)+,fp_err_ua1,%a1 + move.l (%a0),%d0 +- putuser.l %d0,(%a1),fp_err_ua1,%a1 ++ putuser .l,%d0,(%a1),fp_err_ua1,%a1 + jra fp_finish_move + + fp_format_packed: +@@ -227,7 +227,7 @@ fp_format_packed: + + fp_format_word: + jsr fp_conv_ext2short +- putuser.w %d0,(%a1),fp_err_ua1,%a1 ++ putuser .w,%d0,(%a1),fp_err_ua1,%a1 + jra fp_finish_move + + fp_format_double: +@@ -236,7 +236,7 @@ fp_format_double: + + fp_format_byte: + jsr fp_conv_ext2byte +- putuser.b %d0,(%a1),fp_err_ua1,%a1 ++ putuser .b,%d0,(%a1),fp_err_ua1,%a1 + | jra fp_finish_move + + fp_finish_move: +diff --git a/arch/m68k/math-emu/fp_movem.S b/arch/m68k/math-emu/fp_movem.S +index 8354d39..9c74134 100644 +--- a/arch/m68k/math-emu/fp_movem.S ++++ b/arch/m68k/math-emu/fp_movem.S +@@ -141,14 +141,14 @@ fpr_do_movem: + | move register from memory into fpu + jra 3f + 1: printf PMOVEM,"(%p>%p)",2,%a0,%a1 +- getuser.l (%a0)+,%d2,fp_err_ua1,%a0 ++ getuser .l,(%a0)+,%d2,fp_err_ua1,%a0 + lsr.l #8,%d2 + lsr.l #7,%d2 + lsr.w #1,%d2 + move.l %d2,(%a1)+ +- getuser.l (%a0)+,%d2,fp_err_ua1,%a0 ++ getuser .l,(%a0)+,%d2,fp_err_ua1,%a0 + move.l %d2,(%a1)+ +- getuser.l (%a0),%d2,fp_err_ua1,%a0 ++ getuser .l,(%a0),%d2,fp_err_ua1,%a0 + move.l %d2,(%a1) + subq.l #8,%a0 + subq.l #8,%a1 +@@ -164,11 +164,11 @@ fpr_do_movem: + lsl.w #1,%d2 + lsl.l #7,%d2 + lsl.l #8,%d2 +- putuser.l %d2,(%a0)+,fp_err_ua1,%a0 ++ putuser .l,%d2,(%a0)+,fp_err_ua1,%a0 + move.l (%a1)+,%d2 +- putuser.l %d2,(%a0)+,fp_err_ua1,%a0 ++ putuser .l,%d2,(%a0)+,fp_err_ua1,%a0 + move.l (%a1),%d2 +- putuser.l %d2,(%a0),fp_err_ua1,%a0 ++ putuser .l,%d2,(%a0),fp_err_ua1,%a0 + subq.l #8,%a1 + subq.l #8,%a0 + add.l %d0,%a0 +@@ -325,7 +325,7 @@ fpc_do_movem: + | move register from memory into fpu + jra 3f + 1: printf PMOVEM,"(%p>%p)",2,%a0,%a1 +- getuser.l (%a0)+,%d0,fp_err_ua1,%a0 ++ getuser .l,(%a0)+,%d0,fp_err_ua1,%a0 + move.l %d0,(%a1) + 2: addq.l #4,%a1 + 3: lsl.b #1,%d1 +@@ -336,7 +336,7 @@ fpc_do_movem: + | move register from fpu into memory + 1: printf PMOVEM,"(%p>%p)",2,%a1,%a0 + move.l (%a1),%d0 +- putuser.l %d0,(%a0)+,fp_err_ua1,%a0 ++ putuser .l,%d0,(%a0)+,fp_err_ua1,%a0 + 2: addq.l #4,%a1 + 4: lsl.b #1,%d1 + jcs 1b +diff --git a/arch/m68k/math-emu/fp_scan.S b/arch/m68k/math-emu/fp_scan.S +index e4146ed..5f49b93 100644 +--- a/arch/m68k/math-emu/fp_scan.S ++++ b/arch/m68k/math-emu/fp_scan.S +@@ -64,7 +64,7 @@ fp_scan: + | normal fpu instruction? (this excludes fsave/frestore) + fp_get_pc %a0 + printf PDECODE,"%08x: ",1,%a0 +- getuser.b (%a0),%d0,fp_err_ua1,%a0 ++ getuser .b,(%a0),%d0,fp_err_ua1,%a0 + #if 1 + cmp.b #0xf2,%d0 | cpid = 1 + #else +@@ -72,7 +72,7 @@ fp_scan: + #endif + jne fp_nonstd + | first two instruction words are kept in %d2 +- getuser.l (%a0)+,%d2,fp_err_ua1,%a0 ++ getuser .l,(%a0)+,%d2,fp_err_ua1,%a0 + fp_put_pc %a0 + fp_decode_cond: | separate conditional instr + fp_decode_cond_instr_type +@@ -230,7 +230,7 @@ fp_immediate: + movel %a0,%a1 + clr.l %d1 + jra 2f +-1: getuser.b (%a1)+,%d1,fp_err_ua1,%a1 ++1: getuser .b,(%a1)+,%d1,fp_err_ua1,%a1 + printf PDECODE,"%02x",1,%d1 + 2: dbra %d0,1b + movem.l (%sp)+,%d0/%d1 +@@ -252,24 +252,24 @@ fp_fetchsource: + .long fp_byte, fp_ill + + fp_long: +- getuser.l (%a1),%d0,fp_err_ua1,%a1 ++ getuser .l,(%a1),%d0,fp_err_ua1,%a1 + jsr fp_conv_long2ext + jra fp_getdest + + fp_single: +- getuser.l (%a1),%d0,fp_err_ua1,%a1 ++ getuser .l,(%a1),%d0,fp_err_ua1,%a1 + jsr fp_conv_single2ext + jra fp_getdest + + fp_ext: +- getuser.l (%a1)+,%d0,fp_err_ua1,%a1 ++ getuser .l,(%a1)+,%d0,fp_err_ua1,%a1 + lsr.l #8,%d0 + lsr.l #7,%d0 + lsr.w #1,%d0 + move.l %d0,(%a0)+ +- getuser.l (%a1)+,%d0,fp_err_ua1,%a1 ++ getuser .l,(%a1)+,%d0,fp_err_ua1,%a1 + move.l %d0,(%a0)+ +- getuser.l (%a1),%d0,fp_err_ua1,%a1 ++ getuser .l,(%a1),%d0,fp_err_ua1,%a1 + move.l %d0,(%a0) + subq.l #8,%a0 + jra fp_getdest +@@ -279,7 +279,7 @@ fp_pack: + jra fp_ill + + fp_word: +- getuser.w (%a1),%d0,fp_err_ua1,%a1 ++ getuser .w,(%a1),%d0,fp_err_ua1,%a1 + ext.l %d0 + jsr fp_conv_long2ext + jra fp_getdest +@@ -289,7 +289,7 @@ fp_double: + jra fp_getdest + + fp_byte: +- getuser.b (%a1),%d0,fp_err_ua1,%a1 ++ getuser .b,(%a1),%d0,fp_err_ua1,%a1 + extb.l %d0 + jsr fp_conv_long2ext + | jra fp_getdest +@@ -465,7 +465,7 @@ fp_fdsub: + + fp_nonstd: + fp_get_pc %a0 +- getuser.l (%a0),%d0,fp_err_ua1,%a0 ++ getuser .l,(%a0),%d0,fp_err_ua1,%a0 + printf ,"nonstd ((%08x)=%08x)\n",2,%a0,%d0 + moveq #-1,%d0 + rts +diff --git a/arch/m68k/math-emu/fp_util.S b/arch/m68k/math-emu/fp_util.S +index a9f7f01..f9f24d5 100644 +--- a/arch/m68k/math-emu/fp_util.S ++++ b/arch/m68k/math-emu/fp_util.S +@@ -160,11 +160,11 @@ fp_s2e_large: + + fp_conv_double2ext: + #ifdef FPU_EMU_DEBUG +- getuser.l %a1@(0),%d0,fp_err_ua2,%a1 +- getuser.l %a1@(4),%d1,fp_err_ua2,%a1 ++ getuser .l,%a1@(0),%d0,fp_err_ua2,%a1 ++ getuser .l,%a1@(4),%d1,fp_err_ua2,%a1 + printf PCONV,"d2e: %p%p -> %p(",3,%d0,%d1,%a0 + #endif +- getuser.l (%a1)+,%d0,fp_err_ua2,%a1 ++ getuser .l,(%a1)+,%d0,fp_err_ua2,%a1 + move.l %d0,%d1 + lsl.l #8,%d0 | shift high mantissa + lsl.l #3,%d0 +@@ -178,7 +178,7 @@ fp_conv_double2ext: + add.w #0x3fff-0x3ff,%d1 | re-bias the exponent. + 9: move.l %d1,(%a0)+ | fp_ext.sign, fp_ext.exp + move.l %d0,(%a0)+ +- getuser.l (%a1)+,%d0,fp_err_ua2,%a1 ++ getuser .l,(%a1)+,%d0,fp_err_ua2,%a1 + move.l %d0,%d1 + lsl.l #8,%d0 + lsl.l #3,%d0 +@@ -1287,17 +1287,17 @@ fp_conv_ext2double: + lsr.l #4,%d0 + lsr.l #8,%d0 + or.l %d2,%d0 +- putuser.l %d0,(%a1)+,fp_err_ua2,%a1 ++ putuser .l,%d0,(%a1)+,fp_err_ua2,%a1 + moveq #21,%d0 + lsl.l %d0,%d1 + move.l (%a0),%d0 + lsr.l #4,%d0 + lsr.l #7,%d0 + or.l %d1,%d0 +- putuser.l %d0,(%a1),fp_err_ua2,%a1 ++ putuser .l,%d0,(%a1),fp_err_ua2,%a1 + #ifdef FPU_EMU_DEBUG +- getuser.l %a1@(-4),%d0,fp_err_ua2,%a1 +- getuser.l %a1@(0),%d1,fp_err_ua2,%a1 ++ getuser .l,%a1@(-4),%d0,fp_err_ua2,%a1 ++ getuser .l,%a1@(0),%d1,fp_err_ua2,%a1 + printf PCONV,"%p(%08x%08x)\n",3,%a1,%d0,%d1 + #endif + rts +-- +0.99.9.GIT + +- +To unsubscribe from this list: send the line "unsubscribe linux-m68k" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html + diff --git a/debian/patches/bugfix/m68k/m68k-generic-io.diff b/debian/patches/bugfix/m68k/m68k-generic-io.diff new file mode 100644 index 000000000000..da0ad5558022 --- /dev/null +++ b/debian/patches/bugfix/m68k/m68k-generic-io.diff @@ -0,0 +1,234 @@ +From jongk@linux-m68k.org Fri Nov 3 10:12:53 2006 +Date: Fri, 03 Nov 2006 00:06:13 +0100 +From: Kars de Jong <jongk@linux-m68k.org> +To: Geert Uytterhoeven <geert@linux-m68k.org> +Cc: linux-m68k@vger.kernel.org +Subject: [RFC PATCH] m68k: GENERIC_IOMAP support + +On do, 2006-11-02 at 22:34 +0100, Geert Uytterhoeven wrote: +> > OK, here's the patch, without the m68k generic iomap changes. +> +> Ah, the missing io{read,write}*() stuff :-) + +And here is the proposed patch to add iomap support. I think we need to +rethink our I/O support when we want to support all our I/O buses +properly, but that has been discussed before. I will commit my Amiga +PCMCIA support soon, I promise! + +I'm personally in favour of dropping the "generic" m68k kernel support. +Even a specific 2.6.18 kernel with only MVME167 support and the bare +essentials is already 2.5 MBytes these days. I don't even dare to think +of the size of a generic m68k kernel these days. + +Since Debian also builds "specific" kernels these days, I wonder if we +still need "generic" installation type kernels. Dropping that support +does make implementing some of the I/O stuff a lot easier, IMO, since it +can then be done at compile time. + +On vr, 2006-11-03 at 00:06 +0100, Kars de Jong wrote: +> On do, 2006-11-02 at 22:34 +0100, Geert Uytterhoeven wrote: +> > > OK, here's the patch, without the m68k generic iomap changes. +> > +> > Ah, the missing io{read,write}*() stuff :-) +> +> And here is the proposed patch to add iomap support. I think we need to +> rethink our I/O support when we want to support all our I/O buses +> properly, but that has been discussed before. I will commit my Amiga +> PCMCIA support soon, I promise! + +Here's the updated version of this patch. It should now work with Amiga +and Q40 defconfig. + +I don't think the CONFIG_ATARI_ROM_ISA definitions are complete yet, the +32-bit variants are missing. + +Kind regards, + +Kars. + +--- + arch/m68k/Kconfig | 4 ++ + include/asm-m68k/io.h | 63 +++++++++++++++++++++++++++++++++++++--------- + include/asm-m68k/raw_io.h | 8 ++++- + 3 files changed, 61 insertions(+), 14 deletions(-) + +--- linux-m68k-2.6.21.orig/arch/m68k/Kconfig ++++ linux-m68k-2.6.21/arch/m68k/Kconfig +@@ -37,6 +37,10 @@ config TIME_LOW_RES + bool + default y + ++config GENERIC_IOMAP ++ bool ++ default y ++ + config ARCH_MAY_HAVE_PC_FDC + bool + depends on Q40 || (BROKEN && SUN3X) +--- linux-m68k-2.6.21.orig/include/asm-m68k/io.h ++++ linux-m68k-2.6.21/include/asm-m68k/io.h +@@ -27,6 +27,7 @@ + #include <asm/raw_io.h> + #include <asm/virtconvert.h> + ++#include <asm-generic/iomap.h> + + #ifdef CONFIG_ATARI + #include <asm/atarihw.h> +@@ -175,6 +176,16 @@ static inline u16 __iomem *isa_itw(unsig + default: return NULL; /* avoid warnings, just in case */ + } + } ++static inline u32 __iomem *isa_itl(unsigned long addr) ++{ ++ switch(ISA_TYPE) ++ { ++#ifdef CONFIG_AMIGA_PCMCIA ++ case AG_ISA: return (u32 *)AG_ISA_IO_W(addr); ++#endif ++ default: return 0; /* avoid warnings, just in case */ ++ } ++} + static inline u8 __iomem *isa_mtb(unsigned long addr) + { + switch(ISA_TYPE) +@@ -217,8 +228,10 @@ static inline u16 __iomem *isa_mtw(unsig + + #define isa_inb(port) in_8(isa_itb(port)) + #define isa_inw(port) (ISA_SEX ? in_be16(isa_itw(port)) : in_le16(isa_itw(port))) ++#define isa_inl(port) (ISA_SEX ? in_be32(isa_itl(port)) : in_le32(isa_itl(port))) + #define isa_outb(val,port) out_8(isa_itb(port),(val)) + #define isa_outw(val,port) (ISA_SEX ? out_be16(isa_itw(port),(val)) : out_le16(isa_itw(port),(val))) ++#define isa_outl(val,port) (ISA_SEX ? out_be32(isa_itl(port),(val)) : out_le32(isa_itl(port),(val))) + + #define isa_readb(p) in_8(isa_mtb((unsigned long)(p))) + #define isa_readw(p) \ +@@ -280,6 +293,14 @@ static inline void isa_delay(void) + (ISA_SEX ? raw_outsw(isa_itw(port), (u16 *)(buf), (nr)) : \ + raw_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr))) + ++#define isa_insl(port, buf, nr) \ ++ (ISA_SEX ? raw_insl(isa_itl(port), (u32 *)(buf), (nr)) : \ ++ raw_insw_swapw(isa_itw(port), (u16 *)(buf), (nr)<<1)) ++ ++#define isa_outsl(port, buf, nr) \ ++ (ISA_SEX ? raw_outsl(isa_itl(port), (u32 *)(buf), (nr)) : \ ++ raw_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr)<<1)) ++ + #if defined(CONFIG_ATARI_ROM_ISA) + #define isa_rom_inb_p(p) ({ u8 _v = isa_rom_inb(p); isa_delay(); _v; }) + #define isa_rom_inw_p(p) ({ u16 _v = isa_rom_inw(p); isa_delay(); _v; }) +@@ -314,14 +335,16 @@ static inline void isa_delay(void) + #define inw_p isa_inw_p + #define outw isa_outw + #define outw_p isa_outw_p +-#define inl isa_inw +-#define inl_p isa_inw_p +-#define outl isa_outw +-#define outl_p isa_outw_p ++#define inl isa_inl ++#define inl_p isa_inl_p ++#define outl isa_outl ++#define outl_p isa_outl_p + #define insb isa_insb + #define insw isa_insw ++#define insl isa_insl + #define outsb isa_outsb + #define outsw isa_outsw ++#define outsl isa_outsl + #define readb isa_readb + #define readw isa_readw + #define writeb isa_writeb +@@ -330,8 +353,6 @@ static inline void isa_delay(void) + + #if defined(CONFIG_PCI) + +-#define inl(port) in_le32(port) +-#define outl(val,port) out_le32((port),(val)) + #define readl(addr) in_le32(addr) + #define writel(val,addr) out_le32((addr),(val)) + +@@ -346,10 +367,13 @@ static inline void isa_delay(void) + #define readl_relaxed(addr) readl(addr) + + #ifndef CONFIG_ISA ++ + #define inb(port) in_8(port) + #define outb(val,port) out_8((port),(val)) + #define inw(port) in_le16(port) + #define outw(val,port) out_le16((port),(val)) ++#define inl(port) in_le32(port) ++#define outl(val,port) out_le32((port),(val)) + + #else + /* +@@ -401,20 +425,35 @@ static inline void isa_delay(void) + #define outsw isa_rom_outsw + #endif + +-#if !defined(CONFIG_ISA) && !defined(CONFIG_PCI) && !defined(CONFIG_ATARI_ROM_ISA) && defined(CONFIG_HP300) ++#if !defined(CONFIG_ISA) && !defined(CONFIG_PCI) && !defined(CONFIG_ATARI_ROM_ISA) + /* +- * We need to define dummy functions otherwise drivers/serial/8250.c doesn't link ++ * We need to define dummy functions for GENERIC_IOMAP support. + */ +-#define inb(port) 0xff +-#define inb_p(port) 0xff +-#define outb(val,port) do { } while (0) +-#define outb_p(val,port) do { } while (0) ++#define inb(port) 0xff ++#define inb_p(port) 0xff ++#define outb(val,port) do { } while (0) ++#define outb_p(val,port) do { } while (0) ++#define inw(port) 0xffff ++#define outw(val,port) do { } while (0) ++#define inl(port) 0xffffffffUL ++#define outl(val,port) do { } while (0) ++ ++#define insb(port,buf,nr) do { } while (0) ++#define outsb(port,buf,nr) do { } while (0) ++#define insw(port,buf,nr) do { } while (0) ++#define outsw(port,buf,nr) do { } while (0) ++#define insl(port,buf,nr) do { } while (0) ++#define outsl(port,buf,nr) do { } while (0) + + /* + * These should be valid on any ioremap()ed region + */ + #define readb(addr) in_8(addr) + #define writeb(val,addr) out_8((addr),(val)) ++#define readw(addr) in_le16(addr) ++#define writew(val,addr) out_le16((addr),(val)) ++#endif /* !CONFIG_ISA && !CONFIG_PCI && !CONFIG_ATARI_ROM_ISA */ ++#if !defined(CONFIG_PCI) + #define readl(addr) in_le32(addr) + #define writel(val,addr) out_le32((addr),(val)) + #endif +--- linux-m68k-2.6.21.orig/include/asm-m68k/raw_io.h ++++ linux-m68k-2.6.21/include/asm-m68k/raw_io.h +@@ -49,10 +49,16 @@ extern void __iounmap(void *addr, unsign + #define raw_inb in_8 + #define raw_inw in_be16 + #define raw_inl in_be32 ++#define __raw_readb in_8 ++#define __raw_readw in_be16 ++#define __raw_readl in_be32 + + #define raw_outb(val,port) out_8((port),(val)) + #define raw_outw(val,port) out_be16((port),(val)) + #define raw_outl(val,port) out_be32((port),(val)) ++#define __raw_writeb(val,addr) out_8((addr),(val)) ++#define __raw_writew(val,addr) out_be16((addr),(val)) ++#define __raw_writel(val,addr) out_be32((addr),(val)) + + /* + * Atari ROM port (cartridge port) ISA adapter, used for the EtherNEC NE2000 +@@ -432,8 +438,6 @@ static inline void raw_rom_outsw_swapw(v + } + #endif /* CONFIG_ATARI_ROM_ISA */ + +-#define __raw_writel raw_outl +- + #endif /* __KERNEL__ */ + + #endif /* _RAW_IO_H */ diff --git a/debian/patches/bugfix/m68k/m68k-linux-gnu-crosscompile.diff b/debian/patches/bugfix/m68k/m68k-linux-gnu-crosscompile.diff new file mode 100644 index 000000000000..b300da1ac064 --- /dev/null +++ b/debian/patches/bugfix/m68k/m68k-linux-gnu-crosscompile.diff @@ -0,0 +1,20 @@ +Subject: [PATCH] m68k: CROSS_COMPILE = m68k-linux-gnu- + +Recent cross-compilers are called m68k-linux-gnu-gcc instead of m68k-linux-gcc + +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + arch/m68k/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- linux-m68k-2.6.21.orig/arch/m68k/Makefile ++++ linux-m68k-2.6.21/arch/m68k/Makefile +@@ -21,7 +21,7 @@ AS += -m68020 + LDFLAGS := -m m68kelf + ifneq ($(COMPILE_ARCH),$(ARCH)) + # prefix for cross-compiling binaries +- CROSS_COMPILE = m68k-linux- ++ CROSS_COMPILE = m68k-linux-gnu- + endif + + ifdef CONFIG_SUN3 diff --git a/debian/patches/bugfix/m68k/m68k-mvme-scsi-rename.diff b/debian/patches/bugfix/m68k/m68k-mvme-scsi-rename.diff new file mode 100644 index 000000000000..988f73472fad --- /dev/null +++ b/debian/patches/bugfix/m68k/m68k-mvme-scsi-rename.diff @@ -0,0 +1,348 @@ +Subject: [PATCH] m68k: BVME6000 and MVME16x SCSI driver rename + +Rename the source files for the BVME6000 and MVME16x SCSI drivers from *.c to +*_scsi.c + +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> + +--- + drivers/scsi/Makefile | 4 +- + drivers/scsi/bvme6000.c | 76 ----------------------------------------- + drivers/scsi/bvme6000_scsi.c | 76 +++++++++++++++++++++++++++++++++++++++++ + drivers/scsi/mvme16x.c | 78 ------------------------------------------- + drivers/scsi/mvme16x_scsi.c | 78 +++++++++++++++++++++++++++++++++++++++++++ + 5 files changed, 156 insertions(+), 156 deletions(-) + +--- linux-m68k-2.6.21.orig/drivers/scsi/Makefile ++++ linux-m68k-2.6.21/drivers/scsi/Makefile +@@ -53,8 +53,8 @@ obj-$(CONFIG_ATARI_SCSI) += atari_scsi.o + obj-$(CONFIG_MAC_SCSI) += mac_scsi.o + obj-$(CONFIG_SCSI_MAC_ESP) += mac_esp.o NCR53C9x.o + obj-$(CONFIG_SUN3_SCSI) += sun3_scsi.o sun3_scsi_vme.o +-obj-$(CONFIG_MVME16x_SCSI) += mvme16x.o 53c7xx.o +-obj-$(CONFIG_BVME6000_SCSI) += bvme6000.o 53c7xx.o ++obj-$(CONFIG_MVME16x_SCSI) += mvme16x_scsi.o 53c7xx.o ++obj-$(CONFIG_BVME6000_SCSI) += bvme6000_scsi.o 53c7xx.o + obj-$(CONFIG_SCSI_SIM710) += 53c700.o sim710.o + obj-$(CONFIG_SCSI_ADVANSYS) += advansys.o + obj-$(CONFIG_SCSI_PSI240I) += psi240i.o +--- linux-m68k-2.6.21.orig/drivers/scsi/bvme6000.c ++++ /dev/null +@@ -1,76 +0,0 @@ +-/* +- * Detection routine for the NCR53c710 based BVME6000 SCSI Controllers for Linux. +- * +- * Based on work by Alan Hourihane +- */ +-#include <linux/types.h> +-#include <linux/mm.h> +-#include <linux/blkdev.h> +-#include <linux/zorro.h> +- +-#include <asm/setup.h> +-#include <asm/page.h> +-#include <asm/pgtable.h> +-#include <asm/bvme6000hw.h> +-#include <asm/irq.h> +- +-#include "scsi.h" +-#include <scsi/scsi_host.h> +-#include "53c7xx.h" +-#include "bvme6000.h" +- +-#include<linux/stat.h> +- +- +-int bvme6000_scsi_detect(struct scsi_host_template *tpnt) +-{ +- static unsigned char called = 0; +- int clock; +- long long options; +- +- if (called) +- return 0; +- if (!MACH_IS_BVME6000) +- return 0; +- +- tpnt->proc_name = "BVME6000"; +- +- options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT; +- +- clock = 40000000; /* 66MHz SCSI Clock */ +- +- ncr53c7xx_init(tpnt, 0, 710, (unsigned long)BVME_NCR53C710_BASE, +- 0, BVME_IRQ_SCSI, DMA_NONE, +- options, clock); +- called = 1; +- return 1; +-} +- +-static int bvme6000_scsi_release(struct Scsi_Host *shost) +-{ +- if (shost->irq) +- free_irq(shost->irq, NULL); +- if (shost->dma_channel != 0xff) +- free_dma(shost->dma_channel); +- if (shost->io_port && shost->n_io_port) +- release_region(shost->io_port, shost->n_io_port); +- scsi_unregister(shost); +- return 0; +-} +- +-static struct scsi_host_template driver_template = { +- .name = "BVME6000 NCR53c710 SCSI", +- .detect = bvme6000_scsi_detect, +- .release = bvme6000_scsi_release, +- .queuecommand = NCR53c7xx_queue_command, +- .abort = NCR53c7xx_abort, +- .reset = NCR53c7xx_reset, +- .can_queue = 24, +- .this_id = 7, +- .sg_tablesize = 63, +- .cmd_per_lun = 3, +- .use_clustering = DISABLE_CLUSTERING +-}; +- +- +-#include "scsi_module.c" +--- /dev/null ++++ linux-m68k-2.6.21/drivers/scsi/bvme6000_scsi.c +@@ -0,0 +1,76 @@ ++/* ++ * Detection routine for the NCR53c710 based BVME6000 SCSI Controllers for Linux. ++ * ++ * Based on work by Alan Hourihane ++ */ ++#include <linux/types.h> ++#include <linux/mm.h> ++#include <linux/blkdev.h> ++#include <linux/zorro.h> ++ ++#include <asm/setup.h> ++#include <asm/page.h> ++#include <asm/pgtable.h> ++#include <asm/bvme6000hw.h> ++#include <asm/irq.h> ++ ++#include "scsi.h" ++#include <scsi/scsi_host.h> ++#include "53c7xx.h" ++#include "bvme6000.h" ++ ++#include<linux/stat.h> ++ ++ ++int bvme6000_scsi_detect(struct scsi_host_template *tpnt) ++{ ++ static unsigned char called = 0; ++ int clock; ++ long long options; ++ ++ if (called) ++ return 0; ++ if (!MACH_IS_BVME6000) ++ return 0; ++ ++ tpnt->proc_name = "BVME6000"; ++ ++ options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT; ++ ++ clock = 40000000; /* 66MHz SCSI Clock */ ++ ++ ncr53c7xx_init(tpnt, 0, 710, (unsigned long)BVME_NCR53C710_BASE, ++ 0, BVME_IRQ_SCSI, DMA_NONE, ++ options, clock); ++ called = 1; ++ return 1; ++} ++ ++static int bvme6000_scsi_release(struct Scsi_Host *shost) ++{ ++ if (shost->irq) ++ free_irq(shost->irq, NULL); ++ if (shost->dma_channel != 0xff) ++ free_dma(shost->dma_channel); ++ if (shost->io_port && shost->n_io_port) ++ release_region(shost->io_port, shost->n_io_port); ++ scsi_unregister(shost); ++ return 0; ++} ++ ++static struct scsi_host_template driver_template = { ++ .name = "BVME6000 NCR53c710 SCSI", ++ .detect = bvme6000_scsi_detect, ++ .release = bvme6000_scsi_release, ++ .queuecommand = NCR53c7xx_queue_command, ++ .abort = NCR53c7xx_abort, ++ .reset = NCR53c7xx_reset, ++ .can_queue = 24, ++ .this_id = 7, ++ .sg_tablesize = 63, ++ .cmd_per_lun = 3, ++ .use_clustering = DISABLE_CLUSTERING ++}; ++ ++ ++#include "scsi_module.c" +--- linux-m68k-2.6.21.orig/drivers/scsi/mvme16x.c ++++ /dev/null +@@ -1,78 +0,0 @@ +-/* +- * Detection routine for the NCR53c710 based MVME16x SCSI Controllers for Linux. +- * +- * Based on work by Alan Hourihane +- */ +-#include <linux/types.h> +-#include <linux/mm.h> +-#include <linux/blkdev.h> +- +-#include <asm/page.h> +-#include <asm/pgtable.h> +-#include <asm/mvme16xhw.h> +-#include <asm/irq.h> +- +-#include "scsi.h" +-#include <scsi/scsi_host.h> +-#include "53c7xx.h" +-#include "mvme16x.h" +- +-#include<linux/stat.h> +- +- +-int mvme16x_scsi_detect(struct scsi_host_template *tpnt) +-{ +- static unsigned char called = 0; +- int clock; +- long long options; +- +- if (!MACH_IS_MVME16x) +- return 0; +- if (mvme16x_config & MVME16x_CONFIG_NO_SCSICHIP) { +- printk ("SCSI detection disabled, SCSI chip not present\n"); +- return 0; +- } +- if (called) +- return 0; +- +- tpnt->proc_name = "MVME16x"; +- +- options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT; +- +- clock = 66000000; /* 66MHz SCSI Clock */ +- +- ncr53c7xx_init(tpnt, 0, 710, (unsigned long)0xfff47000, +- 0, MVME16x_IRQ_SCSI, DMA_NONE, +- options, clock); +- called = 1; +- return 1; +-} +- +-static int mvme16x_scsi_release(struct Scsi_Host *shost) +-{ +- if (shost->irq) +- free_irq(shost->irq, NULL); +- if (shost->dma_channel != 0xff) +- free_dma(shost->dma_channel); +- if (shost->io_port && shost->n_io_port) +- release_region(shost->io_port, shost->n_io_port); +- scsi_unregister(shost); +- return 0; +-} +- +-static struct scsi_host_template driver_template = { +- .name = "MVME16x NCR53c710 SCSI", +- .detect = mvme16x_scsi_detect, +- .release = mvme16x_scsi_release, +- .queuecommand = NCR53c7xx_queue_command, +- .abort = NCR53c7xx_abort, +- .reset = NCR53c7xx_reset, +- .can_queue = 24, +- .this_id = 7, +- .sg_tablesize = 63, +- .cmd_per_lun = 3, +- .use_clustering = DISABLE_CLUSTERING +-}; +- +- +-#include "scsi_module.c" +--- /dev/null ++++ linux-m68k-2.6.21/drivers/scsi/mvme16x_scsi.c +@@ -0,0 +1,78 @@ ++/* ++ * Detection routine for the NCR53c710 based MVME16x SCSI Controllers for Linux. ++ * ++ * Based on work by Alan Hourihane ++ */ ++#include <linux/types.h> ++#include <linux/mm.h> ++#include <linux/blkdev.h> ++ ++#include <asm/page.h> ++#include <asm/pgtable.h> ++#include <asm/mvme16xhw.h> ++#include <asm/irq.h> ++ ++#include "scsi.h" ++#include <scsi/scsi_host.h> ++#include "53c7xx.h" ++#include "mvme16x.h" ++ ++#include<linux/stat.h> ++ ++ ++int mvme16x_scsi_detect(struct scsi_host_template *tpnt) ++{ ++ static unsigned char called = 0; ++ int clock; ++ long long options; ++ ++ if (!MACH_IS_MVME16x) ++ return 0; ++ if (mvme16x_config & MVME16x_CONFIG_NO_SCSICHIP) { ++ printk ("SCSI detection disabled, SCSI chip not present\n"); ++ return 0; ++ } ++ if (called) ++ return 0; ++ ++ tpnt->proc_name = "MVME16x"; ++ ++ options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT; ++ ++ clock = 66000000; /* 66MHz SCSI Clock */ ++ ++ ncr53c7xx_init(tpnt, 0, 710, (unsigned long)0xfff47000, ++ 0, MVME16x_IRQ_SCSI, DMA_NONE, ++ options, clock); ++ called = 1; ++ return 1; ++} ++ ++static int mvme16x_scsi_release(struct Scsi_Host *shost) ++{ ++ if (shost->irq) ++ free_irq(shost->irq, NULL); ++ if (shost->dma_channel != 0xff) ++ free_dma(shost->dma_channel); ++ if (shost->io_port && shost->n_io_port) ++ release_region(shost->io_port, shost->n_io_port); ++ scsi_unregister(shost); ++ return 0; ++} ++ ++static struct scsi_host_template driver_template = { ++ .name = "MVME16x NCR53c710 SCSI", ++ .detect = mvme16x_scsi_detect, ++ .release = mvme16x_scsi_release, ++ .queuecommand = NCR53c7xx_queue_command, ++ .abort = NCR53c7xx_abort, ++ .reset = NCR53c7xx_reset, ++ .can_queue = 24, ++ .this_id = 7, ++ .sg_tablesize = 63, ++ .cmd_per_lun = 3, ++ .use_clustering = DISABLE_CLUSTERING ++}; ++ ++ ++#include "scsi_module.c" diff --git a/debian/patches/bugfix/m68k/m68k-reformat.diff b/debian/patches/bugfix/m68k/m68k-reformat.diff new file mode 100644 index 000000000000..d218533dd0c5 --- /dev/null +++ b/debian/patches/bugfix/m68k/m68k-reformat.diff @@ -0,0 +1,4818 @@ +Subject: [PATCH] m68k: reformat various m68k files + +From: Roman Zippel <zippel@linux-m68k.org> + +Reformat various m68k files, so they actually look like Linux sources. + +Signed-off-by: Roman Zippel <zippel@linux-m68k.org> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + arch/m68k/amiga/config.c | 1062 +++++++++++++++++++++++------------------------ + arch/m68k/atari/config.c | 983 ++++++++++++++++++++----------------------- + arch/m68k/atari/debug.c | 470 ++++++++++---------- + arch/m68k/kernel/entry.S | 2 + arch/m68k/kernel/head.S | 2 + arch/m68k/kernel/setup.c | 381 ++++++++-------- + arch/m68k/mac/config.c | 161 +++---- + arch/m68k/mac/debug.c | 331 +++++++------- + arch/m68k/q40/config.c | 259 +++++------ + arch/m68k/sun3x/prom.c | 121 ++--- + 10 files changed, 1856 insertions(+), 1916 deletions(-) + +--- linux-m68k-2.6.21.orig/arch/m68k/amiga/config.c ++++ linux-m68k-2.6.21/arch/m68k/amiga/config.c +@@ -22,9 +22,7 @@ + #include <linux/vt_kern.h> + #include <linux/delay.h> + #include <linux/interrupt.h> +-#ifdef CONFIG_ZORRO + #include <linux/zorro.h> +-#endif + + #include <asm/bootinfo.h> + #include <asm/setup.h> +@@ -62,21 +60,21 @@ static char s_cdtv[] __initdata = "CDTV" + static char s_cd32[] __initdata = "CD32"; + static char s_draco[] __initdata = "Draco"; + static char *amiga_models[] __initdata = { +- [AMI_500-AMI_500] = s_a500, +- [AMI_500PLUS-AMI_500] = s_a500p, +- [AMI_600-AMI_500] = s_a600, +- [AMI_1000-AMI_500] = s_a1000, +- [AMI_1200-AMI_500] = s_a1200, +- [AMI_2000-AMI_500] = s_a2000, +- [AMI_2500-AMI_500] = s_a2500, +- [AMI_3000-AMI_500] = s_a3000, +- [AMI_3000T-AMI_500] = s_a3000t, +- [AMI_3000PLUS-AMI_500] = s_a3000p, +- [AMI_4000-AMI_500] = s_a4000, +- [AMI_4000T-AMI_500] = s_a4000t, +- [AMI_CDTV-AMI_500] = s_cdtv, +- [AMI_CD32-AMI_500] = s_cd32, +- [AMI_DRACO-AMI_500] = s_draco, ++ [AMI_500-AMI_500] = s_a500, ++ [AMI_500PLUS-AMI_500] = s_a500p, ++ [AMI_600-AMI_500] = s_a600, ++ [AMI_1000-AMI_500] = s_a1000, ++ [AMI_1200-AMI_500] = s_a1200, ++ [AMI_2000-AMI_500] = s_a2000, ++ [AMI_2500-AMI_500] = s_a2500, ++ [AMI_3000-AMI_500] = s_a3000, ++ [AMI_3000T-AMI_500] = s_a3000t, ++ [AMI_3000PLUS-AMI_500] = s_a3000p, ++ [AMI_4000-AMI_500] = s_a4000, ++ [AMI_4000T-AMI_500] = s_a4000t, ++ [AMI_CDTV-AMI_500] = s_cdtv, ++ [AMI_CD32-AMI_500] = s_cd32, ++ [AMI_DRACO-AMI_500] = s_draco, + }; + + static char amiga_model_name[13] = "Amiga "; +@@ -85,17 +83,17 @@ extern char m68k_debug_device[]; + + static void amiga_sched_init(irq_handler_t handler); + /* amiga specific irq functions */ +-extern void amiga_init_IRQ (void); ++extern void amiga_init_IRQ(void); + static void amiga_get_model(char *model); + static int amiga_get_hardware_list(char *buffer); + /* amiga specific timer functions */ +-static unsigned long amiga_gettimeoffset (void); +-static int a3000_hwclk (int, struct rtc_time *); +-static int a2000_hwclk (int, struct rtc_time *); +-static int amiga_set_clock_mmss (unsigned long); +-static unsigned int amiga_get_ss (void); +-extern void amiga_mksound( unsigned int count, unsigned int ticks ); +-static void amiga_reset (void); ++static unsigned long amiga_gettimeoffset(void); ++static int a3000_hwclk(int, struct rtc_time *); ++static int a2000_hwclk(int, struct rtc_time *); ++static int amiga_set_clock_mmss(unsigned long); ++static unsigned int amiga_get_ss(void); ++extern void amiga_mksound(unsigned int count, unsigned int ticks); ++static void amiga_reset(void); + extern void amiga_init_sound(void); + static void amiga_savekmsg_init(void); + static void amiga_mem_console_write(struct console *co, const char *b, +@@ -108,9 +106,9 @@ static void amiga_heartbeat(int on); + #endif + + static struct console amiga_console_driver = { +- .name = "debug", +- .flags = CON_PRINTBUFFER, +- .index = -1, ++ .name = "debug", ++ .flags = CON_PRINTBUFFER, ++ .index = -1, + }; + + +@@ -119,24 +117,24 @@ static struct console amiga_console_driv + */ + + static struct { +- struct resource _ciab, _ciaa, _custom, _kickstart; ++ struct resource _ciab, _ciaa, _custom, _kickstart; + } mb_resources = { +- ._ciab = { +- .name = "CIA B", .start = 0x00bfd000, .end = 0x00bfdfff +- }, +- ._ciaa = { +- .name = "CIA A", .start = 0x00bfe000, .end = 0x00bfefff +- }, +- ._custom = { +- .name = "Custom I/O", .start = 0x00dff000, .end = 0x00dfffff +- }, +- ._kickstart = { +- .name = "Kickstart ROM", .start = 0x00f80000, .end = 0x00ffffff +- } ++ ._ciab = { ++ .name = "CIA B", .start = 0x00bfd000, .end = 0x00bfdfff ++ }, ++ ._ciaa = { ++ .name = "CIA A", .start = 0x00bfe000, .end = 0x00bfefff ++ }, ++ ._custom = { ++ .name = "Custom I/O", .start = 0x00dff000, .end = 0x00dfffff ++ }, ++ ._kickstart = { ++ .name = "Kickstart ROM", .start = 0x00f80000, .end = 0x00ffffff ++ } + }; + + static struct resource rtc_resource = { +- .start = 0x00dc0000, .end = 0x00dcffff ++ .start = 0x00dc0000, .end = 0x00dcffff + }; + + static struct resource ram_resource[NUM_MEMINFO]; +@@ -148,57 +146,57 @@ static struct resource ram_resource[NUM_ + + int amiga_parse_bootinfo(const struct bi_record *record) + { +- int unknown = 0; +- const unsigned long *data = record->data; ++ int unknown = 0; ++ const unsigned long *data = record->data; + +- switch (record->tag) { ++ switch (record->tag) { + case BI_AMIGA_MODEL: +- amiga_model = *data; +- break; ++ amiga_model = *data; ++ break; + + case BI_AMIGA_ECLOCK: +- amiga_eclock = *data; +- break; ++ amiga_eclock = *data; ++ break; + + case BI_AMIGA_CHIPSET: +- amiga_chipset = *data; +- break; ++ amiga_chipset = *data; ++ break; + + case BI_AMIGA_CHIP_SIZE: +- amiga_chip_size = *(const int *)data; +- break; ++ amiga_chip_size = *(const int *)data; ++ break; + + case BI_AMIGA_VBLANK: +- amiga_vblank = *(const unsigned char *)data; +- break; ++ amiga_vblank = *(const unsigned char *)data; ++ break; + + case BI_AMIGA_PSFREQ: +- amiga_psfreq = *(const unsigned char *)data; +- break; ++ amiga_psfreq = *(const unsigned char *)data; ++ break; + + case BI_AMIGA_AUTOCON: + #ifdef CONFIG_ZORRO +- if (zorro_num_autocon < ZORRO_NUM_AUTO) { +- const struct ConfigDev *cd = (struct ConfigDev *)data; +- struct zorro_dev *dev = &zorro_autocon[zorro_num_autocon++]; +- dev->rom = cd->cd_Rom; +- dev->slotaddr = cd->cd_SlotAddr; +- dev->slotsize = cd->cd_SlotSize; +- dev->resource.start = (unsigned long)cd->cd_BoardAddr; +- dev->resource.end = dev->resource.start+cd->cd_BoardSize-1; +- } else +- printk("amiga_parse_bootinfo: too many AutoConfig devices\n"); ++ if (zorro_num_autocon < ZORRO_NUM_AUTO) { ++ const struct ConfigDev *cd = (struct ConfigDev *)data; ++ struct zorro_dev *dev = &zorro_autocon[zorro_num_autocon++]; ++ dev->rom = cd->cd_Rom; ++ dev->slotaddr = cd->cd_SlotAddr; ++ dev->slotsize = cd->cd_SlotSize; ++ dev->resource.start = (unsigned long)cd->cd_BoardAddr; ++ dev->resource.end = dev->resource.start + cd->cd_BoardSize - 1; ++ } else ++ printk("amiga_parse_bootinfo: too many AutoConfig devices\n"); + #endif /* CONFIG_ZORRO */ +- break; ++ break; + + case BI_AMIGA_SERPER: +- /* serial port period: ignored here */ +- break; ++ /* serial port period: ignored here */ ++ break; + + default: +- unknown = 1; +- } +- return(unknown); ++ unknown = 1; ++ } ++ return unknown; + } + + /* +@@ -207,159 +205,159 @@ int amiga_parse_bootinfo(const struct bi + + static void __init amiga_identify(void) + { +- /* Fill in some default values, if necessary */ +- if (amiga_eclock == 0) +- amiga_eclock = 709379; +- +- memset(&amiga_hw_present, 0, sizeof(amiga_hw_present)); +- +- printk("Amiga hardware found: "); +- if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) { +- printk("[%s] ", amiga_models[amiga_model-AMI_500]); +- strcat(amiga_model_name, amiga_models[amiga_model-AMI_500]); +- } +- +- switch(amiga_model) { +- case AMI_UNKNOWN: +- goto Generic; +- +- case AMI_600: +- case AMI_1200: +- AMIGAHW_SET(A1200_IDE); +- AMIGAHW_SET(PCMCIA); +- case AMI_500: +- case AMI_500PLUS: +- case AMI_1000: +- case AMI_2000: +- case AMI_2500: +- AMIGAHW_SET(A2000_CLK); /* Is this correct for all models? */ +- goto Generic; +- +- case AMI_3000: +- case AMI_3000T: +- AMIGAHW_SET(AMBER_FF); +- AMIGAHW_SET(MAGIC_REKICK); +- /* fall through */ +- case AMI_3000PLUS: +- AMIGAHW_SET(A3000_SCSI); +- AMIGAHW_SET(A3000_CLK); +- AMIGAHW_SET(ZORRO3); +- goto Generic; +- +- case AMI_4000T: +- AMIGAHW_SET(A4000_SCSI); +- /* fall through */ +- case AMI_4000: +- AMIGAHW_SET(A4000_IDE); +- AMIGAHW_SET(A3000_CLK); +- AMIGAHW_SET(ZORRO3); +- goto Generic; +- +- case AMI_CDTV: +- case AMI_CD32: +- AMIGAHW_SET(CD_ROM); +- AMIGAHW_SET(A2000_CLK); /* Is this correct? */ +- goto Generic; +- +- Generic: +- AMIGAHW_SET(AMI_VIDEO); +- AMIGAHW_SET(AMI_BLITTER); +- AMIGAHW_SET(AMI_AUDIO); +- AMIGAHW_SET(AMI_FLOPPY); +- AMIGAHW_SET(AMI_KEYBOARD); +- AMIGAHW_SET(AMI_MOUSE); +- AMIGAHW_SET(AMI_SERIAL); +- AMIGAHW_SET(AMI_PARALLEL); +- AMIGAHW_SET(CHIP_RAM); +- AMIGAHW_SET(PAULA); +- +- switch(amiga_chipset) { +- case CS_OCS: +- case CS_ECS: +- case CS_AGA: +- switch (amiga_custom.deniseid & 0xf) { +- case 0x0c: +- AMIGAHW_SET(DENISE_HR); +- break; +- case 0x08: +- AMIGAHW_SET(LISA); +- break; +- } +- break; +- default: +- AMIGAHW_SET(DENISE); +- break; +- } +- switch ((amiga_custom.vposr>>8) & 0x7f) { +- case 0x00: +- AMIGAHW_SET(AGNUS_PAL); +- break; +- case 0x10: +- AMIGAHW_SET(AGNUS_NTSC); +- break; +- case 0x20: +- case 0x21: +- AMIGAHW_SET(AGNUS_HR_PAL); +- break; +- case 0x30: +- case 0x31: +- AMIGAHW_SET(AGNUS_HR_NTSC); +- break; +- case 0x22: +- case 0x23: +- AMIGAHW_SET(ALICE_PAL); +- break; +- case 0x32: +- case 0x33: +- AMIGAHW_SET(ALICE_NTSC); +- break; +- } +- AMIGAHW_SET(ZORRO); +- break; +- +- case AMI_DRACO: +- panic("No support for Draco yet"); +- +- default: +- panic("Unknown Amiga Model"); +- } ++ /* Fill in some default values, if necessary */ ++ if (amiga_eclock == 0) ++ amiga_eclock = 709379; ++ ++ memset(&amiga_hw_present, 0, sizeof(amiga_hw_present)); ++ ++ printk("Amiga hardware found: "); ++ if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) { ++ printk("[%s] ", amiga_models[amiga_model-AMI_500]); ++ strcat(amiga_model_name, amiga_models[amiga_model-AMI_500]); ++ } ++ ++ switch (amiga_model) { ++ case AMI_UNKNOWN: ++ goto Generic; ++ ++ case AMI_600: ++ case AMI_1200: ++ AMIGAHW_SET(A1200_IDE); ++ AMIGAHW_SET(PCMCIA); ++ case AMI_500: ++ case AMI_500PLUS: ++ case AMI_1000: ++ case AMI_2000: ++ case AMI_2500: ++ AMIGAHW_SET(A2000_CLK); /* Is this correct for all models? */ ++ goto Generic; ++ ++ case AMI_3000: ++ case AMI_3000T: ++ AMIGAHW_SET(AMBER_FF); ++ AMIGAHW_SET(MAGIC_REKICK); ++ /* fall through */ ++ case AMI_3000PLUS: ++ AMIGAHW_SET(A3000_SCSI); ++ AMIGAHW_SET(A3000_CLK); ++ AMIGAHW_SET(ZORRO3); ++ goto Generic; ++ ++ case AMI_4000T: ++ AMIGAHW_SET(A4000_SCSI); ++ /* fall through */ ++ case AMI_4000: ++ AMIGAHW_SET(A4000_IDE); ++ AMIGAHW_SET(A3000_CLK); ++ AMIGAHW_SET(ZORRO3); ++ goto Generic; ++ ++ case AMI_CDTV: ++ case AMI_CD32: ++ AMIGAHW_SET(CD_ROM); ++ AMIGAHW_SET(A2000_CLK); /* Is this correct? */ ++ goto Generic; ++ ++ Generic: ++ AMIGAHW_SET(AMI_VIDEO); ++ AMIGAHW_SET(AMI_BLITTER); ++ AMIGAHW_SET(AMI_AUDIO); ++ AMIGAHW_SET(AMI_FLOPPY); ++ AMIGAHW_SET(AMI_KEYBOARD); ++ AMIGAHW_SET(AMI_MOUSE); ++ AMIGAHW_SET(AMI_SERIAL); ++ AMIGAHW_SET(AMI_PARALLEL); ++ AMIGAHW_SET(CHIP_RAM); ++ AMIGAHW_SET(PAULA); ++ ++ switch (amiga_chipset) { ++ case CS_OCS: ++ case CS_ECS: ++ case CS_AGA: ++ switch (amiga_custom.deniseid & 0xf) { ++ case 0x0c: ++ AMIGAHW_SET(DENISE_HR); ++ break; ++ case 0x08: ++ AMIGAHW_SET(LISA); ++ break; ++ } ++ break; ++ default: ++ AMIGAHW_SET(DENISE); ++ break; ++ } ++ switch ((amiga_custom.vposr>>8) & 0x7f) { ++ case 0x00: ++ AMIGAHW_SET(AGNUS_PAL); ++ break; ++ case 0x10: ++ AMIGAHW_SET(AGNUS_NTSC); ++ break; ++ case 0x20: ++ case 0x21: ++ AMIGAHW_SET(AGNUS_HR_PAL); ++ break; ++ case 0x30: ++ case 0x31: ++ AMIGAHW_SET(AGNUS_HR_NTSC); ++ break; ++ case 0x22: ++ case 0x23: ++ AMIGAHW_SET(ALICE_PAL); ++ break; ++ case 0x32: ++ case 0x33: ++ AMIGAHW_SET(ALICE_NTSC); ++ break; ++ } ++ AMIGAHW_SET(ZORRO); ++ break; + +-#define AMIGAHW_ANNOUNCE(name, str) \ +- if (AMIGAHW_PRESENT(name)) \ +- printk(str) ++ case AMI_DRACO: ++ panic("No support for Draco yet"); ++ ++ default: ++ panic("Unknown Amiga Model"); ++ } + +- AMIGAHW_ANNOUNCE(AMI_VIDEO, "VIDEO "); +- AMIGAHW_ANNOUNCE(AMI_BLITTER, "BLITTER "); +- AMIGAHW_ANNOUNCE(AMBER_FF, "AMBER_FF "); +- AMIGAHW_ANNOUNCE(AMI_AUDIO, "AUDIO "); +- AMIGAHW_ANNOUNCE(AMI_FLOPPY, "FLOPPY "); +- AMIGAHW_ANNOUNCE(A3000_SCSI, "A3000_SCSI "); +- AMIGAHW_ANNOUNCE(A4000_SCSI, "A4000_SCSI "); +- AMIGAHW_ANNOUNCE(A1200_IDE, "A1200_IDE "); +- AMIGAHW_ANNOUNCE(A4000_IDE, "A4000_IDE "); +- AMIGAHW_ANNOUNCE(CD_ROM, "CD_ROM "); +- AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "KEYBOARD "); +- AMIGAHW_ANNOUNCE(AMI_MOUSE, "MOUSE "); +- AMIGAHW_ANNOUNCE(AMI_SERIAL, "SERIAL "); +- AMIGAHW_ANNOUNCE(AMI_PARALLEL, "PARALLEL "); +- AMIGAHW_ANNOUNCE(A2000_CLK, "A2000_CLK "); +- AMIGAHW_ANNOUNCE(A3000_CLK, "A3000_CLK "); +- AMIGAHW_ANNOUNCE(CHIP_RAM, "CHIP_RAM "); +- AMIGAHW_ANNOUNCE(PAULA, "PAULA "); +- AMIGAHW_ANNOUNCE(DENISE, "DENISE "); +- AMIGAHW_ANNOUNCE(DENISE_HR, "DENISE_HR "); +- AMIGAHW_ANNOUNCE(LISA, "LISA "); +- AMIGAHW_ANNOUNCE(AGNUS_PAL, "AGNUS_PAL "); +- AMIGAHW_ANNOUNCE(AGNUS_NTSC, "AGNUS_NTSC "); +- AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "AGNUS_HR_PAL "); +- AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "AGNUS_HR_NTSC "); +- AMIGAHW_ANNOUNCE(ALICE_PAL, "ALICE_PAL "); +- AMIGAHW_ANNOUNCE(ALICE_NTSC, "ALICE_NTSC "); +- AMIGAHW_ANNOUNCE(MAGIC_REKICK, "MAGIC_REKICK "); +- AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA "); +- if (AMIGAHW_PRESENT(ZORRO)) +- printk("ZORRO%s ", AMIGAHW_PRESENT(ZORRO3) ? "3" : ""); +- printk("\n"); ++#define AMIGAHW_ANNOUNCE(name, str) \ ++ if (AMIGAHW_PRESENT(name)) \ ++ printk(str) ++ ++ AMIGAHW_ANNOUNCE(AMI_VIDEO, "VIDEO "); ++ AMIGAHW_ANNOUNCE(AMI_BLITTER, "BLITTER "); ++ AMIGAHW_ANNOUNCE(AMBER_FF, "AMBER_FF "); ++ AMIGAHW_ANNOUNCE(AMI_AUDIO, "AUDIO "); ++ AMIGAHW_ANNOUNCE(AMI_FLOPPY, "FLOPPY "); ++ AMIGAHW_ANNOUNCE(A3000_SCSI, "A3000_SCSI "); ++ AMIGAHW_ANNOUNCE(A4000_SCSI, "A4000_SCSI "); ++ AMIGAHW_ANNOUNCE(A1200_IDE, "A1200_IDE "); ++ AMIGAHW_ANNOUNCE(A4000_IDE, "A4000_IDE "); ++ AMIGAHW_ANNOUNCE(CD_ROM, "CD_ROM "); ++ AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "KEYBOARD "); ++ AMIGAHW_ANNOUNCE(AMI_MOUSE, "MOUSE "); ++ AMIGAHW_ANNOUNCE(AMI_SERIAL, "SERIAL "); ++ AMIGAHW_ANNOUNCE(AMI_PARALLEL, "PARALLEL "); ++ AMIGAHW_ANNOUNCE(A2000_CLK, "A2000_CLK "); ++ AMIGAHW_ANNOUNCE(A3000_CLK, "A3000_CLK "); ++ AMIGAHW_ANNOUNCE(CHIP_RAM, "CHIP_RAM "); ++ AMIGAHW_ANNOUNCE(PAULA, "PAULA "); ++ AMIGAHW_ANNOUNCE(DENISE, "DENISE "); ++ AMIGAHW_ANNOUNCE(DENISE_HR, "DENISE_HR "); ++ AMIGAHW_ANNOUNCE(LISA, "LISA "); ++ AMIGAHW_ANNOUNCE(AGNUS_PAL, "AGNUS_PAL "); ++ AMIGAHW_ANNOUNCE(AGNUS_NTSC, "AGNUS_NTSC "); ++ AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "AGNUS_HR_PAL "); ++ AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "AGNUS_HR_NTSC "); ++ AMIGAHW_ANNOUNCE(ALICE_PAL, "ALICE_PAL "); ++ AMIGAHW_ANNOUNCE(ALICE_NTSC, "ALICE_NTSC "); ++ AMIGAHW_ANNOUNCE(MAGIC_REKICK, "MAGIC_REKICK "); ++ AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA "); ++ if (AMIGAHW_PRESENT(ZORRO)) ++ printk("ZORRO%s ", AMIGAHW_PRESENT(ZORRO3) ? "3" : ""); ++ printk("\n"); + + #undef AMIGAHW_ANNOUNCE + } +@@ -370,119 +368,117 @@ static void __init amiga_identify(void) + + void __init config_amiga(void) + { +- int i; ++ int i; ++ ++ amiga_debug_init(); ++ amiga_identify(); + +- amiga_debug_init(); +- amiga_identify(); ++ /* Yuk, we don't have PCI memory */ ++ iomem_resource.name = "Memory"; ++ for (i = 0; i < 4; i++) ++ request_resource(&iomem_resource, &((struct resource *)&mb_resources)[i]); ++ ++ mach_sched_init = amiga_sched_init; ++ mach_init_IRQ = amiga_init_IRQ; ++ mach_get_model = amiga_get_model; ++ mach_get_hardware_list = amiga_get_hardware_list; ++ mach_gettimeoffset = amiga_gettimeoffset; ++ if (AMIGAHW_PRESENT(A3000_CLK)) { ++ mach_hwclk = a3000_hwclk; ++ rtc_resource.name = "A3000 RTC"; ++ request_resource(&iomem_resource, &rtc_resource); ++ } else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ { ++ mach_hwclk = a2000_hwclk; ++ rtc_resource.name = "A2000 RTC"; ++ request_resource(&iomem_resource, &rtc_resource); ++ } + +- /* Yuk, we don't have PCI memory */ +- iomem_resource.name = "Memory"; +- for (i = 0; i < 4; i++) +- request_resource(&iomem_resource, &((struct resource *)&mb_resources)[i]); +- +- mach_sched_init = amiga_sched_init; +- mach_init_IRQ = amiga_init_IRQ; +- mach_get_model = amiga_get_model; +- mach_get_hardware_list = amiga_get_hardware_list; +- mach_gettimeoffset = amiga_gettimeoffset; +- if (AMIGAHW_PRESENT(A3000_CLK)){ +- mach_hwclk = a3000_hwclk; +- rtc_resource.name = "A3000 RTC"; +- request_resource(&iomem_resource, &rtc_resource); +- } +- else{ /* if (AMIGAHW_PRESENT(A2000_CLK)) */ +- mach_hwclk = a2000_hwclk; +- rtc_resource.name = "A2000 RTC"; +- request_resource(&iomem_resource, &rtc_resource); +- } +- +- mach_max_dma_address = 0xffffffff; /* +- * default MAX_DMA=0xffffffff +- * on all machines. If we don't +- * do so, the SCSI code will not +- * be able to allocate any mem +- * for transfers, unless we are +- * dealing with a Z2 mem only +- * system. /Jes +- */ +- +- mach_set_clock_mmss = amiga_set_clock_mmss; +- mach_get_ss = amiga_get_ss; +- mach_reset = amiga_reset; ++ /* ++ * default MAX_DMA=0xffffffff on all machines. If we don't do so, the SCSI ++ * code will not be able to allocate any mem for transfers, unless we are ++ * dealing with a Z2 mem only system. /Jes ++ */ ++ mach_max_dma_address = 0xffffffff; ++ ++ mach_set_clock_mmss = amiga_set_clock_mmss; ++ mach_get_ss = amiga_get_ss; ++ mach_reset = amiga_reset; + #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE) +- mach_beep = amiga_mksound; ++ mach_beep = amiga_mksound; + #endif + + #ifdef CONFIG_HEARTBEAT +- mach_heartbeat = amiga_heartbeat; ++ mach_heartbeat = amiga_heartbeat; + #endif + +- /* Fill in the clock values (based on the 700 kHz E-Clock) */ +- amiga_masterclock = 40*amiga_eclock; /* 28 MHz */ +- amiga_colorclock = 5*amiga_eclock; /* 3.5 MHz */ +- +- /* clear all DMA bits */ +- amiga_custom.dmacon = DMAF_ALL; +- /* ensure that the DMA master bit is set */ +- amiga_custom.dmacon = DMAF_SETCLR | DMAF_MASTER; +- +- /* don't use Z2 RAM as system memory on Z3 capable machines */ +- if (AMIGAHW_PRESENT(ZORRO3)) { +- int i, j; +- u32 disabled_z2mem = 0; +- for (i = 0; i < m68k_num_memory; i++) +- if (m68k_memory[i].addr < 16*1024*1024) { +- if (i == 0) { +- /* don't cut off the branch we're sitting on */ +- printk("Warning: kernel runs in Zorro II memory\n"); +- continue; +- } +- disabled_z2mem += m68k_memory[i].size; +- m68k_num_memory--; +- for (j = i; j < m68k_num_memory; j++) +- m68k_memory[j] = m68k_memory[j+1]; +- i--; +- } +- if (disabled_z2mem) +- printk("%dK of Zorro II memory will not be used as system memory\n", +- disabled_z2mem>>10); +- } +- +- /* request all RAM */ +- for (i = 0; i < m68k_num_memory; i++) { +- ram_resource[i].name = +- (m68k_memory[i].addr >= 0x01000000) ? "32-bit Fast RAM" : +- (m68k_memory[i].addr < 0x00c00000) ? "16-bit Fast RAM" : +- "16-bit Slow RAM"; +- ram_resource[i].start = m68k_memory[i].addr; +- ram_resource[i].end = m68k_memory[i].addr+m68k_memory[i].size-1; +- request_resource(&iomem_resource, &ram_resource[i]); +- } +- +- /* initialize chipram allocator */ +- amiga_chip_init (); +- +- /* debugging using chipram */ +- if (!strcmp( m68k_debug_device, "mem" )){ +- if (!AMIGAHW_PRESENT(CHIP_RAM)) +- printk("Warning: no chipram present for debugging\n"); +- else { +- amiga_savekmsg_init(); +- amiga_console_driver.write = amiga_mem_console_write; +- register_console(&amiga_console_driver); +- } +- } +- +- /* our beloved beeper */ +- if (AMIGAHW_PRESENT(AMI_AUDIO)) +- amiga_init_sound(); +- +- /* +- * if it is an A3000, set the magic bit that forces +- * a hard rekick +- */ +- if (AMIGAHW_PRESENT(MAGIC_REKICK)) +- *(unsigned char *)ZTWO_VADDR(0xde0002) |= 0x80; ++ /* Fill in the clock values (based on the 700 kHz E-Clock) */ ++ amiga_masterclock = 40*amiga_eclock; /* 28 MHz */ ++ amiga_colorclock = 5*amiga_eclock; /* 3.5 MHz */ ++ ++ /* clear all DMA bits */ ++ amiga_custom.dmacon = DMAF_ALL; ++ /* ensure that the DMA master bit is set */ ++ amiga_custom.dmacon = DMAF_SETCLR | DMAF_MASTER; ++ ++ /* don't use Z2 RAM as system memory on Z3 capable machines */ ++ if (AMIGAHW_PRESENT(ZORRO3)) { ++ int i, j; ++ u32 disabled_z2mem = 0; ++ ++ for (i = 0; i < m68k_num_memory; i++) { ++ if (m68k_memory[i].addr < 16*1024*1024) { ++ if (i == 0) { ++ /* don't cut off the branch we're sitting on */ ++ printk("Warning: kernel runs in Zorro II memory\n"); ++ continue; ++ } ++ disabled_z2mem += m68k_memory[i].size; ++ m68k_num_memory--; ++ for (j = i; j < m68k_num_memory; j++) ++ m68k_memory[j] = m68k_memory[j+1]; ++ i--; ++ } ++ } ++ if (disabled_z2mem) ++ printk("%dK of Zorro II memory will not be used as system memory\n", ++ disabled_z2mem>>10); ++ } ++ ++ /* request all RAM */ ++ for (i = 0; i < m68k_num_memory; i++) { ++ ram_resource[i].name = ++ (m68k_memory[i].addr >= 0x01000000) ? "32-bit Fast RAM" : ++ (m68k_memory[i].addr < 0x00c00000) ? "16-bit Fast RAM" : ++ "16-bit Slow RAM"; ++ ram_resource[i].start = m68k_memory[i].addr; ++ ram_resource[i].end = m68k_memory[i].addr+m68k_memory[i].size-1; ++ request_resource(&iomem_resource, &ram_resource[i]); ++ } ++ ++ /* initialize chipram allocator */ ++ amiga_chip_init(); ++ ++ /* debugging using chipram */ ++ if (!strcmp(m68k_debug_device, "mem")) { ++ if (!AMIGAHW_PRESENT(CHIP_RAM)) ++ printk("Warning: no chipram present for debugging\n"); ++ else { ++ amiga_savekmsg_init(); ++ amiga_console_driver.write = amiga_mem_console_write; ++ register_console(&amiga_console_driver); ++ } ++ } ++ ++ /* our beloved beeper */ ++ if (AMIGAHW_PRESENT(AMI_AUDIO)) ++ amiga_init_sound(); ++ ++ /* ++ * if it is an A3000, set the magic bit that forces ++ * a hard rekick ++ */ ++ if (AMIGAHW_PRESENT(MAGIC_REKICK)) ++ *(unsigned char *)ZTWO_VADDR(0xde0002) |= 0x80; + } + + static unsigned short jiffy_ticks; +@@ -490,12 +486,12 @@ static unsigned short jiffy_ticks; + static void __init amiga_sched_init(irq_handler_t timer_routine) + { + static struct resource sched_res = { +- .name = "timer", .start = 0x00bfd400, .end = 0x00bfd5ff, ++ .name = "timer", .start = 0x00bfd400, .end = 0x00bfd5ff, + }; + jiffy_ticks = (amiga_eclock+HZ/2)/HZ; + + if (request_resource(&mb_resources._ciab, &sched_res)) +- printk("Cannot allocate ciab.ta{lo,hi}\n"); ++ printk("Cannot allocate ciab.ta{lo,hi}\n"); + ciab.cra &= 0xC0; /* turn off timer A, continuous mode, from Eclk */ + ciab.talo = jiffy_ticks % 256; + ciab.tahi = jiffy_ticks / 256; +@@ -513,7 +509,7 @@ static void __init amiga_sched_init(irq_ + #define TICK_SIZE 10000 + + /* This is always executed with interrupts disabled. */ +-static unsigned long amiga_gettimeoffset (void) ++static unsigned long amiga_gettimeoffset(void) + { + unsigned short hi, lo, hi2; + unsigned long ticks, offset = 0; +@@ -585,15 +581,15 @@ static int a2000_hwclk(int op, struct rt + + tod_2000.cntrl1 = TOD2000_CNTRL1_HOLD; + +- while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--) +- { +- tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD; +- udelay(70); +- tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD; ++ while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--) { ++ tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD; ++ udelay(70); ++ tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD; + } + + if (!cnt) +- printk(KERN_INFO "hwclk: timed out waiting for RTC (0x%x)\n", tod_2000.cntrl1); ++ printk(KERN_INFO "hwclk: timed out waiting for RTC (0x%x)\n", ++ tod_2000.cntrl1); + + if (!op) { /* read */ + t->tm_sec = tod_2000.second1 * 10 + tod_2000.second2; +@@ -606,7 +602,7 @@ static int a2000_hwclk(int op, struct rt + if (t->tm_year <= 69) + t->tm_year += 100; + +- if (!(tod_2000.cntrl3 & TOD2000_CNTRL3_24HMODE)){ ++ if (!(tod_2000.cntrl3 & TOD2000_CNTRL3_24HMODE)) { + if (!(tod_2000.hour1 & TOD2000_HOUR1_PM) && t->tm_hour == 12) + t->tm_hour = 0; + else if ((tod_2000.hour1 & TOD2000_HOUR1_PM) && t->tm_hour != 12) +@@ -642,7 +638,7 @@ static int a2000_hwclk(int op, struct rt + return 0; + } + +-static int amiga_set_clock_mmss (unsigned long nowtime) ++static int amiga_set_clock_mmss(unsigned long nowtime) + { + short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; + +@@ -660,8 +656,7 @@ static int amiga_set_clock_mmss (unsigne + + tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD; + +- while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--) +- { ++ while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--) { + tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD; + udelay(70); + tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD; +@@ -681,7 +676,7 @@ static int amiga_set_clock_mmss (unsigne + return 0; + } + +-static unsigned int amiga_get_ss( void ) ++static unsigned int amiga_get_ss(void) + { + unsigned int s; + +@@ -695,71 +690,72 @@ static unsigned int amiga_get_ss( void ) + return s; + } + +-static NORET_TYPE void amiga_reset( void ) ++static NORET_TYPE void amiga_reset(void) + ATTRIB_NORET; + +-static void amiga_reset (void) ++static void amiga_reset(void) + { +- unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040); +- unsigned long jmp_addr = virt_to_phys(&&jmp_addr_label); +- +- local_irq_disable(); +- if (CPU_IS_040_OR_060) +- /* Setup transparent translation registers for mapping +- * of 16 MB kernel segment before disabling translation +- */ +- __asm__ __volatile__ +- ("movel %0,%/d0\n\t" +- "andl #0xff000000,%/d0\n\t" +- "orw #0xe020,%/d0\n\t" /* map 16 MB, enable, cacheable */ +- ".chip 68040\n\t" +- "movec %%d0,%%itt0\n\t" +- "movec %%d0,%%dtt0\n\t" +- ".chip 68k\n\t" +- "jmp %0@\n\t" +- : /* no outputs */ +- : "a" (jmp_addr040)); +- else +- /* for 680[23]0, just disable translation and jump to the physical +- * address of the label +- */ +- __asm__ __volatile__ +- ("pmove %/tc,%@\n\t" +- "bclr #7,%@\n\t" +- "pmove %@,%/tc\n\t" +- "jmp %0@\n\t" +- : /* no outputs */ +- : "a" (jmp_addr)); +- jmp_addr_label040: +- /* disable translation on '040 now */ +- __asm__ __volatile__ +- ("moveq #0,%/d0\n\t" +- ".chip 68040\n\t" +- "movec %%d0,%%tc\n\t" /* disable MMU */ +- ".chip 68k\n\t" +- : /* no outputs */ +- : /* no inputs */ +- : "d0"); +- +- jmp_addr_label: +- /* pickup reset address from AmigaOS ROM, reset devices and jump +- * to reset address +- */ +- __asm__ __volatile__ +- ("movew #0x2700,%/sr\n\t" +- "leal 0x01000000,%/a0\n\t" +- "subl %/a0@(-0x14),%/a0\n\t" +- "movel %/a0@(4),%/a0\n\t" +- "subql #2,%/a0\n\t" +- "bra 1f\n\t" +- /* align on a longword boundary */ +- __ALIGN_STR "\n" +- "1:\n\t" +- "reset\n\t" +- "jmp %/a0@" : /* Just that gcc scans it for % escapes */ ); ++ unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040); ++ unsigned long jmp_addr = virt_to_phys(&&jmp_addr_label); + +- for (;;); ++ local_irq_disable(); ++ if (CPU_IS_040_OR_060) ++ /* Setup transparent translation registers for mapping ++ * of 16 MB kernel segment before disabling translation ++ */ ++ asm volatile ("\n" ++ " move.l %0,%%d0\n" ++ " and.l #0xff000000,%%d0\n" ++ " or.w #0xe020,%%d0\n" /* map 16 MB, enable, cacheable */ ++ " .chip 68040\n" ++ " movec %%d0,%%itt0\n" ++ " movec %%d0,%%dtt0\n" ++ " .chip 68k\n" ++ " jmp %0@\n" ++ : /* no outputs */ ++ : "a" (jmp_addr040) ++ : "d0"); ++ else ++ /* for 680[23]0, just disable translation and jump to the physical ++ * address of the label ++ */ ++ asm volatile ("\n" ++ " pmove %%tc,%@\n" ++ " bclr #7,%@\n" ++ " pmove %@,%%tc\n" ++ " jmp %0@\n" ++ : /* no outputs */ ++ : "a" (jmp_addr)); ++jmp_addr_label040: ++ /* disable translation on '040 now */ ++ asm volatile ("\n" ++ " moveq #0,%%d0\n" ++ " .chip 68040\n" ++ " movec %%d0,%%tc\n" /* disable MMU */ ++ " .chip 68k\n" ++ : /* no outputs */ ++ : /* no inputs */ ++ : "d0"); ++ ++ jmp_addr_label: ++ /* pickup reset address from AmigaOS ROM, reset devices and jump ++ * to reset address ++ */ ++ asm volatile ("\n" ++ " move.w #0x2700,%sr\n" ++ " lea 0x01000000,%a0\n" ++ " sub.l %a0@(-0x14),%a0\n" ++ " move.l %a0@(4),%a0\n" ++ " subq.l #2,%a0\n" ++ " jra 1f\n" ++ /* align on a longword boundary */ ++ " " __ALIGN_STR "\n" ++ "1:\n" ++ " reset\n" ++ " jmp %a0@"); + ++ for (;;) ++ ; + } + + +@@ -773,11 +769,11 @@ static void amiga_reset (void) + #define SAVEKMSG_MAGIC2 0x4B4D5347 /* 'KMSG' */ + + struct savekmsg { +- unsigned long magic1; /* SAVEKMSG_MAGIC1 */ +- unsigned long magic2; /* SAVEKMSG_MAGIC2 */ +- unsigned long magicptr; /* address of magic1 */ +- unsigned long size; +- char data[0]; ++ unsigned long magic1; /* SAVEKMSG_MAGIC1 */ ++ unsigned long magic2; /* SAVEKMSG_MAGIC2 */ ++ unsigned long magicptr; /* address of magic1 */ ++ unsigned long size; ++ char data[0]; + }; + + static struct savekmsg *savekmsg; +@@ -785,100 +781,100 @@ static struct savekmsg *savekmsg; + static void amiga_mem_console_write(struct console *co, const char *s, + unsigned int count) + { +- if (savekmsg->size+count <= SAVEKMSG_MAXMEM-sizeof(struct savekmsg)) { +- memcpy(savekmsg->data+savekmsg->size, s, count); +- savekmsg->size += count; +- } ++ if (savekmsg->size + count <= SAVEKMSG_MAXMEM-sizeof(struct savekmsg)) { ++ memcpy(savekmsg->data + savekmsg->size, s, count); ++ savekmsg->size += count; ++ } + } + + static void amiga_savekmsg_init(void) + { +- static struct resource debug_res = { .name = "Debug" }; ++ static struct resource debug_res = { .name = "Debug" }; + +- savekmsg = amiga_chip_alloc_res(SAVEKMSG_MAXMEM, &debug_res); +- savekmsg->magic1 = SAVEKMSG_MAGIC1; +- savekmsg->magic2 = SAVEKMSG_MAGIC2; +- savekmsg->magicptr = ZTWO_PADDR(savekmsg); +- savekmsg->size = 0; ++ savekmsg = amiga_chip_alloc_res(SAVEKMSG_MAXMEM, &debug_res); ++ savekmsg->magic1 = SAVEKMSG_MAGIC1; ++ savekmsg->magic2 = SAVEKMSG_MAGIC2; ++ savekmsg->magicptr = ZTWO_PADDR(savekmsg); ++ savekmsg->size = 0; + } + + static void amiga_serial_putc(char c) + { +- amiga_custom.serdat = (unsigned char)c | 0x100; +- while (!(amiga_custom.serdatr & 0x2000)) +- ; ++ amiga_custom.serdat = (unsigned char)c | 0x100; ++ while (!(amiga_custom.serdatr & 0x2000)) ++ ; + } + + void amiga_serial_console_write(struct console *co, const char *s, +- unsigned int count) ++ unsigned int count) + { +- while (count--) { +- if (*s == '\n') +- amiga_serial_putc('\r'); +- amiga_serial_putc(*s++); +- } ++ while (count--) { ++ if (*s == '\n') ++ amiga_serial_putc('\r'); ++ amiga_serial_putc(*s++); ++ } + } + + #ifdef CONFIG_SERIAL_CONSOLE + void amiga_serial_puts(const char *s) + { +- amiga_serial_console_write(NULL, s, strlen(s)); ++ amiga_serial_console_write(NULL, s, strlen(s)); + } + + int amiga_serial_console_wait_key(struct console *co) + { +- int ch; ++ int ch; + +- while (!(amiga_custom.intreqr & IF_RBF)) +- barrier(); +- ch = amiga_custom.serdatr & 0xff; +- /* clear the interrupt, so that another character can be read */ +- amiga_custom.intreq = IF_RBF; +- return ch; ++ while (!(amiga_custom.intreqr & IF_RBF)) ++ barrier(); ++ ch = amiga_custom.serdatr & 0xff; ++ /* clear the interrupt, so that another character can be read */ ++ amiga_custom.intreq = IF_RBF; ++ return ch; + } + + void amiga_serial_gets(struct console *co, char *s, int len) + { +- int ch, cnt = 0; ++ int ch, cnt = 0; ++ ++ while (1) { ++ ch = amiga_serial_console_wait_key(co); + +- while (1) { +- ch = amiga_serial_console_wait_key(co); ++ /* Check for backspace. */ ++ if (ch == 8 || ch == 127) { ++ if (cnt == 0) { ++ amiga_serial_putc('\007'); ++ continue; ++ } ++ cnt--; ++ amiga_serial_puts("\010 \010"); ++ continue; ++ } ++ ++ /* Check for enter. */ ++ if (ch == 10 || ch == 13) ++ break; ++ ++ /* See if line is too long. */ ++ if (cnt >= len + 1) { ++ amiga_serial_putc(7); ++ cnt--; ++ continue; ++ } + +- /* Check for backspace. */ +- if (ch == 8 || ch == 127) { +- if (cnt == 0) { +- amiga_serial_putc('\007'); +- continue; +- } +- cnt--; +- amiga_serial_puts("\010 \010"); +- continue; +- } +- +- /* Check for enter. */ +- if (ch == 10 || ch == 13) +- break; +- +- /* See if line is too long. */ +- if (cnt >= len + 1) { +- amiga_serial_putc(7); +- cnt--; +- continue; +- } +- +- /* Store and echo character. */ +- s[cnt++] = ch; +- amiga_serial_putc(ch); +- } +- /* Print enter. */ +- amiga_serial_puts("\r\n"); +- s[cnt] = 0; ++ /* Store and echo character. */ ++ s[cnt++] = ch; ++ amiga_serial_putc(ch); ++ } ++ /* Print enter. */ ++ amiga_serial_puts("\r\n"); ++ s[cnt] = 0; + } + #endif + + static void __init amiga_debug_init(void) + { +- if (!strcmp( m68k_debug_device, "ser" )) { ++ if (!strcmp(m68k_debug_device, "ser" )) { + /* no initialization required (?) */ + amiga_console_driver.write = amiga_serial_console_write; + register_console(&amiga_console_driver); +@@ -888,10 +884,10 @@ static void __init amiga_debug_init(void + #ifdef CONFIG_HEARTBEAT + static void amiga_heartbeat(int on) + { +- if (on) +- ciaa.pra &= ~2; +- else +- ciaa.pra |= 2; ++ if (on) ++ ciaa.pra &= ~2; ++ else ++ ciaa.pra |= 2; + } + #endif + +@@ -901,81 +897,81 @@ static void amiga_heartbeat(int on) + + static void amiga_get_model(char *model) + { +- strcpy(model, amiga_model_name); ++ strcpy(model, amiga_model_name); + } + + + static int amiga_get_hardware_list(char *buffer) + { +- int len = 0; ++ int len = 0; + +- if (AMIGAHW_PRESENT(CHIP_RAM)) +- len += sprintf(buffer+len, "Chip RAM:\t%ldK\n", amiga_chip_size>>10); +- len += sprintf(buffer+len, "PS Freq:\t%dHz\nEClock Freq:\t%ldHz\n", +- amiga_psfreq, amiga_eclock); +- if (AMIGAHW_PRESENT(AMI_VIDEO)) { +- char *type; +- switch(amiga_chipset) { +- case CS_OCS: +- type = "OCS"; +- break; +- case CS_ECS: +- type = "ECS"; +- break; +- case CS_AGA: +- type = "AGA"; +- break; +- default: +- type = "Old or Unknown"; +- break; ++ if (AMIGAHW_PRESENT(CHIP_RAM)) ++ len += sprintf(buffer+len, "Chip RAM:\t%ldK\n", amiga_chip_size>>10); ++ len += sprintf(buffer+len, "PS Freq:\t%dHz\nEClock Freq:\t%ldHz\n", ++ amiga_psfreq, amiga_eclock); ++ if (AMIGAHW_PRESENT(AMI_VIDEO)) { ++ char *type; ++ switch (amiga_chipset) { ++ case CS_OCS: ++ type = "OCS"; ++ break; ++ case CS_ECS: ++ type = "ECS"; ++ break; ++ case CS_AGA: ++ type = "AGA"; ++ break; ++ default: ++ type = "Old or Unknown"; ++ break; ++ } ++ len += sprintf(buffer+len, "Graphics:\t%s\n", type); + } +- len += sprintf(buffer+len, "Graphics:\t%s\n", type); +- } + + #define AMIGAHW_ANNOUNCE(name, str) \ +- if (AMIGAHW_PRESENT(name)) \ +- len += sprintf (buffer+len, "\t%s\n", str) ++ if (AMIGAHW_PRESENT(name)) \ ++ len += sprintf (buffer+len, "\t%s\n", str) + +- len += sprintf (buffer + len, "Detected hardware:\n"); ++ len += sprintf (buffer + len, "Detected hardware:\n"); + +- AMIGAHW_ANNOUNCE(AMI_VIDEO, "Amiga Video"); +- AMIGAHW_ANNOUNCE(AMI_BLITTER, "Blitter"); +- AMIGAHW_ANNOUNCE(AMBER_FF, "Amber Flicker Fixer"); +- AMIGAHW_ANNOUNCE(AMI_AUDIO, "Amiga Audio"); +- AMIGAHW_ANNOUNCE(AMI_FLOPPY, "Floppy Controller"); +- AMIGAHW_ANNOUNCE(A3000_SCSI, "SCSI Controller WD33C93 (A3000 style)"); +- AMIGAHW_ANNOUNCE(A4000_SCSI, "SCSI Controller NCR53C710 (A4000T style)"); +- AMIGAHW_ANNOUNCE(A1200_IDE, "IDE Interface (A1200 style)"); +- AMIGAHW_ANNOUNCE(A4000_IDE, "IDE Interface (A4000 style)"); +- AMIGAHW_ANNOUNCE(CD_ROM, "Internal CD ROM drive"); +- AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "Keyboard"); +- AMIGAHW_ANNOUNCE(AMI_MOUSE, "Mouse Port"); +- AMIGAHW_ANNOUNCE(AMI_SERIAL, "Serial Port"); +- AMIGAHW_ANNOUNCE(AMI_PARALLEL, "Parallel Port"); +- AMIGAHW_ANNOUNCE(A2000_CLK, "Hardware Clock (A2000 style)"); +- AMIGAHW_ANNOUNCE(A3000_CLK, "Hardware Clock (A3000 style)"); +- AMIGAHW_ANNOUNCE(CHIP_RAM, "Chip RAM"); +- AMIGAHW_ANNOUNCE(PAULA, "Paula 8364"); +- AMIGAHW_ANNOUNCE(DENISE, "Denise 8362"); +- AMIGAHW_ANNOUNCE(DENISE_HR, "Denise 8373"); +- AMIGAHW_ANNOUNCE(LISA, "Lisa 8375"); +- AMIGAHW_ANNOUNCE(AGNUS_PAL, "Normal/Fat PAL Agnus 8367/8371"); +- AMIGAHW_ANNOUNCE(AGNUS_NTSC, "Normal/Fat NTSC Agnus 8361/8370"); +- AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "Fat Hires PAL Agnus 8372"); +- AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "Fat Hires NTSC Agnus 8372"); +- AMIGAHW_ANNOUNCE(ALICE_PAL, "PAL Alice 8374"); +- AMIGAHW_ANNOUNCE(ALICE_NTSC, "NTSC Alice 8374"); +- AMIGAHW_ANNOUNCE(MAGIC_REKICK, "Magic Hard Rekick"); +- AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA Slot"); ++ AMIGAHW_ANNOUNCE(AMI_VIDEO, "Amiga Video"); ++ AMIGAHW_ANNOUNCE(AMI_BLITTER, "Blitter"); ++ AMIGAHW_ANNOUNCE(AMBER_FF, "Amber Flicker Fixer"); ++ AMIGAHW_ANNOUNCE(AMI_AUDIO, "Amiga Audio"); ++ AMIGAHW_ANNOUNCE(AMI_FLOPPY, "Floppy Controller"); ++ AMIGAHW_ANNOUNCE(A3000_SCSI, "SCSI Controller WD33C93 (A3000 style)"); ++ AMIGAHW_ANNOUNCE(A4000_SCSI, "SCSI Controller NCR53C710 (A4000T style)"); ++ AMIGAHW_ANNOUNCE(A1200_IDE, "IDE Interface (A1200 style)"); ++ AMIGAHW_ANNOUNCE(A4000_IDE, "IDE Interface (A4000 style)"); ++ AMIGAHW_ANNOUNCE(CD_ROM, "Internal CD ROM drive"); ++ AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "Keyboard"); ++ AMIGAHW_ANNOUNCE(AMI_MOUSE, "Mouse Port"); ++ AMIGAHW_ANNOUNCE(AMI_SERIAL, "Serial Port"); ++ AMIGAHW_ANNOUNCE(AMI_PARALLEL, "Parallel Port"); ++ AMIGAHW_ANNOUNCE(A2000_CLK, "Hardware Clock (A2000 style)"); ++ AMIGAHW_ANNOUNCE(A3000_CLK, "Hardware Clock (A3000 style)"); ++ AMIGAHW_ANNOUNCE(CHIP_RAM, "Chip RAM"); ++ AMIGAHW_ANNOUNCE(PAULA, "Paula 8364"); ++ AMIGAHW_ANNOUNCE(DENISE, "Denise 8362"); ++ AMIGAHW_ANNOUNCE(DENISE_HR, "Denise 8373"); ++ AMIGAHW_ANNOUNCE(LISA, "Lisa 8375"); ++ AMIGAHW_ANNOUNCE(AGNUS_PAL, "Normal/Fat PAL Agnus 8367/8371"); ++ AMIGAHW_ANNOUNCE(AGNUS_NTSC, "Normal/Fat NTSC Agnus 8361/8370"); ++ AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "Fat Hires PAL Agnus 8372"); ++ AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "Fat Hires NTSC Agnus 8372"); ++ AMIGAHW_ANNOUNCE(ALICE_PAL, "PAL Alice 8374"); ++ AMIGAHW_ANNOUNCE(ALICE_NTSC, "NTSC Alice 8374"); ++ AMIGAHW_ANNOUNCE(MAGIC_REKICK, "Magic Hard Rekick"); ++ AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA Slot"); + #ifdef CONFIG_ZORRO +- if (AMIGAHW_PRESENT(ZORRO)) +- len += sprintf(buffer+len, "\tZorro II%s AutoConfig: %d Expansion " +- "Device%s\n", +- AMIGAHW_PRESENT(ZORRO3) ? "I" : "", +- zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s"); ++ if (AMIGAHW_PRESENT(ZORRO)) ++ len += sprintf(buffer+len, "\tZorro II%s AutoConfig: %d Expansion " ++ "Device%s\n", ++ AMIGAHW_PRESENT(ZORRO3) ? "I" : "", ++ zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s"); + #endif /* CONFIG_ZORRO */ + + #undef AMIGAHW_ANNOUNCE + +- return(len); ++ return len; + } +--- linux-m68k-2.6.21.orig/arch/m68k/atari/config.c ++++ linux-m68k-2.6.21/arch/m68k/atari/config.c +@@ -50,19 +50,19 @@ int atari_dont_touch_floppy_select; + int atari_rtc_year_offset; + + /* local function prototypes */ +-static void atari_reset( void ); ++static void atari_reset(void); + static void atari_get_model(char *model); + static int atari_get_hardware_list(char *buffer); + + /* atari specific irq functions */ + extern void atari_init_IRQ (void); +-extern void atari_mksound( unsigned int count, unsigned int ticks ); ++extern void atari_mksound(unsigned int count, unsigned int ticks); + #ifdef CONFIG_HEARTBEAT +-static void atari_heartbeat( int on ); ++static void atari_heartbeat(int on); + #endif + + /* atari specific timer functions (in time.c) */ +-extern void atari_sched_init(irq_handler_t ); ++extern void atari_sched_init(irq_handler_t); + extern unsigned long atari_gettimeoffset (void); + extern int atari_mste_hwclk (int, struct rtc_time *); + extern int atari_tt_hwclk (int, struct rtc_time *); +@@ -73,48 +73,6 @@ extern int atari_tt_set_clock_mmss (unsi + extern void atari_debug_init(void); + + +-/* I've moved hwreg_present() and hwreg_present_bywrite() out into +- * mm/hwtest.c, to avoid having multiple copies of the same routine +- * in the kernel [I wanted them in hp300 and they were already used +- * in the nubus code. NB: I don't have an Atari so this might (just +- * conceivably) break something. +- * I've preserved the #if 0 version of hwreg_present_bywrite() here +- * for posterity. +- * -- Peter Maydell <pmaydell@chiark.greenend.org.uk>, 05/1998 +- */ +- +-#if 0 +-static int __init +-hwreg_present_bywrite(volatile void *regp, unsigned char val) +-{ +- int ret; +- long save_sp, save_vbr; +- static long tmp_vectors[3] = { [2] = (long)&&after_test }; +- +- __asm__ __volatile__ +- ( "movec %/vbr,%2\n\t" /* save vbr value */ +- "movec %4,%/vbr\n\t" /* set up temporary vectors */ +- "movel %/sp,%1\n\t" /* save sp */ +- "moveq #0,%0\n\t" /* assume not present */ +- "moveb %5,%3@\n\t" /* write the hardware reg */ +- "cmpb %3@,%5\n\t" /* compare it */ +- "seq %0" /* comes here only if reg */ +- /* is present */ +- : "=d&" (ret), "=r&" (save_sp), "=r&" (save_vbr) +- : "a" (regp), "r" (tmp_vectors), "d" (val) +- ); +- after_test: +- __asm__ __volatile__ +- ( "movel %0,%/sp\n\t" /* restore sp */ +- "movec %1,%/vbr" /* restore vbr */ +- : : "r" (save_sp), "r" (save_vbr) : "sp" +- ); +- +- return( ret ); +-} +-#endif +- +- + /* ++roman: This is a more elaborate test for an SCC chip, since the plain + * Medusa board generates DTACK at the SCC's standard addresses, but a SCC + * board in the Medusa is possible. Also, the addresses where the ST_ESCC +@@ -123,26 +81,34 @@ hwreg_present_bywrite(volatile void *reg + * should be readable without trouble (from channel A!). + */ + +-static int __init scc_test( volatile char *ctla ) ++static int __init scc_test(volatile char *ctla) + { +- if (!hwreg_present( ctla )) +- return( 0 ); ++ if (!hwreg_present(ctla)) ++ return 0; + MFPDELAY(); + +- *ctla = 2; MFPDELAY(); +- *ctla = 0x40; MFPDELAY(); ++ *ctla = 2; ++ MFPDELAY(); ++ *ctla = 0x40; ++ MFPDELAY(); + +- *ctla = 2; MFPDELAY(); +- if (*ctla != 0x40) return( 0 ); ++ *ctla = 2; ++ MFPDELAY(); ++ if (*ctla != 0x40) ++ return 0; + MFPDELAY(); + +- *ctla = 2; MFPDELAY(); +- *ctla = 0x60; MFPDELAY(); ++ *ctla = 2; ++ MFPDELAY(); ++ *ctla = 0x60; ++ MFPDELAY(); + +- *ctla = 2; MFPDELAY(); +- if (*ctla != 0x60) return( 0 ); ++ *ctla = 2; ++ MFPDELAY(); ++ if (*ctla != 0x60) ++ return 0; + +- return( 1 ); ++ return 1; + } + + +@@ -152,59 +118,58 @@ static int __init scc_test( volatile cha + + int __init atari_parse_bootinfo(const struct bi_record *record) + { +- int unknown = 0; +- const u_long *data = record->data; ++ int unknown = 0; ++ const u_long *data = record->data; + +- switch (record->tag) { ++ switch (record->tag) { + case BI_ATARI_MCH_COOKIE: +- atari_mch_cookie = *data; +- break; ++ atari_mch_cookie = *data; ++ break; + case BI_ATARI_MCH_TYPE: +- atari_mch_type = *data; +- break; ++ atari_mch_type = *data; ++ break; + default: +- unknown = 1; +- } +- return(unknown); ++ unknown = 1; ++ break; ++ } ++ return unknown; + } + + + /* Parse the Atari-specific switches= option. */ +-void __init atari_switches_setup( const char *str, unsigned len ) ++void __init atari_switches_setup(const char *str, unsigned len) + { +- char switches[len+1]; +- char *p; +- int ovsc_shift; +- char *args = switches; +- +- /* copy string to local array, strsep works destructively... */ +- strlcpy( switches, str, sizeof(switches) ); +- atari_switches = 0; +- +- /* parse the options */ +- while ((p = strsep(&args, ",")) != NULL) { +- if (!*p) continue; +- ovsc_shift = 0; +- if (strncmp( p, "ov_", 3 ) == 0) { +- p += 3; +- ovsc_shift = ATARI_SWITCH_OVSC_SHIFT; +- } +- +- if (strcmp( p, "ikbd" ) == 0) { +- /* RTS line of IKBD ACIA */ +- atari_switches |= ATARI_SWITCH_IKBD << ovsc_shift; +- } +- else if (strcmp( p, "midi" ) == 0) { +- /* RTS line of MIDI ACIA */ +- atari_switches |= ATARI_SWITCH_MIDI << ovsc_shift; +- } +- else if (strcmp( p, "snd6" ) == 0) { +- atari_switches |= ATARI_SWITCH_SND6 << ovsc_shift; ++ char switches[len+1]; ++ char *p; ++ int ovsc_shift; ++ char *args = switches; ++ ++ /* copy string to local array, strsep works destructively... */ ++ strlcpy(switches, str, sizeof(switches)); ++ atari_switches = 0; ++ ++ /* parse the options */ ++ while ((p = strsep(&args, ",")) != NULL) { ++ if (!*p) ++ continue; ++ ovsc_shift = 0; ++ if (strncmp(p, "ov_", 3) == 0) { ++ p += 3; ++ ovsc_shift = ATARI_SWITCH_OVSC_SHIFT; ++ } ++ ++ if (strcmp(p, "ikbd") == 0) { ++ /* RTS line of IKBD ACIA */ ++ atari_switches |= ATARI_SWITCH_IKBD << ovsc_shift; ++ } else if (strcmp(p, "midi") == 0) { ++ /* RTS line of MIDI ACIA */ ++ atari_switches |= ATARI_SWITCH_MIDI << ovsc_shift; ++ } else if (strcmp(p, "snd6") == 0) { ++ atari_switches |= ATARI_SWITCH_SND6 << ovsc_shift; ++ } else if (strcmp(p, "snd7") == 0) { ++ atari_switches |= ATARI_SWITCH_SND7 << ovsc_shift; ++ } + } +- else if (strcmp( p, "snd7" ) == 0) { +- atari_switches |= ATARI_SWITCH_SND7 << ovsc_shift; +- } +- } + } + + +@@ -214,284 +179,283 @@ void __init atari_switches_setup( const + + void __init config_atari(void) + { +- unsigned short tos_version; ++ unsigned short tos_version; + +- memset(&atari_hw_present, 0, sizeof(atari_hw_present)); ++ memset(&atari_hw_present, 0, sizeof(atari_hw_present)); + +- atari_debug_init(); ++ atari_debug_init(); + +- ioport_resource.end = 0xFFFFFFFF; /* Change size of I/O space from 64KB +- to 4GB. */ ++ /* Change size of I/O space from 64KB to 4GB. */ ++ ioport_resource.end = 0xFFFFFFFF; + +- mach_sched_init = atari_sched_init; +- mach_init_IRQ = atari_init_IRQ; +- mach_get_model = atari_get_model; +- mach_get_hardware_list = atari_get_hardware_list; +- mach_gettimeoffset = atari_gettimeoffset; +- mach_reset = atari_reset; +- mach_max_dma_address = 0xffffff; ++ mach_sched_init = atari_sched_init; ++ mach_init_IRQ = atari_init_IRQ; ++ mach_get_model = atari_get_model; ++ mach_get_hardware_list = atari_get_hardware_list; ++ mach_gettimeoffset = atari_gettimeoffset; ++ mach_reset = atari_reset; ++ mach_max_dma_address = 0xffffff; + #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE) +- mach_beep = atari_mksound; ++ mach_beep = atari_mksound; + #endif + #ifdef CONFIG_HEARTBEAT +- mach_heartbeat = atari_heartbeat; ++ mach_heartbeat = atari_heartbeat; + #endif + +- /* Set switches as requested by the user */ +- if (atari_switches & ATARI_SWITCH_IKBD) +- acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID; +- if (atari_switches & ATARI_SWITCH_MIDI) +- acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID; +- if (atari_switches & (ATARI_SWITCH_SND6|ATARI_SWITCH_SND7)) { +- sound_ym.rd_data_reg_sel = 14; +- sound_ym.wd_data = sound_ym.rd_data_reg_sel | +- ((atari_switches&ATARI_SWITCH_SND6) ? 0x40 : 0) | +- ((atari_switches&ATARI_SWITCH_SND7) ? 0x80 : 0); +- } +- +- /* ++bjoern: +- * Determine hardware present +- */ ++ /* Set switches as requested by the user */ ++ if (atari_switches & ATARI_SWITCH_IKBD) ++ acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID; ++ if (atari_switches & ATARI_SWITCH_MIDI) ++ acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID; ++ if (atari_switches & (ATARI_SWITCH_SND6|ATARI_SWITCH_SND7)) { ++ sound_ym.rd_data_reg_sel = 14; ++ sound_ym.wd_data = sound_ym.rd_data_reg_sel | ++ ((atari_switches&ATARI_SWITCH_SND6) ? 0x40 : 0) | ++ ((atari_switches&ATARI_SWITCH_SND7) ? 0x80 : 0); ++ } + +- printk( "Atari hardware found: " ); +- if (MACH_IS_MEDUSA || MACH_IS_HADES) { +- /* There's no Atari video hardware on the Medusa, but all the +- * addresses below generate a DTACK so no bus error occurs! */ +- } +- else if (hwreg_present( f030_xreg )) { +- ATARIHW_SET(VIDEL_SHIFTER); +- printk( "VIDEL " ); +- /* This is a temporary hack: If there is Falcon video +- * hardware, we assume that the ST-DMA serves SCSI instead of +- * ACSI. In the future, there should be a better method for +- * this... +- */ +- ATARIHW_SET(ST_SCSI); +- printk( "STDMA-SCSI " ); +- } +- else if (hwreg_present( tt_palette )) { +- ATARIHW_SET(TT_SHIFTER); +- printk( "TT_SHIFTER " ); +- } +- else if (hwreg_present( &shifter.bas_hi )) { +- if (hwreg_present( &shifter.bas_lo ) && +- (shifter.bas_lo = 0x0aau, shifter.bas_lo == 0x0aau)) { +- ATARIHW_SET(EXTD_SHIFTER); +- printk( "EXTD_SHIFTER " ); +- } +- else { +- ATARIHW_SET(STND_SHIFTER); +- printk( "STND_SHIFTER " ); +- } +- } +- if (hwreg_present( &mfp.par_dt_reg )) { +- ATARIHW_SET(ST_MFP); +- printk( "ST_MFP " ); +- } +- if (hwreg_present( &tt_mfp.par_dt_reg )) { +- ATARIHW_SET(TT_MFP); +- printk( "TT_MFP " ); +- } +- if (hwreg_present( &tt_scsi_dma.dma_addr_hi )) { +- ATARIHW_SET(SCSI_DMA); +- printk( "TT_SCSI_DMA " ); +- } +- if (!MACH_IS_HADES && hwreg_present( &st_dma.dma_hi )) { +- ATARIHW_SET(STND_DMA); +- printk( "STND_DMA " ); +- } +- if (MACH_IS_MEDUSA || /* The ST-DMA address registers aren't readable +- * on all Medusas, so the test below may fail */ +- (hwreg_present( &st_dma.dma_vhi ) && +- (st_dma.dma_vhi = 0x55) && (st_dma.dma_hi = 0xaa) && +- st_dma.dma_vhi == 0x55 && st_dma.dma_hi == 0xaa && +- (st_dma.dma_vhi = 0xaa) && (st_dma.dma_hi = 0x55) && +- st_dma.dma_vhi == 0xaa && st_dma.dma_hi == 0x55)) { +- ATARIHW_SET(EXTD_DMA); +- printk( "EXTD_DMA " ); +- } +- if (hwreg_present( &tt_scsi.scsi_data )) { +- ATARIHW_SET(TT_SCSI); +- printk( "TT_SCSI " ); +- } +- if (hwreg_present( &sound_ym.rd_data_reg_sel )) { +- ATARIHW_SET(YM_2149); +- printk( "YM2149 " ); +- } +- if (!MACH_IS_MEDUSA && !MACH_IS_HADES && +- hwreg_present( &tt_dmasnd.ctrl )) { +- ATARIHW_SET(PCM_8BIT); +- printk( "PCM " ); +- } +- if (!MACH_IS_HADES && hwreg_present( &falcon_codec.unused5 )) { +- ATARIHW_SET(CODEC); +- printk( "CODEC " ); +- } +- if (hwreg_present( &dsp56k_host_interface.icr )) { +- ATARIHW_SET(DSP56K); +- printk( "DSP56K " ); +- } +- if (hwreg_present( &tt_scc_dma.dma_ctrl ) && ++ /* ++bjoern: ++ * Determine hardware present ++ */ ++ ++ printk("Atari hardware found: "); ++ if (MACH_IS_MEDUSA || MACH_IS_HADES) { ++ /* There's no Atari video hardware on the Medusa, but all the ++ * addresses below generate a DTACK so no bus error occurs! */ ++ } else if (hwreg_present(f030_xreg)) { ++ ATARIHW_SET(VIDEL_SHIFTER); ++ printk("VIDEL "); ++ /* This is a temporary hack: If there is Falcon video ++ * hardware, we assume that the ST-DMA serves SCSI instead of ++ * ACSI. In the future, there should be a better method for ++ * this... ++ */ ++ ATARIHW_SET(ST_SCSI); ++ printk("STDMA-SCSI "); ++ } else if (hwreg_present(tt_palette)) { ++ ATARIHW_SET(TT_SHIFTER); ++ printk("TT_SHIFTER "); ++ } else if (hwreg_present(&shifter.bas_hi)) { ++ if (hwreg_present(&shifter.bas_lo) && ++ (shifter.bas_lo = 0x0aau, shifter.bas_lo == 0x0aau)) { ++ ATARIHW_SET(EXTD_SHIFTER); ++ printk("EXTD_SHIFTER "); ++ } else { ++ ATARIHW_SET(STND_SHIFTER); ++ printk("STND_SHIFTER "); ++ } ++ } ++ if (hwreg_present(&mfp.par_dt_reg)) { ++ ATARIHW_SET(ST_MFP); ++ printk("ST_MFP "); ++ } ++ if (hwreg_present(&tt_mfp.par_dt_reg)) { ++ ATARIHW_SET(TT_MFP); ++ printk("TT_MFP "); ++ } ++ if (hwreg_present(&tt_scsi_dma.dma_addr_hi)) { ++ ATARIHW_SET(SCSI_DMA); ++ printk("TT_SCSI_DMA "); ++ } ++ if (!MACH_IS_HADES && hwreg_present(&st_dma.dma_hi)) { ++ ATARIHW_SET(STND_DMA); ++ printk("STND_DMA "); ++ } ++ /* ++ * The ST-DMA address registers aren't readable ++ * on all Medusas, so the test below may fail ++ */ ++ if (MACH_IS_MEDUSA || ++ (hwreg_present(&st_dma.dma_vhi) && ++ (st_dma.dma_vhi = 0x55) && (st_dma.dma_hi = 0xaa) && ++ st_dma.dma_vhi == 0x55 && st_dma.dma_hi == 0xaa && ++ (st_dma.dma_vhi = 0xaa) && (st_dma.dma_hi = 0x55) && ++ st_dma.dma_vhi == 0xaa && st_dma.dma_hi == 0x55)) { ++ ATARIHW_SET(EXTD_DMA); ++ printk("EXTD_DMA "); ++ } ++ if (hwreg_present(&tt_scsi.scsi_data)) { ++ ATARIHW_SET(TT_SCSI); ++ printk("TT_SCSI "); ++ } ++ if (hwreg_present(&sound_ym.rd_data_reg_sel)) { ++ ATARIHW_SET(YM_2149); ++ printk("YM2149 "); ++ } ++ if (!MACH_IS_MEDUSA && !MACH_IS_HADES && ++ hwreg_present(&tt_dmasnd.ctrl)) { ++ ATARIHW_SET(PCM_8BIT); ++ printk("PCM "); ++ } ++ if (!MACH_IS_HADES && hwreg_present(&falcon_codec.unused5)) { ++ ATARIHW_SET(CODEC); ++ printk("CODEC "); ++ } ++ if (hwreg_present(&dsp56k_host_interface.icr)) { ++ ATARIHW_SET(DSP56K); ++ printk("DSP56K "); ++ } ++ if (hwreg_present(&tt_scc_dma.dma_ctrl) && + #if 0 +- /* This test sucks! Who knows some better? */ +- (tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) && +- (tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0) ++ /* This test sucks! Who knows some better? */ ++ (tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) && ++ (tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0) + #else +- !MACH_IS_MEDUSA && !MACH_IS_HADES ++ !MACH_IS_MEDUSA && !MACH_IS_HADES + #endif +- ) { +- ATARIHW_SET(SCC_DMA); +- printk( "SCC_DMA " ); +- } +- if (scc_test( &scc.cha_a_ctrl )) { +- ATARIHW_SET(SCC); +- printk( "SCC " ); +- } +- if (scc_test( &st_escc.cha_b_ctrl )) { +- ATARIHW_SET( ST_ESCC ); +- printk( "ST_ESCC " ); +- } +- if (MACH_IS_HADES) +- { +- ATARIHW_SET( VME ); +- printk( "VME " ); +- } +- else if (hwreg_present( &tt_scu.sys_mask )) { +- ATARIHW_SET(SCU); +- /* Assume a VME bus if there's a SCU */ +- ATARIHW_SET( VME ); +- printk( "VME SCU " ); +- } +- if (hwreg_present( (void *)(0xffff9210) )) { +- ATARIHW_SET(ANALOG_JOY); +- printk( "ANALOG_JOY " ); +- } +- if (!MACH_IS_HADES && hwreg_present( blitter.halftone )) { +- ATARIHW_SET(BLITTER); +- printk( "BLITTER " ); +- } +- if (hwreg_present((void *)0xfff00039)) { +- ATARIHW_SET(IDE); +- printk( "IDE " ); +- } ++ ) { ++ ATARIHW_SET(SCC_DMA); ++ printk("SCC_DMA "); ++ } ++ if (scc_test(&scc.cha_a_ctrl)) { ++ ATARIHW_SET(SCC); ++ printk("SCC "); ++ } ++ if (scc_test(&st_escc.cha_b_ctrl)) { ++ ATARIHW_SET(ST_ESCC); ++ printk("ST_ESCC "); ++ } ++ if (MACH_IS_HADES) { ++ ATARIHW_SET(VME); ++ printk("VME "); ++ } else if (hwreg_present(&tt_scu.sys_mask)) { ++ ATARIHW_SET(SCU); ++ /* Assume a VME bus if there's a SCU */ ++ ATARIHW_SET(VME); ++ printk("VME SCU "); ++ } ++ if (hwreg_present((void *)(0xffff9210))) { ++ ATARIHW_SET(ANALOG_JOY); ++ printk("ANALOG_JOY "); ++ } ++ if (!MACH_IS_HADES && hwreg_present(blitter.halftone)) { ++ ATARIHW_SET(BLITTER); ++ printk("BLITTER "); ++ } ++ if (hwreg_present((void *)0xfff00039)) { ++ ATARIHW_SET(IDE); ++ printk("IDE "); ++ } + #if 1 /* This maybe wrong */ +- if (!MACH_IS_MEDUSA && !MACH_IS_HADES && +- hwreg_present( &tt_microwire.data ) && +- hwreg_present( &tt_microwire.mask ) && +- (tt_microwire.mask = 0x7ff, +- udelay(1), +- tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR, +- udelay(1), +- tt_microwire.data != 0)) { +- ATARIHW_SET(MICROWIRE); +- while (tt_microwire.mask != 0x7ff) ; +- printk( "MICROWIRE " ); +- } ++ if (!MACH_IS_MEDUSA && !MACH_IS_HADES && ++ hwreg_present(&tt_microwire.data) && ++ hwreg_present(&tt_microwire.mask) && ++ (tt_microwire.mask = 0x7ff, ++ udelay(1), ++ tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR, ++ udelay(1), ++ tt_microwire.data != 0)) { ++ ATARIHW_SET(MICROWIRE); ++ while (tt_microwire.mask != 0x7ff) ++ ; ++ printk("MICROWIRE "); ++ } + #endif +- if (hwreg_present( &tt_rtc.regsel )) { +- ATARIHW_SET(TT_CLK); +- printk( "TT_CLK " ); +- mach_hwclk = atari_tt_hwclk; +- mach_set_clock_mmss = atari_tt_set_clock_mmss; +- } +- if (!MACH_IS_HADES && hwreg_present( &mste_rtc.sec_ones)) { +- ATARIHW_SET(MSTE_CLK); +- printk( "MSTE_CLK "); +- mach_hwclk = atari_mste_hwclk; +- mach_set_clock_mmss = atari_mste_set_clock_mmss; +- } +- if (!MACH_IS_MEDUSA && !MACH_IS_HADES && +- hwreg_present( &dma_wd.fdc_speed ) && +- hwreg_write( &dma_wd.fdc_speed, 0 )) { +- ATARIHW_SET(FDCSPEED); +- printk( "FDC_SPEED "); +- } +- if (!MACH_IS_HADES && !ATARIHW_PRESENT(ST_SCSI)) { +- ATARIHW_SET(ACSI); +- printk( "ACSI " ); +- } +- printk("\n"); +- +- if (CPU_IS_040_OR_060) +- /* Now it seems to be safe to turn of the tt0 transparent +- * translation (the one that must not be turned off in +- * head.S...) +- */ +- __asm__ volatile ("moveq #0,%/d0\n\t" +- ".chip 68040\n\t" +- "movec %%d0,%%itt0\n\t" +- "movec %%d0,%%dtt0\n\t" +- ".chip 68k" +- : /* no outputs */ +- : /* no inputs */ +- : "d0"); +- +- /* allocator for memory that must reside in st-ram */ +- atari_stram_init (); +- +- /* Set up a mapping for the VMEbus address region: +- * +- * VME is either at phys. 0xfexxxxxx (TT) or 0xa00000..0xdfffff +- * (MegaSTE) In both cases, the whole 16 MB chunk is mapped at +- * 0xfe000000 virt., because this can be done with a single +- * transparent translation. On the 68040, lots of often unused +- * page tables would be needed otherwise. On a MegaSTE or similar, +- * the highest byte is stripped off by hardware due to the 24 bit +- * design of the bus. +- */ ++ if (hwreg_present(&tt_rtc.regsel)) { ++ ATARIHW_SET(TT_CLK); ++ printk("TT_CLK "); ++ mach_hwclk = atari_tt_hwclk; ++ mach_set_clock_mmss = atari_tt_set_clock_mmss; ++ } ++ if (!MACH_IS_HADES && hwreg_present(&mste_rtc.sec_ones)) { ++ ATARIHW_SET(MSTE_CLK); ++ printk("MSTE_CLK "); ++ mach_hwclk = atari_mste_hwclk; ++ mach_set_clock_mmss = atari_mste_set_clock_mmss; ++ } ++ if (!MACH_IS_MEDUSA && !MACH_IS_HADES && ++ hwreg_present(&dma_wd.fdc_speed) && ++ hwreg_write(&dma_wd.fdc_speed, 0)) { ++ ATARIHW_SET(FDCSPEED); ++ printk("FDC_SPEED "); ++ } ++ if (!MACH_IS_HADES && !ATARIHW_PRESENT(ST_SCSI)) { ++ ATARIHW_SET(ACSI); ++ printk("ACSI "); ++ } ++ printk("\n"); + +- if (CPU_IS_020_OR_030) { +- unsigned long tt1_val; +- tt1_val = 0xfe008543; /* Translate 0xfexxxxxx, enable, cache +- * inhibit, read and write, FDC mask = 3, +- * FDC val = 4 -> Supervisor only */ +- __asm__ __volatile__ ( ".chip 68030\n\t" +- "pmove %0@,%/tt1\n\t" +- ".chip 68k" +- : : "a" (&tt1_val) ); +- } +- else { +- __asm__ __volatile__ +- ( "movel %0,%/d0\n\t" +- ".chip 68040\n\t" +- "movec %%d0,%%itt1\n\t" +- "movec %%d0,%%dtt1\n\t" +- ".chip 68k" +- : +- : "g" (0xfe00a040) /* Translate 0xfexxxxxx, enable, +- * supervisor only, non-cacheable/ +- * serialized, writable */ +- : "d0" ); +- +- } +- +- /* Fetch tos version at Physical 2 */ +- /* We my not be able to access this address if the kernel is +- loaded to st ram, since the first page is unmapped. On the +- Medusa this is always the case and there is nothing we can do +- about this, so we just assume the smaller offset. For the TT +- we use the fact that in head.S we have set up a mapping +- 0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible +- in the last 16MB of the address space. */ +- tos_version = (MACH_IS_MEDUSA || MACH_IS_HADES) ? +- 0xfff : *(unsigned short *)0xff000002; +- atari_rtc_year_offset = (tos_version < 0x306) ? 70 : 68; ++ if (CPU_IS_040_OR_060) ++ /* Now it seems to be safe to turn of the tt0 transparent ++ * translation (the one that must not be turned off in ++ * head.S...) ++ */ ++ asm volatile ("\n" ++ " moveq #0,%%d0\n" ++ " .chip 68040\n" ++ " movec %%d0,%%itt0\n" ++ " movec %%d0,%%dtt0\n" ++ " .chip 68k" ++ : /* no outputs */ ++ : /* no inputs */ ++ : "d0"); ++ ++ /* allocator for memory that must reside in st-ram */ ++ atari_stram_init(); ++ ++ /* Set up a mapping for the VMEbus address region: ++ * ++ * VME is either at phys. 0xfexxxxxx (TT) or 0xa00000..0xdfffff ++ * (MegaSTE) In both cases, the whole 16 MB chunk is mapped at ++ * 0xfe000000 virt., because this can be done with a single ++ * transparent translation. On the 68040, lots of often unused ++ * page tables would be needed otherwise. On a MegaSTE or similar, ++ * the highest byte is stripped off by hardware due to the 24 bit ++ * design of the bus. ++ */ ++ ++ if (CPU_IS_020_OR_030) { ++ unsigned long tt1_val; ++ tt1_val = 0xfe008543; /* Translate 0xfexxxxxx, enable, cache ++ * inhibit, read and write, FDC mask = 3, ++ * FDC val = 4 -> Supervisor only */ ++ asm volatile ("\n" ++ " .chip 68030\n" ++ " pmove %0@,%/tt1\n" ++ " .chip 68k" ++ : : "a" (&tt1_val)); ++ } else { ++ asm volatile ("\n" ++ " .chip 68040\n" ++ " movec %0,%%itt1\n" ++ " movec %0,%%dtt1\n" ++ " .chip 68k" ++ : ++ : "d" (0xfe00a040)); /* Translate 0xfexxxxxx, enable, ++ * supervisor only, non-cacheable/ ++ * serialized, writable */ ++ ++ } ++ ++ /* Fetch tos version at Physical 2 */ ++ /* ++ * We my not be able to access this address if the kernel is ++ * loaded to st ram, since the first page is unmapped. On the ++ * Medusa this is always the case and there is nothing we can do ++ * about this, so we just assume the smaller offset. For the TT ++ * we use the fact that in head.S we have set up a mapping ++ * 0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible ++ * in the last 16MB of the address space. ++ */ ++ tos_version = (MACH_IS_MEDUSA || MACH_IS_HADES) ? ++ 0xfff : *(unsigned short *)0xff000002; ++ atari_rtc_year_offset = (tos_version < 0x306) ? 70 : 68; + } + + #ifdef CONFIG_HEARTBEAT +-static void atari_heartbeat( int on ) ++static void atari_heartbeat(int on) + { +- unsigned char tmp; +- unsigned long flags; ++ unsigned char tmp; ++ unsigned long flags; + +- if (atari_dont_touch_floppy_select) +- return; ++ if (atari_dont_touch_floppy_select) ++ return; + +- local_irq_save(flags); +- sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */ +- tmp = sound_ym.rd_data_reg_sel; +- sound_ym.wd_data = on ? (tmp & ~0x02) : (tmp | 0x02); +- local_irq_restore(flags); ++ local_irq_save(flags); ++ sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */ ++ tmp = sound_ym.rd_data_reg_sel; ++ sound_ym.wd_data = on ? (tmp & ~0x02) : (tmp | 0x02); ++ local_irq_restore(flags); + } + #endif + +@@ -526,180 +490,171 @@ static void atari_heartbeat( int on ) + + /* ++andreas: no need for complicated code, just depend on prefetch */ + +-static void atari_reset (void) ++static void atari_reset(void) + { +- long tc_val = 0; +- long reset_addr; ++ long tc_val = 0; ++ long reset_addr; + +- /* On the Medusa, phys. 0x4 may contain garbage because it's no +- ROM. See above for explanation why we cannot use PTOV(4). */ +- reset_addr = MACH_IS_HADES ? 0x7fe00030 : +- MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 : +- *(unsigned long *) 0xff000004; +- +- /* reset ACIA for switch off OverScan, if it's active */ +- if (atari_switches & ATARI_SWITCH_OVSC_IKBD) +- acia.key_ctrl = ACIA_RESET; +- if (atari_switches & ATARI_SWITCH_OVSC_MIDI) +- acia.mid_ctrl = ACIA_RESET; +- +- /* processor independent: turn off interrupts and reset the VBR; +- * the caches must be left enabled, else prefetching the final jump +- * instruction doesn't work. */ +- local_irq_disable(); +- __asm__ __volatile__ +- ("moveq #0,%/d0\n\t" +- "movec %/d0,%/vbr" +- : : : "d0" ); +- +- if (CPU_IS_040_OR_060) { +- unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040); +- if (CPU_IS_060) { +- /* 68060: clear PCR to turn off superscalar operation */ +- __asm__ __volatile__ +- ("moveq #0,%/d0\n\t" +- ".chip 68060\n\t" +- "movec %%d0,%%pcr\n\t" +- ".chip 68k" +- : : : "d0" ); +- } +- +- __asm__ __volatile__ +- ("movel %0,%/d0\n\t" +- "andl #0xff000000,%/d0\n\t" +- "orw #0xe020,%/d0\n\t" /* map 16 MB, enable, cacheable */ +- ".chip 68040\n\t" +- "movec %%d0,%%itt0\n\t" +- "movec %%d0,%%dtt0\n\t" +- ".chip 68k\n\t" +- "jmp %0@\n\t" +- : /* no outputs */ +- : "a" (jmp_addr040) +- : "d0" ); +- jmp_addr_label040: +- __asm__ __volatile__ +- ("moveq #0,%/d0\n\t" +- "nop\n\t" +- ".chip 68040\n\t" +- "cinva %%bc\n\t" +- "nop\n\t" +- "pflusha\n\t" +- "nop\n\t" +- "movec %%d0,%%tc\n\t" +- "nop\n\t" +- /* the following setup of transparent translations is needed on the +- * Afterburner040 to successfully reboot. Other machines shouldn't +- * care about a different tt regs setup, they also didn't care in +- * the past that the regs weren't turned off. */ +- "movel #0xffc000,%%d0\n\t" /* whole insn space cacheable */ +- "movec %%d0,%%itt0\n\t" +- "movec %%d0,%%itt1\n\t" +- "orw #0x40,%/d0\n\t" /* whole data space non-cacheable/ser. */ +- "movec %%d0,%%dtt0\n\t" +- "movec %%d0,%%dtt1\n\t" +- ".chip 68k\n\t" +- "jmp %0@" +- : /* no outputs */ +- : "a" (reset_addr) +- : "d0"); +- } +- else +- __asm__ __volatile__ +- ("pmove %0@,%/tc\n\t" +- "jmp %1@" +- : /* no outputs */ +- : "a" (&tc_val), "a" (reset_addr)); ++ /* ++ * On the Medusa, phys. 0x4 may contain garbage because it's no ++ * ROM. See above for explanation why we cannot use PTOV(4). ++ */ ++ reset_addr = MACH_IS_HADES ? 0x7fe00030 : ++ MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 : ++ *(unsigned long *) 0xff000004; ++ ++ /* reset ACIA for switch off OverScan, if it's active */ ++ if (atari_switches & ATARI_SWITCH_OVSC_IKBD) ++ acia.key_ctrl = ACIA_RESET; ++ if (atari_switches & ATARI_SWITCH_OVSC_MIDI) ++ acia.mid_ctrl = ACIA_RESET; ++ ++ /* processor independent: turn off interrupts and reset the VBR; ++ * the caches must be left enabled, else prefetching the final jump ++ * instruction doesn't work. ++ */ ++ local_irq_disable(); ++ asm volatile ("movec %0,%%vbr" ++ : : "d" (0)); ++ ++ if (CPU_IS_040_OR_060) { ++ unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040); ++ if (CPU_IS_060) { ++ /* 68060: clear PCR to turn off superscalar operation */ ++ asm volatile ("\n" ++ " .chip 68060\n" ++ " movec %0,%%pcr\n" ++ " .chip 68k" ++ : : "d" (0)); ++ } ++ ++ asm volatile ("\n" ++ " move.l %0,%%d0\n" ++ " and.l #0xff000000,%%d0\n" ++ " or.w #0xe020,%%d0\n" /* map 16 MB, enable, cacheable */ ++ " .chip 68040\n" ++ " movec %%d0,%%itt0\n" ++ " movec %%d0,%%dtt0\n" ++ " .chip 68k\n" ++ " jmp %0@" ++ : : "a" (jmp_addr040) ++ : "d0"); ++ jmp_addr_label040: ++ asm volatile ("\n" ++ " moveq #0,%%d0\n" ++ " nop\n" ++ " .chip 68040\n" ++ " cinva %%bc\n" ++ " nop\n" ++ " pflusha\n" ++ " nop\n" ++ " movec %%d0,%%tc\n" ++ " nop\n" ++ /* the following setup of transparent translations is needed on the ++ * Afterburner040 to successfully reboot. Other machines shouldn't ++ * care about a different tt regs setup, they also didn't care in ++ * the past that the regs weren't turned off. */ ++ " move.l #0xffc000,%%d0\n" /* whole insn space cacheable */ ++ " movec %%d0,%%itt0\n" ++ " movec %%d0,%%itt1\n" ++ " or.w #0x40,%/d0\n" /* whole data space non-cacheable/ser. */ ++ " movec %%d0,%%dtt0\n" ++ " movec %%d0,%%dtt1\n" ++ " .chip 68k\n" ++ " jmp %0@" ++ : /* no outputs */ ++ : "a" (reset_addr) ++ : "d0"); ++ } else ++ asm volatile ("\n" ++ " pmove %0@,%%tc\n" ++ " jmp %1@" ++ : /* no outputs */ ++ : "a" (&tc_val), "a" (reset_addr)); + } + + + static void atari_get_model(char *model) + { +- strcpy(model, "Atari "); +- switch (atari_mch_cookie >> 16) { ++ strcpy(model, "Atari "); ++ switch (atari_mch_cookie >> 16) { + case ATARI_MCH_ST: +- if (ATARIHW_PRESENT(MSTE_CLK)) +- strcat (model, "Mega ST"); +- else +- strcat (model, "ST"); +- break; ++ if (ATARIHW_PRESENT(MSTE_CLK)) ++ strcat(model, "Mega ST"); ++ else ++ strcat(model, "ST"); ++ break; + case ATARI_MCH_STE: +- if (MACH_IS_MSTE) +- strcat (model, "Mega STE"); +- else +- strcat (model, "STE"); +- break; ++ if (MACH_IS_MSTE) ++ strcat(model, "Mega STE"); ++ else ++ strcat(model, "STE"); ++ break; + case ATARI_MCH_TT: +- if (MACH_IS_MEDUSA) +- /* Medusa has TT _MCH cookie */ +- strcat (model, "Medusa"); +- else if (MACH_IS_HADES) +- strcat(model, "Hades"); +- else +- strcat (model, "TT"); +- break; ++ if (MACH_IS_MEDUSA) ++ /* Medusa has TT _MCH cookie */ ++ strcat(model, "Medusa"); ++ else if (MACH_IS_HADES) ++ strcat(model, "Hades"); ++ else ++ strcat(model, "TT"); ++ break; + case ATARI_MCH_FALCON: +- strcat (model, "Falcon"); +- if (MACH_IS_AB40) +- strcat (model, " (with Afterburner040)"); +- break; ++ strcat(model, "Falcon"); ++ if (MACH_IS_AB40) ++ strcat(model, " (with Afterburner040)"); ++ break; + default: +- sprintf (model + strlen (model), "(unknown mach cookie 0x%lx)", +- atari_mch_cookie); +- break; +- } ++ sprintf(model + strlen(model), "(unknown mach cookie 0x%lx)", ++ atari_mch_cookie); ++ break; ++ } + } + + + static int atari_get_hardware_list(char *buffer) + { +- int len = 0, i; ++ int len = 0, i; + +- for (i = 0; i < m68k_num_memory; i++) +- len += sprintf (buffer+len, "\t%3ld MB at 0x%08lx (%s)\n", +- m68k_memory[i].size >> 20, m68k_memory[i].addr, +- (m68k_memory[i].addr & 0xff000000 ? +- "alternate RAM" : "ST-RAM")); +- +-#define ATARIHW_ANNOUNCE(name,str) \ +- if (ATARIHW_PRESENT(name)) \ +- len += sprintf (buffer + len, "\t%s\n", str) +- +- len += sprintf (buffer + len, "Detected hardware:\n"); +- ATARIHW_ANNOUNCE(STND_SHIFTER, "ST Shifter"); +- ATARIHW_ANNOUNCE(EXTD_SHIFTER, "STe Shifter"); +- ATARIHW_ANNOUNCE(TT_SHIFTER, "TT Shifter"); +- ATARIHW_ANNOUNCE(VIDEL_SHIFTER, "Falcon Shifter"); +- ATARIHW_ANNOUNCE(YM_2149, "Programmable Sound Generator"); +- ATARIHW_ANNOUNCE(PCM_8BIT, "PCM 8 Bit Sound"); +- ATARIHW_ANNOUNCE(CODEC, "CODEC Sound"); +- ATARIHW_ANNOUNCE(TT_SCSI, "SCSI Controller NCR5380 (TT style)"); +- ATARIHW_ANNOUNCE(ST_SCSI, "SCSI Controller NCR5380 (Falcon style)"); +- ATARIHW_ANNOUNCE(ACSI, "ACSI Interface"); +- ATARIHW_ANNOUNCE(IDE, "IDE Interface"); +- ATARIHW_ANNOUNCE(FDCSPEED, "8/16 Mhz Switch for FDC"); +- ATARIHW_ANNOUNCE(ST_MFP, "Multi Function Peripheral MFP 68901"); +- ATARIHW_ANNOUNCE(TT_MFP, "Second Multi Function Peripheral MFP 68901"); +- ATARIHW_ANNOUNCE(SCC, "Serial Communications Controller SCC 8530"); +- ATARIHW_ANNOUNCE(ST_ESCC, "Extended Serial Communications Controller SCC 85230"); +- ATARIHW_ANNOUNCE(ANALOG_JOY, "Paddle Interface"); +- ATARIHW_ANNOUNCE(MICROWIRE, "MICROWIRE(tm) Interface"); +- ATARIHW_ANNOUNCE(STND_DMA, "DMA Controller (24 bit)"); +- ATARIHW_ANNOUNCE(EXTD_DMA, "DMA Controller (32 bit)"); +- ATARIHW_ANNOUNCE(SCSI_DMA, "DMA Controller for NCR5380"); +- ATARIHW_ANNOUNCE(SCC_DMA, "DMA Controller for SCC"); +- ATARIHW_ANNOUNCE(TT_CLK, "Clock Chip MC146818A"); +- ATARIHW_ANNOUNCE(MSTE_CLK, "Clock Chip RP5C15"); +- ATARIHW_ANNOUNCE(SCU, "System Control Unit"); +- ATARIHW_ANNOUNCE(BLITTER, "Blitter"); +- ATARIHW_ANNOUNCE(VME, "VME Bus"); +- ATARIHW_ANNOUNCE(DSP56K, "DSP56001 processor"); ++ for (i = 0; i < m68k_num_memory; i++) ++ len += sprintf(buffer+len, "\t%3ld MB at 0x%08lx (%s)\n", ++ m68k_memory[i].size >> 20, m68k_memory[i].addr, ++ (m68k_memory[i].addr & 0xff000000 ? ++ "alternate RAM" : "ST-RAM")); ++ ++#define ATARIHW_ANNOUNCE(name, str) \ ++ if (ATARIHW_PRESENT(name)) \ ++ len += sprintf(buffer + len, "\t%s\n", str) ++ ++ len += sprintf(buffer + len, "Detected hardware:\n"); ++ ATARIHW_ANNOUNCE(STND_SHIFTER, "ST Shifter"); ++ ATARIHW_ANNOUNCE(EXTD_SHIFTER, "STe Shifter"); ++ ATARIHW_ANNOUNCE(TT_SHIFTER, "TT Shifter"); ++ ATARIHW_ANNOUNCE(VIDEL_SHIFTER, "Falcon Shifter"); ++ ATARIHW_ANNOUNCE(YM_2149, "Programmable Sound Generator"); ++ ATARIHW_ANNOUNCE(PCM_8BIT, "PCM 8 Bit Sound"); ++ ATARIHW_ANNOUNCE(CODEC, "CODEC Sound"); ++ ATARIHW_ANNOUNCE(TT_SCSI, "SCSI Controller NCR5380 (TT style)"); ++ ATARIHW_ANNOUNCE(ST_SCSI, "SCSI Controller NCR5380 (Falcon style)"); ++ ATARIHW_ANNOUNCE(ACSI, "ACSI Interface"); ++ ATARIHW_ANNOUNCE(IDE, "IDE Interface"); ++ ATARIHW_ANNOUNCE(FDCSPEED, "8/16 Mhz Switch for FDC"); ++ ATARIHW_ANNOUNCE(ST_MFP, "Multi Function Peripheral MFP 68901"); ++ ATARIHW_ANNOUNCE(TT_MFP, "Second Multi Function Peripheral MFP 68901"); ++ ATARIHW_ANNOUNCE(SCC, "Serial Communications Controller SCC 8530"); ++ ATARIHW_ANNOUNCE(ST_ESCC, "Extended Serial Communications Controller SCC 85230"); ++ ATARIHW_ANNOUNCE(ANALOG_JOY, "Paddle Interface"); ++ ATARIHW_ANNOUNCE(MICROWIRE, "MICROWIRE(tm) Interface"); ++ ATARIHW_ANNOUNCE(STND_DMA, "DMA Controller (24 bit)"); ++ ATARIHW_ANNOUNCE(EXTD_DMA, "DMA Controller (32 bit)"); ++ ATARIHW_ANNOUNCE(SCSI_DMA, "DMA Controller for NCR5380"); ++ ATARIHW_ANNOUNCE(SCC_DMA, "DMA Controller for SCC"); ++ ATARIHW_ANNOUNCE(TT_CLK, "Clock Chip MC146818A"); ++ ATARIHW_ANNOUNCE(MSTE_CLK, "Clock Chip RP5C15"); ++ ATARIHW_ANNOUNCE(SCU, "System Control Unit"); ++ ATARIHW_ANNOUNCE(BLITTER, "Blitter"); ++ ATARIHW_ANNOUNCE(VME, "VME Bus"); ++ ATARIHW_ANNOUNCE(DSP56K, "DSP56001 processor"); + +- return(len); ++ return len; + } +- +-/* +- * Local variables: +- * c-indent-level: 4 +- * tab-width: 8 +- * End: +- */ +--- linux-m68k-2.6.21.orig/arch/m68k/atari/debug.c ++++ linux-m68k-2.6.21/arch/m68k/atari/debug.c +@@ -30,317 +30,311 @@ int atari_SCC_init_done; + int atari_SCC_reset_done; + + static struct console atari_console_driver = { +- .name = "debug", +- .flags = CON_PRINTBUFFER, +- .index = -1, ++ .name = "debug", ++ .flags = CON_PRINTBUFFER, ++ .index = -1, + }; + + +-static inline void ata_mfp_out (char c) ++static inline void ata_mfp_out(char c) + { +- while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */ +- barrier (); +- mfp.usart_dta = c; ++ while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */ ++ barrier(); ++ mfp.usart_dta = c; + } + +-void atari_mfp_console_write (struct console *co, const char *str, +- unsigned int count) ++void atari_mfp_console_write(struct console *co, const char *str, ++ unsigned int count) + { +- while (count--) { +- if (*str == '\n') +- ata_mfp_out( '\r' ); +- ata_mfp_out( *str++ ); +- } ++ while (count--) { ++ if (*str == '\n') ++ ata_mfp_out('\r'); ++ ata_mfp_out(*str++); ++ } + } + +-static inline void ata_scc_out (char c) ++static inline void ata_scc_out(char c) + { +- do { ++ do { ++ MFPDELAY(); ++ } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */ + MFPDELAY(); +- } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */ +- MFPDELAY(); +- scc.cha_b_data = c; ++ scc.cha_b_data = c; + } + +-void atari_scc_console_write (struct console *co, const char *str, +- unsigned int count) ++void atari_scc_console_write(struct console *co, const char *str, ++ unsigned int count) + { +- while (count--) { +- if (*str == '\n') +- ata_scc_out( '\r' ); +- ata_scc_out( *str++ ); +- } ++ while (count--) { ++ if (*str == '\n') ++ ata_scc_out('\r'); ++ ata_scc_out(*str++); ++ } + } + +-static inline void ata_midi_out (char c) ++static inline void ata_midi_out(char c) + { +- while (!(acia.mid_ctrl & ACIA_TDRE)) /* wait for tx buf empty */ +- barrier (); +- acia.mid_data = c; ++ while (!(acia.mid_ctrl & ACIA_TDRE)) /* wait for tx buf empty */ ++ barrier(); ++ acia.mid_data = c; + } + +-void atari_midi_console_write (struct console *co, const char *str, +- unsigned int count) ++void atari_midi_console_write(struct console *co, const char *str, ++ unsigned int count) + { +- while (count--) { +- if (*str == '\n') +- ata_midi_out( '\r' ); +- ata_midi_out( *str++ ); +- } ++ while (count--) { ++ if (*str == '\n') ++ ata_midi_out('\r'); ++ ata_midi_out(*str++); ++ } + } + +-static int ata_par_out (char c) ++static int ata_par_out(char c) + { +- unsigned char tmp; +- /* This a some-seconds timeout in case no printer is connected */ +- unsigned long i = loops_per_jiffy > 1 ? loops_per_jiffy : 10000000/HZ; ++ unsigned char tmp; ++ /* This a some-seconds timeout in case no printer is connected */ ++ unsigned long i = loops_per_jiffy > 1 ? loops_per_jiffy : 10000000/HZ; + +- while( (mfp.par_dt_reg & 1) && --i ) /* wait for BUSY == L */ +- ; +- if (!i) return( 0 ); ++ while ((mfp.par_dt_reg & 1) && --i) /* wait for BUSY == L */ ++ ; ++ if (!i) ++ return 0; + +- sound_ym.rd_data_reg_sel = 15; /* select port B */ +- sound_ym.wd_data = c; /* put char onto port */ +- sound_ym.rd_data_reg_sel = 14; /* select port A */ +- tmp = sound_ym.rd_data_reg_sel; +- sound_ym.wd_data = tmp & ~0x20; /* set strobe L */ +- MFPDELAY(); /* wait a bit */ +- sound_ym.wd_data = tmp | 0x20; /* set strobe H */ +- return( 1 ); ++ sound_ym.rd_data_reg_sel = 15; /* select port B */ ++ sound_ym.wd_data = c; /* put char onto port */ ++ sound_ym.rd_data_reg_sel = 14; /* select port A */ ++ tmp = sound_ym.rd_data_reg_sel; ++ sound_ym.wd_data = tmp & ~0x20; /* set strobe L */ ++ MFPDELAY(); /* wait a bit */ ++ sound_ym.wd_data = tmp | 0x20; /* set strobe H */ ++ return 1; + } + +-static void atari_par_console_write (struct console *co, const char *str, +- unsigned int count) ++static void atari_par_console_write(struct console *co, const char *str, ++ unsigned int count) + { +- static int printer_present = 1; +- +- if (!printer_present) +- return; ++ static int printer_present = 1; + +- while (count--) { +- if (*str == '\n') +- if (!ata_par_out( '\r' )) { +- printer_present = 0; ++ if (!printer_present) + return; +- } +- if (!ata_par_out( *str++ )) { +- printer_present = 0; +- return; ++ ++ while (count--) { ++ if (*str == '\n') { ++ if (!ata_par_out('\r')) { ++ printer_present = 0; ++ return; ++ } ++ } ++ if (!ata_par_out(*str++)) { ++ printer_present = 0; ++ return; ++ } + } +- } + } + + #ifdef CONFIG_SERIAL_CONSOLE + int atari_mfp_console_wait_key(struct console *co) + { +- while( !(mfp.rcv_stat & 0x80) ) /* wait for rx buf filled */ +- barrier(); +- return( mfp.usart_dta ); ++ while (!(mfp.rcv_stat & 0x80)) /* wait for rx buf filled */ ++ barrier(); ++ return mfp.usart_dta; + } + + int atari_scc_console_wait_key(struct console *co) + { +- do { ++ do { ++ MFPDELAY(); ++ } while (!(scc.cha_b_ctrl & 0x01)); /* wait for rx buf filled */ + MFPDELAY(); +- } while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */ +- MFPDELAY(); +- return( scc.cha_b_data ); ++ return scc.cha_b_data; + } + + int atari_midi_console_wait_key(struct console *co) + { +- while( !(acia.mid_ctrl & ACIA_RDRF) ) /* wait for rx buf filled */ +- barrier(); +- return( acia.mid_data ); ++ while (!(acia.mid_ctrl & ACIA_RDRF)) /* wait for rx buf filled */ ++ barrier(); ++ return acia.mid_data; + } + #endif + +-/* The following two functions do a quick'n'dirty initialization of the MFP or ++/* ++ * The following two functions do a quick'n'dirty initialization of the MFP or + * SCC serial ports. They're used by the debugging interface, kgdb, and the +- * serial console code. */ ++ * serial console code. ++ */ + #ifndef CONFIG_SERIAL_CONSOLE +-static void __init atari_init_mfp_port( int cflag ) ++static void __init atari_init_mfp_port(int cflag) + #else +-void atari_init_mfp_port( int cflag ) ++void atari_init_mfp_port(int cflag) + #endif + { +- /* timer values for 1200...115200 bps; > 38400 select 110, 134, or 150 +- * bps, resp., and work only correct if there's a RSVE or RSSPEED */ +- static int baud_table[9] = { 16, 11, 8, 4, 2, 1, 175, 143, 128 }; +- int baud = cflag & CBAUD; +- int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x04 : 0x06) : 0; +- int csize = ((cflag & CSIZE) == CS7) ? 0x20 : 0x00; +- +- if (cflag & CBAUDEX) +- baud += B38400; +- if (baud < B1200 || baud > B38400+2) +- baud = B9600; /* use default 9600bps for non-implemented rates */ +- baud -= B1200; /* baud_table[] starts at 1200bps */ +- +- mfp.trn_stat &= ~0x01; /* disable TX */ +- mfp.usart_ctr = parity | csize | 0x88; /* 1:16 clk mode, 1 stop bit */ +- mfp.tim_ct_cd &= 0x70; /* stop timer D */ +- mfp.tim_dt_d = baud_table[baud]; +- mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */ +- mfp.trn_stat |= 0x01; /* enable TX */ +- +- atari_MFP_init_done = 1; +-} +- +-#define SCC_WRITE(reg,val) \ +- do { \ +- scc.cha_b_ctrl = (reg); \ +- MFPDELAY(); \ +- scc.cha_b_ctrl = (val); \ +- MFPDELAY(); \ +- } while(0) ++ /* ++ * timer values for 1200...115200 bps; > 38400 select 110, 134, or 150 ++ * bps, resp., and work only correct if there's a RSVE or RSSPEED ++ */ ++ static int baud_table[9] = { 16, 11, 8, 4, 2, 1, 175, 143, 128 }; ++ int baud = cflag & CBAUD; ++ int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x04 : 0x06) : 0; ++ int csize = ((cflag & CSIZE) == CS7) ? 0x20 : 0x00; ++ ++ if (cflag & CBAUDEX) ++ baud += B38400; ++ if (baud < B1200 || baud > B38400+2) ++ baud = B9600; /* use default 9600bps for non-implemented rates */ ++ baud -= B1200; /* baud_table[] starts at 1200bps */ ++ ++ mfp.trn_stat &= ~0x01; /* disable TX */ ++ mfp.usart_ctr = parity | csize | 0x88; /* 1:16 clk mode, 1 stop bit */ ++ mfp.tim_ct_cd &= 0x70; /* stop timer D */ ++ mfp.tim_dt_d = baud_table[baud]; ++ mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */ ++ mfp.trn_stat |= 0x01; /* enable TX */ ++ ++ atari_MFP_init_done = 1; ++} ++ ++#define SCC_WRITE(reg, val) \ ++ do { \ ++ scc.cha_b_ctrl = (reg); \ ++ MFPDELAY(); \ ++ scc.cha_b_ctrl = (val); \ ++ MFPDELAY(); \ ++ } while (0) + + /* loops_per_jiffy isn't initialized yet, so we can't use udelay(). This does a + * delay of ~ 60us. */ +-#define LONG_DELAY() \ +- do { \ +- int i; \ +- for( i = 100; i > 0; --i ) \ +- MFPDELAY(); \ +- } while(0) ++#define LONG_DELAY() \ ++ do { \ ++ int i; \ ++ for (i = 100; i > 0; --i) \ ++ MFPDELAY(); \ ++ } while (0) + + #ifndef CONFIG_SERIAL_CONSOLE +-static void __init atari_init_scc_port( int cflag ) ++static void __init atari_init_scc_port(int cflag) + #else +-void atari_init_scc_port( int cflag ) ++void atari_init_scc_port(int cflag) + #endif + { +- extern int atari_SCC_reset_done; +- static int clksrc_table[9] = +- /* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */ +- { 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 }; +- static int brgsrc_table[9] = +- /* reg 14: 0 = RTxC, 2 = PCLK */ +- { 2, 2, 2, 2, 2, 2, 0, 2, 2 }; +- static int clkmode_table[9] = +- /* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */ +- { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 }; +- static int div_table[9] = +- /* reg12 (BRG low) */ +- { 208, 138, 103, 50, 24, 11, 1, 0, 0 }; +- +- int baud = cflag & CBAUD; +- int clksrc, clkmode, div, reg3, reg5; +- +- if (cflag & CBAUDEX) +- baud += B38400; +- if (baud < B1200 || baud > B38400+2) +- baud = B9600; /* use default 9600bps for non-implemented rates */ +- baud -= B1200; /* tables starts at 1200bps */ +- +- clksrc = clksrc_table[baud]; +- clkmode = clkmode_table[baud]; +- div = div_table[baud]; +- if (ATARIHW_PRESENT(TT_MFP) && baud >= 6) { +- /* special treatment for TT, where rates >= 38400 are done via TRxC */ +- clksrc = 0x28; /* TRxC */ +- clkmode = baud == 6 ? 0xc0 : +- baud == 7 ? 0x80 : /* really 76800bps */ +- 0x40; /* really 153600bps */ +- div = 0; +- } +- +- reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40; +- reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */; +- +- (void)scc.cha_b_ctrl; /* reset reg pointer */ +- SCC_WRITE( 9, 0xc0 ); /* reset */ +- LONG_DELAY(); /* extra delay after WR9 access */ +- SCC_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 | +- 0x04 /* 1 stopbit */ | +- clkmode ); +- SCC_WRITE( 3, reg3 ); +- SCC_WRITE( 5, reg5 ); +- SCC_WRITE( 9, 0 ); /* no interrupts */ +- LONG_DELAY(); /* extra delay after WR9 access */ +- SCC_WRITE( 10, 0 ); /* NRZ mode */ +- SCC_WRITE( 11, clksrc ); /* main clock source */ +- SCC_WRITE( 12, div ); /* BRG value */ +- SCC_WRITE( 13, 0 ); /* BRG high byte */ +- SCC_WRITE( 14, brgsrc_table[baud] ); +- SCC_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) ); +- SCC_WRITE( 3, reg3 | 1 ); +- SCC_WRITE( 5, reg5 | 8 ); ++ extern int atari_SCC_reset_done; ++ static int clksrc_table[9] = ++ /* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */ ++ { 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 }; ++ static int brgsrc_table[9] = ++ /* reg 14: 0 = RTxC, 2 = PCLK */ ++ { 2, 2, 2, 2, 2, 2, 0, 2, 2 }; ++ static int clkmode_table[9] = ++ /* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */ ++ { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 }; ++ static int div_table[9] = ++ /* reg12 (BRG low) */ ++ { 208, 138, 103, 50, 24, 11, 1, 0, 0 }; ++ ++ int baud = cflag & CBAUD; ++ int clksrc, clkmode, div, reg3, reg5; ++ ++ if (cflag & CBAUDEX) ++ baud += B38400; ++ if (baud < B1200 || baud > B38400+2) ++ baud = B9600; /* use default 9600bps for non-implemented rates */ ++ baud -= B1200; /* tables starts at 1200bps */ ++ ++ clksrc = clksrc_table[baud]; ++ clkmode = clkmode_table[baud]; ++ div = div_table[baud]; ++ if (ATARIHW_PRESENT(TT_MFP) && baud >= 6) { ++ /* special treatment for TT, where rates >= 38400 are done via TRxC */ ++ clksrc = 0x28; /* TRxC */ ++ clkmode = baud == 6 ? 0xc0 : ++ baud == 7 ? 0x80 : /* really 76800bps */ ++ 0x40; /* really 153600bps */ ++ div = 0; ++ } ++ ++ reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40; ++ reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */; ++ ++ (void)scc.cha_b_ctrl; /* reset reg pointer */ ++ SCC_WRITE(9, 0xc0); /* reset */ ++ LONG_DELAY(); /* extra delay after WR9 access */ ++ SCC_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) ++ : 0 | 0x04 /* 1 stopbit */ | clkmode); ++ SCC_WRITE(3, reg3); ++ SCC_WRITE(5, reg5); ++ SCC_WRITE(9, 0); /* no interrupts */ ++ LONG_DELAY(); /* extra delay after WR9 access */ ++ SCC_WRITE(10, 0); /* NRZ mode */ ++ SCC_WRITE(11, clksrc); /* main clock source */ ++ SCC_WRITE(12, div); /* BRG value */ ++ SCC_WRITE(13, 0); /* BRG high byte */ ++ SCC_WRITE(14, brgsrc_table[baud]); ++ SCC_WRITE(14, brgsrc_table[baud] | (div ? 1 : 0)); ++ SCC_WRITE(3, reg3 | 1); ++ SCC_WRITE(5, reg5 | 8); + +- atari_SCC_reset_done = 1; +- atari_SCC_init_done = 1; ++ atari_SCC_reset_done = 1; ++ atari_SCC_init_done = 1; + } + + #ifndef CONFIG_SERIAL_CONSOLE +-static void __init atari_init_midi_port( int cflag ) ++static void __init atari_init_midi_port(int cflag) + #else +-void atari_init_midi_port( int cflag ) ++void atari_init_midi_port(int cflag) + #endif + { +- int baud = cflag & CBAUD; +- int csize = ((cflag & CSIZE) == CS8) ? 0x10 : 0x00; +- /* warning 7N1 isn't possible! (instead 7O2 is used...) */ +- int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x0c : 0x08) : 0x04; +- int div; +- +- /* 4800 selects 7812.5, 115200 selects 500000, all other (incl. 9600 as +- * default) the standard MIDI speed 31250. */ +- if (cflag & CBAUDEX) +- baud += B38400; +- if (baud == B4800) +- div = ACIA_DIV64; /* really 7812.5 bps */ +- else if (baud == B38400+2 /* 115200 */) +- div = ACIA_DIV1; /* really 500 kbps (does that work??) */ +- else +- div = ACIA_DIV16; /* 31250 bps, standard for MIDI */ ++ int baud = cflag & CBAUD; ++ int csize = ((cflag & CSIZE) == CS8) ? 0x10 : 0x00; ++ /* warning 7N1 isn't possible! (instead 7O2 is used...) */ ++ int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x0c : 0x08) : 0x04; ++ int div; ++ ++ /* 4800 selects 7812.5, 115200 selects 500000, all other (incl. 9600 as ++ * default) the standard MIDI speed 31250. */ ++ if (cflag & CBAUDEX) ++ baud += B38400; ++ if (baud == B4800) ++ div = ACIA_DIV64; /* really 7812.5 bps */ ++ else if (baud == B38400+2 /* 115200 */) ++ div = ACIA_DIV1; /* really 500 kbps (does that work??) */ ++ else ++ div = ACIA_DIV16; /* 31250 bps, standard for MIDI */ + +- /* RTS low, ints disabled */ +- acia.mid_ctrl = div | csize | parity | ++ /* RTS low, ints disabled */ ++ acia.mid_ctrl = div | csize | parity | + ((atari_switches & ATARI_SWITCH_MIDI) ? + ACIA_RHTID : ACIA_RLTID); + } + + void __init atari_debug_init(void) + { +- if (!strcmp( m68k_debug_device, "ser" )) { +- /* defaults to ser2 for a Falcon and ser1 otherwise */ +- strcpy( m68k_debug_device, MACH_IS_FALCON ? "ser2" : "ser1" ); +- +- } +- +- if (!strcmp( m68k_debug_device, "ser1" )) { +- /* ST-MFP Modem1 serial port */ +- atari_init_mfp_port( B9600|CS8 ); +- atari_console_driver.write = atari_mfp_console_write; +- } +- else if (!strcmp( m68k_debug_device, "ser2" )) { +- /* SCC Modem2 serial port */ +- atari_init_scc_port( B9600|CS8 ); +- atari_console_driver.write = atari_scc_console_write; +- } +- else if (!strcmp( m68k_debug_device, "midi" )) { +- /* MIDI port */ +- atari_init_midi_port( B9600|CS8 ); +- atari_console_driver.write = atari_midi_console_write; +- } +- else if (!strcmp( m68k_debug_device, "par" )) { +- /* parallel printer */ +- atari_turnoff_irq( IRQ_MFP_BUSY ); /* avoid ints */ +- sound_ym.rd_data_reg_sel = 7; /* select mixer control */ +- sound_ym.wd_data = 0xff; /* sound off, ports are output */ +- sound_ym.rd_data_reg_sel = 15; /* select port B */ +- sound_ym.wd_data = 0; /* no char */ +- sound_ym.rd_data_reg_sel = 14; /* select port A */ +- sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */ +- atari_console_driver.write = atari_par_console_write; +- } +- if (atari_console_driver.write) +- register_console(&atari_console_driver); +-} ++ if (!strcmp(m68k_debug_device, "ser")) { ++ /* defaults to ser2 for a Falcon and ser1 otherwise */ ++ strcpy(m68k_debug_device, MACH_IS_FALCON ? "ser2" : "ser1"); ++ } + +-/* +- * Local variables: +- * c-indent-level: 4 +- * tab-width: 8 +- * End: +- */ ++ if (!strcmp(m68k_debug_device, "ser1")) { ++ /* ST-MFP Modem1 serial port */ ++ atari_init_mfp_port(B9600|CS8); ++ atari_console_driver.write = atari_mfp_console_write; ++ } else if (!strcmp(m68k_debug_device, "ser2")) { ++ /* SCC Modem2 serial port */ ++ atari_init_scc_port(B9600|CS8); ++ atari_console_driver.write = atari_scc_console_write; ++ } else if (!strcmp(m68k_debug_device, "midi")) { ++ /* MIDI port */ ++ atari_init_midi_port(B9600|CS8); ++ atari_console_driver.write = atari_midi_console_write; ++ } else if (!strcmp(m68k_debug_device, "par")) { ++ /* parallel printer */ ++ atari_turnoff_irq(IRQ_MFP_BUSY); /* avoid ints */ ++ sound_ym.rd_data_reg_sel = 7; /* select mixer control */ ++ sound_ym.wd_data = 0xff; /* sound off, ports are output */ ++ sound_ym.rd_data_reg_sel = 15; /* select port B */ ++ sound_ym.wd_data = 0; /* no char */ ++ sound_ym.rd_data_reg_sel = 14; /* select port A */ ++ sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */ ++ atari_console_driver.write = atari_par_console_write; ++ } ++ if (atari_console_driver.write) ++ register_console(&atari_console_driver); ++} +--- linux-m68k-2.6.21.orig/arch/m68k/kernel/entry.S ++++ linux-m68k-2.6.21/arch/m68k/kernel/entry.S +@@ -692,7 +692,7 @@ sys_call_table: + .long sys_tgkill /* 265 */ + .long sys_utimes + .long sys_fadvise64_64 +- .long sys_mbind ++ .long sys_mbind + .long sys_get_mempolicy + .long sys_set_mempolicy /* 270 */ + .long sys_mq_open +--- linux-m68k-2.6.21.orig/arch/m68k/kernel/head.S ++++ linux-m68k-2.6.21/arch/m68k/kernel/head.S +@@ -3195,7 +3195,7 @@ func_start serial_putc,%d0/%d1/%a0/%a1 + jbra L(serial_putc_done) + 3: + #endif +- ++ + L(serial_putc_done): + func_return serial_putc + +--- linux-m68k-2.6.21.orig/arch/m68k/kernel/setup.c ++++ linux-m68k-2.6.21/arch/m68k/kernel/setup.c +@@ -133,78 +133,78 @@ extern void config_hp300(void); + extern void config_q40(void); + extern void config_sun3x(void); + +-extern void mac_debugging_short (int, short); +-extern void mac_debugging_long (int, long); +- + #define MASK_256K 0xfffc0000 + + extern void paging_init(void); + + static void __init m68k_parse_bootinfo(const struct bi_record *record) + { +- while (record->tag != BI_LAST) { +- int unknown = 0; +- const unsigned long *data = record->data; +- switch (record->tag) { +- case BI_MACHTYPE: +- case BI_CPUTYPE: +- case BI_FPUTYPE: +- case BI_MMUTYPE: +- /* Already set up by head.S */ +- break; +- +- case BI_MEMCHUNK: +- if (m68k_num_memory < NUM_MEMINFO) { +- m68k_memory[m68k_num_memory].addr = data[0]; +- m68k_memory[m68k_num_memory].size = data[1]; +- m68k_num_memory++; +- } else +- printk("m68k_parse_bootinfo: too many memory chunks\n"); +- break; +- +- case BI_RAMDISK: +- m68k_ramdisk.addr = data[0]; +- m68k_ramdisk.size = data[1]; +- break; +- +- case BI_COMMAND_LINE: +- strlcpy(m68k_command_line, (const char *)data, sizeof(m68k_command_line)); +- break; +- +- default: +- if (MACH_IS_AMIGA) +- unknown = amiga_parse_bootinfo(record); +- else if (MACH_IS_ATARI) +- unknown = atari_parse_bootinfo(record); +- else if (MACH_IS_MAC) +- unknown = mac_parse_bootinfo(record); +- else if (MACH_IS_Q40) +- unknown = q40_parse_bootinfo(record); +- else if (MACH_IS_BVME6000) +- unknown = bvme6000_parse_bootinfo(record); +- else if (MACH_IS_MVME16x) +- unknown = mvme16x_parse_bootinfo(record); +- else if (MACH_IS_MVME147) +- unknown = mvme147_parse_bootinfo(record); +- else if (MACH_IS_HP300) +- unknown = hp300_parse_bootinfo(record); +- else +- unknown = 1; +- } +- if (unknown) +- printk("m68k_parse_bootinfo: unknown tag 0x%04x ignored\n", +- record->tag); +- record = (struct bi_record *)((unsigned long)record+record->size); +- } ++ while (record->tag != BI_LAST) { ++ int unknown = 0; ++ const unsigned long *data = record->data; ++ ++ switch (record->tag) { ++ case BI_MACHTYPE: ++ case BI_CPUTYPE: ++ case BI_FPUTYPE: ++ case BI_MMUTYPE: ++ /* Already set up by head.S */ ++ break; ++ ++ case BI_MEMCHUNK: ++ if (m68k_num_memory < NUM_MEMINFO) { ++ m68k_memory[m68k_num_memory].addr = data[0]; ++ m68k_memory[m68k_num_memory].size = data[1]; ++ m68k_num_memory++; ++ } else ++ printk("m68k_parse_bootinfo: too many memory chunks\n"); ++ break; ++ ++ case BI_RAMDISK: ++ m68k_ramdisk.addr = data[0]; ++ m68k_ramdisk.size = data[1]; ++ break; ++ ++ case BI_COMMAND_LINE: ++ strlcpy(m68k_command_line, (const char *)data, ++ sizeof(m68k_command_line)); ++ break; ++ ++ default: ++ if (MACH_IS_AMIGA) ++ unknown = amiga_parse_bootinfo(record); ++ else if (MACH_IS_ATARI) ++ unknown = atari_parse_bootinfo(record); ++ else if (MACH_IS_MAC) ++ unknown = mac_parse_bootinfo(record); ++ else if (MACH_IS_Q40) ++ unknown = q40_parse_bootinfo(record); ++ else if (MACH_IS_BVME6000) ++ unknown = bvme6000_parse_bootinfo(record); ++ else if (MACH_IS_MVME16x) ++ unknown = mvme16x_parse_bootinfo(record); ++ else if (MACH_IS_MVME147) ++ unknown = mvme147_parse_bootinfo(record); ++ else if (MACH_IS_HP300) ++ unknown = hp300_parse_bootinfo(record); ++ else ++ unknown = 1; ++ } ++ if (unknown) ++ printk("m68k_parse_bootinfo: unknown tag 0x%04x ignored\n", ++ record->tag); ++ record = (struct bi_record *)((unsigned long)record + ++ record->size); ++ } + +- m68k_realnum_memory = m68k_num_memory; ++ m68k_realnum_memory = m68k_num_memory; + #ifdef CONFIG_SINGLE_MEMORY_CHUNK +- if (m68k_num_memory > 1) { +- printk("Ignoring last %i chunks of physical memory\n", +- (m68k_num_memory - 1)); +- m68k_num_memory = 1; +- } +- m68k_memoffset = m68k_memory[0].addr-PAGE_OFFSET; ++ if (m68k_num_memory > 1) { ++ printk("Ignoring last %i chunks of physical memory\n", ++ (m68k_num_memory - 1)); ++ m68k_num_memory = 1; ++ } ++ m68k_memoffset = m68k_memory[0].addr-PAGE_OFFSET; + #endif + } + +@@ -234,7 +234,7 @@ void __init setup_arch(char **cmdline_p) + /* clear the fpu if we have one */ + if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) { + volatile int zero = 0; +- asm __volatile__ ("frestore %0" : : "m" (zero)); ++ asm volatile ("frestore %0" : : "m" (zero)); + } + #endif + +@@ -262,32 +262,35 @@ void __init setup_arch(char **cmdline_p) + * For the m68k, this is currently only "debug=xxx" to enable printing + * certain kernel messages to some machine-specific device. + */ +- for( p = *cmdline_p; p && *p; ) { +- i = 0; +- if (!strncmp( p, "debug=", 6 )) { +- strlcpy( m68k_debug_device, p+6, sizeof(m68k_debug_device) ); +- if ((q = strchr( m68k_debug_device, ' ' ))) *q = 0; +- i = 1; +- } ++ for (p = *cmdline_p; p && *p;) { ++ i = 0; ++ if (!strncmp(p, "debug=", 6)) { ++ strlcpy(m68k_debug_device, p+6, sizeof(m68k_debug_device)); ++ q = strchr(m68k_debug_device, ' '); ++ if (q) ++ *q = 0; ++ i = 1; ++ } + #ifdef CONFIG_ATARI +- /* This option must be parsed very early */ +- if (!strncmp( p, "switches=", 9 )) { +- extern void atari_switches_setup( const char *, int ); +- atari_switches_setup( p+9, (q = strchr( p+9, ' ' )) ? +- (q - (p+9)) : strlen(p+9) ); +- i = 1; +- } +-#endif +- +- if (i) { +- /* option processed, delete it */ +- if ((q = strchr( p, ' ' ))) +- strcpy( p, q+1 ); +- else +- *p = 0; +- } else { +- if ((p = strchr( p, ' ' ))) ++p; +- } ++ /* This option must be parsed very early */ ++ if (!strncmp(p, "switches=", 9)) { ++ extern void atari_switches_setup(const char *, int); ++ q = strchr(p + 9, ' '); ++ atari_switches_setup(p + 9, q ? (q - (p + 9)) : strlen(p + 9)); ++ i = 1; ++ } ++#endif ++ ++ if (i) { ++ /* option processed, delete it */ ++ if ((q = strchr(p, ' '))) ++ strcpy(p, q + 1); ++ else ++ *p = 0; ++ } else { ++ if ((p = strchr(p, ' '))) ++ ++p; ++ } + } + + #ifdef CONFIG_DUMMY_CONSOLE +@@ -296,62 +299,62 @@ void __init setup_arch(char **cmdline_p) + + switch (m68k_machtype) { + #ifdef CONFIG_AMIGA +- case MACH_AMIGA: ++ case MACH_AMIGA: + config_amiga(); + break; + #endif + #ifdef CONFIG_ATARI +- case MACH_ATARI: ++ case MACH_ATARI: + config_atari(); + break; + #endif + #ifdef CONFIG_MAC +- case MACH_MAC: ++ case MACH_MAC: + config_mac(); + break; + #endif + #ifdef CONFIG_SUN3 +- case MACH_SUN3: ++ case MACH_SUN3: + config_sun3(); + break; + #endif + #ifdef CONFIG_APOLLO +- case MACH_APOLLO: ++ case MACH_APOLLO: + config_apollo(); + break; + #endif + #ifdef CONFIG_MVME147 +- case MACH_MVME147: ++ case MACH_MVME147: + config_mvme147(); + break; + #endif + #ifdef CONFIG_MVME16x +- case MACH_MVME16x: ++ case MACH_MVME16x: + config_mvme16x(); + break; + #endif + #ifdef CONFIG_BVME6000 +- case MACH_BVME6000: ++ case MACH_BVME6000: + config_bvme6000(); + break; + #endif + #ifdef CONFIG_HP300 +- case MACH_HP300: ++ case MACH_HP300: + config_hp300(); + break; + #endif + #ifdef CONFIG_Q40 +- case MACH_Q40: +- config_q40(); ++ case MACH_Q40: ++ config_q40(); + break; + #endif + #ifdef CONFIG_SUN3X +- case MACH_SUN3X: ++ case MACH_SUN3X: + config_sun3x(); + break; + #endif +- default: +- panic ("No configuration setup"); ++ default: ++ panic("No configuration setup"); + } + + #ifndef CONFIG_SUN3 +@@ -380,7 +383,7 @@ void __init setup_arch(char **cmdline_p) + reserve_bootmem(m68k_ramdisk.addr, m68k_ramdisk.size); + initrd_start = (unsigned long)phys_to_virt(m68k_ramdisk.addr); + initrd_end = initrd_start + m68k_ramdisk.size; +- printk ("initrd: %08lx - %08lx\n", initrd_start, initrd_end); ++ printk("initrd: %08lx - %08lx\n", initrd_start, initrd_end); + } + #endif + +@@ -402,18 +405,18 @@ void __init setup_arch(char **cmdline_p) + #if defined(CONFIG_ISA) && defined(MULTI_ISA) + #if defined(CONFIG_Q40) + if (MACH_IS_Q40) { +- isa_type = Q40_ISA; +- isa_sex = 0; ++ isa_type = Q40_ISA; ++ isa_sex = 0; + } + #elif defined(CONFIG_GG2) +- if (MACH_IS_AMIGA && AMIGAHW_PRESENT(GG2_ISA)){ +- isa_type = GG2_ISA; +- isa_sex = 0; ++ if (MACH_IS_AMIGA && AMIGAHW_PRESENT(GG2_ISA)) { ++ isa_type = GG2_ISA; ++ isa_sex = 0; + } + #elif defined(CONFIG_AMIGA_PCMCIA) +- if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)){ +- isa_type = AG_ISA; +- isa_sex = 1; ++ if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)) { ++ isa_type = AG_ISA; ++ isa_sex = 1; + } + #endif + #endif +@@ -421,66 +424,66 @@ void __init setup_arch(char **cmdline_p) + + static int show_cpuinfo(struct seq_file *m, void *v) + { +- const char *cpu, *mmu, *fpu; +- unsigned long clockfreq, clockfactor; ++ const char *cpu, *mmu, *fpu; ++ unsigned long clockfreq, clockfactor; + + #define LOOP_CYCLES_68020 (8) + #define LOOP_CYCLES_68030 (8) + #define LOOP_CYCLES_68040 (3) + #define LOOP_CYCLES_68060 (1) + +- if (CPU_IS_020) { +- cpu = "68020"; +- clockfactor = LOOP_CYCLES_68020; +- } else if (CPU_IS_030) { +- cpu = "68030"; +- clockfactor = LOOP_CYCLES_68030; +- } else if (CPU_IS_040) { +- cpu = "68040"; +- clockfactor = LOOP_CYCLES_68040; +- } else if (CPU_IS_060) { +- cpu = "68060"; +- clockfactor = LOOP_CYCLES_68060; +- } else { +- cpu = "680x0"; +- clockfactor = 0; +- } ++ if (CPU_IS_020) { ++ cpu = "68020"; ++ clockfactor = LOOP_CYCLES_68020; ++ } else if (CPU_IS_030) { ++ cpu = "68030"; ++ clockfactor = LOOP_CYCLES_68030; ++ } else if (CPU_IS_040) { ++ cpu = "68040"; ++ clockfactor = LOOP_CYCLES_68040; ++ } else if (CPU_IS_060) { ++ cpu = "68060"; ++ clockfactor = LOOP_CYCLES_68060; ++ } else { ++ cpu = "680x0"; ++ clockfactor = 0; ++ } + + #ifdef CONFIG_M68KFPU_EMU_ONLY +- fpu="none(soft float)"; ++ fpu = "none(soft float)"; + #else +- if (m68k_fputype & FPU_68881) +- fpu = "68881"; +- else if (m68k_fputype & FPU_68882) +- fpu = "68882"; +- else if (m68k_fputype & FPU_68040) +- fpu = "68040"; +- else if (m68k_fputype & FPU_68060) +- fpu = "68060"; +- else if (m68k_fputype & FPU_SUNFPA) +- fpu = "Sun FPA"; +- else +- fpu = "none"; +-#endif +- +- if (m68k_mmutype & MMU_68851) +- mmu = "68851"; +- else if (m68k_mmutype & MMU_68030) +- mmu = "68030"; +- else if (m68k_mmutype & MMU_68040) +- mmu = "68040"; +- else if (m68k_mmutype & MMU_68060) +- mmu = "68060"; +- else if (m68k_mmutype & MMU_SUN3) +- mmu = "Sun-3"; +- else if (m68k_mmutype & MMU_APOLLO) +- mmu = "Apollo"; +- else +- mmu = "unknown"; ++ if (m68k_fputype & FPU_68881) ++ fpu = "68881"; ++ else if (m68k_fputype & FPU_68882) ++ fpu = "68882"; ++ else if (m68k_fputype & FPU_68040) ++ fpu = "68040"; ++ else if (m68k_fputype & FPU_68060) ++ fpu = "68060"; ++ else if (m68k_fputype & FPU_SUNFPA) ++ fpu = "Sun FPA"; ++ else ++ fpu = "none"; ++#endif ++ ++ if (m68k_mmutype & MMU_68851) ++ mmu = "68851"; ++ else if (m68k_mmutype & MMU_68030) ++ mmu = "68030"; ++ else if (m68k_mmutype & MMU_68040) ++ mmu = "68040"; ++ else if (m68k_mmutype & MMU_68060) ++ mmu = "68060"; ++ else if (m68k_mmutype & MMU_SUN3) ++ mmu = "Sun-3"; ++ else if (m68k_mmutype & MMU_APOLLO) ++ mmu = "Apollo"; ++ else ++ mmu = "unknown"; + +- clockfreq = loops_per_jiffy*HZ*clockfactor; ++ clockfreq = loops_per_jiffy * HZ * clockfactor; + +- seq_printf(m, "CPU:\t\t%s\n" ++ seq_printf(m, "CPU:\t\t%s\n" + "MMU:\t\t%s\n" + "FPU:\t\t%s\n" + "Clocking:\t%lu.%1luMHz\n" +@@ -490,7 +493,7 @@ static int show_cpuinfo(struct seq_file + clockfreq/1000000,(clockfreq/100000)%10, + loops_per_jiffy/(500000/HZ),(loops_per_jiffy/(5000/HZ))%100, + loops_per_jiffy); +- return 0; ++ return 0; + } + + static void *c_start(struct seq_file *m, loff_t *pos) +@@ -506,44 +509,44 @@ static void c_stop(struct seq_file *m, v + { + } + struct seq_operations cpuinfo_op = { +- .start = c_start, +- .next = c_next, +- .stop = c_stop, +- .show = show_cpuinfo, ++ .start = c_start, ++ .next = c_next, ++ .stop = c_stop, ++ .show = show_cpuinfo, + }; + + int get_hardware_list(char *buffer) + { +- int len = 0; +- char model[80]; +- unsigned long mem; +- int i; +- +- if (mach_get_model) +- mach_get_model(model); +- else +- strcpy(model, "Unknown m68k"); +- +- len += sprintf(buffer+len, "Model:\t\t%s\n", model); +- for (mem = 0, i = 0; i < m68k_num_memory; i++) +- mem += m68k_memory[i].size; +- len += sprintf(buffer+len, "System Memory:\t%ldK\n", mem>>10); ++ int len = 0; ++ char model[80]; ++ unsigned long mem; ++ int i; ++ ++ if (mach_get_model) ++ mach_get_model(model); ++ else ++ strcpy(model, "Unknown m68k"); ++ ++ len += sprintf(buffer + len, "Model:\t\t%s\n", model); ++ for (mem = 0, i = 0; i < m68k_num_memory; i++) ++ mem += m68k_memory[i].size; ++ len += sprintf(buffer + len, "System Memory:\t%ldK\n", mem >> 10); + +- if (mach_get_hardware_list) +- len += mach_get_hardware_list(buffer+len); ++ if (mach_get_hardware_list) ++ len += mach_get_hardware_list(buffer + len); + +- return(len); ++ return len; + } + + void check_bugs(void) + { + #ifndef CONFIG_M68KFPU_EMU + if (m68k_fputype == 0) { +- printk( KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, " +- "WHICH IS REQUIRED BY LINUX/M68K ***\n" ); +- printk( KERN_EMERG "Upgrade your hardware or join the FPU " +- "emulation project\n" ); +- panic( "no FPU" ); ++ printk(KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, " ++ "WHICH IS REQUIRED BY LINUX/M68K ***\n"); ++ printk(KERN_EMERG "Upgrade your hardware or join the FPU " ++ "emulation project\n"); ++ panic("no FPU"); + } + #endif /* !CONFIG_M68KFPU_EMU */ + } +--- linux-m68k-2.6.21.orig/arch/m68k/mac/config.c ++++ linux-m68k-2.6.21/arch/m68k/mac/config.c +@@ -59,15 +59,15 @@ extern struct mem_info m68k_ramdisk; + + extern char m68k_command_line[CL_SIZE]; + +-void *mac_env; /* Loaded by the boot asm */ ++void *mac_env; /* Loaded by the boot asm */ + + /* The phys. video addr. - might be bogus on some machines */ + unsigned long mac_orig_videoaddr; + + /* Mac specific timer functions */ +-extern unsigned long mac_gettimeoffset (void); +-extern int mac_hwclk (int, struct rtc_time *); +-extern int mac_set_clock_mmss (unsigned long); ++extern unsigned long mac_gettimeoffset(void); ++extern int mac_hwclk(int, struct rtc_time *); ++extern int mac_set_clock_mmss(unsigned long); + extern int show_mac_interrupts(struct seq_file *, void *); + extern void iop_preinit(void); + extern void iop_init(void); +@@ -99,51 +99,52 @@ static void mac_sched_init(irq_handler_t + + int __init mac_parse_bootinfo(const struct bi_record *record) + { +- int unknown = 0; +- const u_long *data = record->data; ++ int unknown = 0; ++ const u_long *data = record->data; + +- switch (record->tag) { ++ switch (record->tag) { + case BI_MAC_MODEL: +- mac_bi_data.id = *data; +- break; ++ mac_bi_data.id = *data; ++ break; + case BI_MAC_VADDR: +- mac_bi_data.videoaddr = *data; +- break; ++ mac_bi_data.videoaddr = *data; ++ break; + case BI_MAC_VDEPTH: +- mac_bi_data.videodepth = *data; +- break; ++ mac_bi_data.videodepth = *data; ++ break; + case BI_MAC_VROW: +- mac_bi_data.videorow = *data; +- break; ++ mac_bi_data.videorow = *data; ++ break; + case BI_MAC_VDIM: +- mac_bi_data.dimensions = *data; +- break; ++ mac_bi_data.dimensions = *data; ++ break; + case BI_MAC_VLOGICAL: +- mac_bi_data.videological = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK); +- mac_orig_videoaddr = *data; +- break; ++ mac_bi_data.videological = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK); ++ mac_orig_videoaddr = *data; ++ break; + case BI_MAC_SCCBASE: +- mac_bi_data.sccbase = *data; +- break; ++ mac_bi_data.sccbase = *data; ++ break; + case BI_MAC_BTIME: +- mac_bi_data.boottime = *data; +- break; ++ mac_bi_data.boottime = *data; ++ break; + case BI_MAC_GMTBIAS: +- mac_bi_data.gmtbias = *data; +- break; ++ mac_bi_data.gmtbias = *data; ++ break; + case BI_MAC_MEMSIZE: +- mac_bi_data.memsize = *data; +- break; ++ mac_bi_data.memsize = *data; ++ break; + case BI_MAC_CPUID: +- mac_bi_data.cpuid = *data; +- break; +- case BI_MAC_ROMBASE: +- mac_bi_data.rombase = *data; +- break; ++ mac_bi_data.cpuid = *data; ++ break; ++ case BI_MAC_ROMBASE: ++ mac_bi_data.rombase = *data; ++ break; + default: +- unknown = 1; +- } +- return(unknown); ++ unknown = 1; ++ break; ++ } ++ return unknown; + } + + /* +@@ -155,6 +156,7 @@ int __init mac_parse_bootinfo(const stru + static void mac_cache_card_flush(int writeback) + { + unsigned long flags; ++ + local_irq_save(flags); + via_flush_cache(); + local_irq_restore(flags); +@@ -162,28 +164,27 @@ static void mac_cache_card_flush(int wri + + void __init config_mac(void) + { +- if (!MACH_IS_MAC) { +- printk(KERN_ERR "ERROR: no Mac, but config_mac() called!! \n"); +- } ++ if (!MACH_IS_MAC) ++ printk(KERN_ERR "ERROR: no Mac, but config_mac() called!! \n"); + +- mach_sched_init = mac_sched_init; +- mach_init_IRQ = mac_init_IRQ; +- mach_get_model = mac_get_model; +- mach_gettimeoffset = mac_gettimeoffset; ++ mach_sched_init = mac_sched_init; ++ mach_init_IRQ = mac_init_IRQ; ++ mach_get_model = mac_get_model; ++ mach_gettimeoffset = mac_gettimeoffset; + #warning move to adb/via init + #if 0 +- mach_hwclk = mac_hwclk; ++ mach_hwclk = mac_hwclk; + #endif +- mach_set_clock_mmss = mac_set_clock_mmss; +- mach_reset = mac_reset; +- mach_halt = mac_poweroff; +- mach_power_off = mac_poweroff; ++ mach_set_clock_mmss = mac_set_clock_mmss; ++ mach_reset = mac_reset; ++ mach_halt = mac_poweroff; ++ mach_power_off = mac_poweroff; + mach_max_dma_address = 0xffffffff; + #if 0 +- mach_debug_init = mac_debug_init; ++ mach_debug_init = mac_debug_init; + #endif + #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE) +- mach_beep = mac_mksound; ++ mach_beep = mac_mksound; + #endif + #ifdef CONFIG_HEARTBEAT + #if 0 +@@ -199,21 +200,22 @@ void __init config_mac(void) + mac_identify(); + mac_report_hardware(); + +- /* AFAIK only the IIci takes a cache card. The IIfx has onboard +- cache ... someone needs to figure out how to tell if it's on or +- not. */ ++ /* ++ * AFAIK only the IIci takes a cache card. The IIfx has onboard ++ * cache ... someone needs to figure out how to tell if it's on or ++ * not. ++ */ + + if (macintosh_config->ident == MAC_MODEL_IICI +- || macintosh_config->ident == MAC_MODEL_IIFX) { ++ || macintosh_config->ident == MAC_MODEL_IIFX) + mach_l2_flush = mac_cache_card_flush; +- } + + /* + * Check for machine specific fixups. + */ + + #ifdef OLD_NUBUS_CODE +- nubus_sweep_video(); ++ nubus_sweep_video(); + #endif + } + +@@ -233,8 +235,7 @@ void __init config_mac(void) + struct mac_model *macintosh_config; + EXPORT_SYMBOL(macintosh_config); + +-static struct mac_model mac_data_table[]= +-{ ++static struct mac_model mac_data_table[] = { + /* + * We'll pretend to be a Macintosh II, that's pretty safe. + */ +@@ -784,12 +785,12 @@ void mac_identify(void) + if (!model) { + /* no bootinfo model id -> NetBSD booter was used! */ + /* XXX FIXME: breaks for model > 31 */ +- model=(mac_bi_data.cpuid>>2)&63; +- printk (KERN_WARNING "No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n"); ++ model = (mac_bi_data.cpuid >> 2) & 63; ++ printk(KERN_WARNING "No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n"); + } + + macintosh_config = mac_data_table; +- for (m = macintosh_config ; m->ident != -1 ; m++) { ++ for (m = macintosh_config; m->ident != -1; m++) { + if (m->ident == model) { + macintosh_config = m; + break; +@@ -803,25 +804,25 @@ void mac_identify(void) + iop_preinit(); + mac_debug_init(); + +- printk (KERN_INFO "Detected Macintosh model: %d \n", model); ++ printk(KERN_INFO "Detected Macintosh model: %d \n", model); + + /* + * Report booter data: + */ +- printk (KERN_DEBUG " Penguin bootinfo data:\n"); +- printk (KERN_DEBUG " Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n", ++ printk(KERN_DEBUG " Penguin bootinfo data:\n"); ++ printk(KERN_DEBUG " Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n", + mac_bi_data.videoaddr, mac_bi_data.videorow, + mac_bi_data.videodepth, mac_bi_data.dimensions & 0xFFFF, + mac_bi_data.dimensions >> 16); +- printk (KERN_DEBUG " Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n", ++ printk(KERN_DEBUG " Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n", + mac_bi_data.videological, mac_orig_videoaddr, + mac_bi_data.sccbase); +- printk (KERN_DEBUG " Boottime: 0x%lx GMTBias: 0x%lx \n", ++ printk(KERN_DEBUG " Boottime: 0x%lx GMTBias: 0x%lx \n", + mac_bi_data.boottime, mac_bi_data.gmtbias); +- printk (KERN_DEBUG " Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n", ++ printk(KERN_DEBUG " Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n", + mac_bi_data.id, mac_bi_data.cpuid, mac_bi_data.memsize); + #if 0 +- printk ("Ramdisk: addr 0x%lx size 0x%lx\n", ++ printk("Ramdisk: addr 0x%lx size 0x%lx\n", + m68k_ramdisk.addr, m68k_ramdisk.size); + #endif + +@@ -830,22 +831,22 @@ void mac_identify(void) + */ + switch (macintosh_config->scsi_type) { + case MAC_SCSI_OLD: +- MACHW_SET(MAC_SCSI_80); +- break; ++ MACHW_SET(MAC_SCSI_80); ++ break; + case MAC_SCSI_QUADRA: + case MAC_SCSI_QUADRA2: + case MAC_SCSI_QUADRA3: +- MACHW_SET(MAC_SCSI_96); +- if ((macintosh_config->ident == MAC_MODEL_Q900) || +- (macintosh_config->ident == MAC_MODEL_Q950)) +- MACHW_SET(MAC_SCSI_96_2); +- break; ++ MACHW_SET(MAC_SCSI_96); ++ if ((macintosh_config->ident == MAC_MODEL_Q900) || ++ (macintosh_config->ident == MAC_MODEL_Q950)) ++ MACHW_SET(MAC_SCSI_96_2); ++ break; + default: +- printk(KERN_WARNING "config.c: wtf: unknown scsi, using 53c80\n"); +- MACHW_SET(MAC_SCSI_80); +- break; +- ++ printk(KERN_WARNING "config.c: wtf: unknown scsi, using 53c80\n"); ++ MACHW_SET(MAC_SCSI_80); ++ break; + } ++ + iop_init(); + via_init(); + oss_init(); +@@ -860,6 +861,6 @@ void mac_report_hardware(void) + + static void mac_get_model(char *str) + { +- strcpy(str,"Macintosh "); ++ strcpy(str, "Macintosh "); + strcat(str, macintosh_config->name); + } +--- linux-m68k-2.6.21.orig/arch/m68k/mac/debug.c ++++ linux-m68k-2.6.21/arch/m68k/mac/debug.c +@@ -52,7 +52,7 @@ extern void mac_serial_print(const char + */ + + #ifdef DEBUG_SCREEN +-static int peng=0, line=0; ++static int peng, line; + #endif + + void mac_debugging_short(int pos, short num) +@@ -74,15 +74,14 @@ void mac_debugging_short(int pos, short + } + + /* calculate current offset */ +- pengoffset=(unsigned char *)(mac_videobase+(150+line*2)*mac_rowbytes) +- +80*peng; ++ pengoffset = (unsigned char *)mac_videobase + ++ (150+line*2) * mac_rowbytes) + 80 * peng; + +- pptr=pengoffset; ++ pptr = pengoffset; + +- for(i=0;i<8*sizeof(short);i++) /* # of bits */ +- { ++ for (i = 0; i < 8 * sizeof(short); i++) { /* # of bits */ + /* value mask for bit i, reverse order */ +- *pptr++ = (num & ( 1 << (8*sizeof(short)-i-1) ) ? 0xFF : 0x00); ++ *pptr++ = (num & (1 << (8*sizeof(short)-i-1)) ? 0xFF : 0x00); + } + + peng++; +@@ -115,11 +114,10 @@ void mac_debugging_long(int pos, long ad + pengoffset=(unsigned char *)(mac_videobase+(150+line*2)*mac_rowbytes) + +80*peng; + +- pptr=pengoffset; ++ pptr = pengoffset; + +- for(i=0;i<8*sizeof(long);i++) /* # of bits */ +- { +- *pptr++ = (addr & ( 1 << (8*sizeof(long)-i-1) ) ? 0xFF : 0x00); ++ for (i = 0; i < 8 * sizeof(long); i++) { /* # of bits */ ++ *pptr++ = (addr & (1 << (8*sizeof(long)-i-1)) ? 0xFF : 0x00); + } + + peng++; +@@ -136,16 +134,15 @@ void mac_debugging_long(int pos, long ad + * TODO: serial debug code + */ + +-struct mac_SCC +- { +- u_char cha_b_ctrl; +- u_char char_dummy1; +- u_char cha_a_ctrl; +- u_char char_dummy2; +- u_char cha_b_data; +- u_char char_dummy3; +- u_char cha_a_data; +- }; ++struct mac_SCC { ++ u_char cha_b_ctrl; ++ u_char char_dummy1; ++ u_char cha_a_ctrl; ++ u_char char_dummy2; ++ u_char cha_b_data; ++ u_char char_dummy3; ++ u_char cha_a_data; ++}; + + # define scc (*((volatile struct mac_SCC*)mac_bi_data.sccbase)) + +@@ -158,9 +155,9 @@ int mac_SCC_reset_done; + static int scc_port = -1; + + static struct console mac_console_driver = { +- .name = "debug", +- .flags = CON_PRINTBUFFER, +- .index = -1, ++ .name = "debug", ++ .flags = CON_PRINTBUFFER, ++ .index = -1, + }; + + /* +@@ -178,8 +175,8 @@ static struct console mac_console_driver + * this driver if Mac. + */ + +-void mac_debug_console_write (struct console *co, const char *str, +- unsigned int count) ++void mac_debug_console_write(struct console *co, const char *str, ++ unsigned int count) + { + mac_serial_print(str); + } +@@ -190,48 +187,50 @@ void mac_debug_console_write (struct con + + #define uSEC 1 + +-static inline void mac_sccb_out (char c) ++static inline void mac_sccb_out(char c) + { +- int i; +- do { +- for( i = uSEC; i > 0; --i ) ++ int i; ++ ++ do { ++ for (i = uSEC; i > 0; --i) ++ barrier(); ++ } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */ ++ for (i = uSEC; i > 0; --i) + barrier(); +- } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */ +- for( i = uSEC; i > 0; --i ) +- barrier(); +- scc.cha_b_data = c; ++ scc.cha_b_data = c; + } + +-static inline void mac_scca_out (char c) ++static inline void mac_scca_out(char c) + { +- int i; +- do { +- for( i = uSEC; i > 0; --i ) ++ int i; ++ ++ do { ++ for (i = uSEC; i > 0; --i) ++ barrier(); ++ } while (!(scc.cha_a_ctrl & 0x04)); /* wait for tx buf empty */ ++ for (i = uSEC; i > 0; --i) + barrier(); +- } while (!(scc.cha_a_ctrl & 0x04)); /* wait for tx buf empty */ +- for( i = uSEC; i > 0; --i ) +- barrier(); +- scc.cha_a_data = c; +-} +- +-void mac_sccb_console_write (struct console *co, const char *str, +- unsigned int count) +-{ +- while (count--) { +- if (*str == '\n') +- mac_sccb_out( '\r' ); +- mac_sccb_out( *str++ ); +- } +-} +- +-void mac_scca_console_write (struct console *co, const char *str, +- unsigned int count) +-{ +- while (count--) { +- if (*str == '\n') +- mac_scca_out( '\r' ); +- mac_scca_out( *str++ ); +- } ++ scc.cha_a_data = c; ++} ++ ++void mac_sccb_console_write(struct console *co, const char *str, ++ unsigned int count) ++{ ++ while (count--) { ++ if (*str == '\n') ++ mac_sccb_out('\r'); ++ mac_sccb_out(*str++); ++ } ++} ++ ++void mac_scca_console_write(struct console *co, const char *str, ++ unsigned int count) ++{ ++ while (count--) { ++ if (*str == '\n') ++ mac_scca_out('\r'); ++ mac_scca_out(*str++); ++ } + } + + +@@ -239,41 +238,41 @@ void mac_scca_console_write (struct cons + * SCC serial ports. They're used by the debugging interface, kgdb, and the + * serial console code. */ + #define SCCB_WRITE(reg,val) \ +- do { \ +- int i; \ +- scc.cha_b_ctrl = (reg); \ +- for( i = uSEC; i > 0; --i ) \ +- barrier(); \ +- scc.cha_b_ctrl = (val); \ +- for( i = uSEC; i > 0; --i ) \ +- barrier(); \ +- } while(0) ++ do { \ ++ int i; \ ++ scc.cha_b_ctrl = (reg); \ ++ for (i = uSEC; i > 0; --i) \ ++ barrier(); \ ++ scc.cha_b_ctrl = (val); \ ++ for (i = uSEC; i > 0; --i) \ ++ barrier(); \ ++ } while(0) + + #define SCCA_WRITE(reg,val) \ +- do { \ +- int i; \ +- scc.cha_a_ctrl = (reg); \ +- for( i = uSEC; i > 0; --i ) \ +- barrier(); \ +- scc.cha_a_ctrl = (val); \ +- for( i = uSEC; i > 0; --i ) \ +- barrier(); \ +- } while(0) ++ do { \ ++ int i; \ ++ scc.cha_a_ctrl = (reg); \ ++ for (i = uSEC; i > 0; --i) \ ++ barrier(); \ ++ scc.cha_a_ctrl = (val); \ ++ for (i = uSEC; i > 0; --i) \ ++ barrier(); \ ++ } while(0) + + /* loops_per_jiffy isn't initialized yet, so we can't use udelay(). This does a + * delay of ~ 60us. */ + /* Mac: loops_per_jiffy min. 19000 ^= .5 us; MFPDELAY was 0.6 us*/ +-#define LONG_DELAY() \ +- do { \ +- int i; \ +- for( i = 60*uSEC; i > 0; --i ) \ +- barrier(); \ +- } while(0) ++#define LONG_DELAY() \ ++ do { \ ++ int i; \ ++ for (i = 60*uSEC; i > 0; --i) \ ++ barrier(); \ ++ } while(0) + + #ifndef CONFIG_SERIAL_CONSOLE +-static void __init mac_init_scc_port( int cflag, int port ) ++static void __init mac_init_scc_port(int cflag, int port) + #else +-void mac_init_scc_port( int cflag, int port ) ++void mac_init_scc_port(int cflag, int port) + #endif + { + extern int mac_SCC_reset_done; +@@ -292,71 +291,71 @@ void mac_init_scc_port( int cflag, int p + /* reg12 (BRG low) */ + { 94, 62, 46, 22, 10, 4, 1, 0, 0 }; + +- int baud = cflag & CBAUD; +- int clksrc, clkmode, div, reg3, reg5; ++ int baud = cflag & CBAUD; ++ int clksrc, clkmode, div, reg3, reg5; + +- if (cflag & CBAUDEX) +- baud += B38400; +- if (baud < B1200 || baud > B38400+2) +- baud = B9600; /* use default 9600bps for non-implemented rates */ +- baud -= B1200; /* tables starts at 1200bps */ +- +- clksrc = clksrc_table[baud]; +- clkmode = clkmode_table[baud]; +- div = div_table[baud]; +- +- reg3 = (((cflag & CSIZE) == CS8) ? 0xc0 : 0x40); +- reg5 = (((cflag & CSIZE) == CS8) ? 0x60 : 0x20) | 0x82 /* assert DTR/RTS */; +- +- if (port == 1) { +- (void)scc.cha_b_ctrl; /* reset reg pointer */ +- SCCB_WRITE( 9, 0xc0 ); /* reset */ +- LONG_DELAY(); /* extra delay after WR9 access */ +- SCCB_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 | +- 0x04 /* 1 stopbit */ | +- clkmode ); +- SCCB_WRITE( 3, reg3 ); +- SCCB_WRITE( 5, reg5 ); +- SCCB_WRITE( 9, 0 ); /* no interrupts */ +- LONG_DELAY(); /* extra delay after WR9 access */ +- SCCB_WRITE( 10, 0 ); /* NRZ mode */ +- SCCB_WRITE( 11, clksrc ); /* main clock source */ +- SCCB_WRITE( 12, div ); /* BRG value */ +- SCCB_WRITE( 13, 0 ); /* BRG high byte */ +- SCCB_WRITE( 14, 1 ); +- SCCB_WRITE( 3, reg3 | 1 ); +- SCCB_WRITE( 5, reg5 | 8 ); +- } else if (port == 0) { +- (void)scc.cha_a_ctrl; /* reset reg pointer */ +- SCCA_WRITE( 9, 0xc0 ); /* reset */ +- LONG_DELAY(); /* extra delay after WR9 access */ +- SCCA_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 | ++ if (cflag & CBAUDEX) ++ baud += B38400; ++ if (baud < B1200 || baud > B38400+2) ++ baud = B9600; /* use default 9600bps for non-implemented rates */ ++ baud -= B1200; /* tables starts at 1200bps */ ++ ++ clksrc = clksrc_table[baud]; ++ clkmode = clkmode_table[baud]; ++ div = div_table[baud]; ++ ++ reg3 = (((cflag & CSIZE) == CS8) ? 0xc0 : 0x40); ++ reg5 = (((cflag & CSIZE) == CS8) ? 0x60 : 0x20) | 0x82 /* assert DTR/RTS */; ++ ++ if (port == 1) { ++ (void)scc.cha_b_ctrl; /* reset reg pointer */ ++ SCCB_WRITE(9, 0xc0); /* reset */ ++ LONG_DELAY(); /* extra delay after WR9 access */ ++ SCCB_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 | ++ 0x04 /* 1 stopbit */ | ++ clkmode); ++ SCCB_WRITE(3, reg3); ++ SCCB_WRITE(5, reg5); ++ SCCB_WRITE(9, 0); /* no interrupts */ ++ LONG_DELAY(); /* extra delay after WR9 access */ ++ SCCB_WRITE(10, 0); /* NRZ mode */ ++ SCCB_WRITE(11, clksrc); /* main clock source */ ++ SCCB_WRITE(12, div); /* BRG value */ ++ SCCB_WRITE(13, 0); /* BRG high byte */ ++ SCCB_WRITE(14, 1); ++ SCCB_WRITE(3, reg3 | 1); ++ SCCB_WRITE(5, reg5 | 8); ++ } else if (port == 0) { ++ (void)scc.cha_a_ctrl; /* reset reg pointer */ ++ SCCA_WRITE(9, 0xc0); /* reset */ ++ LONG_DELAY(); /* extra delay after WR9 access */ ++ SCCA_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 | + 0x04 /* 1 stopbit */ | +- clkmode ); +- SCCA_WRITE( 3, reg3 ); +- SCCA_WRITE( 5, reg5 ); +- SCCA_WRITE( 9, 0 ); /* no interrupts */ +- LONG_DELAY(); /* extra delay after WR9 access */ +- SCCA_WRITE( 10, 0 ); /* NRZ mode */ +- SCCA_WRITE( 11, clksrc ); /* main clock source */ +- SCCA_WRITE( 12, div ); /* BRG value */ +- SCCA_WRITE( 13, 0 ); /* BRG high byte */ +- SCCA_WRITE( 14, 1 ); +- SCCA_WRITE( 3, reg3 | 1 ); +- SCCA_WRITE( 5, reg5 | 8 ); +- } ++ clkmode); ++ SCCA_WRITE(3, reg3); ++ SCCA_WRITE(5, reg5); ++ SCCA_WRITE(9, 0); /* no interrupts */ ++ LONG_DELAY(); /* extra delay after WR9 access */ ++ SCCA_WRITE(10, 0); /* NRZ mode */ ++ SCCA_WRITE(11, clksrc); /* main clock source */ ++ SCCA_WRITE(12, div); /* BRG value */ ++ SCCA_WRITE(13, 0); /* BRG high byte */ ++ SCCA_WRITE(14, 1); ++ SCCA_WRITE(3, reg3 | 1); ++ SCCA_WRITE(5, reg5 | 8); ++ } + +- mac_SCC_reset_done = 1; +- mac_SCC_init_done = 1; ++ mac_SCC_reset_done = 1; ++ mac_SCC_init_done = 1; + } + #endif /* DEBUG_SERIAL */ + +-void mac_init_scca_port( int cflag ) ++void mac_init_scca_port(int cflag) + { + mac_init_scc_port(cflag, 0); + } + +-void mac_init_sccb_port( int cflag ) ++void mac_init_sccb_port(int cflag) + { + mac_init_scc_port(cflag, 1); + } +@@ -364,34 +363,26 @@ void mac_init_sccb_port( int cflag ) + void __init mac_debug_init(void) + { + #ifdef DEBUG_SERIAL +- if ( !strcmp( m68k_debug_device, "ser" ) +- || !strcmp( m68k_debug_device, "ser1" )) { +- /* Mac modem port */ +- mac_init_scc_port( B9600|CS8, 0 ); +- mac_console_driver.write = mac_scca_console_write; +- scc_port = 0; +- } +- else if (!strcmp( m68k_debug_device, "ser2" )) { +- /* Mac printer port */ +- mac_init_scc_port( B9600|CS8, 1 ); +- mac_console_driver.write = mac_sccb_console_write; +- scc_port = 1; +- } ++ if (!strcmp(m68k_debug_device, "ser") || ++ !strcmp(m68k_debug_device, "ser1")) { ++ /* Mac modem port */ ++ mac_init_scc_port(B9600|CS8, 0); ++ mac_console_driver.write = mac_scca_console_write; ++ scc_port = 0; ++ } else if (!strcmp(m68k_debug_device, "ser2")) { ++ /* Mac printer port */ ++ mac_init_scc_port(B9600|CS8, 1); ++ mac_console_driver.write = mac_sccb_console_write; ++ scc_port = 1; ++ } + #endif + #ifdef DEBUG_HEADS +- if ( !strcmp( m68k_debug_device, "scn" ) +- || !strcmp( m68k_debug_device, "con" )) { +- /* display, using head.S console routines */ +- mac_console_driver.write = mac_debug_console_write; +- } ++ if (!strcmp(m68k_debug_device, "scn") || ++ !strcmp(m68k_debug_device, "con")) { ++ /* display, using head.S console routines */ ++ mac_console_driver.write = mac_debug_console_write; ++ } + #endif +- if (mac_console_driver.write) +- register_console(&mac_console_driver); ++ if (mac_console_driver.write) ++ register_console(&mac_console_driver); + } +- +-/* +- * Local variables: +- * c-indent-level: 4 +- * tab-width: 8 +- * End: +- */ +--- linux-m68k-2.6.21.orig/arch/m68k/q40/config.c ++++ linux-m68k-2.6.21/arch/m68k/q40/config.c +@@ -35,35 +35,35 @@ + #include <asm/machdep.h> + #include <asm/q40_master.h> + +-extern irqreturn_t q40_process_int (int level, struct pt_regs *regs); +-extern void q40_init_IRQ (void); ++extern irqreturn_t q40_process_int(int level, struct pt_regs *regs); ++extern void q40_init_IRQ(void); + static void q40_get_model(char *model); + static int q40_get_hardware_list(char *buffer); + extern void q40_sched_init(irq_handler_t handler); + +-extern unsigned long q40_gettimeoffset (void); +-extern int q40_hwclk (int, struct rtc_time *); +-extern unsigned int q40_get_ss (void); +-extern int q40_set_clock_mmss (unsigned long); ++extern unsigned long q40_gettimeoffset(void); ++extern int q40_hwclk(int, struct rtc_time *); ++extern unsigned int q40_get_ss(void); ++extern int q40_set_clock_mmss(unsigned long); + static int q40_get_rtc_pll(struct rtc_pll_info *pll); + static int q40_set_rtc_pll(struct rtc_pll_info *pll); +-extern void q40_reset (void); ++extern void q40_reset(void); + void q40_halt(void); + extern void q40_waitbut(void); +-void q40_set_vectors (void); ++void q40_set_vectors(void); + +-extern void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/ ); ++extern void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/); + + extern char m68k_debug_device[]; + static void q40_mem_console_write(struct console *co, const char *b, +- unsigned int count); ++ unsigned int count); + + extern int ql_ticks; + + static struct console q40_console_driver = { +- .name = "debug", +- .flags = CON_PRINTBUFFER, +- .index = -1, ++ .name = "debug", ++ .flags = CON_PRINTBUFFER, ++ .index = -1, + }; + + +@@ -74,150 +74,157 @@ static int _cpleft; + static void q40_mem_console_write(struct console *co, const char *s, + unsigned int count) + { +- char *p=(char *)s; ++ const char *p = s; + +- if (count<_cpleft) +- while (count-- >0){ +- *q40_mem_cptr=*p++; +- q40_mem_cptr+=4; +- _cpleft--; +- } ++ if (count < _cpleft) { ++ while (count-- > 0) { ++ *q40_mem_cptr = *p++; ++ q40_mem_cptr += 4; ++ _cpleft--; ++ } ++ } + } ++ + #if 0 + void printq40(char *str) + { +- int l=strlen(str); +- char *p=q40_mem_cptr; ++ int l = strlen(str); ++ char *p = q40_mem_cptr; + +- while (l-- >0 && _cpleft-- >0) +- { +- *p=*str++; +- p+=4; +- } +- q40_mem_cptr=p; ++ while (l-- > 0 && _cpleft-- > 0) { ++ *p = *str++; ++ p += 4; ++ } ++ q40_mem_cptr = p; + } + #endif + +-static int halted=0; ++static int halted; + + #ifdef CONFIG_HEARTBEAT + static void q40_heartbeat(int on) + { +- if (halted) return; ++ if (halted) ++ return; + +- if (on) +- Q40_LED_ON(); +- else +- Q40_LED_OFF(); ++ if (on) ++ Q40_LED_ON(); ++ else ++ Q40_LED_OFF(); + } + #endif + + void q40_reset(void) + { +- halted=1; +- printk ("\n\n*******************************************\n" ++ halted = 1; ++ printk("\n\n*******************************************\n" + "Called q40_reset : press the RESET button!! \n" + "*******************************************\n"); + Q40_LED_ON(); +- while(1) ; ++ while (1) ++ ; + } + void q40_halt(void) + { +- halted=1; +- printk ("\n\n*******************\n" +- " Called q40_halt\n" +- "*******************\n"); ++ halted = 1; ++ printk("\n\n*******************\n" ++ " Called q40_halt\n" ++ "*******************\n"); + Q40_LED_ON(); +- while(1) ; ++ while (1) ++ ; + } + + static void q40_get_model(char *model) + { +- sprintf(model, "Q40"); ++ sprintf(model, "Q40"); + } + + /* No hardware options on Q40? */ + + static int q40_get_hardware_list(char *buffer) + { +- *buffer = '\0'; +- return 0; ++ *buffer = '\0'; ++ return 0; + } + +-static unsigned int serports[]={0x3f8,0x2f8,0x3e8,0x2e8,0}; ++static unsigned int serports[] = ++{ ++ 0x3f8,0x2f8,0x3e8,0x2e8,0 ++}; + void q40_disable_irqs(void) + { +- unsigned i,j; ++ unsigned i, j; + +- j=0; +- while((i=serports[j++])) outb(0,i+UART_IER); +- master_outb(0,EXT_ENABLE_REG); +- master_outb(0,KEY_IRQ_ENABLE_REG); ++ j = 0; ++ while ((i = serports[j++])) ++ outb(0, i + UART_IER); ++ master_outb(0, EXT_ENABLE_REG); ++ master_outb(0, KEY_IRQ_ENABLE_REG); + } + + void __init config_q40(void) + { +- mach_sched_init = q40_sched_init; ++ mach_sched_init = q40_sched_init; + +- mach_init_IRQ = q40_init_IRQ; +- mach_gettimeoffset = q40_gettimeoffset; +- mach_hwclk = q40_hwclk; +- mach_get_ss = q40_get_ss; +- mach_get_rtc_pll = q40_get_rtc_pll; +- mach_set_rtc_pll = q40_set_rtc_pll; +- mach_set_clock_mmss = q40_set_clock_mmss; +- +- mach_reset = q40_reset; +- mach_get_model = q40_get_model; +- mach_get_hardware_list = q40_get_hardware_list; ++ mach_init_IRQ = q40_init_IRQ; ++ mach_gettimeoffset = q40_gettimeoffset; ++ mach_hwclk = q40_hwclk; ++ mach_get_ss = q40_get_ss; ++ mach_get_rtc_pll = q40_get_rtc_pll; ++ mach_set_rtc_pll = q40_set_rtc_pll; ++ mach_set_clock_mmss = q40_set_clock_mmss; ++ ++ mach_reset = q40_reset; ++ mach_get_model = q40_get_model; ++ mach_get_hardware_list = q40_get_hardware_list; + + #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE) +- mach_beep = q40_mksound; ++ mach_beep = q40_mksound; + #endif + #ifdef CONFIG_HEARTBEAT +- mach_heartbeat = q40_heartbeat; ++ mach_heartbeat = q40_heartbeat; + #endif +- mach_halt = q40_halt; ++ mach_halt = q40_halt; + +- /* disable a few things that SMSQ might have left enabled */ +- q40_disable_irqs(); ++ /* disable a few things that SMSQ might have left enabled */ ++ q40_disable_irqs(); + +- /* no DMA at all, but ide-scsi requires it.. make sure +- * all physical RAM fits into the boundary - otherwise +- * allocator may play costly and useless tricks */ +- mach_max_dma_address = 1024*1024*1024; +- +- /* useful for early debugging stages - writes kernel messages into SRAM */ +- if (!strncmp( m68k_debug_device,"mem",3 )) +- { +- /*printk("using NVRAM debug, q40_mem_cptr=%p\n",q40_mem_cptr);*/ +- _cpleft=2000-((long)q40_mem_cptr-0xff020000)/4; +- q40_console_driver.write = q40_mem_console_write; +- register_console(&q40_console_driver); +- } ++ /* no DMA at all, but ide-scsi requires it.. make sure ++ * all physical RAM fits into the boundary - otherwise ++ * allocator may play costly and useless tricks */ ++ mach_max_dma_address = 1024*1024*1024; ++ ++ /* useful for early debugging stages - writes kernel messages into SRAM */ ++ if (!strncmp( m68k_debug_device,"mem", 3)) { ++ /*printk("using NVRAM debug, q40_mem_cptr=%p\n",q40_mem_cptr);*/ ++ _cpleft = 2000 - ((long)q40_mem_cptr-0xff020000) / 4; ++ q40_console_driver.write = q40_mem_console_write; ++ register_console(&q40_console_driver); ++ } + } + + + int q40_parse_bootinfo(const struct bi_record *rec) + { +- return 1; ++ return 1; + } + + +-static inline unsigned char bcd2bin (unsigned char b) ++static inline unsigned char bcd2bin(unsigned char b) + { +- return ((b>>4)*10 + (b&15)); ++ return (b >> 4) * 10 + (b & 15); + } + +-static inline unsigned char bin2bcd (unsigned char b) ++static inline unsigned char bin2bcd(unsigned char b) + { +- return (((b/10)*16) + (b%10)); ++ return (b / 10) * 16 + (b % 10); + } + + +-unsigned long q40_gettimeoffset (void) ++unsigned long q40_gettimeoffset(void) + { +- return 5000*(ql_ticks!=0); ++ return 5000 * (ql_ticks != 0); + } + + +@@ -238,9 +245,9 @@ unsigned long q40_gettimeoffset (void) + + int q40_hwclk(int op, struct rtc_time *t) + { +- if (op) +- { /* Write.... */ +- Q40_RTC_CTRL |= Q40_RTC_WRITE; ++ if (op) { ++ /* Write.... */ ++ Q40_RTC_CTRL |= Q40_RTC_WRITE; + + Q40_RTC_SECS = bin2bcd(t->tm_sec); + Q40_RTC_MINS = bin2bcd(t->tm_min); +@@ -251,25 +258,23 @@ int q40_hwclk(int op, struct rtc_time *t + if (t->tm_wday >= 0) + Q40_RTC_DOW = bin2bcd(t->tm_wday+1); + +- Q40_RTC_CTRL &= ~(Q40_RTC_WRITE); +- } +- else +- { /* Read.... */ +- Q40_RTC_CTRL |= Q40_RTC_READ; +- +- t->tm_year = bcd2bin (Q40_RTC_YEAR); +- t->tm_mon = bcd2bin (Q40_RTC_MNTH)-1; +- t->tm_mday = bcd2bin (Q40_RTC_DATE); +- t->tm_hour = bcd2bin (Q40_RTC_HOUR); +- t->tm_min = bcd2bin (Q40_RTC_MINS); +- t->tm_sec = bcd2bin (Q40_RTC_SECS); +- +- Q40_RTC_CTRL &= ~(Q40_RTC_READ); +- +- if (t->tm_year < 70) +- t->tm_year += 100; +- t->tm_wday = bcd2bin(Q40_RTC_DOW)-1; +- ++ Q40_RTC_CTRL &= ~(Q40_RTC_WRITE); ++ } else { ++ /* Read.... */ ++ Q40_RTC_CTRL |= Q40_RTC_READ; ++ ++ t->tm_year = bcd2bin (Q40_RTC_YEAR); ++ t->tm_mon = bcd2bin (Q40_RTC_MNTH)-1; ++ t->tm_mday = bcd2bin (Q40_RTC_DATE); ++ t->tm_hour = bcd2bin (Q40_RTC_HOUR); ++ t->tm_min = bcd2bin (Q40_RTC_MINS); ++ t->tm_sec = bcd2bin (Q40_RTC_SECS); ++ ++ Q40_RTC_CTRL &= ~(Q40_RTC_READ); ++ ++ if (t->tm_year < 70) ++ t->tm_year += 100; ++ t->tm_wday = bcd2bin(Q40_RTC_DOW)-1; + } + + return 0; +@@ -285,29 +290,25 @@ unsigned int q40_get_ss(void) + * clock is out by > 30 minutes. Logic lifted from atari code. + */ + +-int q40_set_clock_mmss (unsigned long nowtime) ++int q40_set_clock_mmss(unsigned long nowtime) + { + int retval = 0; + short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; + + int rtc_minutes; + ++ rtc_minutes = bcd2bin(Q40_RTC_MINS); + +- rtc_minutes = bcd2bin (Q40_RTC_MINS); +- +- if ((rtc_minutes < real_minutes +- ? real_minutes - rtc_minutes +- : rtc_minutes - real_minutes) < 30) +- { +- Q40_RTC_CTRL |= Q40_RTC_WRITE; ++ if ((rtc_minutes < real_minutes ? ++ real_minutes - rtc_minutes : ++ rtc_minutes - real_minutes) < 30) { ++ Q40_RTC_CTRL |= Q40_RTC_WRITE; + Q40_RTC_MINS = bin2bcd(real_minutes); + Q40_RTC_SECS = bin2bcd(real_seconds); + Q40_RTC_CTRL &= ~(Q40_RTC_WRITE); +- } +- else ++ } else + retval = -1; + +- + return retval; + } + +@@ -318,21 +319,23 @@ int q40_set_clock_mmss (unsigned long no + + static int q40_get_rtc_pll(struct rtc_pll_info *pll) + { +- int tmp=Q40_RTC_CTRL; ++ int tmp = Q40_RTC_CTRL; ++ + pll->pll_value = tmp & Q40_RTC_PLL_MASK; + if (tmp & Q40_RTC_PLL_SIGN) + pll->pll_value = -pll->pll_value; +- pll->pll_max=31; +- pll->pll_min=-31; +- pll->pll_posmult=512; +- pll->pll_negmult=256; +- pll->pll_clock=125829120; ++ pll->pll_max = 31; ++ pll->pll_min = -31; ++ pll->pll_posmult = 512; ++ pll->pll_negmult = 256; ++ pll->pll_clock = 125829120; ++ + return 0; + } + + static int q40_set_rtc_pll(struct rtc_pll_info *pll) + { +- if (!pll->pll_ctrl){ ++ if (!pll->pll_ctrl) { + /* the docs are a bit unclear so I am doublesetting */ + /* RTC_WRITE here ... */ + int tmp = (pll->pll_value & 31) | (pll->pll_value<0 ? 32 : 0) | +--- linux-m68k-2.6.21.orig/arch/m68k/sun3x/prom.c ++++ linux-m68k-2.6.21/arch/m68k/sun3x/prom.c +@@ -34,43 +34,43 @@ e_vector *sun3x_prom_vbr; + /* Handle returning to the prom */ + void sun3x_halt(void) + { +- unsigned long flags; ++ unsigned long flags; + +- /* Disable interrupts while we mess with things */ +- local_irq_save(flags); ++ /* Disable interrupts while we mess with things */ ++ local_irq_save(flags); + +- /* Restore prom vbr */ +- __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr)); ++ /* Restore prom vbr */ ++ asm volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr)); + +- /* Restore prom NMI clock */ +-// sun3x_disable_intreg(5); +- sun3_enable_irq(7); ++ /* Restore prom NMI clock */ ++// sun3x_disable_intreg(5); ++ sun3_enable_irq(7); + +- /* Let 'er rip */ +- __asm__ volatile ("trap #14" : : ); ++ /* Let 'er rip */ ++ asm volatile ("trap #14"); + +- /* Restore everything */ +- sun3_disable_irq(7); +- sun3_enable_irq(5); ++ /* Restore everything */ ++ sun3_disable_irq(7); ++ sun3_enable_irq(5); + +- __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors)); +- local_irq_restore(flags); ++ asm volatile ("movec %0,%%vbr" : : "r" ((void*)vectors)); ++ local_irq_restore(flags); + } + + void sun3x_reboot(void) + { +- /* This never returns, don't bother saving things */ +- local_irq_disable(); ++ /* This never returns, don't bother saving things */ ++ local_irq_disable(); + +- /* Restore prom vbr */ +- __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr)); ++ /* Restore prom vbr */ ++ asm volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr)); + +- /* Restore prom NMI clock */ +- sun3_disable_irq(5); +- sun3_enable_irq(7); ++ /* Restore prom NMI clock */ ++ sun3_disable_irq(5); ++ sun3_enable_irq(7); + +- /* Let 'er rip */ +- (*romvec->pv_reboot)("vmlinux"); ++ /* Let 'er rip */ ++ (*romvec->pv_reboot)("vmlinux"); + } + + extern char m68k_debug_device[]; +@@ -78,54 +78,52 @@ extern char m68k_debug_device[]; + static void sun3x_prom_write(struct console *co, const char *s, + unsigned int count) + { +- while (count--) { +- if (*s == '\n') +- sun3x_putchar('\r'); +- sun3x_putchar(*s++); +- } ++ while (count--) { ++ if (*s == '\n') ++ sun3x_putchar('\r'); ++ sun3x_putchar(*s++); ++ } + } + + /* debug console - write-only */ + + static struct console sun3x_debug = { +- .name = "debug", +- .write = sun3x_prom_write, +- .flags = CON_PRINTBUFFER, +- .index = -1, ++ .name = "debug", ++ .write = sun3x_prom_write, ++ .flags = CON_PRINTBUFFER, ++ .index = -1, + }; + + void sun3x_prom_init(void) + { +- /* Read the vector table */ ++ /* Read the vector table */ + +- sun3x_putchar = *(void (**)(int)) (SUN3X_P_PUTCHAR); +- sun3x_getchar = *(int (**)(void)) (SUN3X_P_GETCHAR); +- sun3x_mayget = *(int (**)(void)) (SUN3X_P_MAYGET); +- sun3x_mayput = *(int (**)(int)) (SUN3X_P_MAYPUT); +- sun3x_prom_reboot = *(void (**)(void)) (SUN3X_P_REBOOT); +- sun3x_prom_abort = *(e_vector *) (SUN3X_P_ABORT); +- romvec = (struct linux_romvec *)SUN3X_PROM_BASE; +- +- idprom_init(); +- +- if(!((idprom->id_machtype & SM_ARCH_MASK) == SM_SUN3X)) { +- printk("Warning: machine reports strange type %02x\n", +- idprom->id_machtype); +- printk("Pretending it's a 3/80, but very afraid...\n"); +- idprom->id_machtype = SM_SUN3X | SM_3_80; +- } +- +- /* point trap #14 at abort. +- * XXX this is futile since we restore the vbr first - oops +- */ +- vectors[VEC_TRAP14] = sun3x_prom_abort; +- +- /* If debug=prom was specified, start the debug console */ +- +- if (!strcmp(m68k_debug_device, "prom")) +- register_console(&sun3x_debug); ++ sun3x_putchar = *(void (**)(int)) (SUN3X_P_PUTCHAR); ++ sun3x_getchar = *(int (**)(void)) (SUN3X_P_GETCHAR); ++ sun3x_mayget = *(int (**)(void)) (SUN3X_P_MAYGET); ++ sun3x_mayput = *(int (**)(int)) (SUN3X_P_MAYPUT); ++ sun3x_prom_reboot = *(void (**)(void)) (SUN3X_P_REBOOT); ++ sun3x_prom_abort = *(e_vector *) (SUN3X_P_ABORT); ++ romvec = (struct linux_romvec *)SUN3X_PROM_BASE; ++ ++ idprom_init(); ++ ++ if (!((idprom->id_machtype & SM_ARCH_MASK) == SM_SUN3X)) { ++ printk("Warning: machine reports strange type %02x\n", ++ idprom->id_machtype); ++ printk("Pretending it's a 3/80, but very afraid...\n"); ++ idprom->id_machtype = SM_SUN3X | SM_3_80; ++ } ++ ++ /* point trap #14 at abort. ++ * XXX this is futile since we restore the vbr first - oops ++ */ ++ vectors[VEC_TRAP14] = sun3x_prom_abort; + ++ /* If debug=prom was specified, start the debug console */ + ++ if (!strcmp(m68k_debug_device, "prom")) ++ register_console(&sun3x_debug); + } + + /* some prom functions to export */ +@@ -141,7 +139,6 @@ int prom_getbool (int node, char *prop) + + void prom_printf(char *fmt, ...) + { +- + } + + void prom_halt (void) +@@ -159,7 +156,7 @@ prom_get_idprom(char *idbuf, int num_byt + int i; + + /* make a copy of the idprom structure */ +- for(i = 0; i < num_bytes; i++) ++ for (i = 0; i < num_bytes; i++) + idbuf[i] = ((char *)SUN3X_IDPROM)[i]; + + return idbuf[0]; diff --git a/debian/patches/bugfix/m68k/mac68k-cuda-adb-fixes.diff b/debian/patches/bugfix/m68k/mac68k-cuda-adb-fixes.diff new file mode 100644 index 000000000000..84932c27c190 --- /dev/null +++ b/debian/patches/bugfix/m68k/mac68k-cuda-adb-fixes.diff @@ -0,0 +1,176 @@ +Subject: [PATCH 10/13] CUDA ADB fixes +Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>, + linuxppc-dev@ozlabs.org + +From: Finn Thain <fthain@telegraphics.com.au> + +Fix the flakiness in the CUDA ADB driver on m68k macs (keypresses getting +wedged down or ADB just going AWOL altogether). + +The only IRQ used by this driver is the VIA shift register IRQ. The PowerMac +conditional code disables the other VIA IRQ sources, so don't mess with the +other IRQ flags in the common code -- m68k macs need them. + +When polling, don't disable local interrupts when we only need to disable the +CUDA interrupt. + +Unless polling, don't clear the shift register IRQ flag. On m68k macs this +creates a race that often breaks CUDA ADB. + +Tested on Quadra 840av and LC630 (both m68k); also Beige G3 (powerpc). + +Signed-off-by: Finn Thain <fthain@telegraphics.com.au> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + drivers/macintosh/via-cuda.c | 58 +++++++++++++++++++++++-------------------- + 1 file changed, 32 insertions(+), 26 deletions(-) + +--- linux-m68k-2.6.21.orig/drivers/macintosh/via-cuda.c ++++ linux-m68k-2.6.21/drivers/macintosh/via-cuda.c +@@ -82,6 +82,7 @@ static unsigned char cuda_rbuf[16]; + static unsigned char *reply_ptr; + static int reading_reply; + static int data_index; ++static int cuda_irq; + #ifdef CONFIG_PPC + static struct device_node *vias; + #endif +@@ -160,10 +161,8 @@ int __init find_via_cuda(void) + /* Clear and enable interrupts, but only on PPC. On 68K it's done */ + /* for us by the main VIA driver in arch/m68k/mac/via.c */ + +-#ifndef CONFIG_MAC + out_8(&via[IFR], 0x7f); /* clear interrupts by writing 1s */ + out_8(&via[IER], IER_SET|SR_INT); /* enable interrupt from SR */ +-#endif + + /* enable autopoll */ + cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1); +@@ -181,24 +180,22 @@ int __init find_via_cuda(void) + + static int __init via_cuda_start(void) + { +- unsigned int irq; +- + if (via == NULL) + return -ENODEV; + + #ifdef CONFIG_MAC +- irq = IRQ_MAC_ADB; ++ cuda_irq = IRQ_MAC_ADB; + #else /* CONFIG_MAC */ +- irq = irq_of_parse_and_map(vias, 0); +- if (irq == NO_IRQ) { ++ cuda_irq = irq_of_parse_and_map(vias, 0); ++ if (cuda_irq == NO_IRQ) { + printk(KERN_ERR "via-cuda: can't map interrupts for %s\n", + vias->full_name); + return -ENODEV; + } +-#endif /* CONFIG_MAP */ ++#endif /* CONFIG_MAC */ + +- if (request_irq(irq, cuda_interrupt, 0, "ADB", cuda_interrupt)) { +- printk(KERN_ERR "via-cuda: can't request irq %d\n", irq); ++ if (request_irq(cuda_irq, cuda_interrupt, 0, "ADB", cuda_interrupt)) { ++ printk(KERN_ERR "via-cuda: can't request irq %d\n", cuda_irq); + return -EAGAIN; + } + +@@ -238,6 +235,7 @@ cuda_init(void) + printk(KERN_ERR "cuda_init_via() failed\n"); + return -ENODEV; + } ++ out_8(&via[IER], IER_SET|SR_INT); /* enable interrupt from SR */ + + return via_cuda_start(); + #endif +@@ -263,15 +261,17 @@ cuda_init_via(void) + out_8(&via[B], in_8(&via[B]) | TACK | TIP); /* negate them */ + out_8(&via[ACR] ,(in_8(&via[ACR]) & ~SR_CTRL) | SR_EXT); /* SR data in */ + (void)in_8(&via[SR]); /* clear any left-over data */ +-#ifndef CONFIG_MAC ++#ifdef CONFIG_PPC + out_8(&via[IER], 0x7f); /* disable interrupts from VIA */ + (void)in_8(&via[IER]); ++#else ++ out_8(&via[IER], SR_INT); /* disable SR interrupt from VIA */ + #endif + + /* delay 4ms and then clear any pending interrupt */ + mdelay(4); + (void)in_8(&via[SR]); +- out_8(&via[IFR], in_8(&via[IFR]) & 0x7f); ++ out_8(&via[IFR], SR_INT); + + /* sync with the CUDA - assert TACK without TIP */ + out_8(&via[B], in_8(&via[B]) & ~TACK); +@@ -282,7 +282,7 @@ cuda_init_via(void) + /* wait for the interrupt and then clear it */ + WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (2)"); + (void)in_8(&via[SR]); +- out_8(&via[IFR], in_8(&via[IFR]) & 0x7f); ++ out_8(&via[IFR], SR_INT); + + /* finish the sync by negating TACK */ + out_8(&via[B], in_8(&via[B]) | TACK); +@@ -291,7 +291,7 @@ cuda_init_via(void) + WAIT_FOR(in_8(&via[B]) & TREQ, "CUDA response to sync (3)"); + WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (4)"); + (void)in_8(&via[SR]); +- out_8(&via[IFR], in_8(&via[IFR]) & 0x7f); ++ out_8(&via[IFR], SR_INT); + out_8(&via[B], in_8(&via[B]) | TIP); /* should be unnecessary */ + + return 0; +@@ -428,16 +428,12 @@ cuda_start(void) + void + cuda_poll(void) + { +- unsigned long flags; +- + /* cuda_interrupt only takes a normal lock, we disable + * interrupts here to avoid re-entering and thus deadlocking. +- * An option would be to disable only the IRQ source with +- * disable_irq(), would that work on m68k ? --BenH + */ +- local_irq_save(flags); ++ disable_irq(cuda_irq); + cuda_interrupt(0, NULL); +- local_irq_restore(flags); ++ enable_irq(cuda_irq); + } + + static irqreturn_t +@@ -448,15 +444,25 @@ cuda_interrupt(int irq, void *arg) + unsigned char ibuf[16]; + int ibuf_len = 0; + int complete = 0; +- unsigned char virq; + + spin_lock(&cuda_lock); + +- virq = in_8(&via[IFR]) & 0x7f; +- out_8(&via[IFR], virq); +- if ((virq & SR_INT) == 0) { +- spin_unlock(&cuda_lock); +- return IRQ_NONE; ++ /* On powermacs, this handler is registered for the VIA IRQ. But it uses ++ * just the shift register IRQ -- other VIA interrupt sources are disabled. ++ * On m68k macs, the VIA IRQ sources are dispatched individually. Unless ++ * we are polling, the shift register IRQ flag has already been cleared. ++ */ ++ ++#ifdef CONFIG_MAC ++ if (!arg) ++#endif ++ { ++ if ((in_8(&via[IFR]) & SR_INT) == 0) { ++ spin_unlock(&cuda_lock); ++ return IRQ_NONE; ++ } else { ++ out_8(&via[IFR], SR_INT); ++ } + } + + status = (~in_8(&via[B]) & (TIP|TREQ)) | (in_8(&via[ACR]) & SR_OUT); diff --git a/debian/patches/bugfix/m68k/mac68k-finish_irq_cleanup.diff b/debian/patches/bugfix/m68k/mac68k-finish_irq_cleanup.diff new file mode 100644 index 000000000000..a7f5a343f5a1 --- /dev/null +++ b/debian/patches/bugfix/m68k/mac68k-finish_irq_cleanup.diff @@ -0,0 +1,162 @@ +Subject: [PATCH 8/13] m68k: Mac IRQ cleanup + +From: Finn Thain <fthain@telegraphics.com.au> + +There are no slow IRQs on Macs since Roman Zippel's IRQ reorganisation that +went into 2.6.16 and removed mac_irq_list[] and the do_mac_irq_list() +dispatcher. (They were implemented in do_mac_irq_list() by lowering the IPL.) +Hence there's no more use for mutual exclusion in the Mac interrupt +dispatchers. Remove it. + +Signed-off-by: Finn Thain <fthain@telegraphics.com.au> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + arch/m68k/mac/baboon.c | 20 +++++++------------- + arch/m68k/mac/oss.c | 4 ---- + arch/m68k/mac/psc.c | 2 -- + arch/m68k/mac/via.c | 10 ---------- + 4 files changed, 7 insertions(+), 29 deletions(-) + +--- linux-m68k-2.6.21.orig/arch/m68k/mac/baboon.c ++++ linux-m68k-2.6.21/arch/m68k/mac/baboon.c +@@ -22,7 +22,7 @@ + /* #define DEBUG_BABOON */ + /* #define DEBUG_IRQS */ + +-int baboon_present,baboon_active; ++int baboon_present; + volatile struct baboon *baboon; + + irqreturn_t baboon_irq(int, void *); +@@ -45,7 +45,6 @@ void __init baboon_init(void) + + baboon = (struct baboon *) BABOON_BASE; + baboon_present = 1; +- baboon_active = 0; + + printk("Baboon detected at %p\n", baboon); + } +@@ -70,9 +69,9 @@ irqreturn_t baboon_irq(int irq, void *de + unsigned char events; + + #ifdef DEBUG_IRQS +- printk("baboon_irq: mb_control %02X mb_ifr %02X mb_status %02X active %02X\n", ++ printk("baboon_irq: mb_control %02X mb_ifr %02X mb_status %02X\n", + (uint) baboon->mb_control, (uint) baboon->mb_ifr, +- (uint) baboon->mb_status, baboon_active); ++ (uint) baboon->mb_status); + #endif + + if (!(events = baboon->mb_ifr & 0x07)) +@@ -81,11 +80,9 @@ irqreturn_t baboon_irq(int irq, void *de + irq_num = IRQ_BABOON_0; + irq_bit = 1; + do { +- if (events & irq_bit/* & baboon_active*/) { +- baboon_active &= ~irq_bit; ++ if (events & irq_bit) { + baboon->mb_ifr &= ~irq_bit; + m68k_handle_int(irq_num); +- baboon_active |= irq_bit; + } + irq_bit <<= 1; + irq_num++; +@@ -99,21 +96,18 @@ irqreturn_t baboon_irq(int irq, void *de + } + + void baboon_irq_enable(int irq) { +- int irq_idx = IRQ_IDX(irq); +- + #ifdef DEBUG_IRQUSE + printk("baboon_irq_enable(%d)\n", irq); + #endif +- baboon_active |= (1 << irq_idx); ++ /* FIXME: figure out how to mask and unmask baboon interrupt sources */ ++ enable_irq(IRQ_NUBUS_C); + } + + void baboon_irq_disable(int irq) { +- int irq_idx = IRQ_IDX(irq); +- + #ifdef DEBUG_IRQUSE + printk("baboon_irq_disable(%d)\n", irq); + #endif +- baboon_active &= ~(1 << irq_idx); ++ disable_irq(IRQ_NUBUS_C); + } + + void baboon_irq_clear(int irq) { +--- linux-m68k-2.6.21.orig/arch/m68k/mac/oss.c ++++ linux-m68k-2.6.21/arch/m68k/mac/oss.c +@@ -112,10 +112,8 @@ irqreturn_t oss_irq(int irq, void *dev_i + oss->irq_pending &= ~OSS_IP_SOUND; + /* FIXME: call sound handler */ + } else if (events & OSS_IP_SCSI) { +- oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED; + oss->irq_pending &= ~OSS_IP_SCSI; + m68k_handle_int(IRQ_MAC_SCSI); +- oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI; + } else { + /* FIXME: error check here? */ + } +@@ -149,10 +147,8 @@ irqreturn_t oss_nubus_irq(int irq, void + --i; + irq_bit >>= 1; + if (events & irq_bit) { +- oss->irq_level[i] = OSS_IRQLEV_DISABLED; + oss->irq_pending &= ~irq_bit; + m68k_handle_int(NUBUS_SOURCE_BASE + i); +- oss->irq_level[i] = OSS_IRQLEV_NUBUS; + } + } while(events & (irq_bit - 1)); + return IRQ_HANDLED; +--- linux-m68k-2.6.21.orig/arch/m68k/mac/psc.c ++++ linux-m68k-2.6.21/arch/m68k/mac/psc.c +@@ -147,10 +147,8 @@ irqreturn_t psc_irq(int irq, void *dev_i + irq_bit = 1; + do { + if (events & irq_bit) { +- psc_write_byte(pIER, irq_bit); + psc_write_byte(pIFR, irq_bit); + m68k_handle_int(irq_num); +- psc_write_byte(pIER, irq_bit | 0x80); + } + irq_num++; + irq_bit <<= 1; +--- linux-m68k-2.6.21.orig/arch/m68k/mac/via.c ++++ linux-m68k-2.6.21/arch/m68k/mac/via.c +@@ -443,11 +443,6 @@ void __init via_nubus_init(void) + /* + * The generic VIA interrupt routines (shamelessly stolen from Alan Cox's + * via6522.c :-), disable/pending masks added. +- * +- * The new interrupt architecture in macints.c takes care of a lot of the +- * gruntwork for us, including tallying the interrupts and calling the +- * handlers on the linked list. All we need to do here is basically generate +- * the machspec interrupt number after clearing the interrupt. + */ + + irqreturn_t via1_irq(int irq, void *dev_id) +@@ -463,10 +458,8 @@ irqreturn_t via1_irq(int irq, void *dev_ + irq_bit = 1; + do { + if (events & irq_bit) { +- via1[vIER] = irq_bit; + via1[vIFR] = irq_bit; + m68k_handle_int(irq_num); +- via1[vIER] = irq_bit | 0x80; + } + ++irq_num; + irq_bit <<= 1; +@@ -502,11 +495,8 @@ irqreturn_t via2_irq(int irq, void *dev_ + irq_bit = 1; + do { + if (events & irq_bit) { +- via2[gIER] = irq_bit; + via2[gIFR] = irq_bit | rbv_clear; + m68k_handle_int(irq_num); +- if (irq_num != IRQ_MAC_NUBUS || nubus_disabled == 0) +- via2[gIER] = irq_bit | 0x80; + } + ++irq_num; + irq_bit <<= 1; diff --git a/debian/patches/bugfix/m68k/mac68k-irq-plan-e.diff b/debian/patches/bugfix/m68k/mac68k-irq-plan-e.diff new file mode 100644 index 000000000000..fb367101d197 --- /dev/null +++ b/debian/patches/bugfix/m68k/mac68k-irq-plan-e.diff @@ -0,0 +1,270 @@ +Subject: [PATCH 7/13] m68k: Mac nubus IRQ fixes (plan E) + +From: Finn Thain <fthain@telegraphics.com.au> + +Some Macs lack a slot interrupt enable register. So the existing code makes +disabled and unregistered slot IRQ lines outputs set high. This seems to work +on quadras, but does not work on genuine VIAs (perhaps the card still succeeds +in pulling the line low, or perhaps because this increases the settle time on +the port A input, meaning that the CA1 IRQ could fire before the slot line +reads active). + +Because of this, the nubus_active flags were used to mask IRQs, which is +actually worse than the problem it tries to solve. Any interrupt masked by +nubus_active will remain asserted and prevent further transitions on CA1. And +so the nubus gets wedged regardless of hardware (emulated VIA ASIC, real VIA +chip or RBV). + +The best solution to this hardware limitation of genuine VIAs is to disable the +umbrella SLOTS IRQ when disabling a slot on those machines. Unfortunately, this +means all slot IRQs get disabled when any slot IRQ is disabled. But it is only +a problem when there's more than 1 device using nubus interrupts. + +Another potential problem for genuine VIAs is an unregistered nubus IRQ. +Eventually it will be possible to enable the CA1 interrupt by installing its +handler only _after_ all nubus drivers have loaded but _before_ the kernel +needs them, at which time this last problem can be fixed. For now it can be +worked around: + + - disable MacOS extensions + - don't boot MacOS (use the Emile bootloader instead) + - get the bootloaders to disable ROM drivers (Penguin does this for video + cards already, don't know about Emile) + - physically remove unsupported cards + +Signed-off-by: Finn Thain <fthain@telegraphics.com.au> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + arch/m68k/mac/via.c | 141 +++++++++++++++++++++++++++++----------------------- + 1 file changed, 80 insertions(+), 61 deletions(-) + +--- linux-m68k-2.6.21.orig/arch/m68k/mac/via.c ++++ linux-m68k-2.6.21/arch/m68k/mac/via.c +@@ -64,7 +64,19 @@ static int gIER,gIFR,gBufA,gBufB; + #define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF) + #define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8) + +-static int nubus_active; ++/* To disable a NuBus slot on Quadras we make the slot IRQ lines outputs, set ++ * high. On RBV we just use the slot interrupt enable register. On Macs with ++ * genuine VIA chips we must use nubus_disabled to keep track of disabled slot ++ * interrupts. When any slot IRQ is disabled we mask the (edge triggered) CA1 ++ * or "SLOTS" interrupt. When no slot is disabled, we unmask the CA1 interrupt. ++ * So, on genuine VIAs, having more than one NuBus IRQ can mean trouble, ++ * because closing one of those drivers can mask all of the NuBus interrupts. ++ * Also, since we can't mask the unregistered slot IRQs on genuine VIAs, it's ++ * possible to get interrupts from cards that MacOS or the ROM has configured ++ * but we have not. FWIW, "Designing Cards and Drivers for Macintosh II and ++ * Macintosh SE", page 9-8, says, a slot IRQ with no driver would crash MacOS. ++ */ ++static u8 nubus_disabled; + + void via_debug_dump(void); + irqreturn_t via1_irq(int, void *); +@@ -383,9 +395,6 @@ int via_get_cache_disable(void) + + void __init via_nubus_init(void) + { +- /* don't set nubus_active = 0 here, it kills the Baboon */ +- /* interrupt that we've already registered. */ +- + /* unlock nubus transactions */ + + if ((macintosh_config->adb_type != MAC_ADB_PB1) && +@@ -399,28 +408,35 @@ void __init via_nubus_init(void) + via2[gBufB] |= 0x02; + } + +- /* disable nubus slot interrupts. */ +- if (rbv_present) { ++ /* Disable all the slot interrupts (where possible). */ ++ ++ switch (macintosh_config->via_type) { ++ case MAC_VIA_II: ++ /* Just make the port A lines inputs. */ ++ switch(macintosh_config->ident) { ++ case MAC_MODEL_II: ++ case MAC_MODEL_IIX: ++ case MAC_MODEL_IICX: ++ case MAC_MODEL_SE30: ++ /* The top two bits are RAM size outputs. */ ++ via2[vDirA] &= 0xC0; ++ break; ++ default: ++ via2[vDirA] &= 0x80; ++ } ++ break; ++ case MAC_VIA_IIci: ++ /* RBV. Disable all the slot interrupts. SIER works like IER. */ + via2[rSIER] = 0x7F; +- via2[rSIER] = nubus_active | 0x80; +- } else { +- /* These are ADB bits on PMU */ ++ break; ++ case MAC_VIA_QUADRA: ++ /* Disable the inactive slot interrupts by making those lines outputs. */ + if ((macintosh_config->adb_type != MAC_ADB_PB1) && +- (macintosh_config->adb_type != MAC_ADB_PB2)) { +- switch(macintosh_config->ident) +- { +- case MAC_MODEL_II: +- case MAC_MODEL_IIX: +- case MAC_MODEL_IICX: +- case MAC_MODEL_SE30: +- via2[vBufA] |= 0x3F; +- via2[vDirA] = ~nubus_active | 0xc0; +- break; +- default: +- via2[vBufA] = 0xFF; +- via2[vDirA] = ~nubus_active; +- } ++ (macintosh_config->adb_type != MAC_ADB_PB2)) { ++ via2[vBufA] |= 0x7F; ++ via2[vDirA] |= 0x7F; + } ++ break; + } + } + +@@ -489,7 +505,8 @@ irqreturn_t via2_irq(int irq, void *dev_ + via2[gIER] = irq_bit; + via2[gIFR] = irq_bit | rbv_clear; + m68k_handle_int(irq_num); +- via2[gIER] = irq_bit | 0x80; ++ if (irq_num != IRQ_MAC_NUBUS || nubus_disabled == 0) ++ via2[gIER] = irq_bit | 0x80; + } + ++irq_num; + irq_bit <<= 1; +@@ -511,7 +528,7 @@ irqreturn_t via_nubus_irq(int irq, void + if (rbv_present) + events &= via2[rSIER]; + else +- events &= nubus_active; ++ events &= ~via2[vDirA]; + if (!events) + return IRQ_NONE; + +@@ -533,7 +550,7 @@ irqreturn_t via_nubus_irq(int irq, void + if (rbv_present) + events &= via2[rSIER]; + else +- events &= nubus_active; ++ events &= ~via2[vDirA]; + } while (events); + return IRQ_HANDLED; + } +@@ -541,38 +558,38 @@ irqreturn_t via_nubus_irq(int irq, void + void via_irq_enable(int irq) { + int irq_src = IRQ_SRC(irq); + int irq_idx = IRQ_IDX(irq); +- int irq_bit = 1 << irq_idx; + + #ifdef DEBUG_IRQUSE + printk(KERN_DEBUG "via_irq_enable(%d)\n", irq); + #endif + + if (irq_src == 1) { +- via1[vIER] = irq_bit | 0x80; ++ via1[vIER] = IER_SET_BIT(irq_idx); + } else if (irq_src == 2) { +- via2[gIER] = irq_bit | 0x80; ++ if (irq != IRQ_MAC_NUBUS || nubus_disabled == 0) ++ via2[gIER] = IER_SET_BIT(irq_idx); + } else if (irq_src == 7) { +- nubus_active |= irq_bit; +- if (rbv_present) { +- /* enable the slot interrupt. SIER works like IER. */ ++ switch (macintosh_config->via_type) { ++ case MAC_VIA_II: ++ nubus_disabled &= ~(1 << irq_idx); ++ /* Enable the CA1 interrupt when no slot is disabled. */ ++ if (!nubus_disabled) ++ via2[gIER] = IER_SET_BIT(1); ++ break; ++ case MAC_VIA_IIci: ++ /* On RBV, enable the slot interrupt. ++ * SIER works like IER. ++ */ + via2[rSIER] = IER_SET_BIT(irq_idx); +- } else { +- /* Make sure the bit is an input, to enable the irq */ +- /* But not on PowerBooks, that's ADB... */ ++ break; ++ case MAC_VIA_QUADRA: ++ /* Make the port A line an input to enable the slot irq. ++ * But not on PowerBooks, that's ADB. ++ */ + if ((macintosh_config->adb_type != MAC_ADB_PB1) && +- (macintosh_config->adb_type != MAC_ADB_PB2)) { +- switch(macintosh_config->ident) +- { +- case MAC_MODEL_II: +- case MAC_MODEL_IIX: +- case MAC_MODEL_IICX: +- case MAC_MODEL_SE30: +- via2[vDirA] &= (~irq_bit | 0xc0); +- break; +- default: +- via2[vDirA] &= ~irq_bit; +- } +- } ++ (macintosh_config->adb_type != MAC_ADB_PB2)) ++ via2[vDirA] &= ~(1 << irq_idx); ++ break; + } + } + } +@@ -580,29 +597,31 @@ void via_irq_enable(int irq) { + void via_irq_disable(int irq) { + int irq_src = IRQ_SRC(irq); + int irq_idx = IRQ_IDX(irq); +- int irq_bit = 1 << irq_idx; + + #ifdef DEBUG_IRQUSE + printk(KERN_DEBUG "via_irq_disable(%d)\n", irq); + #endif + + if (irq_src == 1) { +- via1[vIER] = irq_bit & 0x7F; ++ via1[vIER] = IER_CLR_BIT(irq_idx); + } else if (irq_src == 2) { +- via2[gIER] = irq_bit & 0x7F; ++ via2[gIER] = IER_CLR_BIT(irq_idx); + } else if (irq_src == 7) { +- if (rbv_present) { +- /* disable the slot interrupt. SIER works like IER. */ ++ switch (macintosh_config->via_type) { ++ case MAC_VIA_II: ++ nubus_disabled |= 1 << irq_idx; ++ if (nubus_disabled) ++ via2[gIER] = IER_CLR_BIT(1); ++ break; ++ case MAC_VIA_IIci: + via2[rSIER] = IER_CLR_BIT(irq_idx); +- } else { +- /* disable the nubus irq by changing dir to output */ +- /* except on PMU */ ++ break; ++ case MAC_VIA_QUADRA: + if ((macintosh_config->adb_type != MAC_ADB_PB1) && +- (macintosh_config->adb_type != MAC_ADB_PB2)) { +- via2[vDirA] |= irq_bit; +- } ++ (macintosh_config->adb_type != MAC_ADB_PB2)) ++ via2[vDirA] |= 1 << irq_idx; ++ break; + } +- nubus_active &= ~irq_bit; + } + } + +@@ -638,7 +657,7 @@ int via_irq_pending(int irq) + } else if (irq_src == 2) { + return via2[gIFR] & irq_bit; + } else if (irq_src == 7) { +- /* FIXME: this can't work while a slot irq is disabled! */ ++ /* Always 0 for MAC_VIA_QUADRA if the slot irq is disabled. */ + return ~via2[gBufA] & irq_bit; + } + return 0; diff --git a/debian/patches/bugfix/m68k/mac68k-irq-prep.diff b/debian/patches/bugfix/m68k/mac68k-irq-prep.diff new file mode 100644 index 000000000000..e43e329e9adc --- /dev/null +++ b/debian/patches/bugfix/m68k/mac68k-irq-prep.diff @@ -0,0 +1,375 @@ +Subject: [PATCH 6/13] m68k: Mac IRQ prep + +From: Finn Thain <fthain@telegraphics.com.au> + +Make sure that there are no slot IRQs asserted before leaving the nubus +handler. If there are and we don't then the nubus gets wedged because this +prevents a CA1 transition, which means no more nubus IRQs. + +Make the interrupt dispatch loops terminate sooner. + +Explicitly initialise the VIA latches to make the code more easily understood. + +Also some cleanups. + +Signed-off-by: Finn Thain <fthain@telegraphics.com.au> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + arch/m68k/mac/baboon.c | 12 ++-- + arch/m68k/mac/oss.c | 8 ++ + arch/m68k/mac/psc.c | 19 +++--- + arch/m68k/mac/via.c | 139 ++++++++++++++++++++++++++++++------------------- + 4 files changed, 110 insertions(+), 68 deletions(-) + +--- linux-m68k-2.6.21.orig/arch/m68k/mac/baboon.c ++++ linux-m68k-2.6.21/arch/m68k/mac/baboon.c +@@ -66,7 +66,7 @@ void __init baboon_register_interrupts(v + + irqreturn_t baboon_irq(int irq, void *dev_id) + { +- int irq_bit,i; ++ int irq_bit, irq_num; + unsigned char events; + + #ifdef DEBUG_IRQS +@@ -78,14 +78,18 @@ irqreturn_t baboon_irq(int irq, void *de + if (!(events = baboon->mb_ifr & 0x07)) + return IRQ_NONE; + +- for (i = 0, irq_bit = 1 ; i < 3 ; i++, irq_bit <<= 1) { ++ irq_num = IRQ_BABOON_0; ++ irq_bit = 1; ++ do { + if (events & irq_bit/* & baboon_active*/) { + baboon_active &= ~irq_bit; + baboon->mb_ifr &= ~irq_bit; +- m68k_handle_int(IRQ_BABOON_0 + i); ++ m68k_handle_int(irq_num); + baboon_active |= irq_bit; + } +- } ++ irq_bit <<= 1; ++ irq_num++; ++ } while(events >= irq_bit); + #if 0 + if (baboon->mb_ifr & 0x02) macide_ack_intr(NULL); + /* for now we need to smash all interrupts */ +--- linux-m68k-2.6.21.orig/arch/m68k/mac/oss.c ++++ linux-m68k-2.6.21/arch/m68k/mac/oss.c +@@ -143,14 +143,18 @@ irqreturn_t oss_nubus_irq(int irq, void + #endif + /* There are only six slots on the OSS, not seven */ + +- for (i = 0, irq_bit = 1 ; i < 6 ; i++, irq_bit <<= 1) { ++ i = 6; ++ irq_bit = 0x40; ++ do { ++ --i; ++ irq_bit >>= 1; + if (events & irq_bit) { + oss->irq_level[i] = OSS_IRQLEV_DISABLED; + oss->irq_pending &= ~irq_bit; + m68k_handle_int(NUBUS_SOURCE_BASE + i); + oss->irq_level[i] = OSS_IRQLEV_NUBUS; + } +- } ++ } while(events & (irq_bit - 1)); + return IRQ_HANDLED; + } + +--- linux-m68k-2.6.21.orig/arch/m68k/mac/psc.c ++++ linux-m68k-2.6.21/arch/m68k/mac/psc.c +@@ -131,11 +131,8 @@ irqreturn_t psc_irq(int irq, void *dev_i + { + int pIFR = pIFRbase + ((int) dev_id); + int pIER = pIERbase + ((int) dev_id); +- int base_irq; +- int irq_bit,i; +- unsigned char events; +- +- base_irq = irq << 3; ++ int irq_num; ++ unsigned char irq_bit, events; + + #ifdef DEBUG_IRQS + printk("psc_irq: irq %d pIFR = 0x%02X pIER = 0x%02X\n", +@@ -146,14 +143,18 @@ irqreturn_t psc_irq(int irq, void *dev_i + if (!events) + return IRQ_NONE; + +- for (i = 0, irq_bit = 1 ; i < 4 ; i++, irq_bit <<= 1) { +- if (events & irq_bit) { ++ irq_num = irq << 3; ++ irq_bit = 1; ++ do { ++ if (events & irq_bit) { + psc_write_byte(pIER, irq_bit); + psc_write_byte(pIFR, irq_bit); +- m68k_handle_int(base_irq + i); ++ m68k_handle_int(irq_num); + psc_write_byte(pIER, irq_bit | 0x80); + } +- } ++ irq_num++; ++ irq_bit <<= 1; ++ } while (events >= irq_bit); + return IRQ_HANDLED; + } + +--- linux-m68k-2.6.21.orig/arch/m68k/mac/via.c ++++ linux-m68k-2.6.21/arch/m68k/mac/via.c +@@ -13,6 +13,10 @@ + * for info. A full-text web search on 6522 AND VIA will probably also + * net some usefulness. <cananian@alumni.princeton.edu> 20apr1999 + * ++ * Additional data is here (the SY6522 was used in the Mac II etc): ++ * http://www.6502.org/documents/datasheets/synertek/synertek_sy6522.pdf ++ * http://www.6502.org/documents/datasheets/synertek/synertek_sy6522_programming_reference.pdf ++ * + * PRAM/RTC access algorithms are from the NetBSD RTC toolkit version 1.08b + * by Erik Vogan and adapted to Linux by Joshua M. Thompson (funaho@jurai.org) + * +@@ -37,7 +41,7 @@ volatile __u8 *via1, *via2; + /* See note in mac_via.h about how this is possibly not useful */ + volatile long *via_memory_bogon=(long *)&via_memory_bogon; + #endif +-int rbv_present,via_alt_mapping; ++int rbv_present, via_alt_mapping; + __u8 rbv_clear; + + /* +@@ -138,11 +142,11 @@ void __init via_init(void) + + printk(KERN_INFO "VIA2 at %p is ", via2); + if (rbv_present) { +- printk(KERN_INFO "an RBV\n"); ++ printk("an RBV\n"); + } else if (oss_present) { +- printk(KERN_INFO "an OSS\n"); ++ printk("an OSS\n"); + } else { +- printk(KERN_INFO "a 6522 or clone\n"); ++ printk("a 6522 or clone\n"); + } + + #ifdef DEBUG_VIA +@@ -163,6 +167,7 @@ void __init via_init(void) + via1[vT2CL] = 0; + via1[vT2CH] = 0; + via1[vACR] &= 0x3F; ++ via1[vACR] &= ~0x03; /* disable port A & B latches */ + + /* + * SE/30: disable video IRQ +@@ -234,6 +239,22 @@ void __init via_init(void) + via2[vT2CL] = 0; + via2[vT2CH] = 0; + via2[vACR] &= 0x3F; ++ via2[vACR] &= ~0x03; /* disable port A & B latches */ ++ } ++ ++ /* ++ * Set vPCR for SCSI interrupts (but not on RBV) ++ */ ++ if (!rbv_present) { ++ if (macintosh_config->scsi_type == MAC_SCSI_OLD) { ++ /* CB2 (IRQ) indep. input, positive edge */ ++ /* CA2 (DRQ) indep. input, positive edge */ ++ via2[vPCR] = 0x66; ++ } else { ++ /* CB2 (IRQ) indep. input, negative edge */ ++ /* CA2 (DRQ) indep. input, negative edge */ ++ via2[vPCR] = 0x22; ++ } + } + } + +@@ -367,19 +388,14 @@ void __init via_nubus_init(void) + + /* unlock nubus transactions */ + +- if (!rbv_present) { ++ if ((macintosh_config->adb_type != MAC_ADB_PB1) && ++ (macintosh_config->adb_type != MAC_ADB_PB2)) { + /* set the line to be an output on non-RBV machines */ +- if ((macintosh_config->adb_type != MAC_ADB_PB1) && +- (macintosh_config->adb_type != MAC_ADB_PB2)) { ++ if (!rbv_present) + via2[vDirB] |= 0x02; +- } +- } +- +- /* this seems to be an ADB bit on PMU machines */ +- /* according to MkLinux. -- jmt */ + +- if ((macintosh_config->adb_type != MAC_ADB_PB1) && +- (macintosh_config->adb_type != MAC_ADB_PB2)) { ++ /* this seems to be an ADB bit on PMU machines */ ++ /* according to MkLinux. -- jmt */ + via2[gBufB] |= 0x02; + } + +@@ -420,20 +436,25 @@ void __init via_nubus_init(void) + + irqreturn_t via1_irq(int irq, void *dev_id) + { +- int irq_bit, i; +- unsigned char events, mask; ++ int irq_num; ++ unsigned char irq_bit, events; + +- mask = via1[vIER] & 0x7F; +- if (!(events = via1[vIFR] & mask)) ++ events = via1[vIFR] & via1[vIER] & 0x7F; ++ if (!events) + return IRQ_NONE; + +- for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) ++ irq_num = VIA1_SOURCE_BASE; ++ irq_bit = 1; ++ do { + if (events & irq_bit) { + via1[vIER] = irq_bit; + via1[vIFR] = irq_bit; +- m68k_handle_int(VIA1_SOURCE_BASE + i); ++ m68k_handle_int(irq_num); + via1[vIER] = irq_bit | 0x80; + } ++ ++irq_num; ++ irq_bit <<= 1; ++ } while (events >= irq_bit); + + #if 0 /* freakin' pmu is doing weird stuff */ + if (!oss_present) { +@@ -454,20 +475,25 @@ irqreturn_t via1_irq(int irq, void *dev_ + + irqreturn_t via2_irq(int irq, void *dev_id) + { +- int irq_bit, i; +- unsigned char events, mask; ++ int irq_num; ++ unsigned char irq_bit, events; + +- mask = via2[gIER] & 0x7F; +- if (!(events = via2[gIFR] & mask)) ++ events = via2[gIFR] & via2[gIER] & 0x7F; ++ if (!events) + return IRQ_NONE; + +- for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) ++ irq_num = VIA2_SOURCE_BASE; ++ irq_bit = 1; ++ do { + if (events & irq_bit) { + via2[gIER] = irq_bit; + via2[gIFR] = irq_bit | rbv_clear; +- m68k_handle_int(VIA2_SOURCE_BASE + i); ++ m68k_handle_int(irq_num); + via2[gIER] = irq_bit | 0x80; + } ++ ++irq_num; ++ irq_bit <<= 1; ++ } while (events >= irq_bit); + return IRQ_HANDLED; + } + +@@ -478,19 +504,37 @@ irqreturn_t via2_irq(int irq, void *dev_ + + irqreturn_t via_nubus_irq(int irq, void *dev_id) + { +- int irq_bit, i; +- unsigned char events; ++ int slot_irq; ++ unsigned char slot_bit, events; + +- if (!(events = ~via2[gBufA] & nubus_active)) ++ events = ~via2[gBufA] & 0x7F; ++ if (rbv_present) ++ events &= via2[rSIER]; ++ else ++ events &= nubus_active; ++ if (!events) + return IRQ_NONE; + +- for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) { +- if (events & irq_bit) { +- via_irq_disable(NUBUS_SOURCE_BASE + i); +- m68k_handle_int(NUBUS_SOURCE_BASE + i); +- via_irq_enable(NUBUS_SOURCE_BASE + i); +- } +- } ++ do { ++ slot_irq = IRQ_NUBUS_F; ++ slot_bit = 0x40; ++ do { ++ if (events & slot_bit) { ++ events &= ~slot_bit; ++ m68k_handle_int(slot_irq); ++ } ++ --slot_irq; ++ slot_bit >>= 1; ++ } while (events); ++ ++ /* clear the CA1 interrupt and make certain there's no more. */ ++ via2[gIFR] = 0x02 | rbv_clear; ++ events = ~via2[gBufA] & 0x7F; ++ if (rbv_present) ++ events &= via2[rSIER]; ++ else ++ events &= nubus_active; ++ } while (events); + return IRQ_HANDLED; + } + +@@ -506,20 +550,6 @@ void via_irq_enable(int irq) { + if (irq_src == 1) { + via1[vIER] = irq_bit | 0x80; + } else if (irq_src == 2) { +- /* +- * Set vPCR for SCSI interrupts (but not on RBV) +- */ +- if ((irq_idx == 0) && !rbv_present) { +- if (macintosh_config->scsi_type == MAC_SCSI_OLD) { +- /* CB2 (IRQ) indep. input, positive edge */ +- /* CA2 (DRQ) indep. input, positive edge */ +- via2[vPCR] = 0x66; +- } else { +- /* CB2 (IRQ) indep. input, negative edge */ +- /* CA2 (DRQ) indep. input, negative edge */ +- via2[vPCR] = 0x22; +- } +- } + via2[gIER] = irq_bit | 0x80; + } else if (irq_src == 7) { + nubus_active |= irq_bit; +@@ -557,9 +587,9 @@ void via_irq_disable(int irq) { + #endif + + if (irq_src == 1) { +- via1[vIER] = irq_bit; ++ via1[vIER] = irq_bit & 0x7F; + } else if (irq_src == 2) { +- via2[gIER] = irq_bit; ++ via2[gIER] = irq_bit & 0x7F; + } else if (irq_src == 7) { + if (rbv_present) { + /* disable the slot interrupt. SIER works like IER. */ +@@ -586,7 +616,9 @@ void via_irq_clear(int irq) { + } else if (irq_src == 2) { + via2[gIFR] = irq_bit | rbv_clear; + } else if (irq_src == 7) { +- /* FIXME: hmm.. */ ++ /* FIXME: There is no way to clear an individual nubus slot ++ * IRQ flag, other than getting the device to do it. ++ */ + } + } + +@@ -606,6 +638,7 @@ int via_irq_pending(int irq) + } else if (irq_src == 2) { + return via2[gIFR] & irq_bit; + } else if (irq_src == 7) { ++ /* FIXME: this can't work while a slot irq is disabled! */ + return ~via2[gBufA] & irq_bit; + } + return 0; diff --git a/debian/patches/bugfix/m68k/mac68k-macii-adb-fixes.diff b/debian/patches/bugfix/m68k/mac68k-macii-adb-fixes.diff new file mode 100644 index 000000000000..b1018ce46e3a --- /dev/null +++ b/debian/patches/bugfix/m68k/mac68k-macii-adb-fixes.diff @@ -0,0 +1,873 @@ +Subject: [PATCH 9/13] m68k: Mac II ADB fixes + +From: Finn Thain <fthain@telegraphics.com.au> + +Fix a crash caused by requests placed in the queue with the completed flag +already set. This lead to some ADB_SYNC requests returning early and their +request structs being popped off the stack while still queued. Stack corruption +ensued or an invalid request callback pointer was invoked or both. Eliminate +macii_retransmit() and its buggy implementation of macii_write(). Have +macii_queue_poll() fully initialise the request queues. + +Fix a bug in macii_queue_poll() where the last_req pointer was not being set. +This caused some requests to leave the queue before being completed (and would +also corrupt the stack under certain conditions). + +Fix a race in macii_start that could set the state machine to "reading" while +current_req was null. + +No longer send poll commands with the ADBREQ_REPLY flag -- doing that caused +the replies to be stored in the request buffer where they were forgotten +about. + +Don't autopoll by continuously sending new Talk commands. Get the controller to +do that for us. This reduces the ADB interrupt rate on an idle bus to about 5 +per second. Only autopoll the devices that were probed. + +Explicitly clear the interrupt flag when polling. + +Use disable_irq rather than local_irq_save when polling. + +Remove excess local_irq_save/restore pairs. + +Improve bus timeout and service request detection. + +Remove unused code (last_reply, adb_dir etc) and unneeded code (prefix_len, +first_byte etc). + +Change TIP and TACK to their correct names on this ADB controller (ST_EVEN and +ST_ODD). + +Add some commentry. + +Add a generous quantity of sanity checks (BUG_ONs). + +Let m68k macs use the adb_sync boot param too. + +Tested on Mac II, Mac IIci, Quadra 650, Quadra 700 etc. + +Signed-off-by: Finn Thain <fthain@telegraphics.com.au> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + arch/m68k/kernel/setup.c | 10 + drivers/macintosh/via-macii.c | 582 +++++++++++++++++------------------------- + 2 files changed, 251 insertions(+), 341 deletions(-) + +--- linux-m68k-2.6.21.orig/arch/m68k/kernel/setup.c ++++ linux-m68k-2.6.21/arch/m68k/kernel/setup.c +@@ -513,3 +513,13 @@ void check_bugs(void) + } + #endif /* !CONFIG_M68KFPU_EMU */ + } ++ ++#ifdef CONFIG_ADB ++static int __init adb_probe_sync_enable (char *str) { ++ extern int __adb_probe_sync; ++ __adb_probe_sync = 1; ++ return 1; ++} ++ ++__setup("adb_sync", adb_probe_sync_enable); ++#endif /* CONFIG_ADB */ +--- linux-m68k-2.6.21.orig/drivers/macintosh/via-macii.c ++++ linux-m68k-2.6.21/drivers/macintosh/via-macii.c +@@ -12,6 +12,15 @@ + * 1999-08-02 (jmt) - Initial rewrite for Unified ADB. + * 2000-03-29 Tony Mantler <tonym@mac.linux-m68k.org> + * - Big overhaul, should actually work now. ++ * 2006-12-31 Finn Thain <fthain@telegraphics.com.au> - Another overhaul. ++ * ++ * Suggested reading: ++ * Inside Macintosh, ch. 5 ADB Manager ++ * Guide to the Macinstosh Family Hardware, ch. 8 Apple Desktop Bus ++ * Rockwell R6522 VIA datasheet ++ * ++ * Apple's "ADB Analyzer" bus sniffer is invaluable: ++ * ftp://ftp.apple.com/developer/Tool_Chest/Devices_-_Hardware/Apple_Desktop_Bus/ + */ + + #include <stdarg.h> +@@ -26,7 +35,6 @@ + #include <asm/macints.h> + #include <asm/machw.h> + #include <asm/mac_via.h> +-#include <asm/io.h> + #include <asm/system.h> + + static volatile unsigned char *via; +@@ -51,9 +59,7 @@ static volatile unsigned char *via; + #define ANH (15*RS) /* A-side data, no handshake */ + + /* Bits in B data register: all active low */ +-#define TREQ 0x08 /* Transfer request (input) */ +-#define TACK 0x10 /* Transfer acknowledge (output) */ +-#define TIP 0x20 /* Transfer in progress (output) */ ++#define CTLR_IRQ 0x08 /* Controller rcv status (input) */ + #define ST_MASK 0x30 /* mask for selecting ADB state bits */ + + /* Bits in ACR */ +@@ -65,8 +71,6 @@ static volatile unsigned char *via; + #define IER_SET 0x80 /* set bits in IER */ + #define IER_CLR 0 /* clear bits in IER */ + #define SR_INT 0x04 /* Shift register full/empty */ +-#define SR_DATA 0x08 /* Shift register data */ +-#define SR_CLOCK 0x10 /* Shift register clock */ + + /* ADB transaction states according to GMHW */ + #define ST_CMD 0x00 /* ADB state: command byte */ +@@ -77,7 +81,6 @@ static volatile unsigned char *via; + static int macii_init_via(void); + static void macii_start(void); + static irqreturn_t macii_interrupt(int irq, void *arg); +-static void macii_retransmit(int); + static void macii_queue_poll(void); + + static int macii_probe(void); +@@ -103,29 +106,37 @@ static enum macii_state { + sending, + reading, + read_done, +- awaiting_reply + } macii_state; + +-static int need_poll; +-static int command_byte; +-static int last_reply; +-static int last_active; +- +-static struct adb_request *current_req; +-static struct adb_request *last_req; +-static struct adb_request *retry_req; +-static unsigned char reply_buf[16]; +-static unsigned char *reply_ptr; +-static int reply_len; +-static int reading_reply; +-static int data_index; +-static int first_byte; +-static int prefix_len; +-static int status = ST_IDLE|TREQ; +-static int last_status; +-static int driver_running; +- +-/* debug level 10 required for ADB logging (should be && debug_adb, ideally) */ ++static struct adb_request *current_req; /* first request struct in the queue */ ++static struct adb_request *last_req; /* last request struct in the queue */ ++static unsigned char reply_buf[16]; /* storage for autopolled replies */ ++static unsigned char *reply_ptr; /* next byte in req->data or reply_buf */ ++static int reading_reply; /* store reply in reply_buf else req->reply */ ++static int data_index; /* index of the next byte to send from req->data */ ++static int reply_len; /* number of bytes received in reply_buf or req->reply */ ++static int status; /* VIA's ADB status bits captured upon interrupt */ ++static int last_status; /* status bits as at previous interrupt */ ++static int srq_asserted; /* have to poll for the device that asserted it */ ++static int command_byte; /* the most recent command byte transmitted */ ++static int autopoll_devs; /* bits set are device addresses to be polled */ ++ ++/* Sanity check for request queue. Doesn't check for cycles. */ ++static int request_is_queued(struct adb_request *req) { ++ struct adb_request *cur; ++ unsigned long flags; ++ local_irq_save(flags); ++ cur = current_req; ++ while (cur) { ++ if (cur == req) { ++ local_irq_restore(flags); ++ return 1; ++ } ++ cur = cur->next; ++ } ++ local_irq_restore(flags); ++ return 0; ++} + + /* Check for MacII style ADB */ + static int macii_probe(void) +@@ -147,15 +158,16 @@ int macii_init(void) + local_irq_save(flags); + + err = macii_init_via(); +- if (err) return err; ++ if (err) goto out; + + err = request_irq(IRQ_MAC_ADB, macii_interrupt, IRQ_FLG_LOCK, "ADB", + macii_interrupt); +- if (err) return err; ++ if (err) goto out; + + macii_state = idle; ++out: + local_irq_restore(flags); +- return 0; ++ return err; + } + + /* initialize the hardware */ +@@ -163,12 +175,12 @@ static int macii_init_via(void) + { + unsigned char x; + +- /* Set the lines up. We want TREQ as input TACK|TIP as output */ +- via[DIRB] = (via[DIRB] | TACK | TIP) & ~TREQ; ++ /* We want CTLR_IRQ as input and ST_EVEN | ST_ODD as output lines. */ ++ via[DIRB] = (via[DIRB] | ST_EVEN | ST_ODD) & ~CTLR_IRQ; + + /* Set up state: idle */ + via[B] |= ST_IDLE; +- last_status = via[B] & (ST_MASK|TREQ); ++ last_status = via[B] & (ST_MASK|CTLR_IRQ); + + /* Shift register on input */ + via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT; +@@ -179,81 +191,72 @@ static int macii_init_via(void) + return 0; + } + +-/* Send an ADB poll (Talk Register 0 command, tagged on the front of the request queue) */ ++/* Send an ADB poll (Talk Register 0 command prepended to the request queue) */ + static void macii_queue_poll(void) + { +- static int device = 0; +- static int in_poll=0; ++ /* No point polling the active device as it will never assert SRQ, so ++ * poll the next device in the autopoll list. This could leave us ++ * stuck in a polling loop if an unprobed device is asserting SRQ. ++ * In theory, that could only happen if a device was plugged in after ++ * probing started. Unplugging it again will break the cycle. ++ * (Simply polling the next higher device often ends up polling almost ++ * every device (after wrapping around), which takes too long.) ++ */ ++ int device_mask; ++ int next_device; + static struct adb_request req; +- unsigned long flags; +- +- if (in_poll) printk("macii_queue_poll: double poll!\n"); + +- in_poll++; +- if (++device > 15) device = 1; +- +- adb_request(&req, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1, +- ADB_READREG(device, 0)); +- +- local_irq_save(flags); ++ if (!autopoll_devs) return; + ++ device_mask = (1 << (((command_byte & 0xF0) >> 4) + 1)) - 1; ++ if (autopoll_devs & ~device_mask) ++ next_device = ffs(autopoll_devs & ~device_mask) - 1; ++ else ++ next_device = ffs(autopoll_devs) - 1; ++ ++ BUG_ON(request_is_queued(&req)); ++ ++ adb_request(&req, NULL, ADBREQ_NOSEND, 1, ++ ADB_READREG(next_device, 0)); ++ ++ req.sent = 0; ++ req.complete = 0; ++ req.reply_len = 0; + req.next = current_req; +- current_req = &req; +- +- local_irq_restore(flags); +- macii_start(); +- in_poll--; +-} +- +-/* Send an ADB retransmit (Talk, appended to the request queue) */ +-static void macii_retransmit(int device) +-{ +- static int in_retransmit = 0; +- static struct adb_request rt; +- unsigned long flags; +- +- if (in_retransmit) printk("macii_retransmit: double retransmit!\n"); +- +- in_retransmit++; +- +- adb_request(&rt, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1, +- ADB_READREG(device, 0)); +- +- local_irq_save(flags); + + if (current_req != NULL) { +- last_req->next = &rt; +- last_req = &rt; ++ current_req = &req; + } else { +- current_req = &rt; +- last_req = &rt; ++ current_req = &req; ++ last_req = &req; + } +- +- if (macii_state == idle) macii_start(); +- +- local_irq_restore(flags); +- in_retransmit--; + } + + /* Send an ADB request; if sync, poll out the reply 'till it's done */ + static int macii_send_request(struct adb_request *req, int sync) + { +- int i; ++ int err; ++ unsigned long flags; + +- i = macii_write(req); +- if (i) return i; ++ BUG_ON(request_is_queued(req)); + +- if (sync) { +- while (!req->complete) macii_poll(); ++ local_irq_save(flags); ++ err = macii_write(req); ++ local_irq_restore(flags); ++ ++ if (!err && sync) { ++ while (!req->complete) { ++ macii_poll(); ++ } ++ BUG_ON(request_is_queued(req)); + } +- return 0; ++ ++ return err; + } + +-/* Send an ADB request */ ++/* Send an ADB request (append to request queue) */ + static int macii_write(struct adb_request *req) + { +- unsigned long flags; +- + if (req->nbytes < 2 || req->data[0] != ADB_PACKET || req->nbytes > 15) { + req->complete = 1; + return -EINVAL; +@@ -264,8 +267,6 @@ static int macii_write(struct adb_reques + req->complete = 0; + req->reply_len = 0; + +- local_irq_save(flags); +- + if (current_req != NULL) { + last_req->next = req; + last_req = req; +@@ -274,28 +275,52 @@ static int macii_write(struct adb_reques + last_req = req; + if (macii_state == idle) macii_start(); + } +- +- local_irq_restore(flags); + return 0; + } + + /* Start auto-polling */ + static int macii_autopoll(int devs) + { +- /* Just ping a random default address */ +- if (!(current_req || retry_req)) +- macii_retransmit( (last_active < 16 && last_active > 0) ? last_active : 3); +- return 0; ++ static struct adb_request req; ++ unsigned long flags; ++ int err = 0; ++ ++ /* bit 1 == device 1, and so on. */ ++ autopoll_devs = devs & 0xFFFE; ++ ++ if (!autopoll_devs) return 0; ++ ++ local_irq_save(flags); ++ ++ if (current_req == NULL) { ++ /* Send a Talk Reg 0. The controller will repeatedly transmit ++ * this as long as it is idle. ++ */ ++ adb_request(&req, NULL, ADBREQ_NOSEND, 1, ++ ADB_READREG(ffs(autopoll_devs) - 1, 0)); ++ err = macii_write(&req); ++ } ++ ++ local_irq_restore(flags); ++ return err; ++} ++ ++static inline int need_autopoll(void) { ++ /* Was the last command Talk Reg 0 ++ * and is the target on the autopoll list? ++ */ ++ if ((command_byte & 0x0F) == 0x0C && ++ ((1 << ((command_byte & 0xF0) >> 4)) & autopoll_devs)) ++ return 0; ++ return 1; + } + + /* Prod the chip without interrupts */ + static void macii_poll(void) + { +- unsigned long flags; +- +- local_irq_save(flags); +- if (via[IFR] & SR_INT) macii_interrupt(0, NULL); +- local_irq_restore(flags); ++ disable_irq(IRQ_MAC_ADB); ++ macii_interrupt(0, NULL); ++ enable_irq(IRQ_MAC_ADB); + } + + /* Reset the bus */ +@@ -303,73 +328,34 @@ static int macii_reset_bus(void) + { + static struct adb_request req; + ++ if (request_is_queued(&req)) ++ return 0; ++ + /* Command = 0, Address = ignored */ + adb_request(&req, NULL, 0, 1, ADB_BUSRESET); + ++ /* Don't want any more requests during the Global Reset low time. */ ++ udelay(3000); ++ + return 0; + } + + /* Start sending ADB packet */ + static void macii_start(void) + { +- unsigned long flags; + struct adb_request *req; + + req = current_req; +- if (!req) return; +- +- /* assert macii_state == idle */ +- if (macii_state != idle) { +- printk("macii_start: called while driver busy (%p %x %x)!\n", +- req, macii_state, (uint) via1[B] & (ST_MASK|TREQ)); +- return; +- } + +- local_irq_save(flags); +- +- /* +- * IRQ signaled ?? (means ADB controller wants to send, or might +- * be end of packet if we were reading) +- */ +-#if 0 /* FIXME: This is broke broke broke, for some reason */ +- if ((via[B] & TREQ) == 0) { +- printk("macii_start: weird poll stuff. huh?\n"); +- /* +- * FIXME - we need to restart this on a timer +- * or a collision at boot hangs us. +- * Never set macii_state to idle here, or macii_start +- * won't be called again from send_request! +- * (need to re-check other cases ...) +- */ +- /* +- * if the interrupt handler set the need_poll +- * flag, it's hopefully a SRQ poll or re-Talk +- * so we try to send here anyway +- */ +- if (!need_poll) { +- if (console_loglevel == 10) +- printk("macii_start: device busy - retry %p state %d status %x!\n", +- req, macii_state, +- (uint) via[B] & (ST_MASK|TREQ)); +- retry_req = req; +- /* set ADB status here ? */ +- local_irq_restore(flags); +- return; +- } else { +- need_poll = 0; +- } +- } +-#endif +- /* +- * Another retry pending? (sanity check) ++ BUG_ON(req == NULL); ++ ++ BUG_ON(macii_state != idle); ++ ++ /* Now send it. Be careful though, that first byte of the request ++ * is actually ADB_PACKET; the real data begins at index 1! ++ * And req->nbytes is the number of bytes of real data plus one. + */ +- if (retry_req) { +- retry_req = NULL; +- } + +- /* Now send it. Be careful though, that first byte of the request */ +- /* is actually ADB_PACKET; the real data begins at index 1! */ +- + /* store command byte */ + command_byte = req->data[1]; + /* Output mode */ +@@ -381,115 +367,97 @@ static void macii_start(void) + + macii_state = sending; + data_index = 2; +- +- local_irq_restore(flags); + } + + /* +- * The notorious ADB interrupt handler - does all of the protocol handling, +- * except for starting new send operations. Relies heavily on the ADB +- * controller sending and receiving data, thereby generating SR interrupts +- * for us. This means there has to be always activity on the ADB bus, otherwise +- * the whole process dies and has to be re-kicked by sending TALK requests ... +- * CUDA-based Macs seem to solve this with the autopoll option, for MacII-type +- * ADB the problem isn't solved yet (retransmit of the latest active TALK seems +- * a good choice; either on timeout or on a timer interrupt). ++ * The notorious ADB interrupt handler - does all of the protocol handling. ++ * Relies on the ADB controller sending and receiving data, thereby ++ * generating shift register interrupts (SR_INT) for us. This means there has ++ * to be activity on the ADB bus. The chip will poll to achieve this. + * + * The basic ADB state machine was left unchanged from the original MacII code + * by Alan Cox, which was based on the CUDA driver for PowerMac. +- * The syntax of the ADB status lines seems to be totally different on MacII, +- * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle for +- * sending, and Idle -> Even -> Odd -> Even ->...-> Idle for receiving. Start +- * and end of a receive packet are signaled by asserting /IRQ on the interrupt +- * line. Timeouts are signaled by a sequence of 4 0xFF, with /IRQ asserted on +- * every other byte. SRQ is probably signaled by 3 or more 0xFF tacked on the +- * end of a packet. (Thanks to Guido Koerber for eavesdropping on the ADB +- * protocol with a logic analyzer!!) +- * +- * Note: As of 21/10/97, the MacII ADB part works including timeout detection +- * and retransmit (Talk to the last active device). ++ * The syntax of the ADB status lines is totally different on MacII, ++ * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle ++ * for sending and Idle -> Even -> Odd -> Even ->...-> Idle for receiving. ++ * Start and end of a receive packet are signalled by asserting /IRQ on the ++ * interrupt line (/IRQ means the CTLR_IRQ bit in port B; not to be confused ++ * with the VIA shift register interrupt. /IRQ never actually interrupts the ++ * processor, it's just an ordinary input.) + */ + static irqreturn_t macii_interrupt(int irq, void *arg) + { +- int x, adbdir; +- unsigned long flags; ++ int x; ++ static int entered; + struct adb_request *req; + +- last_status = status; +- +- /* prevent races due to SCSI enabling ints */ +- local_irq_save(flags); +- +- if (driver_running) { +- local_irq_restore(flags); +- return IRQ_NONE; ++ if (!arg) { ++ /* Clear the SR IRQ flag when polling. */ ++ if (via[IFR] & SR_INT) ++ via[IFR] = SR_INT; ++ else ++ return IRQ_NONE; + } + +- driver_running = 1; +- +- status = via[B] & (ST_MASK|TREQ); +- adbdir = via[ACR] & SR_OUT; ++ BUG_ON(entered++); ++ ++ last_status = status; ++ status = via[B] & (ST_MASK|CTLR_IRQ); + + switch (macii_state) { + case idle: ++ if (reading_reply) { ++ reply_ptr = current_req->reply; ++ } else { ++ BUG_ON(current_req != NULL); ++ reply_ptr = reply_buf; ++ } ++ + x = via[SR]; +- first_byte = x; +- /* set ADB state = even for first data byte */ +- via[B] = (via[B] & ~ST_MASK) | ST_EVEN; + +- reply_buf[0] = first_byte; /* was command_byte?? */ +- reply_ptr = reply_buf + 1; +- reply_len = 1; +- prefix_len = 1; +- reading_reply = 0; +- +- macii_state = reading; +- break; ++ if ((status & CTLR_IRQ) && (x == 0xFF)) { ++ /* Bus timeout without SRQ sequence: ++ * data is "FF" while CTLR_IRQ is "H" ++ */ ++ reply_len = 0; ++ srq_asserted = 0; ++ macii_state = read_done; ++ } else { ++ macii_state = reading; ++ *reply_ptr = x; ++ reply_len = 1; ++ } + +- case awaiting_reply: +- /* handshake etc. for II ?? */ +- x = via[SR]; +- first_byte = x; + /* set ADB state = even for first data byte */ + via[B] = (via[B] & ~ST_MASK) | ST_EVEN; +- +- current_req->reply[0] = first_byte; +- reply_ptr = current_req->reply + 1; +- reply_len = 1; +- prefix_len = 1; +- reading_reply = 1; +- +- macii_state = reading; + break; + + case sending: + req = current_req; + if (data_index >= req->nbytes) { +- /* print an error message if a listen command has no data */ +- if (((command_byte & 0x0C) == 0x08) +- /* && (console_loglevel == 10) */ +- && (data_index == 2)) +- printk("MacII ADB: listen command with no data: %x!\n", +- command_byte); +- /* reset to shift in */ +- via[ACR] &= ~SR_OUT; +- x = via[SR]; +- /* set ADB state idle - might get SRQ */ +- via[B] = (via[B] & ~ST_MASK) | ST_IDLE; +- + req->sent = 1; ++ macii_state = idle; + + if (req->reply_expected) { +- macii_state = awaiting_reply; ++ reading_reply = 1; + } else { + req->complete = 1; + current_req = req->next; + if (req->done) (*req->done)(req); +- macii_state = idle; +- if (current_req || retry_req) ++ ++ if (current_req) + macii_start(); + else +- macii_retransmit((command_byte & 0xF0) >> 4); ++ if (need_autopoll()) ++ macii_autopoll(autopoll_devs); ++ } ++ ++ if (macii_state == idle) { ++ /* reset to shift in */ ++ via[ACR] &= ~SR_OUT; ++ x = via[SR]; ++ /* set ADB state idle - might get SRQ */ ++ via[B] = (via[B] & ~ST_MASK) | ST_IDLE; + } + } else { + via[SR] = req->data[data_index++]; +@@ -505,147 +473,79 @@ static irqreturn_t macii_interrupt(int i + break; + + case reading: ++ x = via[SR]; ++ BUG_ON((status & ST_MASK) == ST_CMD || ++ (status & ST_MASK) == ST_IDLE); + +- /* timeout / SRQ handling for II hw */ +- if( (first_byte == 0xFF && (reply_len-prefix_len)==2 +- && memcmp(reply_ptr-2,"\xFF\xFF",2)==0) || +- ((reply_len-prefix_len)==3 +- && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0)) +- { +- /* +- * possible timeout (in fact, most probably a +- * timeout, since SRQ can't be signaled without +- * transfer on the bus). +- * The last three bytes seen were FF, together +- * with the starting byte (in case we started +- * on 'idle' or 'awaiting_reply') this probably +- * makes four. So this is mostl likely #5! +- * The timeout signal is a pattern 1 0 1 0 0.. +- * on /INT, meaning we missed it :-( +- */ +- x = via[SR]; +- if (x != 0xFF) printk("MacII ADB: mistaken timeout/SRQ!\n"); ++ /* Bus timeout with SRQ sequence: ++ * data is "XX FF" while CTLR_IRQ is "L L" ++ * End of packet without SRQ sequence: ++ * data is "XX...YY 00" while CTLR_IRQ is "L...H L" ++ * End of packet SRQ sequence: ++ * data is "XX...YY 00" while CTLR_IRQ is "L...L L" ++ * (where XX is the first response byte and ++ * YY is the last byte of valid response data.) ++ */ + +- if ((status & TREQ) == (last_status & TREQ)) { +- /* Not a timeout. Unsolicited SRQ? weird. */ +- /* Terminate the SRQ packet and poll */ +- need_poll = 1; ++ srq_asserted = 0; ++ if (!(status & CTLR_IRQ)) { ++ if (x == 0xFF) { ++ if (!(last_status & CTLR_IRQ)) { ++ macii_state = read_done; ++ reply_len = 0; ++ srq_asserted = 1; ++ } ++ } else if (x == 0x00) { ++ macii_state = read_done; ++ if (!(last_status & CTLR_IRQ)) ++ srq_asserted = 1; + } +- /* There's no packet to get, so reply is blank */ +- via[B] ^= ST_MASK; +- reply_ptr -= (reply_len-prefix_len); +- reply_len = prefix_len; +- macii_state = read_done; +- break; +- } /* end timeout / SRQ handling for II hw. */ ++ } + +- if((reply_len-prefix_len)>3 +- && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0) +- { +- /* SRQ tacked on data packet */ +- /* Terminate the packet (SRQ never ends) */ +- x = via[SR]; +- macii_state = read_done; +- reply_len -= 3; +- reply_ptr -= 3; +- need_poll = 1; +- /* need to continue; next byte not seen else */ +- } else { +- /* Sanity check */ +- if (reply_len > 15) reply_len = 0; +- /* read byte */ +- x = via[SR]; +- *reply_ptr = x; ++ if (macii_state == reading) { ++ BUG_ON(reply_len > 15); + reply_ptr++; ++ *reply_ptr = x; + reply_len++; + } +- /* The usual handshake ... */ + +- /* +- * NetBSD hints that the next to last byte +- * is sent with IRQ !! +- * Guido found out it's the last one (0x0), +- * but IRQ should be asserted already. +- * Problem with timeout detection: First +- * transition to /IRQ might be second +- * byte of timeout packet! +- * Timeouts are signaled by 4x FF. +- */ +- if (((status & TREQ) == 0) && (x == 0x00)) { /* != 0xFF */ +- /* invert state bits, toggle ODD/EVEN */ +- via[B] ^= ST_MASK; +- +- /* adjust packet length */ +- reply_len--; +- reply_ptr--; +- macii_state = read_done; +- } else { +- /* not caught: ST_CMD */ +- /* required for re-entry 'reading'! */ +- if ((status & ST_MASK) == ST_IDLE) { +- /* (in)sanity check - set even */ +- via[B] = (via[B] & ~ST_MASK) | ST_EVEN; +- } else { +- /* invert state bits */ +- via[B] ^= ST_MASK; +- } +- } ++ /* invert state bits, toggle ODD/EVEN */ ++ via[B] ^= ST_MASK; + break; + + case read_done: + x = via[SR]; ++ + if (reading_reply) { ++ reading_reply = 0; + req = current_req; +- req->reply_len = reply_ptr - req->reply; ++ req->reply_len = reply_len; + req->complete = 1; + current_req = req->next; + if (req->done) (*req->done)(req); +- } else { +- adb_input(reply_buf, reply_ptr - reply_buf, 0); +- } ++ } else if (reply_len && autopoll_devs) ++ adb_input(reply_buf, reply_len, 0); + +- /* +- * remember this device ID; it's the latest we got a +- * reply from! +- */ +- last_reply = command_byte; +- last_active = (command_byte & 0xF0) >> 4; ++ macii_state = idle; + + /* SRQ seen before, initiate poll now */ +- if (need_poll) { +- macii_state = idle; ++ if (srq_asserted) + macii_queue_poll(); +- need_poll = 0; +- break; +- } +- +- /* set ADB state to idle */ +- via[B] = (via[B] & ~ST_MASK) | ST_IDLE; +- +- /* /IRQ seen, so the ADB controller has data for us */ +- if ((via[B] & TREQ) != 0) { +- macii_state = reading; + +- reply_buf[0] = command_byte; +- reply_ptr = reply_buf + 1; +- reply_len = 1; +- prefix_len = 1; +- reading_reply = 0; +- } else { +- /* no IRQ, send next packet or wait */ +- macii_state = idle; +- if (current_req) +- macii_start(); +- else +- macii_retransmit(last_active); +- } ++ if (current_req) ++ macii_start(); ++ else ++ if (need_autopoll()) ++ macii_autopoll(autopoll_devs); ++ ++ if (macii_state == idle) ++ via[B] = (via[B] & ~ST_MASK) | ST_IDLE; + break; + + default: + break; + } +- /* reset mutex and interrupts */ +- driver_running = 0; +- local_irq_restore(flags); ++ ++ entered--; + return IRQ_HANDLED; + } diff --git a/debian/patches/bugfix/m68k/mac68k-macmace-fixes.diff b/debian/patches/bugfix/m68k/mac68k-macmace-fixes.diff new file mode 100644 index 000000000000..a97885b26615 --- /dev/null +++ b/debian/patches/bugfix/m68k/mac68k-macmace-fixes.diff @@ -0,0 +1,951 @@ +Subject: [PATCH 11/13] m68k: macmace fixes +Cc: Jeff Garzik <jgarzik@pobox.com>, netdev@vger.kernel.org + +From: Finn Thain <fthain@telegraphics.com.au> + +Fix a race condition in the transmit code, where the dma interrupt could update +the free tx buffer count concurrently and wedge the tx queue. + +Fix the misuse of the rx frame status and rx frame length registers: no more +"fifo overrun" errors caused by the OFLOW bit being tested in the frame length +register (instead of the status register), and no more missed packets due to +incorrect length taken from status register (instead of the frame length +register). + +Fix a panic (skb_over_panic BUG) caused by allocating and then copying an +incoming packet while the packet length register was changing. + +Cut-and-paste the reset code from the powermac mace driver (mace.c), so the NIC +functions when MacOS does not initialise it (important for anyone wanting to +use the Emile boot loader). + +Cut-and-paste the error counting and timeout recovery code from mace.c. + +Fix over allocation of rx buffer memory (it's page order, not page count). + +Converted to driver model. + +Converted to DMA API. + +Since I've run out of ways to make it fail, and since it performs well now, +promote the driver from EXPERIMENTAL status. Tested on both quadra 840av and +660av. + +Signed-off-by: Finn Thain <fthain@telegraphics.com.au> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + drivers/net/Kconfig | 4 + drivers/net/Space.c | 4 + drivers/net/macmace.c | 591 ++++++++++++++++++++++++++++++-------------------- + 3 files changed, 364 insertions(+), 235 deletions(-) + +--- linux-m68k-2.6.21.orig/drivers/net/Kconfig ++++ linux-m68k-2.6.21/drivers/net/Kconfig +@@ -337,8 +337,8 @@ config MACSONIC + be called macsonic. + + config MACMACE +- bool "Macintosh (AV) onboard MACE ethernet (EXPERIMENTAL)" +- depends on NET_ETHERNET && MAC && EXPERIMENTAL ++ bool "Macintosh (AV) onboard MACE ethernet" ++ depends on NET_ETHERNET && MAC + select CRC32 + help + Support for the onboard AMD 79C940 MACE Ethernet controller used in +--- linux-m68k-2.6.21.orig/drivers/net/Space.c ++++ linux-m68k-2.6.21/drivers/net/Space.c +@@ -83,7 +83,6 @@ extern struct net_device *bagetlance_pro + extern struct net_device *mvme147lance_probe(int unit); + extern struct net_device *tc515_probe(int unit); + extern struct net_device *lance_probe(int unit); +-extern struct net_device *mace_probe(int unit); + extern struct net_device *mac8390_probe(int unit); + extern struct net_device *mac89x0_probe(int unit); + extern struct net_device *mc32_probe(int unit); +@@ -274,9 +273,6 @@ static struct devprobe2 m68k_probes[] __ + #ifdef CONFIG_MVME147_NET /* MVME147 internal Ethernet */ + {mvme147lance_probe, 0}, + #endif +-#ifdef CONFIG_MACMACE /* Mac 68k Quadra AV builtin Ethernet */ +- {mace_probe, 0}, +-#endif + #ifdef CONFIG_MAC8390 /* NuBus NS8390-based cards */ + {mac8390_probe, 0}, + #endif +--- linux-m68k-2.6.21.orig/drivers/net/macmace.c ++++ linux-m68k-2.6.21/drivers/net/macmace.c +@@ -12,6 +12,11 @@ + * Copyright (C) 1998 Alan Cox <alan@redhat.com> + * + * Modified heavily by Joshua M. Thompson based on Dave Huang's NetBSD driver ++ * ++ * Copyright (C) 2007 Finn Thain ++ * ++ * Converted to DMA API, converted to unified driver model, ++ * sync'd some routines with mace.c and fixed various bugs. + */ + + +@@ -23,8 +28,9 @@ + #include <linux/string.h> + #include <linux/crc32.h> + #include <linux/bitrev.h> ++#include <linux/dma-mapping.h> ++#include <linux/platform_device.h> + #include <asm/io.h> +-#include <asm/pgtable.h> + #include <asm/irq.h> + #include <asm/macintosh.h> + #include <asm/macints.h> +@@ -32,13 +38,20 @@ + #include <asm/page.h> + #include "mace.h" + +-#define N_TX_RING 1 +-#define N_RX_RING 8 +-#define N_RX_PAGES ((N_RX_RING * 0x0800 + PAGE_SIZE - 1) / PAGE_SIZE) ++static char mac_mace_string[] = "macmace"; ++static struct platform_device *mac_mace_device; ++ ++#define N_TX_BUFF_ORDER 0 ++#define N_TX_RING (1 << N_TX_BUFF_ORDER) ++#define N_RX_BUFF_ORDER 3 ++#define N_RX_RING (1 << N_RX_BUFF_ORDER) ++ + #define TX_TIMEOUT HZ + +-/* Bits in transmit DMA status */ +-#define TX_DMA_ERR 0x80 ++#define MACE_BUFF_SIZE 0x800 ++ ++/* Chip rev needs workaround on HW & multicast addr change */ ++#define BROKEN_ADDRCHG_REV 0x0941 + + /* The MACE is simply wired down on a Mac68K box */ + +@@ -47,40 +60,46 @@ + + struct mace_data { + volatile struct mace *mace; +- volatile unsigned char *tx_ring; +- volatile unsigned char *tx_ring_phys; +- volatile unsigned char *rx_ring; +- volatile unsigned char *rx_ring_phys; ++ unsigned char *tx_ring; ++ dma_addr_t tx_ring_phys; ++ unsigned char *rx_ring; ++ dma_addr_t rx_ring_phys; + int dma_intr; + struct net_device_stats stats; + int rx_slot, rx_tail; + int tx_slot, tx_sloti, tx_count; ++ int chipid; ++ struct device *device; + }; + + struct mace_frame { +- u16 len; +- u16 status; +- u16 rntpc; +- u16 rcvcc; +- u32 pad1; +- u32 pad2; ++ u8 rcvcnt; ++ u8 pad1; ++ u8 rcvsts; ++ u8 pad2; ++ u8 rntpc; ++ u8 pad3; ++ u8 rcvcc; ++ u8 pad4; ++ u32 pad5; ++ u32 pad6; + u8 data[1]; + /* And frame continues.. */ + }; + + #define PRIV_BYTES sizeof(struct mace_data) + +-extern void psc_debug_dump(void); +- + static int mace_open(struct net_device *dev); + static int mace_close(struct net_device *dev); + static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev); + static struct net_device_stats *mace_stats(struct net_device *dev); + static void mace_set_multicast(struct net_device *dev); + static int mace_set_address(struct net_device *dev, void *addr); ++static void mace_reset(struct net_device *dev); + static irqreturn_t mace_interrupt(int irq, void *dev_id); + static irqreturn_t mace_dma_intr(int irq, void *dev_id); + static void mace_tx_timeout(struct net_device *dev); ++static void __mace_set_address(struct net_device *dev, void *addr); + + /* + * Load a receive DMA channel with a base address and ring length +@@ -88,7 +107,7 @@ static void mace_tx_timeout(struct net_d + + static void mace_load_rxdma_base(struct net_device *dev, int set) + { +- struct mace_data *mp = (struct mace_data *) dev->priv; ++ struct mace_data *mp = netdev_priv(dev); + + psc_write_word(PSC_ENETRD_CMD + set, 0x0100); + psc_write_long(PSC_ENETRD_ADDR + set, (u32) mp->rx_ring_phys); +@@ -103,7 +122,7 @@ static void mace_load_rxdma_base(struct + + static void mace_rxdma_reset(struct net_device *dev) + { +- struct mace_data *mp = (struct mace_data *) dev->priv; ++ struct mace_data *mp = netdev_priv(dev); + volatile struct mace *mace = mp->mace; + u8 maccc = mace->maccc; + +@@ -130,7 +149,7 @@ static void mace_rxdma_reset(struct net_ + + static void mace_txdma_reset(struct net_device *dev) + { +- struct mace_data *mp = (struct mace_data *) dev->priv; ++ struct mace_data *mp = netdev_priv(dev); + volatile struct mace *mace = mp->mace; + u8 maccc; + +@@ -168,7 +187,7 @@ static void mace_dma_off(struct net_devi + * model of Macintrash has a MACE (AV macintoshes) + */ + +-struct net_device *mace_probe(int unit) ++static int __devinit mace_probe(struct platform_device *pdev) + { + int j; + struct mace_data *mp; +@@ -179,24 +198,28 @@ struct net_device *mace_probe(int unit) + int err; + + if (found || macintosh_config->ether_type != MAC_ETHER_MACE) +- return ERR_PTR(-ENODEV); ++ return -ENODEV; + + found = 1; /* prevent 'finding' one on every device probe */ + + dev = alloc_etherdev(PRIV_BYTES); + if (!dev) +- return ERR_PTR(-ENOMEM); ++ return -ENOMEM; + +- if (unit >= 0) +- sprintf(dev->name, "eth%d", unit); ++ mp = netdev_priv(dev); ++ ++ mp->device = &pdev->dev; ++ SET_NETDEV_DEV(dev, &pdev->dev); ++ SET_MODULE_OWNER(dev); + +- mp = (struct mace_data *) dev->priv; + dev->base_addr = (u32)MACE_BASE; + mp->mace = (volatile struct mace *) MACE_BASE; + + dev->irq = IRQ_MAC_MACE; + mp->dma_intr = IRQ_MAC_MACE_DMA; + ++ mp->chipid = mp->mace->chipid_hi << 8 | mp->mace->chipid_lo; ++ + /* + * The PROM contains 8 bytes which total 0xFF when XOR'd + * together. Due to the usual peculiar apple brain damage +@@ -217,7 +240,7 @@ struct net_device *mace_probe(int unit) + + if (checksum != 0xFF) { + free_netdev(dev); +- return ERR_PTR(-ENODEV); ++ return -ENODEV; + } + + memset(&mp->stats, 0, sizeof(mp->stats)); +@@ -237,22 +260,98 @@ struct net_device *mace_probe(int unit) + + err = register_netdev(dev); + if (!err) +- return dev; ++ return 0; + + free_netdev(dev); +- return ERR_PTR(err); ++ return err; ++} ++ ++/* ++ * Reset the chip. ++ */ ++ ++static void mace_reset(struct net_device *dev) ++{ ++ struct mace_data *mp = netdev_priv(dev); ++ volatile struct mace *mb = mp->mace; ++ int i; ++ ++ /* soft-reset the chip */ ++ i = 200; ++ while (--i) { ++ mb->biucc = SWRST; ++ if (mb->biucc & SWRST) { ++ udelay(10); ++ continue; ++ } ++ break; ++ } ++ if (!i) { ++ printk(KERN_ERR "macmace: cannot reset chip!\n"); ++ return; ++ } ++ ++ mb->maccc = 0; /* turn off tx, rx */ ++ mb->imr = 0xFF; /* disable all intrs for now */ ++ i = mb->ir; ++ ++ mb->biucc = XMTSP_64; ++ mb->utr = RTRD; ++ mb->fifocc = XMTFW_8 | RCVFW_64 | XMTFWU | RCVFWU; ++ ++ mb->xmtfc = AUTO_PAD_XMIT; /* auto-pad short frames */ ++ mb->rcvfc = 0; ++ ++ /* load up the hardware address */ ++ __mace_set_address(dev, dev->dev_addr); ++ ++ /* clear the multicast filter */ ++ if (mp->chipid == BROKEN_ADDRCHG_REV) ++ mb->iac = LOGADDR; ++ else { ++ mb->iac = ADDRCHG | LOGADDR; ++ while ((mb->iac & ADDRCHG) != 0) ++ ; ++ } ++ for (i = 0; i < 8; ++i) ++ mb->ladrf = 0; ++ ++ /* done changing address */ ++ if (mp->chipid != BROKEN_ADDRCHG_REV) ++ mb->iac = 0; ++ ++ mb->plscc = PORTSEL_AUI; + } + + /* + * Load the address on a mace controller. + */ + +-static int mace_set_address(struct net_device *dev, void *addr) ++static void __mace_set_address(struct net_device *dev, void *addr) + { +- unsigned char *p = addr; +- struct mace_data *mp = (struct mace_data *) dev->priv; ++ struct mace_data *mp = netdev_priv(dev); + volatile struct mace *mb = mp->mace; ++ unsigned char *p = addr; + int i; ++ ++ /* load up the hardware address */ ++ if (mp->chipid == BROKEN_ADDRCHG_REV) ++ mb->iac = PHYADDR; ++ else { ++ mb->iac = ADDRCHG | PHYADDR; ++ while ((mb->iac & ADDRCHG) != 0) ++ ; ++ } ++ for (i = 0; i < 6; ++i) ++ mb->padr = dev->dev_addr[i] = p[i]; ++ if (mp->chipid != BROKEN_ADDRCHG_REV) ++ mb->iac = 0; ++} ++ ++static int mace_set_address(struct net_device *dev, void *addr) ++{ ++ struct mace_data *mp = netdev_priv(dev); ++ volatile struct mace *mb = mp->mace; + unsigned long flags; + u8 maccc; + +@@ -260,15 +359,10 @@ static int mace_set_address(struct net_d + + maccc = mb->maccc; + +- /* load up the hardware address */ +- mb->iac = ADDRCHG | PHYADDR; +- while ((mb->iac & ADDRCHG) != 0); +- +- for (i = 0; i < 6; ++i) { +- mb->padr = dev->dev_addr[i] = p[i]; +- } ++ __mace_set_address(dev, addr); + + mb->maccc = maccc; ++ + local_irq_restore(flags); + + return 0; +@@ -281,31 +375,11 @@ static int mace_set_address(struct net_d + + static int mace_open(struct net_device *dev) + { +- struct mace_data *mp = (struct mace_data *) dev->priv; ++ struct mace_data *mp = netdev_priv(dev); + volatile struct mace *mb = mp->mace; +-#if 0 +- int i; + +- i = 200; +- while (--i) { +- mb->biucc = SWRST; +- if (mb->biucc & SWRST) { +- udelay(10); +- continue; +- } +- break; +- } +- if (!i) { +- printk(KERN_ERR "%s: software reset failed!!\n", dev->name); +- return -EAGAIN; +- } +-#endif +- +- mb->biucc = XMTSP_64; +- mb->fifocc = XMTFW_16 | RCVFW_64 | XMTFWU | RCVFWU | XMTBRST | RCVBRST; +- mb->xmtfc = AUTO_PAD_XMIT; +- mb->plscc = PORTSEL_AUI; +- /* mb->utr = RTRD; */ ++ /* reset the chip */ ++ mace_reset(dev); + + if (request_irq(dev->irq, mace_interrupt, 0, dev->name, dev)) { + printk(KERN_ERR "%s: can't get irq %d\n", dev->name, dev->irq); +@@ -319,25 +393,21 @@ static int mace_open(struct net_device * + + /* Allocate the DMA ring buffers */ + +- mp->rx_ring = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, N_RX_PAGES); +- mp->tx_ring = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, 0); +- +- if (mp->tx_ring==NULL || mp->rx_ring==NULL) { +- if (mp->rx_ring) free_pages((u32) mp->rx_ring, N_RX_PAGES); +- if (mp->tx_ring) free_pages((u32) mp->tx_ring, 0); +- free_irq(dev->irq, dev); +- free_irq(mp->dma_intr, dev); +- printk(KERN_ERR "%s: unable to allocate DMA buffers\n", dev->name); +- return -ENOMEM; ++ mp->tx_ring = dma_alloc_coherent(mp->device, ++ N_TX_RING * MACE_BUFF_SIZE, ++ &mp->tx_ring_phys, GFP_KERNEL); ++ if (mp->tx_ring == NULL) { ++ printk(KERN_ERR "%s: unable to allocate DMA tx buffers\n", dev->name); ++ goto out1; + } + +- mp->rx_ring_phys = (unsigned char *) virt_to_bus((void *)mp->rx_ring); +- mp->tx_ring_phys = (unsigned char *) virt_to_bus((void *)mp->tx_ring); +- +- /* We want the Rx buffer to be uncached and the Tx buffer to be writethrough */ +- +- kernel_set_cachemode((void *)mp->rx_ring, N_RX_PAGES * PAGE_SIZE, IOMAP_NOCACHE_NONSER); +- kernel_set_cachemode((void *)mp->tx_ring, PAGE_SIZE, IOMAP_WRITETHROUGH); ++ mp->rx_ring = dma_alloc_coherent(mp->device, ++ N_RX_RING * MACE_BUFF_SIZE, ++ &mp->rx_ring_phys, GFP_KERNEL); ++ if (mp->rx_ring == NULL) { ++ printk(KERN_ERR "%s: unable to allocate DMA rx buffers\n", dev->name); ++ goto out2; ++ } + + mace_dma_off(dev); + +@@ -348,34 +418,22 @@ static int mace_open(struct net_device * + psc_write_word(PSC_ENETWR_CTL, 0x0400); + psc_write_word(PSC_ENETRD_CTL, 0x0400); + +-#if 0 +- /* load up the hardware address */ +- +- mb->iac = ADDRCHG | PHYADDR; +- +- while ((mb->iac & ADDRCHG) != 0); +- +- for (i = 0; i < 6; ++i) +- mb->padr = dev->dev_addr[i]; +- +- /* clear the multicast filter */ +- mb->iac = ADDRCHG | LOGADDR; +- +- while ((mb->iac & ADDRCHG) != 0); +- +- for (i = 0; i < 8; ++i) +- mb->ladrf = 0; +- +- mb->plscc = PORTSEL_GPSI + ENPLSIO; +- +- mb->maccc = ENXMT | ENRCV; +- mb->imr = RCVINT; +-#endif +- + mace_rxdma_reset(dev); + mace_txdma_reset(dev); + ++ /* turn it on! */ ++ mb->maccc = ENXMT | ENRCV; ++ /* enable all interrupts except receive interrupts */ ++ mb->imr = RCVINT; + return 0; ++ ++out2: ++ dma_free_coherent(mp->device, N_TX_RING * MACE_BUFF_SIZE, ++ mp->tx_ring, mp->tx_ring_phys); ++out1: ++ free_irq(dev->irq, dev); ++ free_irq(mp->dma_intr, dev); ++ return -ENOMEM; + } + + /* +@@ -384,19 +442,13 @@ static int mace_open(struct net_device * + + static int mace_close(struct net_device *dev) + { +- struct mace_data *mp = (struct mace_data *) dev->priv; ++ struct mace_data *mp = netdev_priv(dev); + volatile struct mace *mb = mp->mace; + + mb->maccc = 0; /* disable rx and tx */ + mb->imr = 0xFF; /* disable all irqs */ + mace_dma_off(dev); /* disable rx and tx dma */ + +- free_irq(dev->irq, dev); +- free_irq(IRQ_MAC_MACE_DMA, dev); +- +- free_pages((u32) mp->rx_ring, N_RX_PAGES); +- free_pages((u32) mp->tx_ring, 0); +- + return 0; + } + +@@ -406,15 +458,20 @@ static int mace_close(struct net_device + + static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) + { +- struct mace_data *mp = (struct mace_data *) dev->priv; ++ struct mace_data *mp = netdev_priv(dev); ++ unsigned long flags; + +- /* Stop the queue if the buffer is full */ ++ /* Stop the queue since there's only the one buffer */ + ++ local_irq_save(flags); ++ netif_stop_queue(dev); + if (!mp->tx_count) { +- netif_stop_queue(dev); +- return 1; ++ printk(KERN_ERR "macmace: tx queue running but no free buffers.\n"); ++ local_irq_restore(flags); ++ return NETDEV_TX_BUSY; + } + mp->tx_count--; ++ local_irq_restore(flags); + + mp->stats.tx_packets++; + mp->stats.tx_bytes += skb->len; +@@ -433,23 +490,26 @@ static int mace_xmit_start(struct sk_buf + + dev_kfree_skb(skb); + +- return 0; ++ dev->trans_start = jiffies; ++ return NETDEV_TX_OK; + } + + static struct net_device_stats *mace_stats(struct net_device *dev) + { +- struct mace_data *p = (struct mace_data *) dev->priv; +- return &p->stats; ++ struct mace_data *mp = netdev_priv(dev); ++ return &mp->stats; + } + + static void mace_set_multicast(struct net_device *dev) + { +- struct mace_data *mp = (struct mace_data *) dev->priv; ++ struct mace_data *mp = netdev_priv(dev); + volatile struct mace *mb = mp->mace; + int i, j; + u32 crc; + u8 maccc; ++ unsigned long flags; + ++ local_irq_save(flags); + maccc = mb->maccc; + mb->maccc &= ~PROM; + +@@ -474,116 +534,122 @@ static void mace_set_multicast(struct ne + } + } + +- mb->iac = ADDRCHG | LOGADDR; +- while (mb->iac & ADDRCHG); +- +- for (i = 0; i < 8; ++i) { +- mb->ladrf = multicast_filter[i]; ++ if (mp->chipid == BROKEN_ADDRCHG_REV) ++ mb->iac = LOGADDR; ++ else { ++ mb->iac = ADDRCHG | LOGADDR; ++ while ((mb->iac & ADDRCHG) != 0) ++ ; + } ++ for (i = 0; i < 8; ++i) ++ mb->ladrf = multicast_filter[i]; ++ if (mp->chipid != BROKEN_ADDRCHG_REV) ++ mb->iac = 0; + } + + mb->maccc = maccc; ++ local_irq_restore(flags); + } + +-/* +- * Miscellaneous interrupts are handled here. We may end up +- * having to bash the chip on the head for bad errors +- */ +- + static void mace_handle_misc_intrs(struct mace_data *mp, int intr) + { + volatile struct mace *mb = mp->mace; + static int mace_babbles, mace_jabbers; + +- if (intr & MPCO) { ++ if (intr & MPCO) + mp->stats.rx_missed_errors += 256; +- } +- mp->stats.rx_missed_errors += mb->mpc; /* reading clears it */ +- +- if (intr & RNTPCO) { ++ mp->stats.rx_missed_errors += mb->mpc; /* reading clears it */ ++ if (intr & RNTPCO) + mp->stats.rx_length_errors += 256; +- } +- mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */ +- +- if (intr & CERR) { ++ mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */ ++ if (intr & CERR) + ++mp->stats.tx_heartbeat_errors; +- } +- if (intr & BABBLE) { +- if (mace_babbles++ < 4) { +- printk(KERN_DEBUG "mace: babbling transmitter\n"); +- } +- } +- if (intr & JABBER) { +- if (mace_jabbers++ < 4) { +- printk(KERN_DEBUG "mace: jabbering transceiver\n"); +- } +- } ++ if (intr & BABBLE) ++ if (mace_babbles++ < 4) ++ printk(KERN_DEBUG "macmace: babbling transmitter\n"); ++ if (intr & JABBER) ++ if (mace_jabbers++ < 4) ++ printk(KERN_DEBUG "macmace: jabbering transceiver\n"); + } + +-/* +- * A transmit error has occurred. (We kick the transmit side from +- * the DMA completion) +- */ +- +-static void mace_xmit_error(struct net_device *dev) ++static irqreturn_t mace_interrupt(int irq, void *dev_id) + { +- struct mace_data *mp = (struct mace_data *) dev->priv; ++ struct net_device *dev = (struct net_device *) dev_id; ++ struct mace_data *mp = netdev_priv(dev); + volatile struct mace *mb = mp->mace; +- u8 xmtfs, xmtrc; ++ int intr, fs; ++ unsigned int flags; ++ ++ /* don't want the dma interrupt handler to fire */ ++ local_irq_save(flags); + +- xmtfs = mb->xmtfs; +- xmtrc = mb->xmtrc; ++ intr = mb->ir; /* read interrupt register */ ++ mace_handle_misc_intrs(mp, intr); + +- if (xmtfs & XMTSV) { +- if (xmtfs & UFLO) { +- printk("%s: DMA underrun.\n", dev->name); +- mp->stats.tx_errors++; +- mp->stats.tx_fifo_errors++; +- mace_txdma_reset(dev); ++ if (intr & XMTINT) { ++ fs = mb->xmtfs; ++ if ((fs & XMTSV) == 0) { ++ printk(KERN_ERR "macmace: xmtfs not valid! (fs=%x)\n", fs); ++ mace_reset(dev); ++ /* ++ * XXX mace likes to hang the machine after a xmtfs error. ++ * This is hard to reproduce, reseting *may* help ++ */ + } +- if (xmtfs & RTRY) { +- mp->stats.collisions++; ++ /* dma should have finished */ ++ if (!mp->tx_count) { ++ printk(KERN_DEBUG "macmace: tx ring ran out? (fs=%x)\n", fs); ++ } ++ /* Update stats */ ++ if (fs & (UFLO|LCOL|LCAR|RTRY)) { ++ ++mp->stats.tx_errors; ++ if (fs & LCAR) ++ ++mp->stats.tx_carrier_errors; ++ else if (fs & (UFLO|LCOL|RTRY)) { ++ ++mp->stats.tx_aborted_errors; ++ if (mb->xmtfs & UFLO) { ++ printk(KERN_ERR "%s: DMA underrun.\n", dev->name); ++ mp->stats.tx_fifo_errors++; ++ mace_txdma_reset(dev); ++ } ++ } + } + } +-} + +-/* +- * A receive interrupt occurred. +- */ ++ if (mp->tx_count) ++ netif_wake_queue(dev); + +-static void mace_recv_interrupt(struct net_device *dev) +-{ +-/* struct mace_data *mp = (struct mace_data *) dev->priv; */ +-// volatile struct mace *mb = mp->mace; +-} ++ local_irq_restore(flags); + +-/* +- * Process the chip interrupt +- */ ++ return IRQ_HANDLED; ++} + +-static irqreturn_t mace_interrupt(int irq, void *dev_id) ++static void mace_tx_timeout(struct net_device *dev) + { +- struct net_device *dev = (struct net_device *) dev_id; +- struct mace_data *mp = (struct mace_data *) dev->priv; ++ struct mace_data *mp = netdev_priv(dev); + volatile struct mace *mb = mp->mace; +- u8 ir; ++ unsigned long flags; + +- ir = mb->ir; +- mace_handle_misc_intrs(mp, ir); ++ local_irq_save(flags); + +- if (ir & XMTINT) { +- mace_xmit_error(dev); +- } +- if (ir & RCVINT) { +- mace_recv_interrupt(dev); +- } +- return IRQ_HANDLED; +-} ++ /* turn off both tx and rx and reset the chip */ ++ mb->maccc = 0; ++ printk(KERN_ERR "macmace: transmit timeout - resetting\n"); ++ mace_txdma_reset(dev); ++ mace_reset(dev); + +-static void mace_tx_timeout(struct net_device *dev) +-{ +-/* struct mace_data *mp = (struct mace_data *) dev->priv; */ +-// volatile struct mace *mb = mp->mace; ++ /* restart rx dma */ ++ mace_rxdma_reset(dev); ++ ++ mp->tx_count = N_TX_RING; ++ netif_wake_queue(dev); ++ ++ /* turn it on! */ ++ mb->maccc = ENXMT | ENRCV; ++ /* enable all interrupts except receive interrupts */ ++ mb->imr = RCVINT; ++ ++ local_irq_restore(flags); + } + + /* +@@ -592,41 +658,40 @@ static void mace_tx_timeout(struct net_d + + static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf) + { +- struct mace_data *mp = (struct mace_data *) dev->priv; ++ struct mace_data *mp = netdev_priv(dev); + struct sk_buff *skb; ++ unsigned int frame_status = mf->rcvsts; + +- if (mf->status & RS_OFLO) { +- printk("%s: fifo overflow.\n", dev->name); +- mp->stats.rx_errors++; +- mp->stats.rx_fifo_errors++; +- } +- if (mf->status&(RS_CLSN|RS_FRAMERR|RS_FCSERR)) ++ if (frame_status & (RS_OFLO | RS_CLSN | RS_FRAMERR | RS_FCSERR)) { + mp->stats.rx_errors++; ++ if (frame_status & RS_OFLO) { ++ printk(KERN_DEBUG "%s: fifo overflow.\n", dev->name); ++ mp->stats.rx_fifo_errors++; ++ } ++ if (frame_status & RS_CLSN) ++ mp->stats.collisions++; ++ if (frame_status & RS_FRAMERR) ++ mp->stats.rx_frame_errors++; ++ if (frame_status & RS_FCSERR) ++ mp->stats.rx_crc_errors++; ++ } else { ++ unsigned int frame_length = mf->rcvcnt + ((frame_status & 0x0F) << 8 ); + +- if (mf->status&RS_CLSN) { +- mp->stats.collisions++; +- } +- if (mf->status&RS_FRAMERR) { +- mp->stats.rx_frame_errors++; +- } +- if (mf->status&RS_FCSERR) { +- mp->stats.rx_crc_errors++; +- } ++ skb = dev_alloc_skb(frame_length + 2); ++ if (!skb) { ++ mp->stats.rx_dropped++; ++ return; ++ } ++ skb_reserve(skb, 2); ++ memcpy(skb_put(skb, frame_length), mf->data, frame_length); + +- skb = dev_alloc_skb(mf->len+2); +- if (!skb) { +- mp->stats.rx_dropped++; +- return; ++ skb->dev = dev; ++ skb->protocol = eth_type_trans(skb, dev); ++ netif_rx(skb); ++ dev->last_rx = jiffies; ++ mp->stats.rx_packets++; ++ mp->stats.rx_bytes += frame_length; + } +- skb_reserve(skb,2); +- memcpy(skb_put(skb, mf->len), mf->data, mf->len); +- +- skb->dev = dev; +- skb->protocol = eth_type_trans(skb, dev); +- netif_rx(skb); +- dev->last_rx = jiffies; +- mp->stats.rx_packets++; +- mp->stats.rx_bytes += mf->len; + } + + /* +@@ -636,7 +701,7 @@ static void mace_dma_rx_frame(struct net + static irqreturn_t mace_dma_intr(int irq, void *dev_id) + { + struct net_device *dev = (struct net_device *) dev_id; +- struct mace_data *mp = (struct mace_data *) dev->priv; ++ struct mace_data *mp = netdev_priv(dev); + int left, head; + u16 status; + u32 baka; +@@ -663,7 +728,8 @@ static irqreturn_t mace_dma_intr(int irq + /* Loop through the ring buffer and process new packages */ + + while (mp->rx_tail < head) { +- mace_dma_rx_frame(dev, (struct mace_frame *) (mp->rx_ring + (mp->rx_tail * 0x0800))); ++ mace_dma_rx_frame(dev, (struct mace_frame*) (mp->rx_ring ++ + (mp->rx_tail * MACE_BUFF_SIZE))); + mp->rx_tail++; + } + +@@ -690,9 +756,76 @@ static irqreturn_t mace_dma_intr(int irq + psc_write_word(PSC_ENETWR_CMD + mp->tx_sloti, 0x0100); + mp->tx_sloti ^= 0x10; + mp->tx_count++; +- netif_wake_queue(dev); + } + return IRQ_HANDLED; + } + + MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Macintosh MACE ethernet driver"); ++ ++static int __devexit mac_mace_device_remove (struct platform_device *pdev) ++{ ++ struct net_device *dev = platform_get_drvdata(pdev); ++ struct mace_data *mp = netdev_priv(dev); ++ ++ unregister_netdev(dev); ++ ++ free_irq(dev->irq, dev); ++ free_irq(IRQ_MAC_MACE_DMA, dev); ++ ++ dma_free_coherent(mp->device, N_RX_RING * MACE_BUFF_SIZE, ++ mp->rx_ring, mp->rx_ring_phys); ++ dma_free_coherent(mp->device, N_TX_RING * MACE_BUFF_SIZE, ++ mp->tx_ring, mp->tx_ring_phys); ++ ++ free_netdev(dev); ++ ++ return 0; ++} ++ ++static struct platform_driver mac_mace_driver = { ++ .probe = mace_probe, ++ .remove = __devexit_p(mac_mace_device_remove), ++ .driver = { ++ .name = mac_mace_string, ++ }, ++}; ++ ++static int __init mac_mace_init_module(void) ++{ ++ int err; ++ ++ if ((err = platform_driver_register(&mac_mace_driver))) { ++ printk(KERN_ERR "Driver registration failed\n"); ++ return err; ++ } ++ ++ mac_mace_device = platform_device_alloc(mac_mace_string, 0); ++ if (!mac_mace_device) ++ goto out_unregister; ++ ++ if (platform_device_add(mac_mace_device)) { ++ platform_device_put(mac_mace_device); ++ mac_mace_device = NULL; ++ } ++ ++ return 0; ++ ++out_unregister: ++ platform_driver_unregister(&mac_mace_driver); ++ ++ return -ENOMEM; ++} ++ ++static void __exit mac_mace_cleanup_module(void) ++{ ++ platform_driver_unregister(&mac_mace_driver); ++ ++ if (mac_mace_device) { ++ platform_device_unregister(mac_mace_device); ++ mac_mace_device = NULL; ++ } ++} ++ ++module_init(mac_mace_init_module); ++module_exit(mac_mace_cleanup_module); diff --git a/debian/patches/bugfix/m68k/mac68k-macsonic-via-alt-mapping.diff b/debian/patches/bugfix/m68k/mac68k-macsonic-via-alt-mapping.diff new file mode 100644 index 000000000000..0998c9cab31a --- /dev/null +++ b/debian/patches/bugfix/m68k/mac68k-macsonic-via-alt-mapping.diff @@ -0,0 +1,194 @@ +Subject: [PATCH 13/13] SONIC interrupt handling +Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>, + Jeff Garzik <jgarzik@pobox.com>, netdev@vger.kernel.org, + linux-mips@linux-mips.org + +From: Finn Thain <fthain@telegraphics.com.au> + +Install the built-in macsonic interrupt handler on both IRQs when using +via_alt_mapping. Otherwise the rare interrupt that still comes from the +nubus slot will wedge the nubus. + +$ cat /proc/interrupts +auto 2: 89176 via2 +auto 3: 744367 sonic +auto 4: 0 scc +auto 6: 318363 via1 +auto 7: 0 NMI +mac 9: 119413 framebuffer vbl +mac 10: 1971 ADB +mac 14: 198517 timer +mac 17: 89104 nubus +mac 19: 72 Mac ESP SCSI +mac 56: 629 sonic +mac 62: 1142593 ide0 + +Version 1 of this patch had a bug where a nubus sonic card would register +two interrupt handlers. Only a built-in sonic needs both. + +Versions 2 and 3 needed some cleanups, as Raylynn Knight and Christoph +Hellwig pointed out (thanks). + +Signed-off-by: Finn Thain <fthain@telegraphics.com.au> +--- + drivers/net/jazzsonic.c | 23 +++++++++++++++++++---- + drivers/net/macsonic.c | 46 ++++++++++++++++++++++++++++++++++++++++++---- + drivers/net/sonic.c | 25 ------------------------- + 3 files changed, 61 insertions(+), 33 deletions(-) + +--- linux-m68k-2.6.22-rc1.orig/drivers/net/jazzsonic.c ++++ linux-m68k-2.6.22-rc1/drivers/net/jazzsonic.c +@@ -88,6 +88,23 @@ static unsigned short known_revisions[] + 0xffff /* end of list */ + }; + ++static int jazzsonic_open(struct net_device* dev) ++{ ++ if (request_irq(dev->irq, &sonic_interrupt, IRQF_DISABLED, "sonic", dev)) { ++ printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq); ++ return -EAGAIN; ++ } ++ return sonic_open(dev); ++} ++ ++static int jazzsonic_close(struct net_device* dev) ++{ ++ int err; ++ err = sonic_close(dev); ++ free_irq(dev->irq, dev); ++ return err; ++} ++ + static int __init sonic_probe1(struct net_device *dev) + { + static unsigned version_printed; +@@ -169,8 +186,8 @@ static int __init sonic_probe1(struct ne + lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS + * SONIC_BUS_SCALE(lp->dma_bitmode)); + +- dev->open = sonic_open; +- dev->stop = sonic_close; ++ dev->open = jazzsonic_open; ++ dev->stop = jazzsonic_close; + dev->hard_start_xmit = sonic_send_packet; + dev->get_stats = sonic_get_stats; + dev->set_multicast_list = &sonic_multicast_list; +@@ -260,8 +277,6 @@ MODULE_DESCRIPTION("Jazz SONIC ethernet + module_param(sonic_debug, int, 0); + MODULE_PARM_DESC(sonic_debug, "jazzsonic debug level (1-4)"); + +-#define SONIC_IRQ_FLAG IRQF_DISABLED +- + #include "sonic.c" + + static int __devexit jazz_sonic_device_remove (struct platform_device *pdev) +--- linux-m68k-2.6.22-rc1.orig/drivers/net/macsonic.c ++++ linux-m68k-2.6.22-rc1/drivers/net/macsonic.c +@@ -130,6 +130,46 @@ static inline void bit_reverse_addr(unsi + addr[i] = bitrev8(addr[i]); + } + ++static irqreturn_t macsonic_interrupt(int irq, void *dev_id) ++{ ++ irqreturn_t result; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ result = sonic_interrupt(irq, dev_id); ++ local_irq_restore(flags); ++ return result; ++} ++ ++static int macsonic_open(struct net_device* dev) ++{ ++ if (request_irq(dev->irq, &sonic_interrupt, IRQ_FLG_FAST, "sonic", dev)) { ++ printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq); ++ return -EAGAIN; ++ } ++ /* Under the A/UX interrupt scheme, the onboard SONIC interrupt comes ++ * in at priority level 3. However, we sometimes get the level 2 inter- ++ * rupt as well, which must prevent re-entrance of the sonic handler. ++ */ ++ if (dev->irq == IRQ_AUTO_3) ++ if (request_irq(IRQ_NUBUS_9, &macsonic_interrupt, IRQ_FLG_FAST, "sonic", dev)) { ++ printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, IRQ_NUBUS_9); ++ free_irq(dev->irq, dev); ++ return -EAGAIN; ++ } ++ return sonic_open(dev); ++} ++ ++static int macsonic_close(struct net_device* dev) ++{ ++ int err; ++ err = sonic_close(dev); ++ free_irq(dev->irq, dev); ++ if (dev->irq == IRQ_AUTO_3) ++ free_irq(IRQ_NUBUS_9, dev); ++ return err; ++} ++ + int __init macsonic_init(struct net_device* dev) + { + struct sonic_local* lp = netdev_priv(dev); +@@ -160,8 +200,8 @@ int __init macsonic_init(struct net_devi + lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS + * SONIC_BUS_SCALE(lp->dma_bitmode)); + +- dev->open = sonic_open; +- dev->stop = sonic_close; ++ dev->open = macsonic_open; ++ dev->stop = macsonic_close; + dev->hard_start_xmit = sonic_send_packet; + dev->get_stats = sonic_get_stats; + dev->set_multicast_list = &sonic_multicast_list; +@@ -572,8 +612,6 @@ MODULE_DESCRIPTION("Macintosh SONIC ethe + module_param(sonic_debug, int, 0); + MODULE_PARM_DESC(sonic_debug, "macsonic debug level (1-4)"); + +-#define SONIC_IRQ_FLAG IRQ_FLG_FAST +- + #include "sonic.c" + + static int __devexit mac_sonic_device_remove (struct platform_device *pdev) +--- linux-m68k-2.6.22-rc1.orig/drivers/net/sonic.c ++++ linux-m68k-2.6.22-rc1/drivers/net/sonic.c +@@ -50,29 +50,6 @@ static int sonic_open(struct net_device + if (sonic_debug > 2) + printk("sonic_open: initializing sonic driver.\n"); + +- /* +- * We don't need to deal with auto-irq stuff since we +- * hardwire the sonic interrupt. +- */ +-/* +- * XXX Horrible work around: We install sonic_interrupt as fast interrupt. +- * This means that during execution of the handler interrupt are disabled +- * covering another bug otherwise corrupting data. This doesn't mean +- * this glue works ok under all situations. +- * +- * Note (dhd): this also appears to prevent lockups on the Macintrash +- * when more than one Ethernet card is installed (knock on wood) +- * +- * Note (fthain): whether the above is still true is anyones guess. Certainly +- * the buffer handling algorithms will not tolerate re-entrance without some +- * mutual exclusion added. Anyway, the memcpy has now been eliminated from the +- * rx code to make this a faster "fast interrupt". +- */ +- if (request_irq(dev->irq, &sonic_interrupt, SONIC_IRQ_FLAG, "sonic", dev)) { +- printk(KERN_ERR "\n%s: unable to get IRQ %d .\n", dev->name, dev->irq); +- return -EAGAIN; +- } +- + for (i = 0; i < SONIC_NUM_RRS; i++) { + struct sk_buff *skb = dev_alloc_skb(SONIC_RBSIZE + 2); + if (skb == NULL) { +@@ -169,8 +146,6 @@ static int sonic_close(struct net_device + } + } + +- free_irq(dev->irq, dev); /* release the IRQ */ +- + return 0; + } + diff --git a/debian/patches/bugfix/m68k/mac68k-patch_A-mac68k_cvs_nubus_defines.diff b/debian/patches/bugfix/m68k/mac68k-patch_A-mac68k_cvs_nubus_defines.diff new file mode 100644 index 000000000000..7572b96cc5e6 --- /dev/null +++ b/debian/patches/bugfix/m68k/mac68k-patch_A-mac68k_cvs_nubus_defines.diff @@ -0,0 +1,222 @@ +Subject: [PATCH 3/13] NuBus header update +Cc: nubus-pmac-users@lists.sourceforge.net + +From: Finn Thain <fthain@telegraphics.com.au> + +Sync the nubus defines with the latest code in the mac68k repo. Some of these +are needed for DP8390 driver update in the next patch. + +Signed-off-by: Finn Thain <fthain@telegraphics.com.au> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + drivers/net/macsonic.c | 2 + include/linux/nubus.h | 126 +++++++++++++++++++++++++++++-------------------- + 2 files changed, 76 insertions(+), 52 deletions(-) + +--- linux-m68k-2.6.21.orig/drivers/net/macsonic.c ++++ linux-m68k-2.6.21/drivers/net/macsonic.c +@@ -402,7 +402,7 @@ int __init macsonic_ident(struct nubus_d + ndev->dr_sw == NUBUS_DRSW_DAYNA) + return MACSONIC_DAYNA; + +- if (ndev->dr_hw == NUBUS_DRHW_SONIC_LC && ++ if (ndev->dr_hw == NUBUS_DRHW_APPLE_SONIC_LC && + ndev->dr_sw == 0) { /* huh? */ + return MACSONIC_APPLE16; + } +--- linux-m68k-2.6.21.orig/include/linux/nubus.h ++++ linux-m68k-2.6.21/include/linux/nubus.h +@@ -28,18 +28,18 @@ enum nubus_category { + }; + + enum nubus_type_network { +- NUBUS_TYPE_ETHERNET = 0x0001, +- NUBUS_TYPE_RS232 = 0x0002 ++ NUBUS_TYPE_ETHERNET = 0x0001, ++ NUBUS_TYPE_RS232 = 0x0002 + }; + + enum nubus_type_display { +- NUBUS_TYPE_VIDEO = 0x0001 ++ NUBUS_TYPE_VIDEO = 0x0001 + }; + + enum nubus_type_cpu { +- NUBUS_TYPE_68020 = 0x0003, +- NUBUS_TYPE_68030 = 0x0004, +- NUBUS_TYPE_68040 = 0x0005 ++ NUBUS_TYPE_68020 = 0x0003, ++ NUBUS_TYPE_68030 = 0x0004, ++ NUBUS_TYPE_68040 = 0x0005 + }; + + /* Known <Cat,Type,SW,HW> tuples: (according to TattleTech and Slots) +@@ -56,6 +56,7 @@ enum nubus_type_cpu { + * + * SONIC comm-slot/on-board and DuoDock Ethernet: <4,1,1,272> + * SONIC LC-PDS Ethernet (Dayna, but like Apple 16-bit, sort of): <4,1,1,271> ++ * Apple SONIC LC-PDS Ethernet ("Apple Ethernet LC Twisted-Pair Card"): <4,1,0,281> + * Sonic Systems Ethernet A-Series Card: <4,1,268,256> + * Asante MacCon NuBus-A: <4,1,260,256> (alpha-1.0,1.1 revision) + * ROM on the above card: <2,1,0,0> +@@ -80,24 +81,26 @@ enum nubus_type_cpu { + /* Add known DrSW values here */ + enum nubus_drsw { + /* NUBUS_CAT_DISPLAY */ +- NUBUS_DRSW_APPLE = 0x0001, +- NUBUS_DRSW_APPLE_HIRES = 0x0013, /* MacII HiRes card driver */ ++ NUBUS_DRSW_APPLE = 0x0001, ++ NUBUS_DRSW_APPLE_HIRES = 0x0013, /* MacII HiRes card driver */ + + /* NUBUS_CAT_NETWORK */ +- NUBUS_DRSW_CABLETRON = 0x0001, +- NUBUS_DRSW_SONIC_LC = 0x0001, +- NUBUS_DRSW_KINETICS = 0x0103, +- NUBUS_DRSW_ASANTE = 0x0104, +- NUBUS_DRSW_DAYNA = 0x010b, +- NUBUS_DRSW_FARALLON = 0x010c, +- NUBUS_DRSW_APPLE_SN = 0x010f, +- NUBUS_DRSW_DAYNA2 = 0x0115, ++ NUBUS_DRSW_3COM = 0x0000, ++ NUBUS_DRSW_CABLETRON = 0x0001, ++ NUBUS_DRSW_SONIC_LC = 0x0001, ++ NUBUS_DRSW_KINETICS = 0x0103, ++ NUBUS_DRSW_ASANTE = 0x0104, ++ NUBUS_DRSW_TECHWORKS = 0x0109, ++ NUBUS_DRSW_DAYNA = 0x010b, ++ NUBUS_DRSW_FARALLON = 0x010c, ++ NUBUS_DRSW_APPLE_SN = 0x010f, ++ NUBUS_DRSW_DAYNA2 = 0x0115, + NUBUS_DRSW_FOCUS = 0x011a, + NUBUS_DRSW_ASANTE_CS = 0x011d, /* use asante SMC9194 driver */ +- NUBUS_DRSW_DAYNA_LC = 0x011e, ++ NUBUS_DRSW_DAYNA_LC = 0x011e, + + /* NUBUS_CAT_CPU */ +- NUBUS_DRSW_NONE = 0x0000, ++ NUBUS_DRSW_NONE = 0x0000, + }; + + /* DrHW: Uniquely identifies the hardware interface to a board (or at +@@ -107,27 +110,48 @@ enum nubus_drsw { + /* Add known DrHW values here */ + enum nubus_drhw { + /* NUBUS_CAT_DISPLAY */ +- NUBUS_DRHW_APPLE_TFB = 0x0001, /* Toby frame buffer card */ +- NUBUS_DRHW_APPLE_HRVC = 0x0013, /* Mac II High Res Video card */ +- NUBUS_DRHW_APPLE_RBV1 = 0x0018, /* IIci RBV video */ +- NUBUS_DRHW_APPLE_MDC = 0x0019, /* Macintosh Display Card */ +- NUBUS_DRHW_APPLE_SONORA = 0x0022, /* Sonora built-in video */ +- NUBUS_DRHW_APPLE_JET = 0x0029, /* Jet framebuffer (DuoDock) */ ++ NUBUS_DRHW_APPLE_TFB = 0x0001, /* Toby frame buffer card */ ++ NUBUS_DRHW_APPLE_WVC = 0x0006, /* Apple Workstation Video Card */ ++ NUBUS_DRHW_SIGMA_CLRMAX = 0x0007, /* Sigma Design ColorMax */ ++ NUBUS_DRHW_APPLE_SE30 = 0x0009, /* Apple SE/30 video */ ++ NUBUS_DRHW_APPLE_HRVC = 0x0013, /* Mac II High-Res Video Card */ ++ NUBUS_DRHW_APPLE_PVC = 0x0017, /* Mac II Portrait Video Card */ ++ NUBUS_DRHW_APPLE_RBV1 = 0x0018, /* IIci RBV video */ ++ NUBUS_DRHW_APPLE_MDC = 0x0019, /* Macintosh Display Card */ ++ NUBUS_DRHW_APPLE_SONORA = 0x0022, /* Sonora built-in video */ ++ NUBUS_DRHW_APPLE_24AC = 0x002b, /* Mac 24AC Video Card */ + NUBUS_DRHW_APPLE_VALKYRIE = 0x002e, +- NUBUS_DRHW_THUNDER24 = 0x02cb, /* SuperMac Thunder/24 */ ++ NUBUS_DRHW_APPLE_JET = 0x0029, /* Jet framebuffer (DuoDock) */ ++ NUBUS_DRHW_SMAC_GFX = 0x0105, /* SuperMac GFX */ ++ NUBUS_DRHW_RASTER_CB264 = 0x013B, /* RasterOps ColorBoard 264 */ ++ NUBUS_DRHW_MICRON_XCEED = 0x0146, /* Micron Exceed color */ ++ NUBUS_DRHW_RDIUS_GSC = 0x0153, /* Radius GS/C */ ++ NUBUS_DRHW_SMAC_SPEC8 = 0x017B, /* SuperMac Spectrum/8 */ ++ NUBUS_DRHW_SMAC_SPEC24 = 0x017C, /* SuperMac Spectrum/24 */ ++ NUBUS_DRHW_RASTER_CB364 = 0x026F, /* RasterOps ColorBoard 364 */ ++ NUBUS_DRHW_RDIUS_DCGX = 0x027C, /* Radius DirectColor/GX */ ++ NUBUS_DRHW_RDIUS_PC8 = 0x0291, /* Radius PrecisionColor 8 */ ++ NUBUS_DRHW_LAPIS_PCS8 = 0x0292, /* Lapis ProColorServer 8 */ ++ NUBUS_DRHW_RASTER_24LXI = 0x02A0, /* RasterOps 8/24 XLi */ ++ NUBUS_DRHW_RASTER_PBPGT = 0x02A5, /* RasterOps PaintBoard Prism GT */ ++ NUBUS_DRHW_EMACH_FSX = 0x02AE, /* E-Machines Futura SX */ ++ NUBUS_DRHW_SMAC_THUND24 = 0x02CB, /* SuperMac Thunder/24 */ ++ NUBUS_DRHW_RDIUS_PC24XP = 0x0406, /* Radius PrecisionColor 24Xp */ ++ NUBUS_DRHW_RDIUS_PC24X = 0x040A, /* Radius PrecisionColor 24X */ ++ NUBUS_DRHW_RDIUS_PC8XJ = 0x040B, /* Radius PrecisionColor 8XJ */ + + /* NUBUS_CAT_NETWORK */ +- NUBUS_DRHW_INTERLAN = 0x0100, +- NUBUS_DRHW_SMC9194 = 0x0101, +- NUBUS_DRHW_KINETICS = 0x0106, +- NUBUS_DRHW_CABLETRON = 0x0109, +- NUBUS_DRHW_ASANTE_LC = 0x010f, +- NUBUS_DRHW_SONIC = 0x0110, +- NUBUS_DRHW_SONIC_NB = 0x0118, +- NUBUS_DRHW_SONIC_LC = 0x0119, +- +- /* NUBUS_CAT_COMMUNICATIONS */ +- NUBUS_DRHW_DOVEFAX = 0x0100, ++ NUBUS_DRHW_INTERLAN = 0x0100, ++ NUBUS_DRHW_SMC9194 = 0x0101, ++ NUBUS_DRHW_KINETICS = 0x0106, ++ NUBUS_DRHW_CABLETRON = 0x0109, ++ NUBUS_DRHW_ASANTE_LC = 0x010f, ++ NUBUS_DRHW_SONIC = 0x0110, ++ NUBUS_DRHW_TECHWORKS = 0x0112, ++ NUBUS_DRHW_APPLE_SONIC_NB = 0x0118, ++ NUBUS_DRHW_APPLE_SONIC_LC = 0x0119, ++ NUBUS_DRHW_FOCUS = 0x011c, ++ NUBUS_DRHW_SONNET = 0x011d, + }; + + /* Resource IDs: These are the identifiers for the various weird and +@@ -153,17 +177,17 @@ enum nubus_res_id { + + /* Category-specific resources. */ + enum nubus_board_res_id { +- NUBUS_RESID_BOARDID = 0x0020, ++ NUBUS_RESID_BOARDID = 0x0020, + NUBUS_RESID_PRAMINITDATA = 0x0021, +- NUBUS_RESID_PRIMARYINIT = 0x0022, ++ NUBUS_RESID_PRIMARYINIT = 0x0022, + NUBUS_RESID_TIMEOUTCONST = 0x0023, +- NUBUS_RESID_VENDORINFO = 0x0024, +- NUBUS_RESID_BOARDFLAGS = 0x0025, +- NUBUS_RESID_SECONDINIT = 0x0026, ++ NUBUS_RESID_VENDORINFO = 0x0024, ++ NUBUS_RESID_BOARDFLAGS = 0x0025, ++ NUBUS_RESID_SECONDINIT = 0x0026, + + /* Not sure why Apple put these next two in here */ +- NUBUS_RESID_VIDNAMES = 0x0041, +- NUBUS_RESID_VIDMODES = 0x007e ++ NUBUS_RESID_VIDNAMES = 0x0041, ++ NUBUS_RESID_VIDMODES = 0x007e + }; + + /* Fields within the vendor info directory */ +@@ -185,13 +209,13 @@ enum nubus_cpu_res_id { + }; + + enum nubus_display_res_id { +- NUBUS_RESID_GAMMADIR = 0x0040, +- NUBUS_RESID_FIRSTMODE = 0x0080, +- NUBUS_RESID_SECONDMODE = 0x0081, +- NUBUS_RESID_THIRDMODE = 0x0082, +- NUBUS_RESID_FOURTHMODE = 0x0083, +- NUBUS_RESID_FIFTHMODE = 0x0084, +- NUBUS_RESID_SIXTHMODE = 0x0085 ++ NUBUS_RESID_GAMMADIR = 0x0040, ++ NUBUS_RESID_FIRSTMODE = 0x0080, ++ NUBUS_RESID_SECONDMODE = 0x0081, ++ NUBUS_RESID_THIRDMODE = 0x0082, ++ NUBUS_RESID_FOURTHMODE = 0x0083, ++ NUBUS_RESID_FIFTHMODE = 0x0084, ++ NUBUS_RESID_SIXTHMODE = 0x0085 + }; + + struct nubus_dir +@@ -214,7 +238,7 @@ struct nubus_board { + struct nubus_board* next; + struct nubus_dev* first_dev; + +- /* Only 9-E actually exist, though 0-8 are also theoretically ++ /* Only 9-E actually exist, though 0-8 are also theoretically + possible, and 0 is a special case which represents the + motherboard and onboard peripherals (Ethernet, video) */ + int slot; diff --git a/debian/patches/bugfix/m68k/mac68k-patch_B-mac68k_cvs_DP8390_update.diff b/debian/patches/bugfix/m68k/mac68k-patch_B-mac68k_cvs_DP8390_update.diff new file mode 100644 index 000000000000..3ee8e2bd4e56 --- /dev/null +++ b/debian/patches/bugfix/m68k/mac68k-patch_B-mac68k_cvs_DP8390_update.diff @@ -0,0 +1,398 @@ +Subject: [PATCH 4/13] m68k: Mac DP8390 update +Cc: Jeff Garzik <jgarzik@pobox.com>, netdev@vger.kernel.org + +From: Finn Thain <fthain@telegraphics.com.au> + +Fix the support for C/NET nubus ethernet cards etc. Sync up the DP8390 driver +with the latest code in the mac68k repo. + +Signed-off-by: Finn Thain <fthain@telegraphics.com.au> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + drivers/net/mac8390.c | 245 +++++++++++++++++++++++++++++++++++--------------- + 1 file changed, 175 insertions(+), 70 deletions(-) + +--- linux-m68k-2.6.21.orig/drivers/net/mac8390.c ++++ linux-m68k-2.6.21/drivers/net/mac8390.c +@@ -14,6 +14,8 @@ + /* 2001-05-15: support for Cabletron ported from old daynaport driver + * and fixed access to Sonic Sys card which masquerades as a Farallon + * by rayk@knightsmanor.org */ ++/* 2002-12-30: Try to support more cards, some clues from NetBSD driver */ ++/* 2003-12-26: Make sure Asante cards always work. */ + + #include <linux/module.h> + #include <linux/kernel.h> +@@ -61,25 +63,21 @@ static char version[] = + #define DAYNA_8390_BASE 0x80000 + #define DAYNA_8390_MEM 0x00000 + +-#define KINETICS_8390_BASE 0x80000 +-#define KINETICS_8390_MEM 0x00000 +- + #define CABLETRON_8390_BASE 0x90000 + #define CABLETRON_8390_MEM 0x00000 + ++#define INTERLAN_8390_BASE 0xE0000 ++#define INTERLAN_8390_MEM 0xD0000 ++ + enum mac8390_type { + MAC8390_NONE = -1, + MAC8390_APPLE, + MAC8390_ASANTE, +- MAC8390_FARALLON, /* Apple, Asante, and Farallon are all compatible */ ++ MAC8390_FARALLON, + MAC8390_CABLETRON, + MAC8390_DAYNA, + MAC8390_INTERLAN, + MAC8390_KINETICS, +- MAC8390_FOCUS, +- MAC8390_SONICSYS, +- MAC8390_DAYNA2, +- MAC8390_DAYNA3, + }; + + static const char * cardname[] = { +@@ -90,10 +88,6 @@ static const char * cardname[] = { + "dayna", + "interlan", + "kinetics", +- "focus", +- "sonic systems", +- "dayna2", +- "dayna_lc", + }; + + static int word16[] = { +@@ -104,10 +98,6 @@ static int word16[] = { + 0, /* dayna */ + 1, /* interlan */ + 0, /* kinetics */ +- 1, /* focus (??) */ +- 1, /* sonic systems */ +- 1, /* dayna2 */ +- 1, /* dayna-lc */ + }; + + /* on which cards do we use NuBus resources? */ +@@ -119,10 +109,12 @@ static int useresources[] = { + 0, /* dayna */ + 0, /* interlan */ + 0, /* kinetics */ +- 0, /* focus (??) */ +- 1, /* sonic systems */ +- 1, /* dayna2 */ +- 1, /* dayna-lc */ ++}; ++ ++enum mac8390_access { ++ ACCESS_UNKNOWN = 0, ++ ACCESS_32, ++ ACCESS_16, + }; + + extern enum mac8390_type mac8390_ident(struct nubus_dev * dev); +@@ -134,8 +126,9 @@ static int mac8390_initdev(struct net_de + static int mac8390_open(struct net_device * dev); + static int mac8390_close(struct net_device * dev); + static void mac8390_no_reset(struct net_device *dev); ++static void interlan_reset(struct net_device *dev); + +-/* Sane (32-bit chunk memory read/write) - Apple/Asante/Farallon do this*/ ++/* Sane (32-bit chunk memory read/write) - Some Farallon and Apple do this*/ + static void sane_get_8390_hdr(struct net_device *dev, + struct e8390_pkt_hdr *hdr, int ring_page); + static void sane_block_input(struct net_device * dev, int count, +@@ -172,23 +165,93 @@ static void word_memcpy_fromcard(void *t + + enum mac8390_type __init mac8390_ident(struct nubus_dev * dev) + { +- if (dev->dr_sw == NUBUS_DRSW_ASANTE) +- return MAC8390_ASANTE; +- if (dev->dr_sw == NUBUS_DRSW_FARALLON) +- return MAC8390_FARALLON; +- if (dev->dr_sw == NUBUS_DRSW_KINETICS) +- return MAC8390_KINETICS; +- if (dev->dr_sw == NUBUS_DRSW_DAYNA) +- return MAC8390_DAYNA; +- if (dev->dr_sw == NUBUS_DRSW_DAYNA2) +- return MAC8390_DAYNA2; +- if (dev->dr_sw == NUBUS_DRSW_DAYNA_LC) +- return MAC8390_DAYNA3; +- if (dev->dr_hw == NUBUS_DRHW_CABLETRON) +- return MAC8390_CABLETRON; ++ switch (dev->dr_sw) { ++ case NUBUS_DRSW_3COM: ++ switch (dev->dr_hw) { ++ case NUBUS_DRHW_APPLE_SONIC_NB: ++ case NUBUS_DRHW_APPLE_SONIC_LC: ++ case NUBUS_DRHW_SONNET: ++ return MAC8390_NONE; ++ break; ++ default: ++ return MAC8390_APPLE; ++ break; ++ } ++ break; ++ ++ case NUBUS_DRSW_APPLE: ++ switch (dev->dr_hw) { ++ case NUBUS_DRHW_ASANTE_LC: ++ return MAC8390_NONE; ++ break; ++ case NUBUS_DRHW_CABLETRON: ++ return MAC8390_CABLETRON; ++ break; ++ default: ++ return MAC8390_APPLE; ++ break; ++ } ++ break; ++ ++ case NUBUS_DRSW_ASANTE: ++ return MAC8390_ASANTE; ++ break; ++ ++ case NUBUS_DRSW_TECHWORKS: ++ case NUBUS_DRSW_DAYNA2: ++ case NUBUS_DRSW_DAYNA_LC: ++ if (dev->dr_hw == NUBUS_DRHW_CABLETRON) ++ return MAC8390_CABLETRON; ++ else ++ return MAC8390_APPLE; ++ break; ++ ++ case NUBUS_DRSW_FARALLON: ++ return MAC8390_FARALLON; ++ break; ++ ++ case NUBUS_DRSW_KINETICS: ++ switch (dev->dr_hw) { ++ case NUBUS_DRHW_INTERLAN: ++ return MAC8390_INTERLAN; ++ break; ++ default: ++ return MAC8390_KINETICS; ++ break; ++ } ++ break; ++ ++ case NUBUS_DRSW_DAYNA: ++ // These correspond to Dayna Sonic cards ++ // which use the macsonic driver ++ if (dev->dr_hw == NUBUS_DRHW_SMC9194 || ++ dev->dr_hw == NUBUS_DRHW_INTERLAN ) ++ return MAC8390_NONE; ++ else ++ return MAC8390_DAYNA; ++ break; ++ } + return MAC8390_NONE; + } + ++enum mac8390_access __init mac8390_testio(volatile unsigned long membase) ++{ ++ unsigned long outdata = 0xA5A0B5B0; ++ unsigned long indata = 0x00000000; ++ /* Try writing 32 bits */ ++ memcpy((char *)membase, (char *)&outdata, 4); ++ /* Now compare them */ ++ if (memcmp((char *)&outdata, (char *)membase, 4) == 0) ++ return ACCESS_32; ++ /* Write 16 bit output */ ++ word_memcpy_tocard((char *)membase, (char *)&outdata, 4); ++ /* Now read it back */ ++ word_memcpy_fromcard((char *)&indata, (char *)membase, 4); ++ if (outdata == indata) ++ return ACCESS_16; ++ return ACCESS_UNKNOWN; ++} ++ + int __init mac8390_memsize(unsigned long membase) + { + unsigned long flags; +@@ -287,14 +350,6 @@ struct net_device * __init mac8390_probe + continue; + } else { + nubus_get_rsrc_mem(dev->dev_addr, &ent, 6); +- /* Some Sonic Sys cards masquerade as Farallon */ +- if (cardtype == MAC8390_FARALLON && +- dev->dev_addr[0] == 0x0 && +- dev->dev_addr[1] == 0x40 && +- dev->dev_addr[2] == 0x10) { +- /* This is really Sonic Sys card */ +- cardtype = MAC8390_SONICSYS; +- } + } + + if (useresources[cardtype] == 1) { +@@ -334,6 +389,17 @@ struct net_device * __init mac8390_probe + dev->mem_start + + mac8390_memsize(dev->mem_start); + break; ++ case MAC8390_INTERLAN: ++ dev->base_addr = ++ (int)(ndev->board->slot_addr + ++ INTERLAN_8390_BASE); ++ dev->mem_start = ++ (int)(ndev->board->slot_addr + ++ INTERLAN_8390_MEM); ++ dev->mem_end = ++ dev->mem_start + ++ mac8390_memsize(dev->mem_start); ++ break; + case MAC8390_CABLETRON: + dev->base_addr = + (int)(ndev->board->slot_addr + +@@ -356,8 +422,8 @@ struct net_device * __init mac8390_probe + + default: + printk(KERN_ERR "Card type %s is" +- " unsupported, sorry\n", +- cardname[cardtype]); ++ " unsupported, sorry\n", ++ ndev->board->name); + continue; + } + } +@@ -438,7 +504,7 @@ static int __init mac8390_initdev(struct + 24, 26, 28, 30 + }; + +- int access_bitmode; ++ int access_bitmode = 0; + + /* Now fill in our stuff */ + dev->open = &mac8390_open; +@@ -468,29 +534,47 @@ static int __init mac8390_initdev(struct + + /* Fill in model-specific information and functions */ + switch(type) { +- case MAC8390_SONICSYS: +- /* 16 bit card, register map is reversed */ +- ei_status.reset_8390 = &mac8390_no_reset; +- ei_status.block_input = &slow_sane_block_input; +- ei_status.block_output = &slow_sane_block_output; +- ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; +- ei_status.reg_offset = back4_offsets; +- access_bitmode = 0; +- break; + case MAC8390_FARALLON: + case MAC8390_APPLE: ++ switch(mac8390_testio(dev->mem_start)) { ++ case ACCESS_UNKNOWN: ++ printk("Don't know how to access card memory!\n"); ++ return -ENODEV; ++ break; ++ ++ case ACCESS_16: ++ /* 16 bit card, register map is reversed */ ++ ei_status.reset_8390 = &mac8390_no_reset; ++ ei_status.block_input = &slow_sane_block_input; ++ ei_status.block_output = &slow_sane_block_output; ++ ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; ++ ei_status.reg_offset = back4_offsets; ++ break; ++ ++ case ACCESS_32: ++ /* 32 bit card, register map is reversed */ ++ ei_status.reset_8390 = &mac8390_no_reset; ++ ei_status.block_input = &sane_block_input; ++ ei_status.block_output = &sane_block_output; ++ ei_status.get_8390_hdr = &sane_get_8390_hdr; ++ ei_status.reg_offset = back4_offsets; ++ access_bitmode = 1; ++ break; ++ } ++ break; ++ + case MAC8390_ASANTE: +- case MAC8390_DAYNA2: +- case MAC8390_DAYNA3: +- /* 32 bit card, register map is reversed */ +- /* sane */ ++ /* Some Asante cards pass the 32 bit test ++ * but overwrite system memory when run at 32 bit. ++ * so we run them all at 16 bit. ++ */ + ei_status.reset_8390 = &mac8390_no_reset; +- ei_status.block_input = &sane_block_input; +- ei_status.block_output = &sane_block_output; +- ei_status.get_8390_hdr = &sane_get_8390_hdr; ++ ei_status.block_input = &slow_sane_block_input; ++ ei_status.block_output = &slow_sane_block_output; ++ ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; + ei_status.reg_offset = back4_offsets; +- access_bitmode = 1; + break; ++ + case MAC8390_CABLETRON: + /* 16 bit card, register map is short forward */ + ei_status.reset_8390 = &mac8390_no_reset; +@@ -498,21 +582,30 @@ static int __init mac8390_initdev(struct + ei_status.block_output = &slow_sane_block_output; + ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; + ei_status.reg_offset = fwrd2_offsets; +- access_bitmode = 0; + break; ++ + case MAC8390_DAYNA: + case MAC8390_KINETICS: +- /* 16 bit memory */ ++ /* 16 bit memory, register map is forward */ + /* dayna and similar */ + ei_status.reset_8390 = &mac8390_no_reset; + ei_status.block_input = &dayna_block_input; + ei_status.block_output = &dayna_block_output; + ei_status.get_8390_hdr = &dayna_get_8390_hdr; + ei_status.reg_offset = fwrd4_offsets; +- access_bitmode = 0; + break; ++ ++ case MAC8390_INTERLAN: ++ /* 16 bit memory, register map is forward */ ++ ei_status.reset_8390 = &interlan_reset; ++ ei_status.block_input = &slow_sane_block_input; ++ ei_status.block_output = &slow_sane_block_output; ++ ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; ++ ei_status.reg_offset = fwrd4_offsets; ++ break; ++ + default: +- printk(KERN_ERR "Card type %s is unsupported, sorry\n", cardname[type]); ++ printk(KERN_ERR "Card type %s is unsupported, sorry\n", ndev->board->name); + return -ENODEV; + } + +@@ -530,9 +623,9 @@ static int __init mac8390_initdev(struct + printk(":"); + } + } +- printk(" IRQ %d, shared memory at %#lx-%#lx, %d-bit access.\n", +- dev->irq, dev->mem_start, dev->mem_end-1, +- access_bitmode?32:16); ++ printk(" IRQ %d, %d KB shared memory at %#lx, %d-bit access.\n", ++ dev->irq, (int)((dev->mem_end - dev->mem_start)/0x1000) * 4, ++ dev->mem_start, access_bitmode?32:16); + return 0; + } + +@@ -561,6 +654,18 @@ static void mac8390_no_reset(struct net_ + return; + } + ++static void interlan_reset(struct net_device *dev) ++{ ++ unsigned char *target=nubus_slot_addr(IRQ2SLOT(dev->irq)); ++ if (ei_debug > 1) ++ printk("Need to reset the NS8390 t=%lu...", jiffies); ++ ei_status.txing = 0; ++ target[0xC0000] = 0; ++ if (ei_debug > 1) ++ printk("reset complete\n"); ++ return; ++} ++ + /* dayna_memcpy_fromio/dayna_memcpy_toio */ + /* directly from daynaport.c by Alan Cox */ + static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from, int count) diff --git a/debian/patches/bugfix/m68k/mac68k-patch_d-via-alt-mapping.diff b/debian/patches/bugfix/m68k/mac68k-patch_d-via-alt-mapping.diff new file mode 100644 index 000000000000..78a098803a19 --- /dev/null +++ b/debian/patches/bugfix/m68k/mac68k-patch_d-via-alt-mapping.diff @@ -0,0 +1,30 @@ +Subject: [PATCH 2/13] m68k: Mac interrupt priorities + +From: Finn Thain <fthain@telegraphics.com.au> + +Add some more machines that support A/UX interrupt priorities. There are +probably others as well, but I've only tested these ones so far. + +Signed-off-by: Finn Thain <fthain@telegraphics.com.au> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + arch/m68k/mac/via.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- linux-m68k-2.6.21.orig/arch/m68k/mac/via.c ++++ linux-m68k-2.6.21/arch/m68k/mac/via.c +@@ -193,8 +193,14 @@ void __init via_init(void) + /* that the IIfx emulates this alternate mapping using the OSS. */ + + switch(macintosh_config->ident) { ++ case MAC_MODEL_P475: ++ case MAC_MODEL_P475F: ++ case MAC_MODEL_P575: ++ case MAC_MODEL_Q605: ++ case MAC_MODEL_Q605_ACC: + case MAC_MODEL_C610: + case MAC_MODEL_Q610: ++ case MAC_MODEL_Q630: + case MAC_MODEL_C650: + case MAC_MODEL_Q650: + case MAC_MODEL_Q700: diff --git a/debian/patches/bugfix/m68k/mac68k-remove-unused-adb-header.diff b/debian/patches/bugfix/m68k/mac68k-remove-unused-adb-header.diff new file mode 100644 index 000000000000..b6cc37c12c08 --- /dev/null +++ b/debian/patches/bugfix/m68k/mac68k-remove-unused-adb-header.diff @@ -0,0 +1,92 @@ +Subject: [PATCH 1/13] m68k: remove unused adb.h + +From: Finn Thain <fthain@telegraphics.com.au> + +The asm-m68k/adb.h header is unused. Some definitions are wrong and the rest +are duplicated in linux/adb.h. Remove it. + +Signed-off-by: Finn Thain <fthain@telegraphics.com.au> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> + +--- + include/asm-m68k/adb.h | 75 ------------------------------------------------- + 1 file changed, 75 deletions(-) + +--- linux-m68k-2.6.21.orig/include/asm-m68k/adb.h ++++ /dev/null +@@ -1,75 +0,0 @@ +-/* +- * Definitions for talking to ADB and CUDA. The CUDA is a microcontroller +- * which controls the ADB, system power, RTC, and various other things on +- * later Macintoshes +- * +- * Copyright (C) 1996 Paul Mackerras. +- */ +- +-/* First byte sent to or received from CUDA */ +-#define ADB_PACKET 0 +-#define CUDA_PACKET 1 +-#define ERROR_PACKET 2 +-#define TIMER_PACKET 3 +-#define POWER_PACKET 4 +-#define MACIIC_PACKET 5 +- +-/* ADB commands (2nd byte) */ +-#define ADB_BUSRESET 0 +-#define ADB_FLUSH(id) (1 + ((id) << 4)) +-#define ADB_WRITEREG(id, reg) (8 + (reg) + ((id) << 4)) +-#define ADB_READREG(id, reg) (0xc + (reg) + ((id) << 4)) +- +-/* ADB default device IDs (upper 4 bits of 2nd byte) */ +-#define ADB_DONGLE 1 /* "software execution control" devices */ +-#define ADB_KEYBOARD 2 +-#define ADB_MOUSE 3 +-#define ADB_TABLET 4 +-#define ADB_MODEM 5 +-#define ADB_MISC 7 /* maybe a monitor */ +- +-/* CUDA commands (2nd byte) */ +-#define CUDA_WARM_START 0 +-#define CUDA_AUTOPOLL 1 +-#define CUDA_GET_6805_ADDR 2 +-#define CUDA_GET_TIME 3 +-#define CUDA_GET_PRAM 7 +-#define CUDA_SET_6805_ADDR 8 +-#define CUDA_SET_TIME 9 +-#define CUDA_POWERDOWN 0xa +-#define CUDA_POWERUP_TIME 0xb +-#define CUDA_SET_PRAM 0xc +-#define CUDA_MS_RESET 0xd +-#define CUDA_SEND_DFAC 0xe +-#define CUDA_RESET_SYSTEM 0x11 +-#define CUDA_SET_IPL 0x12 +-#define CUDA_SET_AUTO_RATE 0x14 +-#define CUDA_GET_AUTO_RATE 0x16 +-#define CUDA_SET_DEVICE_LIST 0x19 +-#define CUDA_GET_DEVICE_LIST 0x1a +-#define CUDA_GET_SET_IIC 0x22 +- +-#ifdef __KERNEL__ +- +-struct adb_request { +- unsigned char data[16]; +- int nbytes; +- unsigned char reply[16]; +- int reply_len; +- unsigned char reply_expected; +- unsigned char sent; +- unsigned char got_reply; +- void (*done)(struct adb_request *); +- void *arg; +- struct adb_request *next; +-}; +- +-void via_adb_init(void); +-int adb_request(struct adb_request *req, +- void (*done)(struct adb_request *), int nbytes, ...); +-int adb_send_request(struct adb_request *req); +-void adb_poll(void); +-int adb_register(int default_id, +- void (*handler)(unsigned char *, int, struct pt_regs *)); +- +-#endif /* __KERNEL */ diff --git a/debian/patches/bugfix/m68k/mac68k-revert-remaining-irq-damage.diff b/debian/patches/bugfix/m68k/mac68k-revert-remaining-irq-damage.diff new file mode 100644 index 000000000000..bfc12bad9044 --- /dev/null +++ b/debian/patches/bugfix/m68k/mac68k-revert-remaining-irq-damage.diff @@ -0,0 +1,80 @@ +Subject: [PATCH 5/13] m68k: reverse Mac IRQ damage + +From: Finn Thain <fthain@telegraphics.com.au> + +Reverse the last of a monumental brown-paper-bag commit that went into the 2.3 +kernel. + +Signed-off-by: Finn Thain <fthain@telegraphics.com.au> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + arch/m68k/mac/baboon.c | 2 +- + arch/m68k/mac/oss.c | 6 +++--- + arch/m68k/mac/psc.c | 2 +- + arch/m68k/mac/via.c | 2 +- + 4 files changed, 6 insertions(+), 6 deletions(-) + +--- linux-m68k-2.6.21.orig/arch/m68k/mac/baboon.c ++++ linux-m68k-2.6.21/arch/m68k/mac/baboon.c +@@ -81,9 +81,9 @@ irqreturn_t baboon_irq(int irq, void *de + for (i = 0, irq_bit = 1 ; i < 3 ; i++, irq_bit <<= 1) { + if (events & irq_bit/* & baboon_active*/) { + baboon_active &= ~irq_bit; ++ baboon->mb_ifr &= ~irq_bit; + m68k_handle_int(IRQ_BABOON_0 + i); + baboon_active |= irq_bit; +- baboon->mb_ifr &= ~irq_bit; + } + } + #if 0 +--- linux-m68k-2.6.21.orig/arch/m68k/mac/oss.c ++++ linux-m68k-2.6.21/arch/m68k/mac/oss.c +@@ -109,12 +109,12 @@ irqreturn_t oss_irq(int irq, void *dev_i + /* FIXME: how do you clear a pending IRQ? */ + + if (events & OSS_IP_SOUND) { +- /* FIXME: call sound handler */ + oss->irq_pending &= ~OSS_IP_SOUND; ++ /* FIXME: call sound handler */ + } else if (events & OSS_IP_SCSI) { + oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED; +- m68k_handle_int(IRQ_MAC_SCSI); + oss->irq_pending &= ~OSS_IP_SCSI; ++ m68k_handle_int(IRQ_MAC_SCSI); + oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI; + } else { + /* FIXME: error check here? */ +@@ -146,8 +146,8 @@ irqreturn_t oss_nubus_irq(int irq, void + for (i = 0, irq_bit = 1 ; i < 6 ; i++, irq_bit <<= 1) { + if (events & irq_bit) { + oss->irq_level[i] = OSS_IRQLEV_DISABLED; +- m68k_handle_int(NUBUS_SOURCE_BASE + i); + oss->irq_pending &= ~irq_bit; ++ m68k_handle_int(NUBUS_SOURCE_BASE + i); + oss->irq_level[i] = OSS_IRQLEV_NUBUS; + } + } +--- linux-m68k-2.6.21.orig/arch/m68k/mac/psc.c ++++ linux-m68k-2.6.21/arch/m68k/mac/psc.c +@@ -149,8 +149,8 @@ irqreturn_t psc_irq(int irq, void *dev_i + for (i = 0, irq_bit = 1 ; i < 4 ; i++, irq_bit <<= 1) { + if (events & irq_bit) { + psc_write_byte(pIER, irq_bit); +- m68k_handle_int(base_irq + i); + psc_write_byte(pIFR, irq_bit); ++ m68k_handle_int(base_irq + i); + psc_write_byte(pIER, irq_bit | 0x80); + } + } +--- linux-m68k-2.6.21.orig/arch/m68k/mac/via.c ++++ linux-m68k-2.6.21/arch/m68k/mac/via.c +@@ -430,8 +430,8 @@ irqreturn_t via1_irq(int irq, void *dev_ + for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) + if (events & irq_bit) { + via1[vIER] = irq_bit; +- m68k_handle_int(VIA1_SOURCE_BASE + i); + via1[vIFR] = irq_bit; ++ m68k_handle_int(VIA1_SOURCE_BASE + i); + via1[vIER] = irq_bit | 0x80; + } + diff --git a/debian/patches/bugfix/m68k/mac68k-sonic-fixes.diff b/debian/patches/bugfix/m68k/mac68k-sonic-fixes.diff new file mode 100644 index 000000000000..580678611ac6 --- /dev/null +++ b/debian/patches/bugfix/m68k/mac68k-sonic-fixes.diff @@ -0,0 +1,106 @@ +Subject: [PATCH 12/13] SONIC: small fix and cleanup +Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>, + Jeff Garzik <jgarzik@pobox.com>, netdev@vger.kernel.org, + linux-mips@linux-mips.org + +From: Finn Thain <fthain@telegraphics.com.au> + +Fix a potential problem in the timeout handling: don't free the DMA buffers +before resetting the chip. + +Also a trivial cleanup. Bring macsonic and jazzsonic into sync. + +Signed-off-by: Finn Thain <fthain@telegraphics.com.au> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + drivers/net/jazzsonic.c | 4 ++-- + drivers/net/macsonic.c | 17 ++++++++--------- + drivers/net/sonic.c | 7 ++++++- + 3 files changed, 16 insertions(+), 12 deletions(-) + +--- linux-m68k-2.6.21.orig/drivers/net/jazzsonic.c ++++ linux-m68k-2.6.21/drivers/net/jazzsonic.c +@@ -269,11 +269,11 @@ static int __devexit jazz_sonic_device_r + struct net_device *dev = platform_get_drvdata(pdev); + struct sonic_local* lp = netdev_priv(dev); + +- unregister_netdev (dev); ++ unregister_netdev(dev); + dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), + lp->descriptors, lp->descriptors_laddr); + release_region (dev->base_addr, SONIC_MEM_SIZE); +- free_netdev (dev); ++ free_netdev(dev); + + return 0; + } +--- linux-m68k-2.6.21.orig/drivers/net/macsonic.c ++++ linux-m68k-2.6.21/drivers/net/macsonic.c +@@ -522,7 +522,7 @@ int __init mac_nubus_sonic_probe(struct + return macsonic_init(dev); + } + +-static int __init mac_sonic_probe(struct platform_device *device) ++static int __init mac_sonic_probe(struct platform_device *pdev) + { + struct net_device *dev; + struct sonic_local *lp; +@@ -534,8 +534,8 @@ static int __init mac_sonic_probe(struct + return -ENOMEM; + + lp = netdev_priv(dev); +- lp->device = &device->dev; +- SET_NETDEV_DEV(dev, &device->dev); ++ lp->device = &pdev->dev; ++ SET_NETDEV_DEV(dev, &pdev->dev); + SET_MODULE_OWNER(dev); + + /* This will catch fatal stuff like -ENOMEM as well as success */ +@@ -576,15 +576,15 @@ MODULE_PARM_DESC(sonic_debug, "macsonic + + #include "sonic.c" + +-static int __devexit mac_sonic_device_remove (struct platform_device *device) ++static int __devexit mac_sonic_device_remove (struct platform_device *pdev) + { +- struct net_device *dev = platform_get_drvdata(device); ++ struct net_device *dev = platform_get_drvdata(pdev); + struct sonic_local* lp = netdev_priv(dev); + +- unregister_netdev (dev); ++ unregister_netdev(dev); + dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), + lp->descriptors, lp->descriptors_laddr); +- free_netdev (dev); ++ free_netdev(dev); + + return 0; + } +@@ -607,9 +607,8 @@ static int __init mac_sonic_init_module( + } + + mac_sonic_device = platform_device_alloc(mac_sonic_string, 0); +- if (!mac_sonic_device) { ++ if (!mac_sonic_device) + goto out_unregister; +- } + + if (platform_device_add(mac_sonic_device)) { + platform_device_put(mac_sonic_device); +--- linux-m68k-2.6.21.orig/drivers/net/sonic.c ++++ linux-m68k-2.6.21/drivers/net/sonic.c +@@ -179,8 +179,13 @@ static void sonic_tx_timeout(struct net_ + { + struct sonic_local *lp = netdev_priv(dev); + int i; +- /* Stop the interrupts for this */ ++ /* ++ * put the Sonic into software-reset mode and ++ * disable all interrupts before releasing DMA buffers ++ */ + SONIC_WRITE(SONIC_IMR, 0); ++ SONIC_WRITE(SONIC_ISR, 0x7fff); ++ SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); + /* We could resend the original skbs. Easier to re-initialise. */ + for (i = 0; i < SONIC_NUM_TDS; i++) { + if(lp->tx_laddr[i]) { diff --git a/debian/patches/bugfix/m68k/nfeth-virt_to_phys.diff b/debian/patches/bugfix/m68k/nfeth-virt_to_phys.diff new file mode 100644 index 000000000000..c89e6df799a5 --- /dev/null +++ b/debian/patches/bugfix/m68k/nfeth-virt_to_phys.diff @@ -0,0 +1,19 @@ +Subject: [PATCH] m68k: ARAnyM virtual Ethernet missing include + +Add missing #include <asm/virtconvert.h> (needed for virt_to_phys()) + +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + arch/m68k/emu/nfeth.c | 1 + + 1 file changed, 1 insertion(+) + +--- linux-m68k-2.6.21.orig/arch/m68k/emu/nfeth.c ++++ linux-m68k-2.6.21/arch/m68k/emu/nfeth.c +@@ -14,6 +14,7 @@ + #include <linux/module.h> + #include <net/ieee80211.h> + #include <asm/natfeat.h> ++#include <asm/virtconvert.h> + + enum { + GET_VERSION = 0, /* no parameters, return NFAPI_VERSION in d0 */ diff --git a/debian/patches/bugfix/m68k/pmu_queue_request-conflict.diff b/debian/patches/bugfix/m68k/pmu_queue_request-conflict.diff new file mode 100644 index 000000000000..6a3ee51f680e --- /dev/null +++ b/debian/patches/bugfix/m68k/pmu_queue_request-conflict.diff @@ -0,0 +1,32 @@ +Subject: m68k: pmu_queue_request() declaration conflict + +From: Finn Thain <fthain@telegraphics.com.au> + +Fixes a "static qualifier follows non-static qualifier" error from gcc 4. + +Signed-off-by: Finn Thain <fthain@telegraphics.com.au> +Signed-off-by: Roman Zippel <zippel@linux-m68k.org> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + drivers/macintosh/via-pmu68k.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- linux-m68k-2.6.21.orig/drivers/macintosh/via-pmu68k.c ++++ linux-m68k-2.6.21/drivers/macintosh/via-pmu68k.c +@@ -111,7 +111,6 @@ static int pmu_send_request(struct adb_r + static int pmu_autopoll(int devs); + void pmu_poll(void); + static int pmu_reset_bus(void); +-static int pmu_queue_request(struct adb_request *req); + + static void pmu_start(void); + static void send_byte(int x); +@@ -475,7 +474,7 @@ pmu_request(struct adb_request *req, voi + return pmu_queue_request(req); + } + +-static int ++int + pmu_queue_request(struct adb_request *req) + { + unsigned long flags; diff --git a/debian/patches/bugfix/m68k/sun3-3x-cg3-bw2.diff b/debian/patches/bugfix/m68k/sun3-3x-cg3-bw2.diff new file mode 100644 index 000000000000..a9bff3ae83cf --- /dev/null +++ b/debian/patches/bugfix/m68k/sun3-3x-cg3-bw2.diff @@ -0,0 +1,887 @@ +From: David Miller <davem@davemloft.net> +To: sammy@sammy.net +Cc: linux-m68k@vger.kernel.org +Subject: Re: [PATCH] cg3/bw2: add Sun3/Sun3x support + +From: Sam Creasey <sammy@sammy.net> +Date: Tue, 3 Apr 2007 10:32:35 -0400 + +> This patch (re) introduces support for the CG3 driver on Sun3, and for +> BW2 on Sun3x. It applies cleanly to both the m68k CVS tree and the +> vanilla tree. +> +> Signed-off-by: Sam Creasey <sammy@sammy.net> + +If you guys want to share driver code with the Sparc port, please do +it properly. + +I am not applying a pile of ifdef's that basically duplicate half of +the existing driver. + +What you can do instead is to build a fake openprom device tree and +register those devices with the generic device subsystem, and then the +driver will mostly just work out of the box. It should be easy to +duplicate the arch/sparc64/kernel/prom.c and of_device.c code you +use as well as the driver interfaces in include/asm-sparc64/prom.h +and of_device.h + +This way you don't need to shit all over the drivers adding hardcoded +register addresses and ad-hoc probing code. For special behaviors, +you can add openprom node properties that the driver can test for at +run time to guide behavior, again instead of ifdefs. + +--------------------------------------------------------------------------- + +From sammy@sammy.net Tue Apr 3 16:47:32 2007 +Date: Tue, 3 Apr 2007 10:32:35 -0400 +From: Sam Creasey <sammy@sammy.net> +To: linux-m68k@vger.kernel.org, David S. Miller <davem@davemloft.net> +Subject: [PATCH] cg3/bw2: add Sun3/Sun3x support + +This patch (re) introduces support for the CG3 driver on Sun3, and for +BW2 on Sun3x. It applies cleanly to both the m68k CVS tree and the +vanilla tree. + +Signed-off-by: Sam Creasey <sammy@sammy.net> + +--- + drivers/video/Kconfig | 14 ++ + drivers/video/Makefile | 1 + drivers/video/bw2.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++-- + drivers/video/cg3.c | 212 ++++++++++++++++++++++++++++++++++++++++++- + drivers/video/p4lib.c | 107 ++++++++++++++++++++++ + drivers/video/p4lib.h | 56 +++++++++++ + drivers/video/sbuslib.c | 13 ++ + 7 files changed, 616 insertions(+), 19 deletions(-) + +--- linux-m68k-2.6.21.orig/drivers/video/Kconfig ++++ linux-m68k-2.6.21/drivers/video/Kconfig +@@ -600,6 +600,16 @@ config FB_GBE_MEM + This is the amount of memory reserved for the framebuffer, + which can be any value between 1MB and 8MB. + ++config FB_SUN3 ++ bool "Sun3 framebuffer support" ++ depends on (FB = y) && (SUN3 || SUN3X) ++ help ++ Support framebuffer devices on Sun3/3x. Note that if you say yes ++ here, any framebuffer drivers you select MUST be installed in the ++ target system, or be disabled on the command line. (e.g. if you ++ don't have a bw2, include video=bw2fb:off. If you don't have ++ a cg3, include video=cg3fb:off.) ++ + config FB_SBUS + bool "SBUS and UPA framebuffers" + depends on (FB = y) && SPARC +@@ -608,7 +618,7 @@ config FB_SBUS + + config FB_BW2 + bool "BWtwo support" +- depends on (FB = y) && (SPARC && FB_SBUS) ++ depends on (FB = y) && ((SPARC && FB_SBUS) || (SUN3X && FB_SUN3)) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT +@@ -617,7 +627,7 @@ config FB_BW2 + + config FB_CG3 + bool "CGthree support" +- depends on (FB = y) && (SPARC && FB_SBUS) ++ depends on (FB = y) && ((SPARC && FB_SBUS) || (SUN3 && FB_SUN3)) + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT +--- linux-m68k-2.6.21.orig/drivers/video/Makefile ++++ linux-m68k-2.6.21/drivers/video/Makefile +@@ -106,6 +106,7 @@ obj-$(CONFIG_FB_VESA) += ves + obj-$(CONFIG_FB_IMAC) += imacfb.o + obj-$(CONFIG_FB_VGA16) += vga16fb.o vgastate.o + obj-$(CONFIG_FB_OF) += offb.o ++obj-$(CONFIG_FB_SUN3) += p4lib.o + + # the test framebuffer is last + obj-$(CONFIG_FB_VIRTUAL) += vfb.o +--- linux-m68k-2.6.21.orig/drivers/video/bw2.c ++++ linux-m68k-2.6.21/drivers/video/bw2.c +@@ -20,18 +20,29 @@ + + #include <asm/io.h> + #include <asm/oplib.h> ++#ifndef CONFIG_FB_SUN3 + #include <asm/prom.h> + #include <asm/of_device.h> ++#endif + #include <asm/fbio.h> + + #include "sbuslib.h" + ++#ifdef CONFIG_FB_SUN3 ++#ifdef CONFIG_SUN3 ++#include <asm/sun3mmu.h> ++#endif ++#include <asm/machines.h> ++#include <asm/idprom.h> ++#include <asm/sbus.h> ++#include "p4lib.h" ++#endif + /* + * Local functions. + */ +- ++#ifndef CONFIG_FB_SUN3 + static int bw2_blank(int, struct fb_info *); +- ++#endif + static int bw2_mmap(struct fb_info *, struct vm_area_struct *); + static int bw2_ioctl(struct fb_info *, unsigned int, unsigned long); + +@@ -41,7 +52,11 @@ static int bw2_ioctl(struct fb_info *, u + + static struct fb_ops bw2_ops = { + .owner = THIS_MODULE, ++#ifdef CONFIG_FB_SUN3 ++ .fb_blank = NULL, ++#else + .fb_blank = bw2_blank, ++#endif + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +@@ -53,7 +68,18 @@ static struct fb_ops bw2_ops = { + }; + + /* OBio addresses for the bwtwo registers */ ++#ifdef CONFIG_FB_SUN3 ++/* sun3 series */ ++#define BWTWO_OBMEM_ADDR 0x1f000000 ++#define BWTWO_OBMEM_ADDR_50 0x00100000 ++#define BWTWO_OBMEM_ADDR_P4 0x1f300000 ++#define BWTWO_OBMEM_ADDR_3X 0x50300000 ++/* is this true for 3/50? */ ++#define BWTWO_FB_OFFSET 0x100000 ++#define BWTWO_OBMEM_HIGHRES_60 0x1f1c0000 ++#else + #define BWTWO_REGISTER_OFFSET 0x400000 ++#endif + + struct bt_regs { + u32 addr; +@@ -108,8 +134,11 @@ struct bw2_regs { + + struct bw2_par { + spinlock_t lock; ++#ifdef CONFIG_FB_SUN3 ++ volatile u32 *regs; ++#else + struct bw2_regs __iomem *regs; +- ++#endif + u32 flags; + #define BW2_FLAG_BLANKED 0x00000001 + +@@ -118,6 +147,7 @@ struct bw2_par { + unsigned long fbsize; + }; + ++#ifndef CONFIG_FB_SUN3 + /** + * bw2_blank - Optional function. Blanks the display. + * @blank_mode: the blank mode we want. +@@ -156,6 +186,7 @@ bw2_blank(int blank, struct fb_info *inf + + return 0; + } ++#endif + + static struct sbus_mmap_map bw2_mmap_map[] = { + { +@@ -198,6 +229,17 @@ static void __devinit bw2_init_fix(struc + info->fix.accel = FB_ACCEL_SUN_BWTWO; + } + ++struct all_info { ++ struct fb_info info; ++ struct bw2_par par; ++}; ++/* CONFIG_FB_SUN3 has a different implementation for the remaining ++ functions, since: ++ 1) No OpenProm ++ 2) Fixed frequency ++ 3) No support for multiple BWtwo's */ ++#ifndef CONFIG_FB_SUN3 ++ + static u8 bw2regs_1600[] __devinitdata = { + 0x14, 0x8b, 0x15, 0x28, 0x16, 0x03, 0x17, 0x13, + 0x18, 0x7b, 0x19, 0x05, 0x1a, 0x34, 0x1b, 0x2e, +@@ -279,11 +321,6 @@ static void __devinit bw2_do_default_mod + } + } + +-struct all_info { +- struct fb_info info; +- struct bw2_par par; +-}; +- + static int __devinit bw2_init_one(struct of_device *op) + { + struct device_node *dp = op->node; +@@ -397,6 +434,185 @@ static void __exit bw2_exit(void) + return of_unregister_driver(&bw2_driver); + } + ++#else /* !CONFIG_FB_SUN3 */ ++ ++static struct all_info *bw2_all = NULL; ++ ++static void bw2_do_default_mode(struct bw2_par *par, struct fb_info *info, ++ int *linebytes) ++{ ++ int highres = 0; ++ ++ if(idprom->id_machtype == (SM_SUN3|SM_3_260)) ++ /* the 3/260 is allegedly always highres */ ++ highres = 1; ++ if(idprom->id_machtype == (SM_SUN3|SM_3_60)) { ++#ifdef CONFIG_SUN3 ++ /* we won't hit this unless running on a sun3 anyway */ ++ volatile u32 *reg; ++ u32 il ++ ++ reg = sun3_ioremap(BW2_OBMEM_HIGHRES_60, sizeof(u32), ++ SUN3_PAGE_TYPE_MEMORY); ++ i = *reg; ++ iounmap(reg); ++ if((i != -1) && (i& 0x80) == 0) ++ highres = 1; ++#endif ++ } ++ ++ if(highres) { ++ info->var.xres = info->var.xres_virtual = 1600; ++ info->var.yres = info->var.yres_virtual = 1280; ++ *linebytes = 1600 / 8; ++ } ++} ++ ++ ++static int __devinit bw2_init_one(unsigned long phys_addr) ++{ ++ struct all_info *all; ++ int linebytes, err, id; ++ all = kzalloc(sizeof(*all), GFP_KERNEL); ++ if (!all) ++ return -ENOMEM; ++ ++ spin_lock_init(&all->par.lock); ++ ++ all->par.physbase = phys_addr; ++ ++#ifdef CONFIG_SUN3 ++ all->par.regs = sun3_ioremap(phys_addr, sizeof(u32), ++ SUN3_PAGE_TYPE_MEMORY); ++#else ++ all->par.regs = ioremap_nocache(phys_addr, sizeof(u32)); ++#endif ++ /* look for the p4 register, or assume we're OBIO if it's not found */ ++ id = p4fb_get_id(all->par.regs); ++ printk("bwtwo: p4id %08x\n", id); ++ ++ /* mutable memory address, probably save to say we've got an onboard fb */ ++ if(id == -1) { ++ iounmap((void *)all->par.regs); ++ /* only currently supported on sun3. Perhaps someday sun4. */ ++ if((idprom->id_machtype & SM_ARCH_MASK) != SM_SUN3) { ++ kfree(all); ++ return -ENODEV; ++ } ++ ++ p4fb_fill_var(&all->info.var, NULL, 1); ++ bw2_do_default_mode(&all->par, &all->info, &linebytes); ++ } else { ++ if(id != P4_ID_BW2) { ++ kfree(all); ++ iounmap((void *)all->par.regs); ++ return -ENODEV; ++ } ++ ++ p4fb_fill_var(&all->info.var, (volatile u32 *)all->par.regs, 1); ++ } ++ ++ linebytes = all->info.var.xres / 8; ++ ++ all->info.var.red.length = all->info.var.green.length = ++ all->info.var.blue.length = all->info.var.bits_per_pixel; ++ all->info.var.red.offset = all->info.var.green.offset = ++ all->info.var.blue.offset = 0; ++ ++ all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); ++ ++ all->info.flags = FBINFO_DEFAULT; ++ all->info.fbops = &bw2_ops; ++ ++ if(id == -1) { ++#ifdef CONFIG_SUN3 ++ all->info.screen_base = sun3_ioremap(phys_addr, ++ all->par.fbsize, ++ SUN3_PAGE_TYPE_MEMORY); ++#else ++ all->info.screen_base = ioremap(phys_addr, ++ all->par.fbsize); ++#endif ++ } else { ++#ifdef CONFIG_SUN3 ++ all->info.screen_base = sun3_ioremap(phys_addr + BWTWO_FB_OFFSET, ++ all->par.fbsize, ++ SUN3_PAGE_TYPE_MEMORY); ++#else ++ all->info.screen_base = ioremap(phys_addr + BWTWO_FB_OFFSET, ++ all->par.fbsize); ++#endif ++ } ++ ++ p4fb_video_enable(all->par.regs); ++ ++ all->info.par = &all->par; ++ ++ bw2_init_fix(&all->info, linebytes); ++ ++ err= register_framebuffer(&all->info); ++ if (err < 0) { ++ iounmap((void *)all->par.regs); ++ iounmap((void *)all->info.screen_base); ++ kfree(all); ++ return err; ++ } ++ ++ bw2_all = all; ++ ++ printk("%s: bwtwo at %lx\n", ++ all->info.fix.id, all->par.physbase); ++ ++ return 0; ++} ++ ++static int __init bw2_init(void) ++{ ++ if(fb_get_options("bw2fb", NULL)) ++ return -ENODEV; ++ ++ if(bw2_all != NULL) ++ return -ENODEV; ++ ++ /* currently only sun3/80 P4 is supported/tested */ ++ switch(idprom->id_machtype) { ++ case SM_SUN3X|SM_3_80: ++ case SM_SUN3X|SM_3_460: ++ return bw2_init_one(BWTWO_OBMEM_ADDR_3X); ++ ++ case SM_SUN3|SM_3_50: ++ return bw2_init_one(BWTWO_OBMEM_ADDR_50); ++ ++ case SM_SUN3|SM_3_160: ++ case SM_SUN3|SM_3_260: ++ case SM_SUN3|SM_3_110: ++ case SM_SUN3|SM_3_60: ++ return bw2_init_one(BWTWO_OBMEM_ADDR); ++ default: ++ break; ++ } ++ ++ return -ENODEV; ++} ++ ++static void __exit bw2_exit(void) ++{ ++ struct all_info *all = bw2_all; ++ if(bw2_all == NULL) ++ return; ++ ++ unregister_framebuffer(&all->info); ++ ++ iounmap((void *)all->par.regs); ++ iounmap((void *)all->info.screen_base); ++ ++ kfree(all); ++ ++ bw2_all = NULL; ++ ++ return; ++} ++#endif /* CONFIG_FB_SUN3 */ + + module_init(bw2_init); + module_exit(bw2_exit); +--- linux-m68k-2.6.21.orig/drivers/video/cg3.c ++++ linux-m68k-2.6.21/drivers/video/cg3.c +@@ -20,12 +20,24 @@ + + #include <asm/io.h> + #include <asm/oplib.h> ++#ifndef CONFIG_FB_SUN3 + #include <asm/prom.h> + #include <asm/of_device.h> ++#endif + #include <asm/fbio.h> + + #include "sbuslib.h" + ++#ifdef CONFIG_FB_SUN3 ++#ifdef CONFIG_SUN3 ++#include <asm/sun3mmu.h> ++#endif ++#include <asm/machines.h> ++#include <asm/idprom.h> ++#include <asm/sbus.h> ++#include "p4lib.h" ++#endif ++ + /* + * Local functions. + */ +@@ -108,8 +120,16 @@ struct cg3_regs { + }; + + /* Offset of interesting structures in the OBIO space */ +-#define CG3_REGS_OFFSET 0x400000UL +-#define CG3_RAM_OFFSET 0x800000UL ++#ifdef CONFIG_SUN3 ++#define CGFOUR_OBMEM_ADDR_60 0x1f000000 ++#define CGFOUR_OBMEM_ADDR_110 0x1f300000 ++#define CG3_REGS_OFFSET (-0x100000) ++#define CG3_RAM_OFFSET 0x500000UL ++#else ++#define CG3_REGS_OFFSET 0x400000UL ++#define CG3_RAM_OFFSET 0x800000UL ++#endif ++ + + struct cg3_par { + spinlock_t lock; +@@ -250,6 +270,18 @@ static int cg3_ioctl(struct fb_info *inf + * Initialisation + */ + ++struct all_info { ++ struct fb_info info; ++ struct cg3_par par; ++}; ++ ++ ++/* CONFIG_FB_SUN3 has a different implementation for the remaining ++ functions, since: ++ 1) No OpenProm ++ 2) Fixed frequency ++ 3) No support for multiple CGthree's */ ++#ifndef CONFIG_FB_SUN3 + static void __devinit cg3_init_fix(struct fb_info *info, int linebytes, + struct device_node *dp) + { +@@ -351,12 +383,8 @@ static void __devinit cg3_do_default_mod + regp = (u8 __iomem *)&par->regs->cmap.control; + sbus_writeb(p[1], regp); + } +-} + +-struct all_info { +- struct fb_info info; +- struct cg3_par par; +-}; ++} + + static int __devinit cg3_init_one(struct of_device *op) + { +@@ -426,8 +454,8 @@ static int __devinit cg3_init_one(struct + + dev_set_drvdata(&op->dev, all); + +- printk("%s: cg3 at %lx:%lx\n", +- dp->full_name, all->par.which_io, all->par.physbase); ++ printk("%s: cg3 at %lx\n", ++ dp->full_name, all->par.physbase); + + return 0; + } +@@ -488,6 +516,172 @@ static void __exit cg3_exit(void) + of_unregister_driver(&cg3_driver); + } + ++#else /* !CONFIG_FB_SUN3 */ ++static void ++cg3_init_fix(struct fb_info *info, int linebytes) ++{ ++ ++ strcpy(info->fix.id, "SUN3 CG3"); ++ ++ info->fix.type = FB_TYPE_PACKED_PIXELS; ++ info->fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ ++ info->fix.line_length = linebytes; ++ ++ info->fix.accel = FB_ACCEL_SUN_CGTHREE; ++} ++static void cg3_do_default_mode(struct cg3_par *par) ++{ ++ /* kick up the sun3 -- 66hz prom mode only */ ++ /* this also turns off the overlay in case it's really a cg4 */ ++ ++ par->regs->cmap.addr = 4; ++ par->regs->cmap.control = 0xff; ++ par->regs->cmap.addr = 5; ++ par->regs->cmap.control = 0; ++ par->regs->cmap.addr = 6; ++ par->regs->cmap.control = 0x40; ++ par->regs->cmap.addr = 7; ++ par->regs->cmap.control = 0; ++ ++} ++ ++/* The Sun3 version of this driver only supports one cgthree. ++ This really isn't an issue, because it also only supports ++ the 3/60 OBIO cg3, and not vme cards (of which there could be more ++ than one) */ ++static struct all_info *cg3_all = NULL; ++ ++static int __devinit cg3_init_one(unsigned long phys_addr) ++{ ++ struct all_info *all; ++ int linebytes, err; ++ volatile u32 *p4reg = NULL; ++ ++ all = kzalloc(sizeof(*all), GFP_KERNEL); ++ if (!all) ++ return -ENOMEM; ++ ++ spin_lock_init(&all->par.lock); ++ ++ all->par.physbase = phys_addr; ++ ++#if 0 ++ /* it would be nice to use p4 registers here, but it appears ++ * some P4 framebuffers don't actually have useful data. ++ * So we just plod along regardless */ ++ p4reg = sun3_ioremap(all->par.physbase, sizeof(u32), ++ SUN3_PAGE_TYPE_MEMORY); ++ id = p4fb_get_id(p4reg); ++ printk("cg3: p4id %08x\n", *p4reg); ++ ++ if(id != P4_ID_CG4) { ++ iounmap((void *)p4reg); ++ kfree(all); ++ return -ENODEV; ++ } ++ ++#endif ++ p4fb_fill_var(&all->info.var, p4reg, 8); ++ if(p4reg != NULL) ++ iounmap((void *)p4reg); ++ ++ all->info.var.red.length = 8; ++ all->info.var.green.length = 8; ++ all->info.var.blue.length = 8; ++ linebytes = all->info.var.xres; ++ ++ all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); ++ ++ all->par.regs = (struct cg3_regs *) ++ sun3_ioremap(all->par.physbase + CG3_REGS_OFFSET, ++ sizeof(struct cg3_regs), SUN3_PAGE_TYPE_MEMORY); ++ ++ ++ all->info.flags = FBINFO_DEFAULT; ++ all->info.fbops = &cg3_ops; ++ all->info.screen_base = (char *) ++ sun3_ioremap(all->par.physbase + CG3_RAM_OFFSET, ++ all->par.fbsize, SUN3_PAGE_TYPE_MEMORY); ++ all->info.par = &all->par; ++ ++ cg3_blank(0, &all->info); ++ ++ cg3_do_default_mode(&all->par); ++ ++ if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { ++ kfree(all); ++ return -ENOMEM; ++ } ++ ++ fb_set_cmap(&all->info.cmap, &all->info); ++ ++ cg3_init_fix(&all->info, linebytes); ++ ++ err = register_framebuffer(&all->info); ++ if (err < 0) { ++ fb_dealloc_cmap(&all->info.cmap); ++ iounmap(all->par.regs); ++ iounmap(all->info.screen_base); ++ kfree(all); ++ return err; ++ } ++ ++ cg3_all = all; ++ ++ printk("%s: cg3 at %lx\n", ++ all->info.fix.id, all->par.physbase); ++ ++ return 0; ++} ++ ++static int __init cg3_init(void) ++{ ++ if (fb_get_options("cg3fb", NULL)) ++ return -ENODEV; ++ ++ if(cg3_all != NULL) ++ return -ENODEV; ++ ++ /* currently only sun3/60 P4 is supported/tested */ ++ switch(idprom->id_machtype) { ++ case SM_SUN3|SM_3_60: ++ return cg3_init_one(CGFOUR_OBMEM_ADDR_60); ++ ++ case SM_SUN3|SM_3_110: ++ /* 3/110 is a guess, no 3/110 to test on */ ++ return cg3_init_one(CGFOUR_OBMEM_ADDR_110); ++ ++ default: ++ break; ++ } ++ ++ return -ENODEV; ++} ++ ++static void __exit cg3_exit(void) ++{ ++ struct all_info *all = cg3_all; ++ ++ if(cg3_all == NULL) ++ return; ++ ++ unregister_framebuffer(&all->info); ++ fb_dealloc_cmap(&all->info.cmap); ++ ++ iounmap(all->par.regs); ++ iounmap(all->info.screen_base); ++ ++ kfree(all); ++ ++ cg3_all = NULL; ++ ++ return; ++ ++} ++ ++#endif /* CONFIG_FB_SUN3 */ ++ + module_init(cg3_init); + module_exit(cg3_exit); + +--- /dev/null ++++ linux-m68k-2.6.21/drivers/video/p4lib.c +@@ -0,0 +1,107 @@ ++/* p4lib.c: Helper library for Sun P4 framebuffer drivers ++ * ++ * Copyright (C) 2007 Sam Creasey (sammy@sammy.net) ++ */ ++ ++#include <linux/compat.h> ++#include <linux/kernel.h> ++#include <linux/types.h> ++ ++#include <linux/fb.h> ++ ++#include "p4lib.h" ++ ++int p4fb_get_id(volatile u32 *p4reg) ++{ ++ ++#ifdef CONFIG_SUN3 ++ /* this code makes the 3x cry, and it can't have onboard fb anyway */ ++ u32 x, old; ++ ++ /* attempt to read the id bit back from the p4 register, if ++ * we're able to modify the value, conclude there's no p4 ++ * device there. This should enable us to determine if we're ++ * dealing with, for example, a builtin bw2 or a p4 bw2. */ ++ ++ old = *p4reg; ++ x = old & ~P4_CTRL_RESET; ++ ++ *p4reg = x ^ P4_ID_MASK; ++ if((*p4reg ^ x) & P4_ID_MASK) { ++ /* we managed to change the type bits, not a p4 port */ ++ *p4reg = old; ++ return -1; ++ } ++#endif ++ return ((*p4reg) & P4_ID_MASK) >> P4_ID_SHIFT; ++} ++ ++int p4fb_get_res(volatile u32 *p4reg) ++{ ++ return ((*p4reg) & P4_RES_MASK) >> P4_RES_SHIFT; ++} ++ ++void p4fb_video_enable(volatile u32 *p4reg) ++{ ++ u32 x; ++ ++ x = *p4reg; ++ x &= ~(P4_CTRL_VIDEO_EN | P4_CTRL_INT); ++ x |= P4_CTRL_VIDEO_EN; ++ *p4reg = x; ++ ++} ++ ++/* This function basically assumes that p4fb_get_id returns a sane ++ * value for this card/instance. If this was not true, calling with ++ * NULL for p4reg will return the defaults */ ++void p4fb_fill_var(struct fb_var_screeninfo *var, volatile u32 *p4reg, int bpp) ++{ ++ memset(var, 0, sizeof(*var)); ++ ++ if(p4reg == NULL) { ++ var->xres = 1152; ++ var->yres = 900; ++ } else { ++ switch(p4fb_get_res(p4reg)) { ++ case P4_RES_1600X1280: ++ var->xres = 1600; ++ var->yres = 1280; ++ break; ++ case P4_RES_1152X900: ++ var->xres = 1152; ++ var->yres = 900; ++ break; ++ case P4_RES_1024X1024: ++ var->xres = 1024; ++ var->yres = 1024; ++ break; ++ case P4_RES_1280X1024: ++ var->xres = 1280; ++ var->yres = 1024; ++ break; ++ case P4_RES_1440X1440: ++ var->xres = 1440; ++ var->yres = 1400; ++ break; ++ case P4_RES_640X480: ++ var->xres = 640; ++ var->yres = 480; ++ break; ++ default: ++ /* this may or may not be the right thing to ++ * do here, but plod on anyway */ ++ var->xres = 1152; ++ var->yres = 900; ++ break; ++ } ++ } ++ ++ var->xres_virtual = var->xres; ++ var->yres_virtual = var->yres; ++ var->bits_per_pixel = bpp; ++} ++ ++EXPORT_SYMBOL(p4fb_get_id); ++EXPORT_SYMBOL(p4fb_get_res); ++EXPORT_SYMBOL(p4fb_fill_var); +--- /dev/null ++++ linux-m68k-2.6.21/drivers/video/p4lib.h +@@ -0,0 +1,56 @@ ++/* p4lib.h: helper functions for p4 framebuffers */ ++ ++#ifndef _P4LIB_H ++#define _P4LIB_H ++ ++/* register defintions applicable to p4 framebuffers found on some ++ Sun3/3x machines (and some Sun4 machines, though these are not ++ currently supported or tested). These machines have a single 32bit ++ register at the start of the p4 address space. ++ ++ The format of this register is as follows: ++ ++ bit 31 : unused ++ bits 30-28: type ++ bits 27-24: resolution ++ bits 23-8: unused ++ bits 7-0: status/control ++ ++ The CG8 may break this format, if that turns out to be true, I'll ++ fix once I have a CG8 to test against... ++*/ ++ ++/* control register, lower 8bits */ ++#define P4_CTRL_DIAG 0x80 /* ??? */ ++#define P4_CTRL_RBCLR 0x40 /* ??? */ ++#define P4_CTRL_VIDEO_EN 0x20 /* enable video */ ++#define P4_CTRL_SYNC 0x10 /* ??? */ ++#define P4_CTRL_VTRACE 0x08 /* ??? */ ++#define P4_CTRL_INT 0x04 /* read: int pending, write: clear int */ ++#define P4_CTRL_INT_EN 0x02 /* enable interrupts */ ++#define P4_CTRL_RESET 0x01 /* reset */ ++ ++/* framebuffer identification -- bits 31-28 */ ++#define P4_ID_MASK 0x70000000 ++#define P4_ID_SHIFT 24 ++#define P4_ID_BW2 0x00 ++#define P4_ID_CG4 0x40 /* supported in linux as a cg3 */ ++#define P4_ID_CG6 0x60 ++ ++/* framebuffer resolution - bits 27-24 */ ++#define P4_RES_MASK 0x0f000000 ++#define P4_RES_SHIFT 24 ++#define P4_RES_1600X1280 0x00 ++#define P4_RES_1152X900 0x01 /* only tested resolution */ ++#define P4_RES_1024X1024 0x02 ++#define P4_RES_1280X1024 0x03 ++#define P4_RES_1440X1440 0x04 ++#define P4_RES_640X480 0x05 ++ ++/* actual helper functions */ ++extern int p4fb_get_id(volatile u32 *p4reg); ++extern int p4fb_get_res(volatile u32 *p4reg); ++extern void p4fb_video_enable(volatile u32 *p4reg); ++extern void p4fb_fill_var(struct fb_var_screeninfo *var, volatile u32 *p4reg, int bpp); ++ ++#endif /* P4LIB_H */ +--- linux-m68k-2.6.21.orig/drivers/video/sbuslib.c ++++ linux-m68k-2.6.21/drivers/video/sbuslib.c +@@ -13,6 +13,10 @@ + #include <asm/oplib.h> + #include <asm/fbio.h> + ++#if defined(CONFIG_SUN3) || defined(CONFIG_SUN3X) ++#include <asm/uaccess.h> ++#endif ++ + #include "sbuslib.h" + + void sbusfb_fill_var(struct fb_var_screeninfo *var, int prom_node, int bpp) +@@ -21,6 +25,7 @@ void sbusfb_fill_var(struct fb_var_scree + + var->xres = prom_getintdefault(prom_node, "width", 1152); + var->yres = prom_getintdefault(prom_node, "height", 900); ++ + var->xres_virtual = var->xres; + var->yres_virtual = var->yres; + var->bits_per_pixel = bpp; +@@ -80,12 +85,20 @@ int sbusfb_mmap_helper(struct sbus_mmap_ + } + if (page + map_size > size) + map_size = size - page; ++#if !defined(CONFIG_FB_SUN3) + r = io_remap_pfn_range(vma, + vma->vm_start + page, + MK_IOSPACE_PFN(iospace, + map_offset >> PAGE_SHIFT), + map_size, + vma->vm_page_prot); ++#else ++ r = io_remap_pfn_range(vma, ++ vma->vm_start + page, ++ map_offset, map_size, ++ vma->vm_page_prot); ++#endif ++ + if (r) + return -EAGAIN; + page += map_size; diff --git a/debian/patches/bugfix/m68k/sun3-3x-serial.diff b/debian/patches/bugfix/m68k/sun3-3x-serial.diff new file mode 100644 index 000000000000..d49c94941d19 --- /dev/null +++ b/debian/patches/bugfix/m68k/sun3-3x-serial.diff @@ -0,0 +1,486 @@ +From: David Miller <davem@davemloft.net> +To: sammy@sammy.net +Cc: linux-m68k@vger.kernel.org +Subject: Re: [PATCH] Sun3/3x Serial driver support + +From: Sam Creasey <sammy@sammy.net> +Date: Tue, 3 Apr 2007 10:43:42 -0400 + +> Adds serial support for sun3/3x machines. This patch has basically +> been around for years, but my own laziness has kept me from committing +> upstream. +> +> Signed-off-by: Sam Creasey <sammy@sammy.net> + +Same thing here, please build a proper openprom device tree in +the sun3 port and then you'll need to make few, if any, +changes to the sparc drivers. + +I've made these drivers as portable as possible, frankly, and +if you cook up proper in-kernel device objects, you'll need +to do no porting at all. + +--------------------------------------------------------------------------- + +From sammy@sammy.net Tue Apr 3 16:47:31 2007 +Date: Tue, 3 Apr 2007 10:43:42 -0400 +From: Sam Creasey <sammy@sammy.net> +To: linux-m68k@vger.kernel.org, David S. Miller <davem@davemloft.net> +Subject: [PATCH] Sun3/3x Serial driver support + +Adds serial support for sun3/3x machines. This patch has basically +been around for years, but my own laziness has kept me from committing +upstream. + +Signed-off-by: Sam Creasey <sammy@sammy.net> + +--- + drivers/serial/Kconfig | 4 + drivers/serial/suncore.c | 4 + drivers/serial/sunzilog.c | 200 +++++++++++++++++++++++++++++++++++++++++++--- + 3 files changed, 195 insertions(+), 13 deletions(-) + +--- linux-m68k-2.6.21.orig/drivers/serial/Kconfig ++++ linux-m68k-2.6.21/drivers/serial/Kconfig +@@ -543,14 +543,14 @@ config SERIAL_UARTLITE_CONSOLE + + config SERIAL_SUNCORE + bool +- depends on SPARC ++ depends on SPARC || SUN3 || SUN3X + select SERIAL_CORE + select SERIAL_CORE_CONSOLE + default y + + config SERIAL_SUNZILOG + tristate "Sun Zilog8530 serial support" +- depends on SPARC ++ depends on SPARC || SUN3 || SUN3X + help + This driver supports the Zilog8530 serial ports found on many Sparc + systems. Say Y or M if you want to be able to these serial ports. +--- linux-m68k-2.6.21.orig/drivers/serial/suncore.c ++++ linux-m68k-2.6.21/drivers/serial/suncore.c +@@ -29,6 +29,7 @@ EXPORT_SYMBOL(sunserial_current_minor); + void + sunserial_console_termios(struct console *con) + { ++#if !defined(CONFIG_SUN3) && !defined (CONFIG_SUN3X) + char mode[16], buf[16], *s; + char *mode_prop = "ttyX-mode"; + char *cd_prop = "ttyX-ignore-cd"; +@@ -162,6 +163,9 @@ no_options: + } + + con->cflag = cflag; ++#else /* CONFIG_SUN3(X) */ ++ con->cflag = CREAD | HUPCL | CLOCAL | B9600 | CS8; ++#endif + } + + EXPORT_SYMBOL(sunserial_console_termios); +--- linux-m68k-2.6.21.orig/drivers/serial/sunzilog.c ++++ linux-m68k-2.6.21/drivers/serial/sunzilog.c +@@ -35,13 +35,30 @@ + + #include <asm/io.h> + #include <asm/irq.h> +-#include <asm/prom.h> +-#include <asm/of_device.h> + + #if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) + #define SUPPORT_SYSRQ + #endif + ++#if defined(CONFIG_SUN3) || defined(CONFIG_SUN3X) ++#include <asm/oplib.h> ++#include <asm/sbus.h> ++#define readb sbus_readb ++#define writeb sbus_writeb ++ ++#else ++#include <asm/prom.h> ++#include <asm/of_device.h> ++#endif ++ ++#ifdef CONFIG_SUN3 ++#include <asm/sun3mmu.h> ++#endif ++ ++#ifdef CONFIG_SUN3X ++#include <asm/sun3xprom.h> ++#endif ++ + #include <linux/serial_core.h> + + #include "suncore.h" +@@ -415,7 +432,15 @@ static void sunzilog_status_handle(struc + if (!(status & BRK_ABRT)) + break; + } +- sun_do_break(); ++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) ++ sun_do_break(); ++#else ++#ifdef CONFIG_SUN3 ++ prom_reboot(""); ++#else ++ sun3x_reboot(); ++#endif ++#endif + return; + } + } +@@ -523,6 +548,13 @@ static irqreturn_t sunzilog_interrupt(in + struct tty_struct *tty; + unsigned char r3; + ++#if defined(CONFIG_SUN3) || defined(CONFIG_SUN3X) ++ if(!channel) { ++ up = up->next; ++ continue; ++ } ++#endif ++ + spin_lock(&up->port.lock); + r3 = read_zsreg(channel, R3); + +@@ -1193,6 +1225,7 @@ static struct console sunzilog_console_o + + static inline struct console *SUNZILOG_CONSOLE(void) + { ++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) + int i; + + if (con_is_present()) +@@ -1209,6 +1242,10 @@ static inline struct console *SUNZILOG_C + + sunzilog_console_ops.index = i; + sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS; ++#else ++ sunzilog_console_ops.index = 0; ++ sunzilog_port_table[0].flags |= SUNZILOG_FLAG_IS_CONS; ++#endif + + return &sunzilog_console_ops; + } +@@ -1266,6 +1303,8 @@ static void __init sunzilog_register_ser + } + #endif + ++static int zilog_irq = -1; ++ + static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up) + { + struct zilog_channel __iomem *channel; +@@ -1276,9 +1315,16 @@ static void __devinit sunzilog_init_hw(s + + spin_lock_irqsave(&up->port.lock, flags); + if (ZS_IS_CHANNEL_A(up)) { ++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) + write_zsreg(channel, R9, FHWRES); + ZSDELAY_LONG(); ++#endif + (void) read_zsreg(channel, R0); ++#ifdef CONFIG_SUN3 ++ /* should sun3x run here? */ ++ /* program the int vector */ ++ write_zsreg(channel, R2, 0x18+zilog_irq); ++#endif + } + + if (up->flags & (SUNZILOG_FLAG_CONS_KEYB | +@@ -1293,7 +1339,11 @@ static void __devinit sunzilog_init_hw(s + up->curregs[R4] = PAR_EVEN | X16CLK | SB1; + up->curregs[R3] = RxENAB | Rx8; + up->curregs[R5] = TxENAB | Tx8; ++#ifdef CONFIG_SUN3 ++ up->curregs[R9] = MIE; ++#else + up->curregs[R9] = NV | MIE; ++#endif + up->curregs[R10] = NRZ; + up->curregs[R11] = TCBR | RCBR; + baud = 9600; +@@ -1314,9 +1364,75 @@ static void __devinit sunzilog_init_hw(s + #endif + } + +-static int zilog_irq = -1; ++#if defined(CONFIG_SUN3) || defined(CONFIG_SUN3X) ++static struct zilog_layout * __init get_zs(int chip) ++{ ++ unsigned int vaddr = 0; + ++ if (chip < 0 || chip >= NUM_SUNZILOG) { ++ prom_printf("SunZilog: Illegal chip number %d in get_zs.\n", chip); ++ prom_halt(); ++ } ++ ++#ifndef CONFIG_SUN3X ++ /* sun3 OBIO version */ ++ /* Grrr, these have to be hardcoded aieee */ ++ switch(chip) { ++ case 0: ++ for(vaddr = 0xfe00000; vaddr < (0xfe00000 + ++ SUN3_PMEG_SIZE); vaddr += SUN3_PTE_SIZE) { ++ unsigned long iopte; ++ ++ iopte = sun3_get_pte(vaddr); ++ if(!(iopte & SUN3_PAGE_TYPE_IO)) /* this an io page? */ ++ continue; ++ ++ if(((iopte & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT) == ++ 0x20000) { ++ break; ++ } ++ } ++ break; ++ case 1: ++ for(vaddr = 0xfe00000; vaddr < (0xfe00000 + ++ SUN3_PMEG_SIZE); vaddr += SUN3_PTE_SIZE) { ++ ++ unsigned long iopte; ++ ++ iopte = sun3_get_pte(vaddr); ++ if(!(iopte & SUN3_PAGE_TYPE_IO)) /* this an io page? */ ++ continue; ++ ++ if(((iopte & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT) == ++ 0) { ++ break; ++ } ++ } ++ break; ++ }; ++#else ++ /* sun3x is a wee bit cleaner. :) */ ++ switch(chip) { ++ case 0: ++ vaddr = SUN3X_ZS2; ++ break; ++ ++ case 1: ++ vaddr = SUN3X_ZS1; ++ break; ++ } ++#endif ++ ++ if(!vaddr) ++ panic("get_zs whee no serial chip mappable"); ++ ++ return (struct zilog_layout *)(unsigned long) vaddr; ++} ++ ++static int __devinit zs_probe(void) ++#else + static int __devinit zs_probe(struct of_device *op, const struct of_device_id *match) ++#endif + { + static int inst; + struct uart_sunzilog_port *up; +@@ -1325,51 +1441,70 @@ static int __devinit zs_probe(struct of_ + int err; + + keyboard_mouse = 0; ++#if defined(CONFIG_SUN3) || defined(CONFIG_SUN3X) ++ sunzilog_chip_regs[inst] = get_zs(inst); ++ if(inst) ++ keyboard_mouse = 1; ++#else + if (of_find_property(op->node, "keyboard", NULL)) + keyboard_mouse = 1; + + sunzilog_chip_regs[inst] = of_ioremap(&op->resource[0], 0, + sizeof(struct zilog_layout), + "zs"); ++#endif /* CONFIG_SUN3 || CONFIG_SUN3X */ ++ + if (!sunzilog_chip_regs[inst]) + return -ENOMEM; + + rp = sunzilog_chip_regs[inst]; + ++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) + if (zilog_irq == -1) + zilog_irq = op->irqs[0]; ++#endif + + up = &sunzilog_port_table[inst * 2]; + + /* Channel A */ +- up[0].port.mapbase = op->resource[0].start + 0x00; + up[0].port.membase = (void __iomem *) &rp->channelA; +- up[0].port.iotype = UPIO_MEM; ++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) ++ up[0].port.mapbase = op->resource[0].start + 0x00; + up[0].port.irq = op->irqs[0]; ++ up[0].port.dev = &op->dev; ++#else ++ up[0].port.mapbase = (unsigned long)up[0].port.membase; ++ up[0].port.irq = zilog_irq; ++#endif ++ up[0].port.iotype = UPIO_MEM; + up[0].port.uartclk = ZS_CLOCK; + up[0].port.fifosize = 1; + up[0].port.ops = &sunzilog_pops; + up[0].port.type = PORT_SUNZILOG; + up[0].port.flags = 0; + up[0].port.line = (inst * 2) + 0; +- up[0].port.dev = &op->dev; + up[0].flags |= SUNZILOG_FLAG_IS_CHANNEL_A; + if (keyboard_mouse) + up[0].flags |= SUNZILOG_FLAG_CONS_KEYB; + sunzilog_init_hw(&up[0]); + + /* Channel B */ +- up[1].port.mapbase = op->resource[0].start + 0x04; + up[1].port.membase = (void __iomem *) &rp->channelB; +- up[1].port.iotype = UPIO_MEM; ++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) ++ up[1].port.mapbase = op->resource[0].start + 0x04; + up[1].port.irq = op->irqs[0]; ++ up[1].port.dev = &op->dev; ++#else ++ up[1].port.mapbase = (unsigned long)up[1].port.membase; ++ up[1].port.irq = zilog_irq; ++#endif ++ up[1].port.iotype = UPIO_MEM; + up[1].port.uartclk = ZS_CLOCK; + up[1].port.fifosize = 1; + up[1].port.ops = &sunzilog_pops; + up[1].port.type = PORT_SUNZILOG; + up[1].port.flags = 0; + up[1].port.line = (inst * 2) + 1; +- up[1].port.dev = &op->dev; + up[1].flags |= 0; + if (keyboard_mouse) + up[1].flags |= SUNZILOG_FLAG_CONS_MOUSE; +@@ -1378,33 +1513,50 @@ static int __devinit zs_probe(struct of_ + if (!keyboard_mouse) { + err = uart_add_one_port(&sunzilog_reg, &up[0].port); + if (err) { ++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) + of_iounmap(&op->resource[0], + rp, sizeof(struct zilog_layout)); ++#endif + return err; + } + err = uart_add_one_port(&sunzilog_reg, &up[1].port); + if (err) { + uart_remove_one_port(&sunzilog_reg, &up[0].port); ++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) + of_iounmap(&op->resource[0], + rp, sizeof(struct zilog_layout)); ++#endif + return err; + } + } else { ++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) + printk(KERN_INFO "%s: Keyboard at MMIO %lx (irq = %d) " + "is a zs\n", + op->dev.bus_id, up[0].port.mapbase, op->irqs[0]); + printk(KERN_INFO "%s: Mouse at MMIO %lx (irq = %d) " + "is a zs\n", + op->dev.bus_id, up[1].port.mapbase, op->irqs[0]); ++#else ++ printk(KERN_INFO "zs%d: Keyboard at MMIO %lx (irq = %d) " ++ "is a zs\n", ++ inst, up[0].port.mapbase, zilog_irq); ++ printk(KERN_INFO "zs%d: Mouse at MMIO %lx (irq = %d) " ++ "is a zs\n", ++ inst, up[1].port.mapbase, zilog_irq); ++#endif + } + ++ ++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) + dev_set_drvdata(&op->dev, &up[0]); ++#endif + + inst++; + + return 0; + } + ++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) + static void __devexit zs_remove_one(struct uart_sunzilog_port *up) + { + if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) { +@@ -1445,13 +1597,17 @@ static struct of_platform_driver zs_driv + .probe = zs_probe, + .remove = __devexit_p(zs_remove), + }; ++#endif /* !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) */ + + static int __init sunzilog_init(void) + { ++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) + struct device_node *dp; ++#endif + int err, uart_count; + int num_keybms; + ++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) + NUM_SUNZILOG = 0; + num_keybms = 0; + for_each_node_by_name(dp, "zs") { +@@ -1459,6 +1615,10 @@ static int __init sunzilog_init(void) + if (of_find_property(dp, "keyboard", NULL)) + num_keybms++; + } ++#else ++ NUM_SUNZILOG = 2; ++ num_keybms = 1; ++#endif + + uart_count = 0; + if (NUM_SUNZILOG) { +@@ -1481,6 +1641,7 @@ static int __init sunzilog_init(void) + + sunserial_current_minor += uart_count; + } ++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) + + err = of_register_driver(&zs_driver, &of_bus_type); + if (err) +@@ -1492,12 +1653,28 @@ static int __init sunzilog_init(void) + if (err) + goto out_unregister_driver; + } ++#else ++ ++ zilog_irq = 6; ++ err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_DISABLED, ++ "zs", sunzilog_irq_chain); ++ if (err) ++ goto out_unregister_uart; ++ ++ /* probe for two zs instances on sun3/3x */ ++ zs_probe(); ++ zs_probe(); ++ ++ ++#endif + + out: + return err; + ++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) + out_unregister_driver: + of_unregister_driver(&zs_driver); ++#endif + + out_unregister_uart: + if (NUM_SUNZILOG) { +@@ -1512,8 +1689,9 @@ out_free_tables: + + static void __exit sunzilog_exit(void) + { ++#if !defined(CONFIG_SUN3) && !defined(CONFIG_SUN3X) + of_unregister_driver(&zs_driver); +- ++#endif + if (zilog_irq != -1) { + free_irq(zilog_irq, sunzilog_irq_chain); + zilog_irq = -1; diff --git a/debian/patches/bugfix/m68k/sun3-numints.diff b/debian/patches/bugfix/m68k/sun3-numints.diff new file mode 100644 index 000000000000..1eea7a7fdb7d --- /dev/null +++ b/debian/patches/bugfix/m68k/sun3-numints.diff @@ -0,0 +1,23 @@ +Subject: [PATCH] m68k: Correct number of interrupts for Sun3 + +From: Sam Creasey <sammy@sammy.net> + +Only attempt to initialize the amount of interrupts a sun3 actually has... + +Signed-off-by: Sam Creasey <sammy@sammy.net> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + arch/m68k/sun3/sun3ints.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- linux-m68k-2.6.21.orig/arch/m68k/sun3/sun3ints.c ++++ linux-m68k-2.6.21/arch/m68k/sun3/sun3ints.c +@@ -103,7 +103,7 @@ void sun3_init_IRQ(void) + + m68k_setup_auto_interrupt(sun3_inthandle); + m68k_setup_irq_controller(&sun3_irq_controller, IRQ_AUTO_1, 7); +- m68k_setup_user_interrupt(VEC_USER, 192, NULL); ++ m68k_setup_user_interrupt(VEC_USER, 128, NULL); + + request_irq(IRQ_AUTO_5, sun3_int5, 0, "int5", NULL); + request_irq(IRQ_AUTO_7, sun3_int7, 0, "int7", NULL); diff --git a/debian/patches/bugfix/m68k/unnecessary-m68k_memoffset.diff b/debian/patches/bugfix/m68k/unnecessary-m68k_memoffset.diff new file mode 100644 index 000000000000..b646820100d1 --- /dev/null +++ b/debian/patches/bugfix/m68k/unnecessary-m68k_memoffset.diff @@ -0,0 +1,30 @@ +Subject: [PATCH] m68k: Remove unnecessary m68k_memoffset export and init + +From: Roman Zippel <zippel@linux-m68k.org> + +Remove an unnecessary m68k_memoffset export and initialization + +Signed-off-by: Roman Zippel <zippel@linux-m68k.org> +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + arch/m68k/kernel/setup.c | 2 -- + 1 file changed, 2 deletions(-) + +--- linux-m68k-2.6.21.orig/arch/m68k/kernel/setup.c ++++ linux-m68k-2.6.21/arch/m68k/kernel/setup.c +@@ -61,7 +61,6 @@ int m68k_num_memory; + int m68k_realnum_memory; + EXPORT_SYMBOL(m68k_realnum_memory); + unsigned long m68k_memoffset; +-EXPORT_SYMBOL(m68k_memoffset); + struct mem_info m68k_memory[NUM_MEMINFO]; + EXPORT_SYMBOL(m68k_memory); + +@@ -199,7 +198,6 @@ static void __init m68k_parse_bootinfo(c + (m68k_num_memory - 1)); + m68k_num_memory = 1; + } +- m68k_memoffset = m68k_memory[0].addr-PAGE_OFFSET; + #endif + } + diff --git a/debian/patches/bugfix/m68k/via-pmu68k-dead-code.diff b/debian/patches/bugfix/m68k/via-pmu68k-dead-code.diff new file mode 100644 index 000000000000..3d57ea2d1e71 --- /dev/null +++ b/debian/patches/bugfix/m68k/via-pmu68k-dead-code.diff @@ -0,0 +1,263 @@ +Subject: [PATCH] remove dead code in via-pmu68k +Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> + +From: Johannes Berg <johannes@sipsolutions.net> + +When suspend is ever implemented for pmu68k it really should follow the +generic pm_ops concept and not mirror the platform-specific /dev/pmu +device with ioctls on it. Hence, this patch removes the unused code there; +should the implementers need it they can look at via-pmu.c and/or the +history of the file. + +Signed-off-by: Johannes Berg <johannes@sipsolutions.net +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + drivers/macintosh/via-pmu68k.c | 240 ----------------------------------------- + 1 file changed, 240 deletions(-) + +--- linux-m68k-2.6.21.orig/drivers/macintosh/via-pmu68k.c ++++ linux-m68k-2.6.21/drivers/macintosh/via-pmu68k.c +@@ -818,243 +818,3 @@ pmu_present(void) + { + return (pmu_kind != PMU_UNKNOWN); + } +- +-#if 0 /* needs some work for 68K */ +- +-/* +- * This struct is used to store config register values for +- * PCI devices which may get powered off when we sleep. +- */ +-static struct pci_save { +- u16 command; +- u16 cache_lat; +- u16 intr; +-} *pbook_pci_saves; +-static int n_pbook_pci_saves; +- +-static inline void +-pbook_pci_save(void) +-{ +- int npci; +- struct pci_dev *pd = NULL; +- struct pci_save *ps; +- +- npci = 0; +- while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) +- ++npci; +- n_pbook_pci_saves = npci; +- if (npci == 0) +- return; +- ps = kmalloc(npci * sizeof(*ps), GFP_KERNEL); +- pbook_pci_saves = ps; +- if (ps == NULL) +- return; +- +- pd = NULL; +- while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) { +- pci_read_config_word(pd, PCI_COMMAND, &ps->command); +- pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat); +- pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr); +- ++ps; +- --npci; +- } +-} +- +-static inline void +-pbook_pci_restore(void) +-{ +- u16 cmd; +- struct pci_save *ps = pbook_pci_saves; +- struct pci_dev *pd = NULL; +- int j; +- +- while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) { +- if (ps->command == 0) +- continue; +- pci_read_config_word(pd, PCI_COMMAND, &cmd); +- if ((ps->command & ~cmd) == 0) +- continue; +- switch (pd->hdr_type) { +- case PCI_HEADER_TYPE_NORMAL: +- for (j = 0; j < 6; ++j) +- pci_write_config_dword(pd, +- PCI_BASE_ADDRESS_0 + j*4, +- pd->resource[j].start); +- pci_write_config_dword(pd, PCI_ROM_ADDRESS, +- pd->resource[PCI_ROM_RESOURCE].start); +- pci_write_config_word(pd, PCI_CACHE_LINE_SIZE, +- ps->cache_lat); +- pci_write_config_word(pd, PCI_INTERRUPT_LINE, +- ps->intr); +- pci_write_config_word(pd, PCI_COMMAND, ps->command); +- break; +- /* other header types not restored at present */ +- } +- } +-} +- +-/* +- * Put the powerbook to sleep. +- */ +-#define IRQ_ENABLE ((unsigned int *)0xf3000024) +-#define MEM_CTRL ((unsigned int *)0xf8000070) +- +-int powerbook_sleep(void) +-{ +- int ret, i, x; +- static int save_backlight; +- static unsigned int save_irqen; +- unsigned long msr; +- unsigned int hid0; +- unsigned long p, wait; +- struct adb_request sleep_req; +- +- /* Notify device drivers */ +- ret = blocking_notifier_call_chain(&sleep_notifier_list, +- PBOOK_SLEEP, NULL); +- if (ret & NOTIFY_STOP_MASK) +- return -EBUSY; +- +- /* Sync the disks. */ +- /* XXX It would be nice to have some way to ensure that +- * nobody is dirtying any new buffers while we wait. */ +- sys_sync(); +- +- /* Turn off the display backlight */ +- save_backlight = backlight_enabled; +- if (save_backlight) +- pmu_enable_backlight(0); +- +- /* Give the disks a little time to actually finish writing */ +- for (wait = jiffies + (HZ/4); time_before(jiffies, wait); ) +- mb(); +- +- /* Disable all interrupts except pmu */ +- save_irqen = in_le32(IRQ_ENABLE); +- for (i = 0; i < 32; ++i) +- if (i != vias->intrs[0].line && (save_irqen & (1 << i))) +- disable_irq(i); +- asm volatile("mtdec %0" : : "r" (0x7fffffff)); +- +- /* Save the state of PCI config space for some slots */ +- pbook_pci_save(); +- +- /* Set the memory controller to keep the memory refreshed +- while we're asleep */ +- for (i = 0x403f; i >= 0x4000; --i) { +- out_be32(MEM_CTRL, i); +- do { +- x = (in_be32(MEM_CTRL) >> 16) & 0x3ff; +- } while (x == 0); +- if (x >= 0x100) +- break; +- } +- +- /* Ask the PMU to put us to sleep */ +- pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); +- while (!sleep_req.complete) +- mb(); +- /* displacement-flush the L2 cache - necessary? */ +- for (p = KERNELBASE; p < KERNELBASE + 0x100000; p += 0x1000) +- i = *(volatile int *)p; +- asleep = 1; +- +- /* Put the CPU into sleep mode */ +- asm volatile("mfspr %0,1008" : "=r" (hid0) :); +- hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP; +- asm volatile("mtspr 1008,%0" : : "r" (hid0)); +- local_save_flags(msr); +- msr |= MSR_POW | MSR_EE; +- local_irq_restore(msr); +- udelay(10); +- +- /* OK, we're awake again, start restoring things */ +- out_be32(MEM_CTRL, 0x3f); +- pbook_pci_restore(); +- +- /* wait for the PMU interrupt sequence to complete */ +- while (asleep) +- mb(); +- +- /* reenable interrupts */ +- for (i = 0; i < 32; ++i) +- if (i != vias->intrs[0].line && (save_irqen & (1 << i))) +- enable_irq(i); +- +- /* Notify drivers */ +- blocking_notifier_call_chain(&sleep_notifier_list, PBOOK_WAKE, NULL); +- +- /* reenable ADB autopoll */ +- pmu_adb_autopoll(adb_dev_map); +- +- /* Turn on the screen backlight, if it was on before */ +- if (save_backlight) +- pmu_enable_backlight(1); +- +- /* Wait for the hard disk to spin up */ +- +- return 0; +-} +- +-/* +- * Support for /dev/pmu device +- */ +-static int pmu_open(struct inode *inode, struct file *file) +-{ +- return 0; +-} +- +-static ssize_t pmu_read(struct file *file, char *buf, +- size_t count, loff_t *ppos) +-{ +- return 0; +-} +- +-static ssize_t pmu_write(struct file *file, const char *buf, +- size_t count, loff_t *ppos) +-{ +- return 0; +-} +- +-static int pmu_ioctl(struct inode * inode, struct file *filp, +- u_int cmd, u_long arg) +-{ +- int error; +- __u32 value; +- +- switch (cmd) { +- case PMU_IOC_SLEEP: +- return -ENOSYS; +- case PMU_IOC_GET_BACKLIGHT: +- return put_user(backlight_level, (__u32 *)arg); +- case PMU_IOC_SET_BACKLIGHT: +- error = get_user(value, (__u32 *)arg); +- if (!error) +- pmu_set_brightness(value); +- return error; +- case PMU_IOC_GET_MODEL: +- return put_user(pmu_kind, (__u32 *)arg); +- } +- return -EINVAL; +-} +- +-static const struct file_operations pmu_device_fops = { +- .read = pmu_read, +- .write = pmu_write, +- .ioctl = pmu_ioctl, +- .open = pmu_open, +-}; +- +-static struct miscdevice pmu_device = { +- PMU_MINOR, "pmu", &pmu_device_fops +-}; +- +-void pmu_device_init(void) +-{ +- if (!via) +- return; +- if (misc_register(&pmu_device) < 0) +- printk(KERN_ERR "via-pmu68k: cannot register misc device.\n"); +-} +-#endif /* CONFIG_PMAC_PBOOK */ +- diff --git a/debian/patches/bugfix/m68k/zorro-resource_size_t-warnings.diff b/debian/patches/bugfix/m68k/zorro-resource_size_t-warnings.diff new file mode 100644 index 000000000000..0bdc7d7987a7 --- /dev/null +++ b/debian/patches/bugfix/m68k/zorro-resource_size_t-warnings.diff @@ -0,0 +1,50 @@ +Subject: [PATCH] Amiga Zorro bus: kill resource_size_t warnings + +Kill resource_size_t warnings by casting resource_size_t to unsigned long when +formatting Zorro bus resources, as they are always 32-bit. + +Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> +--- + drivers/zorro/proc.c | 5 +++-- + drivers/zorro/zorro-sysfs.c | 3 ++- + drivers/zorro/zorro.c | 3 ++- + 3 files changed, 7 insertions(+), 4 deletions(-) + +--- linux-m68k-2.6.21.orig/drivers/zorro/proc.c ++++ linux-m68k-2.6.21/drivers/zorro/proc.c +@@ -90,8 +90,9 @@ get_zorro_dev_info(char *buf, char **sta + for (slot = cnt = 0; slot < zorro_num_autocon && count > cnt; slot++) { + struct zorro_dev *z = &zorro_autocon[slot]; + len = sprintf(buf, "%02x\t%08x\t%08lx\t%08lx\t%02x\n", slot, +- z->id, zorro_resource_start(z), +- zorro_resource_len(z), z->rom.er_Type); ++ z->id, (unsigned long)zorro_resource_start(z), ++ (unsigned long)zorro_resource_len(z), ++ z->rom.er_Type); + at += len; + if (at >= pos) { + if (!*start) { +--- linux-m68k-2.6.21.orig/drivers/zorro/zorro-sysfs.c ++++ linux-m68k-2.6.21/drivers/zorro/zorro-sysfs.c +@@ -42,7 +42,8 @@ static ssize_t zorro_show_resource(struc + struct zorro_dev *z = to_zorro_dev(dev); + + return sprintf(buf, "0x%08lx 0x%08lx 0x%08lx\n", +- zorro_resource_start(z), zorro_resource_end(z), ++ (unsigned long)zorro_resource_start(z), ++ (unsigned long)zorro_resource_end(z), + zorro_resource_flags(z)); + } + +--- linux-m68k-2.6.21.orig/drivers/zorro/zorro.c ++++ linux-m68k-2.6.21/drivers/zorro/zorro.c +@@ -164,7 +164,8 @@ static int __init zorro_init(void) + if (request_resource(zorro_find_parent_resource(z), &z->resource)) + printk(KERN_ERR "Zorro: Address space collision on device %s " + "[%lx:%lx]\n", +- z->name, zorro_resource_start(z), zorro_resource_end(z)); ++ z->name, (unsigned long)zorro_resource_start(z), ++ (unsigned long)zorro_resource_end(z)); + sprintf(z->dev.bus_id, "%02x", i); + z->dev.parent = &zorro_bus.dev; + z->dev.bus = &zorro_bus_type; |