diff --git a/debian/patches/bugfix/m68k/130-adbraw.diff b/debian/patches/bugfix/m68k/130-adbraw.diff new file mode 100644 index 000000000..2cabbd468 --- /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 000000000..2ef342af6 --- /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 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 000000000..5ce087b90 --- /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 + #include + #include ++#include + #include + #include + #include +@@ -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 000000000..b4537dc69 --- /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 000000000..01c02d095 --- /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 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 ++ */ ++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 ++ ++#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, ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++/*#include */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#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 " ++#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 000000000..eaad1204f --- /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 000000000..71e738b66 --- /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 000000000..6827b6698 --- /dev/null +++ b/debian/patches/bugfix/m68k/357-mac89x0.diff @@ -0,0 +1,177 @@ +Subject: [PATCH] m68k: Mac89x0 Ethernet netif updates +Cc: Jeff Garzik , netdev@vger.kernel.org + +From: Matthias Urlichs + +Macintosh CS89x0 Ethernet: Netif updates +Addition of netif_stop_queue() before transmission by Michael Schmitz + +Signed-off-by: Geert Uytterhoeven +--- + 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 000000000..8d4c0aec0 --- /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 + +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 000000000..efa2d962d --- /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 + +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 +Signed-off-by: Geert Uytterhoeven + +--- + 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 000000000..10e6823bb --- /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 + +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 +Signed-off-by: Geert Uytterhoeven +--- + 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 000000000..7ea927520 --- /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 + +Wrap direct thread_info access + +Signed-off-by: Roman Zippel +Signed-off-by: Geert Uytterhoeven +--- + 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 000000000..94aa02f46 --- /dev/null +++ b/debian/patches/bugfix/m68k/611-module_fixup.diff @@ -0,0 +1,214 @@ +Subject: [PATCH] m68k: runtime patching infrastructure + +From: Roman Zippel + +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 +Signed-off-by: Geert Uytterhoeven +--- + 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 + #include + #include +@@ -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 ++ + #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 000000000..ef8ec464f --- /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 + +Fix support for discontinuous memory + +Signed-off-by: Roman Zippel +Signed-off-by: Geert Uytterhoeven +--- + 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 + #include + #include + #include +@@ -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 + #include + #include ++#include + #include + #include + #include +@@ -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 + + +- + #ifdef CONFIG_SUN3 + #include + #else + #include + #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 ++#include + #include + #include + +-#ifdef CONFIG_AMIGA +-#include +-#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 000000000..823760cee --- /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 +--- + 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 000000000..71342f24a --- /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 + +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 + +Signed-off-by: Roman Zippel + +--- + 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 000000000..118979186 --- /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 + +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 +Signed-off-by: Roman Zippel +Signed-off-by: Geert Uytterhoeven +--- + 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 ++ * ++ * which, in turn, was ++ * ++ * Based on atari_SCC.c which was ++ * Copyright 1994-95 Roman Hodek ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++#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 000000000..af3401833 --- /dev/null +++ b/debian/patches/bugfix/m68k/634-atari_scsi.diff @@ -0,0 +1,228 @@ +Cc: James E.J. Bottomley , + linux-scsi@vger.kernel.org +Subject: [PATCH] m68k: Atari SCSI revival + +From: Michael Schmitz + +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 +Signed-off-by: Roman Zippel +Signed-off-by: Geert Uytterhoeven +--- + 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 000000000..2aed8c8c8 --- /dev/null +++ b/debian/patches/bugfix/m68k/635-atari_input.diff @@ -0,0 +1,1162 @@ +Cc: Dmitry Torokhov , + linux-input@atrey.karlin.mff.cuni.cz +Subject: [PATCH] m68k: Atari keyboard and mouse support. + +From: Michael Schmitz + +Atari keyboard and mouse support. +(reformating and Kconfig fixes by Roman Zippel) + +Signed-off-by: Michael Schmitz +Signed-off-by: Roman Zippel +Signed-off-by: Geert Uytterhoeven +--- + 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++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 , or by paper mail: ++ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Michael Schmitz "); ++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 ++ */ ++ ++ ++/* ++ * 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 ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Michael Schmitz "); ++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 000000000..da79fd9df --- /dev/null +++ b/debian/patches/bugfix/m68k/636-atafb.diff @@ -0,0 +1,5530 @@ +Cc: Antonino Daplas , + James Simmons , + linux-fbdev-devel@lists.sourceforge.net +Subject: [PATCH] m68k: Atari fb revival + +From: Michael Schmitz + +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 +Signed-off-by: Roman Zippel +Signed-off-by: Geert Uytterhoeven +--- + 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 + #include + +-#include