]> git.neil.brown.name Git - history.git/commitdiff
Import 2.3.14pre2 2.3.14pre2
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:26:54 +0000 (15:26 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:26:54 +0000 (15:26 -0500)
126 files changed:
Documentation/Configure.help
Documentation/isapnp.txt [new file with mode: 0644]
MAINTAINERS
arch/alpha/kernel/machvec.h
arch/alpha/lib/io.c
arch/i386/defconfig
arch/i386/kernel/setup.c
arch/m68k/Makefile
arch/m68k/amiga/amiints.c
arch/m68k/amiga/cia.c
arch/m68k/amiga/config.c
arch/m68k/config.in
arch/m68k/kernel/entry.S
arch/m68k/kernel/head.S
arch/m68k/kernel/ints.c
arch/m68k/kernel/m68k_defs.h
arch/m68k/kernel/process.c
arch/m68k/kernel/ptrace.c
arch/m68k/kernel/signal.c
arch/m68k/kernel/traps.c
arch/m68k/math-emu/Makefile [new file with mode: 0644]
arch/m68k/math-emu/fp_arith.c [new file with mode: 0644]
arch/m68k/math-emu/fp_arith.h [new file with mode: 0644]
arch/m68k/math-emu/fp_cond.S [new file with mode: 0644]
arch/m68k/math-emu/fp_decode.h [new file with mode: 0644]
arch/m68k/math-emu/fp_emu.h [new file with mode: 0644]
arch/m68k/math-emu/fp_entry.S [new file with mode: 0644]
arch/m68k/math-emu/fp_log.c [new file with mode: 0644]
arch/m68k/math-emu/fp_move.S [new file with mode: 0644]
arch/m68k/math-emu/fp_movem.S [new file with mode: 0644]
arch/m68k/math-emu/fp_scan.S [new file with mode: 0644]
arch/m68k/math-emu/fp_trig.c [new file with mode: 0644]
arch/m68k/math-emu/fp_trig.h [new file with mode: 0644]
arch/m68k/math-emu/fp_util.S [new file with mode: 0644]
arch/m68k/math-emu/multi_arith.h [new file with mode: 0644]
arch/m68k/q40/README
arch/m68k/q40/config.c
arch/m68k/q40/q40ints.c
drivers/block/floppy.c
drivers/char/busmouse.c
drivers/char/q40_keyb.c
drivers/isdn/avmb1/b1.c
drivers/isdn/avmb1/b1isa.c
drivers/isdn/avmb1/b1pcmcia.c
drivers/isdn/avmb1/t1isa.c
drivers/isdn/divert/divert_init.c
drivers/isdn/divert/isdn_divert.c
drivers/isdn/divert/isdn_divert.h
drivers/isdn/eicon/eicon.h
drivers/isdn/eicon/eicon_idi.c
drivers/isdn/eicon/eicon_idi.h
drivers/isdn/eicon/eicon_io.c
drivers/isdn/eicon/eicon_isa.c
drivers/isdn/eicon/eicon_pci.c
drivers/isdn/hisax/bkm_a4t.c
drivers/isdn/hisax/bkm_a8.c
drivers/isdn/hisax/callc.c
drivers/isdn/hisax/elsa_ser.c
drivers/isdn/hisax/gazel.c
drivers/isdn/hisax/hfc_pci.c
drivers/isdn/hisax/isdnl1.c
drivers/isdn/hisax/isurf.c
drivers/isdn/isdn_bsdcomp.c
drivers/isdn/isdn_tty.h
drivers/isdn/isdn_ttyfax.c
drivers/net/a2065.c
drivers/net/apne.c
drivers/net/ariadne.c
drivers/net/ariadne2.c
drivers/net/hydra.c
drivers/parport/parport_mfc3.c
drivers/pnp/Config.in
drivers/pnp/Makefile
drivers/pnp/isapnp.c [new file with mode: 0644]
drivers/pnp/isapnp_proc.c [new file with mode: 0644]
drivers/scsi/53c7xx.c
drivers/scsi/oktagon_esp.c
drivers/scsi/scsi_error.c
drivers/sound/lowlevel/awe_compat-fbsd.h [deleted file]
drivers/sound/lowlevel/awe_compat-linux.h [deleted file]
drivers/usb/audio.c
drivers/usb/hub.c
drivers/usb/mouse.c
drivers/usb/proc_usb.c
drivers/usb/uhci.c
drivers/usb/uhci.h
drivers/usb/usb-debug.c
drivers/usb/usb.c
drivers/usb/usb.h
drivers/video/clgenfb.c
drivers/video/offb.c
drivers/video/tgafb.c
drivers/video/vga.h
drivers/video/vgacon.c
fs/partitions/Config.in
fs/partitions/amiga.c
include/asm-alpha/compiler.h
include/asm-alpha/core_apecs.h
include/asm-alpha/core_cia.h
include/asm-alpha/core_lca.h
include/asm-alpha/core_mcpcia.h
include/asm-alpha/core_polaris.h
include/asm-alpha/core_pyxis.h
include/asm-alpha/core_t2.h
include/asm-alpha/core_tsunami.h
include/asm-alpha/io.h
include/asm-alpha/jensen.h
include/asm-alpha/machvec.h
include/asm-alpha/smp.h
include/asm-alpha/vga.h
include/asm-m68k/fpu.h
include/asm-m68k/irq.h
include/asm-m68k/math-emu.h [new file with mode: 0644]
include/asm-m68k/setup.h
include/linux/cyclomx.h
include/linux/ioport.h
include/linux/isapnp.h [new file with mode: 0644]
include/linux/isdn.h
include/linux/isdn_ppp.h
include/linux/isdnif.h
include/linux/pci.h
include/linux/sched.h
init/main.c
kernel/printk.c
mm/vmscan.c
net/netsyms.c

index 6c63d56dd17c17d2269081aec64c4608e9117a72..11846eec1ce9a58eb2bbac1aa360190ab1eb7778 100644 (file)
@@ -10663,6 +10663,33 @@ CONFIG_M68060
   If you anticipate running this kernel on a computer with a MC68060
   processor, say Y. Otherwise, say N.
 
+Math emulation support
+CONFIG_M68KFPU_EMU
+  At some point in the future, this will cause floating-point math
+  instructions to be emulated by the kernel on machines that lack a
+  floating-point math coprocessor.  Thrill-seekers and chronically
+  sleep-deprived psychotic hacker types can say Y now, everyone else
+  should probably wait a while.
+
+Math emulation only kernel
+CONFIG_M68KFPU_EMU_ONLY
+  This option prevents any floating-point instructions from being
+  compiled into the kernel, thereby the kernel doesn't save any
+  floating point context anymore during task switches, so this
+  kernel will only be usable on machines without a floating-point
+  math coprocessor. This makes the kernel a bit faster as no tests
+  needs to be executed whether a floating-point instruction in the
+  kernel should be executed or not.
+
+Math emulation extra precision
+CONFIG_M68KFPU_EMU_EXTRAPREC
+  The fpu uses normally a few bit more during calculations for
+  correct rounding, the emulator can (often) do the same but this
+  extra calculation can cost quite some time, so you can disable
+  it here. The emulator will then "only" calculate with a 64 bit
+  mantissa and round slightly incorrect, what is more then enough
+  for normal usage.
+
 Advanced processor options
 CONFIG_ADVANCED_CPU
   This gives you access to some advanced options for the CPU. The
diff --git a/Documentation/isapnp.txt b/Documentation/isapnp.txt
new file mode 100644 (file)
index 0000000..5791260
--- /dev/null
@@ -0,0 +1,147 @@
+ISA Plug & Play support by Jaroslav Kysela <perex@suse.cz>
+=========================================================
+
+Interface /proc/isapnp
+======================
+
+Read commands:
+--------------
+
+No comment..
+
+Write commands:
+---------------
+
+With the write interface you can simply activate or modify the configuration
+for ISA Plug & Play devices. It is mainly useable for drivers which don't
+use the ISA Plug & Play kernel support yet.
+
+card <idx> <vendor>    - select PnP device by vendor identification
+csn <CSN>              - select PnP device by CSN
+dev <idx> <logdev>     - select logical device
+auto                   - run autoconfigure
+activate               - activate logical device
+deactivate             - deactivate logical device
+port <idx> <value>     - set port 0-7 to value
+irq <idx> <value>      - set IRQ 0-1 to value
+dma <idx> <value>      - set DMA 0-1 to value
+memory <idx> <value>   - set memory 0-3 to value
+poke <reg> <value>     - poke configuration byte to selected register
+pokew <reg> <value>    - poke configuration word to selected register
+poked <reg> <value>    - poke configuration dword to selected register
+
+Explanation:
+       - variable <idx> begins with zero
+       - variable <CSN> begins with one
+       - <vendor> is in form 'PNP0000'
+       - <logdev> is in form 'PNP0000'
+
+Example:
+
+cat > /proc/isapnp <<EOF
+card 0 CSC7537
+dev 0 CSC0000
+port 0 0x534
+port 1 0x388
+port 2 0x220
+irq 0 5
+dma 0 1
+dma 1 3
+poke 0x70 9
+activate
+logdev 0 CSC0001
+port 0 0x240
+activate
+EOF
+
+Information for developers
+==========================
+
+Finding appropriate device
+--------------------------
+
+extern struct pci_bus *isapnp_find_card(unsigned short vendor,
+                                        unsigned short device,
+                                        struct pci_bus *from);
+
+The above function finds a ISA PnP card. For the vendor device should
+be used ISAPNP_VENDOR(a,b,c) where a,b,c are characters or integers.
+For the device number should be used ISAPNP_DEVICE(x) macro where x is
+integer value. Both vendor and device numbers can be get from contents
+of the /proc/isapnp file.
+
+extern struct pci_dev *isapnp_find_dev(struct pci_bus *card,
+                                       unsigned short vendor,
+                                       unsigned short function,
+                                       struct pci_dev *from);
+
+The above function finds the ISA PnP device. If card is NULL, then
+the global search mode is used (all devices are used for the searching).
+Otherwise only devices which belongs to the specified card are verified.
+For the function number can be used ISAPNP_FUNCTION(x) macro which works
+similarly as the ISAPNP_DEVICE(x) macro.
+
+ISA PnP configuration
+=====================
+
+There are two ways how can be ISA PnP interface used.
+
+First way is lowlevel
+---------------------
+
+All ISA PNP configuration registers are accessible via lowlevel
+isapnp_cfg_(set|get)_(byte|word|dword) functions.
+
+Before any lowlevel function 
+The function isapnp_cfg_begin() must be called before any lowlevel function.
+The function isapnp_cfg_end() must be always called after configuration
+otherwise the access to the ISA PnP configuration functions will be blocked.
+
+Second way is auto-configuration
+--------------------------------
+
+These two functions gives to the driver the real power of the ISA PnP
+feature. First function dev->prepare() only initialize the resource
+members in the device structure. This structure contains all resources
+set to auto configuration values after the initialization. The driver for
+ISA PnP device may modify (or not) some resources to skip auto configuration
+for the given resource.
+
+The function isapnp_configure does:
+       - resources which have the auto configuration value are configured
+       - the auto configuration is created using ISA PnP resource map
+       - the function writes configuration to ISA PnP configuration registers
+       - the function returns to the caller actual used resources
+
+Example (game port initialization)
+==================================
+
+/*** initialization ***/
+
+       struct pci_dev *dev;
+
+       /* find the first game port, use standard PnP IDs */
+       dev = isapnp_find_dev(NULL,
+                             ISAPNP_VENDOR('P','N','P'),
+                             ISAPNP_FUNCTION(0xb02f),
+                             NULL);
+       if (!dev)
+               return -ENODEV;
+       if (dev->prepare(dev)<0)
+               return -EAGAIN;
+       if (!dev->ro) {
+               /* override resource */
+               if (user_port != USER_PORT_AUTO_VALUE)
+                       dev->resource[0].start = user_port;
+       }
+       if (dev->activate(dev)<0) {
+               printk("isapnp configure failed (out of resources?)\n");
+               return -ENOMEM;
+       }
+       user_port = dev->resource[0].start;             /* get real port */
+
+/*** deactivation ***/
+
+       /* to deactivate use: */
+       if (dev)
+               dev->deactivate(dev);
index 7ab5c19b4bca7cb4829e6381921090acc2d7f371..0b7a55d323ba050a387b39eac5232b68b35ffb0a 100644 (file)
@@ -377,7 +377,7 @@ S:  Maintained
 
 HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series
 P:     Jaroslav Kysela
-M:     perex@jcu.cz
+M:     perex@suse.cz
 S:     Maintained
 
 IBM MCA SCSI SUBSYSTEM DRIVER
@@ -434,6 +434,11 @@ L:      linux-irda@list.uit.no
 W:      http://www.cs.uit.no/linux-irda/
 S:      Maintained
 
+ISAPNP
+P:     Jaroslav Kysela
+M:     perex@suse.cz
+S:     Maintained
+
 ISDN SUBSYSTEM
 P:     Fritz Elfert
 M:     fritz@wuemaus.franken.de
index 54fc1f914294e8de343ceb0d633cde9f66debe05..ff25662060fd46f9dc04c2c8584bbf826b33407a 100644 (file)
@@ -71,7 +71,8 @@
        mv_writew:              CAT(low1,_writew),                      \
        mv_writel:              CAT(low1,_writel),                      \
        mv_writeq:              CAT(low1,_writeq),                      \
-       mv_dense_mem:           CAT(low2,_dense_mem)
+       mv_ioremap:             CAT(low2,_ioremap),                     \
+       mv_is_ioaddr:           CAT(low2,_is_ioaddr)
 
 #define IO(UP,low1,low2)                                               \
        IO_LITE(UP,low1,low2),                                          \
index 71ba9d4bf6b0e1f0f8984a6dc2a190e10f0681ae..4e6839bddcdb3318aa7d6d613171222f2948073c 100644 (file)
@@ -37,45 +37,96 @@ void _outl(unsigned int b, unsigned long addr)
        __outl(b, addr);
 }
 
+unsigned long ___raw_readb(unsigned long addr)
+{
+       return __readb(addr);
+}
+
+unsigned long ___raw_readw(unsigned long addr)
+{
+       return __readw(addr);
+}
+
+unsigned long ___raw_readl(unsigned long addr)
+{
+       return __readl(addr);
+}
+
+unsigned long ___raw_readq(unsigned long addr)
+{
+       return __readq(addr);
+}
 
 unsigned long _readb(unsigned long addr)
 {
-       return __readb(addr);
+       unsigned long r = __readb(addr);
+       mb();
+       return r;
 }
 
 unsigned long _readw(unsigned long addr)
 {
-       return __readw(addr);
+       unsigned long r = __readw(addr);
+       mb();
+       return r;
 }
 
 unsigned long _readl(unsigned long addr)
 {
-       return __readl(addr);
+       unsigned long r = __readl(addr);
+       mb();
+       return r;
 }
 
 unsigned long _readq(unsigned long addr)
 {
-       return __readq(addr);
+       unsigned long r = __readq(addr);
+       mb();
+       return r;
+}
+
+void ___raw_writeb(unsigned char b, unsigned long addr)
+{
+       __writeb(b, addr);
+}
+
+void ___raw_writeb(unsigned short b, unsigned long addr)
+{
+       __writew(b, addr);
+}
+
+void ___raw_writel(unsigned int b, unsigned long addr)
+{
+       __writel(b, addr);
+}
+
+void ___raw_writeq(unsigned long b, unsigned long addr)
+{
+       __writeq(b, addr);
 }
 
 void _writeb(unsigned char b, unsigned long addr)
 {
        __writeb(b, addr);
+       mb();
 }
 
 void _writew(unsigned short b, unsigned long addr)
 {
        __writew(b, addr);
+       mb();
 }
 
 void _writel(unsigned int b, unsigned long addr)
 {
        __writel(b, addr);
+       mb();
 }
 
 void _writeq(unsigned long b, unsigned long addr)
 {
        __writeq(b, addr);
+       mb();
 }
 
 /*
@@ -363,7 +414,7 @@ void _memcpy_fromio(void * to, unsigned long from, long count)
        if (count >= 8 && ((long)to & 7) == (from & 7)) {
                count -= 8;
                do {
-                       *(u64 *)to = readq(from);
+                       *(u64 *)to = __raw_readq(from);
                        count -= 8;
                        to += 8;
                        from += 8;
@@ -374,7 +425,7 @@ void _memcpy_fromio(void * to, unsigned long from, long count)
        if (count >= 4 && ((long)to & 3) == (from & 3)) {
                count -= 4;
                do {
-                       *(u32 *)to = readl(from);
+                       *(u32 *)to = __raw_readl(from);
                        count -= 4;
                        to += 4;
                        from += 4;
@@ -385,7 +436,7 @@ void _memcpy_fromio(void * to, unsigned long from, long count)
        if (count >= 2 && ((long)to & 1) == (from & 1)) {
                count -= 2;
                do {
-                       *(u16 *)to = readw(from);
+                       *(u16 *)to = __raw_readw(from);
                        count -= 2;
                        to += 2;
                        from += 2;
@@ -394,7 +445,7 @@ void _memcpy_fromio(void * to, unsigned long from, long count)
        }
 
        while (count > 0) {
-               *(u8 *) to = readb(from);
+               *(u8 *) to = __raw_readb(from);
                count--;
                to++;
                from++;
@@ -414,7 +465,7 @@ void _memcpy_toio(unsigned long to, const void * from, long count)
        if (count >= 8 && (to & 7) == ((long)from & 7)) {
                count -= 8;
                do {
-                       writeq(*(const u64 *)from, to);
+                       __raw_writeq(*(const u64 *)from, to);
                        count -= 8;
                        to += 8;
                        from += 8;
@@ -425,7 +476,7 @@ void _memcpy_toio(unsigned long to, const void * from, long count)
        if (count >= 4 && (to & 3) == ((long)from & 3)) {
                count -= 4;
                do {
-                       writel(*(const u32 *)from, to);
+                       __raw_writel(*(const u32 *)from, to);
                        count -= 4;
                        to += 4;
                        from += 4;
@@ -436,7 +487,7 @@ void _memcpy_toio(unsigned long to, const void * from, long count)
        if (count >= 2 && (to & 1) == ((long)from & 1)) {
                count -= 2;
                do {
-                       writew(*(const u16 *)from, to);
+                       __raw_writeb(*(const u16 *)from, to);
                        count -= 2;
                        to += 2;
                        from += 2;
@@ -445,11 +496,12 @@ void _memcpy_toio(unsigned long to, const void * from, long count)
        }
 
        while (count > 0) {
-               writeb(*(const u8 *) from, to);
+               __raw_writeb(*(const u8 *) from, to);
                count--;
                to++;
                from++;
        }
+       mb();
 }
 
 /*
@@ -459,21 +511,21 @@ void _memset_c_io(unsigned long to, unsigned long c, long count)
 {
        /* Handle any initial odd byte */
        if (count > 0 && (to & 1)) {
-               writeb(c, to);
+               __raw_writeb(c, to);
                to++;
                count--;
        }
 
        /* Handle any initial odd halfword */
        if (count >= 2 && (to & 2)) {
-               writew(c, to);
+               __raw_writeb(c, to);
                to += 2;
                count -= 2;
        }
 
        /* Handle any initial odd word */
        if (count >= 4 && (to & 4)) {
-               writel(c, to);
+               __raw_writel(c, to);
                to += 4;
                count -= 4;
        }
@@ -483,7 +535,7 @@ void _memset_c_io(unsigned long to, unsigned long c, long count)
        count -= 8;
        if (count >= 0) {
                do {
-                       writeq(c, to);
+                       __raw_writeq(c, to);
                        to += 8;
                        count -= 8;
                } while (count >= 0);
@@ -492,20 +544,21 @@ void _memset_c_io(unsigned long to, unsigned long c, long count)
 
        /* The tail is word-aligned if we still have count >= 4 */
        if (count >= 4) {
-               writel(c, to);
+               __raw_writel(c, to);
                to += 4;
                count -= 4;
        }
 
        /* The tail is half-word aligned if we have count >= 2 */
        if (count >= 2) {
-               writew(c, to);
+               __raw_writeb(c, to);
                to += 2;
                count -= 2;
        }
 
        /* And finally, one last byte.. */
        if (count) {
-               writeb(c, to);
+               __raw_writeb(c, to);
        }
+       mb();
 }
index f8494ca16d95447a853ee899bb45697313d0c153..cbc76fa92c8dcb8d71e21c557c71db7fea4ef1fe 100644 (file)
@@ -69,6 +69,12 @@ CONFIG_BINFMT_MISC=y
 # CONFIG_I2O_SCSI is not set
 # CONFIG_I2O_PROC is not set
 
+#
+# Plug and Play configuration
+#
+CONFIG_PNP=y
+CONFIG_ISAPNP=y
+
 #
 # Block devices
 #
index a94fa0a160e63e7396380bb035eeb8f9c51cbf9a..2d51e51a364bf850f945aceedd8c2de670fb6078 100644 (file)
@@ -93,7 +93,7 @@ extern int rd_image_start;    /* starting block # of image */
 #endif
 
 extern int root_mountflags;
-extern int _etext, _edata, _end;
+extern int _text, _etext, _edata, _end;
 extern unsigned long cpu_hz;
 
 /*
@@ -251,7 +251,7 @@ visws_get_board_type_and_rev(void)
 static char command_line[COMMAND_LINE_SIZE] = { 0, };
        char saved_command_line[COMMAND_LINE_SIZE];
 
-struct resource standard_resources[] = {
+struct resource standard_io_resources[] = {
        { "dma1", 0x00, 0x1f },
        { "pic1", 0x20, 0x3f },
        { "timer", 0x40, 0x5f },
@@ -262,14 +262,90 @@ struct resource standard_resources[] = {
        { "fpu", 0xf0, 0xff }
 };
 
-/* For demonstration purposes only.. */
-#define keyboard_resources (standard_resources+3)
-struct resource kbd_status_resource = { "status", 0x60, 0x60 };
+#define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource))
+
+/* System RAM - interrupted by the 640kB-1M hole */
+#define code_resource (ram_resources[3])
+#define data_resource (ram_resources[4])
+static struct resource ram_resources[] = {
+       { "System RAM", 0x000000, 0x09ffff, IORESOURCE_BUSY },
+       { "System RAM", 0x100000, 0x100000, IORESOURCE_BUSY },
+       { "Video RAM area", 0x0a0000, 0x0bffff },
+       { "Kernel code", 0x100000, 0 },
+       { "Kernel data", 0, 0 }
+};
+
+/* System ROM resources */
+#define MAXROMS 6
+static struct resource rom_resources[MAXROMS] = {
+       { "System ROM", 0xF0000, 0xFFFFF, IORESOURCE_BUSY },
+       { "Video ROM", 0xc0000, 0xc7fff }
+};
+
+#define romsignature(x) (*(unsigned short *)(x) == 0xaa55)
+
+static void __init probe_roms(void)
+{
+       int roms = 1;
+       unsigned long base;
+       unsigned char *romstart;
+
+       request_resource(&iomem_resource, rom_resources+0);
+
+       /* Video ROM is standard at C000:0000 - C7FF:0000, check signature */
+       for (base = 0xC0000; base < 0xE0000; base += 2048) {
+               romstart = bus_to_virt(base);
+               if (!romsignature(romstart))
+                       continue;
+               request_resource(&iomem_resource, rom_resources + roms);
+               roms++;
+               break;
+       }
+
+       /* Extension roms at C800:0000 - DFFF:0000 */
+       for (base = 0xC8000; base < 0xE0000; base += 2048) {
+               unsigned long length;
 
-#define STANDARD_RESOURCES (sizeof(standard_resources)/sizeof(struct resource))
+               romstart = bus_to_virt(base);
+               if (!romsignature(romstart))
+                       continue;
+               length = romstart[2] * 512;
+               if (length) {
+                       unsigned int i;
+                       unsigned char chksum;
+
+                       chksum = 0;
+                       for (i = 0; i < length; i++)
+                               chksum += romstart[i];
+
+                       /* Good checksum? */
+                       if (!chksum) {
+                               rom_resources[roms].start = base;
+                               rom_resources[roms].end = base + length - 1;
+                               rom_resources[roms].name = "Extension ROM";
+
+                               request_resource(&iomem_resource, rom_resources + roms);
+                               roms++;
+                               if (roms >= MAXROMS)
+                                       return;
+                       }
+               }
+       }
+
+       /* Final check for motherboard extension rom at E000:0000 */
+       base = 0xE0000;
+       romstart = bus_to_virt(base);
+
+       if (romsignature(romstart)) {
+               rom_resources[roms].start = base;
+               rom_resources[roms].end = base + 65535;
+               rom_resources[roms].name = "Extension ROM";
 
-__initfunc(void setup_arch(char **cmdline_p,
-       unsigned long * memory_start_p, unsigned long * memory_end_p))
+               request_resource(&iomem_resource, rom_resources + roms);
+       }
+}
+
+void __init setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p)
 {
        unsigned long memory_start, memory_end;
        char c = ' ', *to = command_line, *from = COMMAND_LINE;
@@ -301,6 +377,8 @@ __initfunc(void setup_arch(char **cmdline_p,
        }
 #endif
 
+       ram_resources[1].end = memory_end-1;
+
        memory_end &= PAGE_MASK;
 #ifdef CONFIG_BLK_DEV_RAM
        rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
@@ -310,11 +388,16 @@ __initfunc(void setup_arch(char **cmdline_p,
        if (!MOUNT_ROOT_RDONLY)
                root_mountflags &= ~MS_RDONLY;
        memory_start = (unsigned long) &_end;
-       init_mm.start_code = PAGE_OFFSET;
+       init_mm.start_code = (unsigned long) &_text;
        init_mm.end_code = (unsigned long) &_etext;
        init_mm.end_data = (unsigned long) &_edata;
        init_mm.brk = (unsigned long) &_end;
 
+       code_resource.start = virt_to_bus(&_text);
+       code_resource.end = virt_to_bus(&_etext)-1;
+       data_resource.start = virt_to_bus(&_etext);
+       data_resource.end = virt_to_bus(&_edata)-1;
+
        /* Save unparsed command line copy for /proc/cmdline */
        memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
        saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
@@ -339,6 +422,8 @@ __initfunc(void setup_arch(char **cmdline_p,
                                        memory_end = memory_end << 20;
                                        from++;
                                }
+                               if (memory_end > ram_resources[1].end)
+                                       ram_resources[1].end = memory_end-1;
                        }
                }
                c = *(from++);
@@ -351,6 +436,14 @@ __initfunc(void setup_arch(char **cmdline_p,
        *to = '\0';
        *cmdline_p = command_line;
 
+       /* Request the standard RAM and ROM resources - they eat up PCI memory space */
+       request_resource(&iomem_resource, ram_resources+0);
+       request_resource(&iomem_resource, ram_resources+1);
+       request_resource(&iomem_resource, ram_resources+2);
+       request_resource(ram_resources+1, &code_resource);
+       request_resource(ram_resources+1, &data_resource);
+       probe_roms();
+
 #define VMALLOC_RESERVE        (128 << 20)     /* 128MB for vmalloc and initrd */
 #define MAXMEM ((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE))
 
@@ -386,9 +479,8 @@ __initfunc(void setup_arch(char **cmdline_p,
 #endif
 
        /* request I/O space for devices used on all i[345]86 PCs */
-       for (i = 0; i < STANDARD_RESOURCES; i++)
-               request_resource(&ioport_resource, standard_resources+i);
-       request_resource(keyboard_resources, &kbd_status_resource);
+       for (i = 0; i < STANDARD_IO_RESOURCES; i++)
+               request_resource(&ioport_resource, standard_io_resources+i);
 
 #ifdef CONFIG_VT
 #if defined(CONFIG_VGA_CONSOLE)
index 3a5957b095e2cf64919fae67c92175b91291d1c8..bc914b9b0e60132ef55ac27f25b355e5fbda334d 100644 (file)
@@ -116,6 +116,11 @@ CORE_FILES := $(CORE_FILES) arch/m68k/ifpsp060/ifpsp.o
 SUBDIRS := $(SUBDIRS) arch/m68k/ifpsp060
 endif
 
+ifdef CONFIG_M68KFPU_EMU
+CORE_FILES := $(CORE_FILES) arch/m68k/math-emu/mathemu.o
+SUBDIRS := $(SUBDIRS) arch/m68k/math-emu
+endif
+
 lilo:  vmlinux
        if [ -f $(INSTALL_PATH)/vmlinux ]; then mv -f $(INSTALL_PATH)/vmlinux $(INSTALL_PATH)/vmlinux.old; fi
        if [ -f $(INSTALL_PATH)/System.map ]; then mv -f $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
index 4fb8864568502edac750247e534ead4cf4cf77dd..57a92b99c52289175e3166c53951d0c5834a8563 100644 (file)
  *                           called again.
  *           The whole interrupt handling for CIAs is moved to cia.c
  *           /Roman Zippel
+ *
+ * 07/08/99: rewamp of the interrupt handling - we now have two types of
+ *           interrupts, normal and fast handlers, fast handlers being
+ *           marked with SA_INTERRUPT and runs with all other interrupts
+ *           disabled. Normal interrupts disable their own source but
+ *           run with all other interrupt sources enabled.
+ *           PORTS and EXTER interrupts are always shared even if the
+ *           drivers do not explicitly mark this when calling
+ *           request_irq which they really should do.
+ *           This is similar to the way interrupts are handled on all
+ *           other architectures and makes a ton of sense besides
+ *           having the advantage of making it easier to share
+ *           drivers.
+ *           /Jes
  */
 
 #include <linux/types.h>
@@ -70,7 +84,7 @@ static void ami_badint(int irq, void *dev_id, struct pt_regs *fp)
  * the amiga IRQ handling routines.
  */
 
-__initfunc(void amiga_init_IRQ(void))
+void __init amiga_init_IRQ(void)
 {
        int i;
 
@@ -81,7 +95,7 @@ __initfunc(void amiga_init_IRQ(void))
                } else {
                        ami_irq_list[i] = new_irq_node();
                        ami_irq_list[i]->handler = ami_badint;
-                       ami_irq_list[i]->flags   = IRQ_FLG_STD;
+                       ami_irq_list[i]->flags   = 0;
                        ami_irq_list[i]->dev_id  = NULL;
                        ami_irq_list[i]->devname = NULL;
                        ami_irq_list[i]->next    = NULL;
@@ -117,19 +131,18 @@ static inline void amiga_insert_irq(irq_node_t **list, irq_node_t *node)
 
        cur = *list;
 
-       if (node->flags & IRQ_FLG_FAST) {
-               node->flags &= ~IRQ_FLG_SLOW;
-               while (cur && cur->flags & IRQ_FLG_FAST) {
-                       list = &cur->next;
-                       cur = cur->next;
-               }
-       } else if (node->flags & IRQ_FLG_SLOW) {
-               while (cur) {
+       if (node->flags & SA_INTERRUPT) {
+               if (node->flags & SA_SHIRQ)
+                       return;
+               /*
+                * There should never be more than one
+                */
+               while (cur && cur->flags & SA_INTERRUPT) {
                        list = &cur->next;
                        cur = cur->next;
                }
        } else {
-               while (cur && !(cur->flags & IRQ_FLG_SLOW)) {
+               while (cur) {
                        list = &cur->next;
                        cur = cur->next;
                }
@@ -168,13 +181,15 @@ static inline void amiga_delete_irq(irq_node_t **list, void *dev_id)
  *                     If the addition was successful, it returns 0.
  */
 
-int amiga_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+int amiga_request_irq(unsigned int irq,
+                     void (*handler)(int, void *, struct pt_regs *),
                       unsigned long flags, const char *devname, void *dev_id)
 {
        irq_node_t *node;
 
        if (irq >= AMI_IRQS) {
-               printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__, irq, devname);
+               printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__,
+                       irq, devname);
                return -ENXIO;
        }
 
@@ -190,6 +205,11 @@ int amiga_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_r
                return cia_request_irq(&ciaa_base, irq - IRQ_AMIGA_CIAA,
                                       handler, flags, devname, dev_id);
 
+       /*
+        * IRQ_AMIGA_PORTS & IRQ_AMIGA_EXTER defaults to shared,
+        * we could add a check here for the SA_SHIRQ flag but all drivers
+        * should be aware of sharing anyway.
+        */
        if (ami_servers[irq]) {
                if (!(node = new_irq_node()))
                        return -ENOMEM;
@@ -200,18 +220,6 @@ int amiga_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_r
                node->next    = NULL;
                amiga_insert_irq(&ami_irq_list[irq], node);
        } else {
-               if (!(ami_irq_list[irq]->flags & IRQ_FLG_STD)) {
-                       if (ami_irq_list[irq]->flags & IRQ_FLG_LOCK) {
-                               printk("%s: IRQ %d from %s is not replaceable\n",
-                                      __FUNCTION__, irq, ami_irq_list[irq]->devname);
-                               return -EBUSY;
-                       }
-                       if (!(flags & IRQ_FLG_REPLACE)) {
-                               printk("%s: %s can't replace IRQ %d from %s\n",
-                                      __FUNCTION__, devname, irq, ami_irq_list[irq]->devname);
-                               return -EBUSY;
-                       }
-               }
                ami_irq_list[irq]->handler = handler;
                ami_irq_list[irq]->flags   = flags;
                ami_irq_list[irq]->dev_id  = dev_id;
@@ -255,7 +263,7 @@ void amiga_free_irq(unsigned int irq, void *dev_id)
                        printk("%s: removing probably wrong IRQ %d from %s\n",
                               __FUNCTION__, irq, ami_irq_list[irq]->devname);
                ami_irq_list[irq]->handler = ami_badint;
-               ami_irq_list[irq]->flags   = IRQ_FLG_STD;
+               ami_irq_list[irq]->flags   = 0;
                ami_irq_list[irq]->dev_id  = NULL;
                ami_irq_list[irq]->devname = NULL;
                custom.intena = ami_intena_vals[irq];
@@ -345,37 +353,58 @@ inline void amiga_do_irq(int irq, struct pt_regs *fp)
 void amiga_do_irq_list(int irq, struct pt_regs *fp, struct irq_server *server)
 {
        irq_node_t *node, *slow_nodes;
-       unsigned short flags;
+       unsigned short flags, intena;
 
        kstat.irqs[0][SYS_IRQS + irq]++;
        if (server->count++)
                server->reentrance = 1;
-       /* serve first fast and normal handlers */
-       for (node = ami_irq_list[irq];
-            node && (!(node->flags & IRQ_FLG_SLOW));
-            node = node->next)
-               node->handler(irq, node->dev_id, fp);
-       custom.intreq = ami_intena_vals[irq];
+
+       intena = ami_intena_vals[irq];
+       custom.intreq = intena;
+
+       /* serve first fast handlers - there can only be one of these */
+       node = ami_irq_list[irq];
+
+       /*
+        * Timer interrupts show up like this
+        */
        if (!node) {
                server->count--;
                return;
        }
+
+       if (node && (node->flags & SA_INTERRUPT)) {
+               save_flags(flags);
+               cli();
+               node->handler(irq, node->dev_id, fp);
+               restore_flags(flags);
+
+               server->count--;
+               return;
+       }
+
+       /*
+        * Disable the interrupt source in question and reenable all
+        * other interrupts. No interrupt handler should ever touch
+        * the intena flags directly!
+        */
+       custom.intena = intena;
        save_flags(flags);
-       restore_flags((flags & ~0x0700) | (fp->sr & 0x0700));
-       /* if slow handlers exists, serve them now */
+       sti();
+
        slow_nodes = node;
        for (;;) {
                for (; node; node = node->next)
                        node->handler(irq, node->dev_id, fp);
-               /* if reentrance occurred, serve slow handlers again */
-               custom.intena = ami_intena_vals[irq];
+
                if (!server->reentrance) {
                        server->count--;
-                       custom.intena = IF_SETCLR | ami_intena_vals[irq];
+                       restore_flags(flags);
+                       custom.intena = IF_SETCLR | intena;
                        return;
                }
+
                server->reentrance = 0;
-               custom.intena = IF_SETCLR | ami_intena_vals[irq];
                node = slow_nodes;
        }
 }
@@ -493,24 +522,13 @@ int amiga_get_irq_list(char *buf)
        for (i = 0; i < AMI_STD_IRQS; i++) {
                if (!(node = ami_irq_list[i]))
                        continue;
-               if (node->flags & IRQ_FLG_STD)
-                       continue;
                len += sprintf(buf+len, "ami  %2d: %10u ", i,
                               kstat.irqs[0][SYS_IRQS + i]);
                do {
-                       if (ami_servers[i]) {
-                               if (node->flags & IRQ_FLG_FAST)
-                                       len += sprintf(buf+len, "F ");
-                               else if (node->flags & IRQ_FLG_SLOW)
-                                       len += sprintf(buf+len, "S ");
-                               else
-                                       len += sprintf(buf+len, "  ");
-                       } else {
-                               if (node->flags & IRQ_FLG_LOCK)
-                                       len += sprintf(buf+len, "L ");
-                               else
-                                       len += sprintf(buf+len, "  ");
-                       }
+                       if (node->flags & SA_INTERRUPT)
+                               len += sprintf(buf+len, "F ");
+                       else
+                               len += sprintf(buf+len, "  ");
                        len += sprintf(buf+len, "%s\n", node->devname);
                        if ((node = node->next))
                                len += sprintf(buf+len, "                    ");
index 8f27234b486de0861249a1e25eb08bc7410b38a3..cda8986994aaea823a7064ca2cb7e92719256cd6 100644 (file)
@@ -94,20 +94,6 @@ int cia_request_irq(struct ciabase *base, unsigned int irq,
 {
        u_char mask;
 
-       if (!(base->irq_list[irq].flags & IRQ_FLG_STD)) {
-               if (base->irq_list[irq].flags & IRQ_FLG_LOCK) {
-                       printk("%s: IRQ %i from %s is not replaceable\n",
-                              __FUNCTION__, base->cia_irq + irq,
-                              base->irq_list[irq].devname);
-                       return -EBUSY;
-               }
-               if (!(flags & IRQ_FLG_REPLACE)) {
-                       printk("%s: %s can't replace IRQ %i from %s\n", __FUNCTION__,
-                              devname, base->cia_irq + irq,
-                              base->irq_list[irq].devname);
-                       return -EBUSY;
-               }
-       }
        base->irq_list[irq].handler = handler;
        base->irq_list[irq].flags   = flags;
        base->irq_list[irq].dev_id  = dev_id;
@@ -128,7 +114,7 @@ void cia_free_irq(struct ciabase *base, unsigned int irq, void *dev_id)
                       base->irq_list[irq].devname);
 
        base->irq_list[irq].handler = NULL;
-       base->irq_list[irq].flags   = IRQ_FLG_STD;
+       base->irq_list[irq].flags   = 0;
 
        cia_able_irq(base, 1 << irq);
 }
@@ -153,14 +139,14 @@ static void cia_handler(int irq, void *dev_id, struct pt_regs *fp)
        amiga_do_irq_list(base->server_irq, fp, &base->server);
 }
 
-__initfunc(void cia_init_IRQ(struct ciabase *base))
+void __init cia_init_IRQ(struct ciabase *base)
 {
        int i;
 
        /* init isr handlers */
        for (i = 0; i < CIA_IRQS; i++) {
                base->irq_list[i].handler = NULL;
-               base->irq_list[i].flags   = IRQ_FLG_STD;
+               base->irq_list[i].flags   = 0;
        }
 
        /* clear any pending interrupt and turn off all interrupts */
@@ -168,7 +154,7 @@ __initfunc(void cia_init_IRQ(struct ciabase *base))
        cia_able_irq(base, CIA_ICR_ALL);
 
        /* install CIA handler */
-       request_irq(base->handler_irq, cia_handler, IRQ_FLG_LOCK, base->name, base);
+       request_irq(base->handler_irq, cia_handler, 0, base->name, base);
 
        custom.intena = IF_SETCLR | base->int_mask;
 }
@@ -179,15 +165,10 @@ int cia_get_irq_list(struct ciabase *base, char *buf)
 
        j = base->cia_irq;
        for (i = 0; i < CIA_IRQS; i++) {
-               if (!(base->irq_list[i].flags & IRQ_FLG_STD)) {
-                       len += sprintf(buf+len, "cia  %2d: %10d ", j + i,
-                                      kstat.irqs[0][SYS_IRQS + j + i]);
-                       if (base->irq_list[i].flags & IRQ_FLG_LOCK)
-                               len += sprintf(buf+len, "L ");
-                       else
-                               len += sprintf(buf+len, "  ");
-                       len += sprintf(buf+len, "%s\n", base->irq_list[i].devname);
-               }
+               len += sprintf(buf+len, "cia  %2d: %10d ", j + i,
+                              kstat.irqs[0][SYS_IRQS + j + i]);
+                       len += sprintf(buf+len, "  ");
+               len += sprintf(buf+len, "%s\n", base->irq_list[i].devname);
        }
        return len;
 }
index 37b5bde3c4eb6f49f1dc054c4c02ccf84078e03a..95eaa76f38c54855ef04dd626580c9664fb90c73 100644 (file)
@@ -173,7 +173,7 @@ int amiga_parse_bootinfo(const struct bi_record *record)
      *  Identify builtin hardware
      */
 
-__initfunc(static void amiga_identify(void))
+static void __init amiga_identify(void)
 {
   /* Fill in some default values, if necessary */
   if (amiga_eclock == 0)
@@ -334,7 +334,7 @@ __initfunc(static void amiga_identify(void))
      *  Setup the Amiga configuration info
      */
 
-__initfunc(void config_amiga(void))
+void __init config_amiga(void)
 {
   amiga_debug_init();
   amiga_identify();
@@ -446,8 +446,8 @@ __initfunc(void config_amiga(void))
 
 static unsigned short jiffy_ticks;
 
-__initfunc(static void amiga_sched_init(void (*timer_routine)(int, void *,
-                                       struct pt_regs *)))
+static void __init amiga_sched_init(void (*timer_routine)(int, void *,
+                                                         struct pt_regs *))
 {
        jiffy_ticks = (amiga_eclock+HZ/2)/HZ;
 
@@ -460,8 +460,7 @@ __initfunc(static void amiga_sched_init(void (*timer_routine)(int, void *,
         * Please don't change this to use ciaa, as it interferes with the
         * SCSI code. We'll have to take a look at this later
         */
-       request_irq(IRQ_AMIGA_CIAB_TA, timer_routine, IRQ_FLG_LOCK,
-                   "timer", NULL);
+       request_irq(IRQ_AMIGA_CIAB_TA, timer_routine, 0, "timer", NULL);
        /* start timer */
        ciab.cra |= 0x11;
 }
@@ -880,7 +879,7 @@ void amiga_serial_gets(struct console *co, char *s, int len)
 }
 #endif
 
-__initfunc(static void amiga_debug_init(void))
+static void __init amiga_debug_init(void)
 {
        if (!strcmp( m68k_debug_device, "ser" )) {
                /* no initialization required (?) */
index f1143d34f7f171cdaece77a4f6512f454dfcb11b..51a3cebc13e2a56ad7a4b21450319fddc07084e6 100644 (file)
@@ -58,6 +58,13 @@ bool '68020 support' CONFIG_M68020
 bool '68030 support' CONFIG_M68030
 bool '68040 support' CONFIG_M68040
 bool '68060 support' CONFIG_M68060
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  bool 'Math emulation support' CONFIG_M68KFPU_EMU
+  if [ "$CONFIG_M68KFPU_EMU" = "y" ]; then
+    bool 'Math emulation extra precision' CONFIG_M68KFPU_EMU_EXTRAPREC
+    bool 'Math emulation only kernel' CONFIG_M68KFPU_EMU_ONLY
+  fi
+fi
 bool 'Advanced configuration options' CONFIG_ADVANCED
 if [ "$CONFIG_ADVANCED" = "y" ]; then
   bool 'Use read-modify-write instructions' CONFIG_RMW_INSNS
index 2bdab4be75e816aa3105f42914c5aaa380a88450..1e8e7fd2f168be2e9296b3eb043a65f14c0a8f09 100644 (file)
@@ -164,6 +164,36 @@ do_delayed_trace:
        addql   #4,%sp
        jra     5b
 
+
+#if 0
+#if CONFIG_AMIGA
+SYMBOL_NAME_LABEL(ami_inthandler)
+       addql   #1,SYMBOL_NAME(local_irq_count)
+       SAVE_ALL_INT
+       GET_CURRENT(%d0)
+
+       bfextu  %sp@(PT_VECTOR){#4,#12},%d0
+       movel   %d0,%a0
+       addql   #1,%a0@(SYMBOL_NAME(kstat)+STAT_IRQ-VECOFF(VEC_SPUR))
+       movel   %a0@(SYMBOL_NAME(autoirq_list)-VECOFF(VEC_SPUR)),%a0
+
+| amiga vector int handler get the req mask instead of irq vector
+       lea     CUSTOMBASE,%a1
+       movew   %a1@(C_INTREQR),%d0
+       andw    %a1@(C_INTENAR),%d0
+
+| prepare stack (push frame pointer, dev_id & req mask)
+       pea     %sp@
+       movel   %a0@(IRQ_DEVID),%sp@-
+       movel   %d0,%sp@-
+       pea     %pc@(SYMBOL_NAME(ret_from_interrupt):w)
+       jbra    @(IRQ_HANDLER,%a0)@(0)
+
+ENTRY(nmi_handler)
+       rte
+#endif
+#endif
+
 /*
 ** This is the main interrupt handler, responsible for calling process_int()
 */
@@ -183,7 +213,7 @@ SYMBOL_NAME_LABEL(inthandler)
        jbeq    1f
        jbsr    SYMBOL_NAME(floppy_hardint)
        jbra    3f
-1:             
+1:
 #endif         
        jbsr    SYMBOL_NAME(process_int)|  process the IRQ
 3:             addql   #8,%sp                  |  pop parameters off stack
@@ -191,7 +221,7 @@ SYMBOL_NAME_LABEL(inthandler)
 SYMBOL_NAME_LABEL(ret_from_interrupt)
        subql   #1,SYMBOL_NAME(local_irq_count)
        jeq     1f
-2:     
+2:
        RESTORE_ALL
 1:
 #if 1
@@ -295,6 +325,11 @@ SYMBOL_NAME_LABEL(resume)
        movel   %sp,%a0@(TASK_THREAD+THREAD_KSP)
 
        /* save floating point context */
+#ifndef CONFIG_M68KFPU_EMU_ONLY
+#ifdef CONFIG_M68KFPU_EMU
+       tstl    SYMBOL_NAME(m68k_fputype)
+       jeq     3f
+#endif
        fsave   %a0@(TASK_THREAD+THREAD_FPSTATE)
 
 #if defined(CONFIG_M68060)
@@ -316,6 +351,7 @@ SYMBOL_NAME_LABEL(resume)
 2:     fmovemx %fp0-%fp7,%a0@(TASK_THREAD+THREAD_FPREG)
        fmoveml %fpcr/%fpsr/%fpiar,%a0@(TASK_THREAD+THREAD_FPCNTL)
 3:
+#endif /* CONFIG_M68KFPU_EMU_ONLY */
        /* Return previous task in %d1 */
        movel   %curptr,%d1
 
@@ -323,7 +359,11 @@ SYMBOL_NAME_LABEL(resume)
        movel   %a1,%curptr
 
        /* restore floating point context */
-
+#ifndef CONFIG_M68KFPU_EMU_ONLY
+#ifdef CONFIG_M68KFPU_EMU
+       tstl    SYMBOL_NAME(m68k_fputype)
+       jeq     4f
+#endif
 #if defined(CONFIG_M68060)
 #if !defined(CPU_M68060_ONLY)
        btst    #3,SYMBOL_NAME(m68k_cputype)+3
@@ -343,6 +383,8 @@ SYMBOL_NAME_LABEL(resume)
 2:     fmovemx %a1@(TASK_THREAD+THREAD_FPREG),%fp0-%fp7
        fmoveml %a1@(TASK_THREAD+THREAD_FPCNTL),%fpcr/%fpsr/%fpiar
 3:     frestore %a1@(TASK_THREAD+THREAD_FPSTATE)
+4:
+#endif /* CONFIG_M68KFPU_EMU_ONLY */
 
        /* restore the kernel stack pointer */
        movel   %a1@(TASK_THREAD+THREAD_KSP),%sp
index 361b10cb663a3681a9b730fbc87220d7590945bd..49285b86d46a18f5ba1ae209cb36ffd1982643d3 100644 (file)
@@ -503,10 +503,18 @@ func_define       putn,1
 
 .macro puts            string
 #if defined(CONSOLE) || defined(SERIAL_DEBUG)
+/* The __INITDATA stuff is a no-op when ftrace or kgdb are turned on */
+#if defined(CONFIG_FTRACE) || defined(CONFIG_KGDB)
+       bra 1f
+#endif
        __INITDATA
 .Lstr\@:
        .string "\string"
        __FINIT
+#if defined(CONFIG_FTRACE) || defined(CONFIG_KGDB)
+       .align 2
+1:
+#endif
        pea     %pc@(.Lstr\@)
        func_call       puts
        addql   #4,%sp
index 31931a920ebc70daa54bb2888306a3a45a048039..9dc6427e63209ce0db9a3a2535b297a39180e250 100644 (file)
@@ -86,14 +86,14 @@ void (*mach_free_irq) (unsigned int, void *) = dummy_free_irq;
  * the IRQ handling routines.
  */
 
-__initfunc(void init_IRQ(void))
+void __init init_IRQ(void)
 {
        int i;
 
        for (i = 0; i < SYS_IRQS; i++) {
                if (mach_default_handler)
                        irq_list[i].handler = (*mach_default_handler)[i];
-               irq_list[i].flags   = IRQ_FLG_STD;
+               irq_list[i].flags   = 0;
                irq_list[i].dev_id  = NULL;
                irq_list[i].devname = default_names[i];
        }
@@ -144,6 +144,7 @@ int sys_request_irq(unsigned int irq,
                return -ENXIO;
        }
 
+#if 0
        if (!(irq_list[irq].flags & IRQ_FLG_STD)) {
                if (irq_list[irq].flags & IRQ_FLG_LOCK) {
                        printk("%s: IRQ %d from %s is not replaceable\n",
@@ -156,6 +157,8 @@ int sys_request_irq(unsigned int irq,
                        return -EBUSY;
                }
        }
+#endif
+
        irq_list[irq].handler = handler;
        irq_list[irq].flags   = flags;
        irq_list[irq].dev_id  = dev_id;
@@ -175,7 +178,7 @@ void sys_free_irq(unsigned int irq, void *dev_id)
                       __FUNCTION__, irq, irq_list[irq].devname);
 
        irq_list[irq].handler = (*mach_default_handler)[irq];
-       irq_list[irq].flags   = IRQ_FLG_STD;
+       irq_list[irq].flags   = 0;
        irq_list[irq].dev_id  = NULL;
        irq_list[irq].devname = default_names[irq];
 }
@@ -250,9 +253,6 @@ int get_irq_list(char *buf)
                for (i = 0; i < SYS_IRQS; i++) {
                        len += sprintf(buf+len, "auto %2d: %10u ", i,
                                       i ? kstat.irqs[0][i] : num_spurious);
-                       if (irq_list[i].flags & IRQ_FLG_LOCK)
-                               len += sprintf(buf+len, "L ");
-                       else
                                len += sprintf(buf+len, "  ");
                        len += sprintf(buf+len, "%s\n", irq_list[i].devname);
                }
index 4926a6dadac17cc3d7332f0d9f88af04eb096829..374e56e27529f2621811601f1b42b34d14308241 100644 (file)
@@ -7,19 +7,29 @@
 #define TASK_FLAGS 4
 #define TASK_SIGPENDING 8
 #define TASK_NEEDRESCHED 20
-#define TASK_TSS 470
-#define TASK_MM 622
-#define TSS_KSP 0
-#define TSS_USP 4
-#define TSS_SR 8
-#define TSS_FS 10
-#define TSS_CRP 12
-#define TSS_ESP0 20
-#define TSS_FPREG 24
-#define TSS_FPCNTL 120
-#define TSS_FPSTATE 132
+#define TASK_THREAD 482
+#define TASK_MM 634
+#define TASK_ACTIVE_MM 638
+#define THREAD_KSP 0
+#define THREAD_USP 4
+#define THREAD_SR 8
+#define THREAD_FS 10
+#define THREAD_CRP 12
+#define THREAD_ESP0 20
+#define THREAD_FPREG 24
+#define THREAD_FPCNTL 120
+#define THREAD_FPSTATE 132
 #define PT_D0 32
 #define PT_ORIG_D0 36
+#define PT_D1 0
+#define PT_D2 4
+#define PT_D3 8
+#define PT_D4 12
+#define PT_D5 16
+#define PT_A0 20
+#define PT_A1 24
+#define PT_A2 28
+#define PT_PC 46
 #define PT_SR 44
 #define PT_VECTOR 50
 #define IRQ_HANDLER 0
 #define FBCON_FONT_DESC_HEIGHT 12
 #define FBCON_FONT_DESC_DATA 16
 #define FBCON_FONT_DESC_PREF 20
+#define SIGSEGV 11
+#define SEGV_MAPERR 1
+#define SIGTRAP 5
+#define TRAP_TRACE 2
 #define CUSTOMBASE -2132807680
 #define C_INTENAR 28
 #define C_INTREQR 30
index ff4819b9aa3705eb05276db68679d496879668c6..b676d5e2a0fb682002e29b66056d7384342682b5 100644 (file)
@@ -58,7 +58,7 @@ static void default_idle(void)
 {
        while(1) {
                if (!current->need_resched)
-#ifdef MACH_ATARI_ONLY
+#if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES)
                        /* block out HSYNC on the atari (falcon) */
                        __asm__("stop #0x2200" : : : "cc");
 #else
@@ -161,9 +161,10 @@ void flush_thread(void)
        unsigned long zero = 0;
        set_fs(USER_DS);
        current->thread.fs = __USER_DS;
-       asm volatile (".chip 68k/68881\n\t"
-                     "frestore %0@\n\t"
-                     ".chip 68k" : : "a" (&zero));
+       if (!FPU_IS_EMU)
+               asm volatile (".chip 68k/68881\n\t"
+                             "frestore %0@\n\t"
+                             ".chip 68k" : : "a" (&zero));
 }
 
 /*
@@ -224,16 +225,18 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
         */
        p->thread.fs = get_fs().seg;
 
-       /* Copy the current fpu state */
-       asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
-
-       if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2])
-         asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
-                       "fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
-                       : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0])
-                       : "memory");
-       /* Restore the state in case the fpu was busy */
-       asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
+       if (!FPU_IS_EMU) {
+               /* Copy the current fpu state */
+               asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
+
+               if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2])
+                 asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
+                               "fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
+                               : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0])
+                               : "memory");
+               /* Restore the state in case the fpu was busy */
+               asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
+       }
 
        return 0;
 }
@@ -244,18 +247,32 @@ int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)
 {
        char fpustate[216];
 
-  /* First dump the fpu context to avoid protocol violation.  */
-  asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
-  if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2])
-     return 0;
+       if (FPU_IS_EMU) {
+               int i;
+
+               memcpy(fpu->fpcntl, current->thread.fpcntl, 12);
+               memcpy(fpu->fpregs, current->thread.fp, 96);
+               /* Convert internal fpu reg representation
+                * into long double format
+                */
+               for (i = 0; i < 24; i += 3)
+                       fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) |
+                                        ((fpu->fpregs[i] & 0x0000ffff) << 16);
+               return 1;
+       }
+
+       /* First dump the fpu context to avoid protocol violation.  */
+       asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
+       if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2])
+               return 0;
 
-  asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
+       asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
                :: "m" (fpu->fpcntl[0])
                : "memory");
-  asm volatile ("fmovemx %/fp0-%/fp7,%0"
+       asm volatile ("fmovemx %/fp0-%/fp7,%0"
                :: "m" (fpu->fpregs[0])
                : "memory");
-  return 1;
+       return 1;
 }
 
 /*
index 9d72d90b5264d2b4ca910197fc812718ba9c8c2c..7db64849dd29ff9c6ee16b9b1ccf4425a563a25b 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
+#include <linux/config.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -384,10 +385,17 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                                tmp = get_reg(child, addr);
                                if (addr == PT_SR)
                                        tmp >>= 16;
-                       }
-                       else if (addr >= 21 && addr < 49)
+                       } else if (addr >= 21 && addr < 49) {
                                tmp = child->thread.fp[addr - 21];
-                       else
+#ifdef CONFIG_M68KFPU_EMU
+                               /* Convert internal fpu reg representation
+                                * into long double format
+                                */
+                               if (FPU_IS_EMU && (addr < 45) && !(addr % 3))
+                                       tmp = ((tmp & 0xffff0000) << 15) |
+                                             ((tmp & 0x0000ffff) << 16);
+#endif
+                       } else
                                goto out;
                        ret = put_user(tmp,(unsigned long *) data);
                        goto out;
@@ -423,6 +431,16 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                        }
                        if (addr >= 21 && addr < 48)
                        {
+#ifdef CONFIG_M68KFPU_EMU
+                               /* Convert long double format
+                                * into internal fpu reg representation
+                                */
+                               if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) {
+                                       data = (unsigned long)data << 15;
+                                       data = (data & 0xffff0000) |
+                                              ((data & 0x0000ffff) >> 1);
+                               }
+#endif
                                child->thread.fp[addr - 21] = data;
                                ret = 0;
                        }
index d6302cb28c73c08e6a3461354542cd15e61b3700..f35dd94c521cf58e110c857da8a0d74ecc726a19 100644 (file)
  * 68060 fixes by Jesper Skov
  *
  * 1997-12-01  Modified for POSIX.1b signals by Andreas Schwab
+ *
+ * mathemu support by Roman Zippel
+ *  (Note: fpstate in the signal context is completly ignored for the emulator
+ *         and the internal floating point format is put on stack)
  */
 
 /*
@@ -190,6 +194,13 @@ static inline int restore_fpu_state(struct sigcontext *sc)
 {
        int err = 1;
 
+       if (FPU_IS_EMU) {
+           /* restore registers */
+           memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12);
+           memcpy(current->thread.fp, sc->sc_fpregs, 24);
+           return 0;
+       }
+
        if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
            /* Verify the frame format.  */
            if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version))
@@ -242,6 +253,18 @@ static inline int rt_restore_fpu_state(struct ucontext *uc)
        fpregset_t fpregs;
        int err = 1;
 
+       if (FPU_IS_EMU) {
+               /* restore fpu control register */
+               if (__copy_from_user(current->thread.fpcntl,
+                               &uc->uc_mcontext.fpregs.f_pcr, 12))
+                       goto out;
+               /* restore all other fpu register */
+               if (__copy_from_user(current->thread.fp,
+                               uc->uc_mcontext.fpregs.f_fpregs, 96))
+                       goto out;
+               return 0;
+       }
+
        if (__get_user(*(long *)fpstate, (long *)&uc->uc_fpstate))
                goto out;
        if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
@@ -539,6 +562,13 @@ badframe:
 
 static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs)
 {
+       if (FPU_IS_EMU) {
+               /* save registers */
+               memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12);
+               memcpy(sc->sc_fpregs, current->thread.fp, 24);
+               return;
+       }
+
        __asm__ volatile (".chip 68k/68881\n\t"
                          "fsave %0\n\t"
                          ".chip 68k"
@@ -570,6 +600,16 @@ static inline int rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs)
        int context_size = CPU_IS_060 ? 8 : 0;
        int err = 0;
 
+       if (FPU_IS_EMU) {
+               /* save fpu control register */
+               err |= copy_to_user(&uc->uc_mcontext.fpregs.f_pcr,
+                               current->thread.fpcntl, 12);
+               /* save all other fpu register */
+               err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs,
+                               current->thread.fp, 96);
+               return err;
+       }
+
        __asm__ volatile (".chip 68k/68881\n\t"
                          "fsave %0\n\t"
                          ".chip 68k"
index f895ad5e73d2543eec35f003d6ea563d1bcf70e5..151b6384e602199c294706e16a01b4d311ae6915 100644 (file)
@@ -47,6 +47,7 @@ asmlinkage void buserr(void);
 asmlinkage void trap(void);
 asmlinkage void inthandler(void);
 asmlinkage void nmihandler(void);
+asmlinkage void fpu_emu(void);
 
 e_vector vectors[256] = {
        0, 0, buserr, trap, trap, trap, trap, trap,
@@ -65,12 +66,12 @@ asm(".text\n"
     __ALIGN_STR "\n"
     SYMBOL_NAME_STR(nmihandler) ": rte");
 
-__initfunc(void base_trap_init(void))
+void __init base_trap_init(void)
 {
        /* setup the exception vector table */
        __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors));
 
-       if (CPU_IS_040) {
+       if (CPU_IS_040 && !FPU_IS_EMU) {
                /* set up FPSP entry points */
                asmlinkage void dz_vec(void) asm ("dz");
                asmlinkage void inex_vec(void) asm ("inex");
@@ -93,6 +94,12 @@ __initfunc(void base_trap_init(void))
                vectors[VEC_FPUNSUP] = unsupp_vec;
        }
        if (CPU_IS_060) {
+               /* set up ISP entry points */
+               asmlinkage void unimp_vec(void) asm ("_060_isp_unimp");
+
+               vectors[VEC_UNIMPII] = unimp_vec;
+       }
+       if (CPU_IS_060 && !FPU_IS_EMU) {
                /* set up IFPSP entry points */
                asmlinkage void snan_vec(void) asm ("_060_fpsp_snan");
                asmlinkage void operr_vec(void) asm ("_060_fpsp_operr");
@@ -104,8 +111,6 @@ __initfunc(void base_trap_init(void))
                asmlinkage void unsupp_vec(void) asm ("_060_fpsp_unsupp");
                asmlinkage void effadd_vec(void) asm ("_060_fpsp_effadd");
 
-               asmlinkage void unimp_vec(void) asm ("_060_isp_unimp");
-
                vectors[VEC_FPNAN] = snan_vec;
                vectors[VEC_FPOE] = operr_vec;
                vectors[VEC_FPOVER] = ovfl_vec;
@@ -115,14 +120,10 @@ __initfunc(void base_trap_init(void))
                vectors[VEC_LINE11] = fline_vec;
                vectors[VEC_FPUNSUP] = unsupp_vec;
                vectors[VEC_UNIMPEA] = effadd_vec;
-
-               /* set up ISP entry points */
-
-               vectors[VEC_UNIMPII] = unimp_vec;
        }
 }
 
-__initfunc(void trap_init (void))
+void __init trap_init (void)
 {
        int i;
 
@@ -133,18 +134,17 @@ __initfunc(void trap_init (void))
        for (i = 64; i < 256; i++)
                vectors[i] = inthandler;
 
+#ifdef CONFIG_M68KFPU_EMU
+       if (FPU_IS_EMU)
+               vectors[VEC_LINE11] = fpu_emu;
+#endif
+
         /* if running on an amiga, make the NMI interrupt do nothing */
        if (MACH_IS_AMIGA) {
                vectors[VEC_INT7] = nmihandler;
        }
 }
 
-void set_evector(int vecnum, void (*handler)(void))
-{
-       if (vecnum >= 0 && vecnum <= 256)
-               vectors[vecnum] = handler;
-}
-
 
 static inline void console_verbose(void)
 {
@@ -152,6 +152,7 @@ static inline void console_verbose(void)
        console_loglevel = 15;
 }
 
+
 static char *vec_names[] = {
        "RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR",
        "ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc",
@@ -180,7 +181,6 @@ static char *space_names[] = {
        };
 
 
-
 void die_if_kernel(char *,struct pt_regs *,int);
 asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
                              unsigned long error_code);
@@ -507,44 +507,6 @@ static inline void bus_error030 (struct frame *fp)
            else
                    asm volatile ("ploadr %1,%0@" : /* no outputs */
                                  : "a" (addr), "d" (ssw));
-
-#if 0
-           /* If this was a data fault due to an invalid page and a
-              prefetch is pending on the same page, simulate it (but
-              only if the page is now valid).  Otherwise we'll get an
-              weird insn access.  */
-           if ((ssw & RB) && (mmusr & MMU_I))
-             {
-               unsigned long iaddr;
-
-               if ((fp->ptregs.format) == 0xB)
-                 iaddr = fp->un.fmtb.baddr;
-               else
-                 iaddr = fp->ptregs.pc + 4;
-               if (((addr ^ iaddr) & PAGE_MASK) == 0)
-                 {
-                   /* We only need to check the ATC as the entry has
-                      already been set up above.  */
-                   asm volatile ("ptestr #1,%1@,#0\n\t"
-                                 "pmove %/psr,%0@"
-                                 : : "a" (&temp), "a" (iaddr));
-                   mmusr = temp;
-#ifdef DEBUG
-                   printk ("prefetch iaddr=%#lx ssw=%#x mmusr=%#x\n",
-                           iaddr, ssw, mmusr);
-#endif
-                   if (!(mmusr & MMU_I))
-                     {
-                       unsigned short insn;
-                       asm volatile ("movesw %1@,%0"
-                                     : "=r" (insn)
-                                     : "a" (iaddr));
-                       fp->un.fmtb.isb = insn;
-                       fp->un.fmtb.ssw &= ~RB;
-                     }
-                 }
-             }
-#endif
          }
 
        /* Now handle the instruction fault. */
@@ -598,43 +560,6 @@ static inline void bus_error030 (struct frame *fp)
                die_if_kernel("Oops",&fp->ptregs,mmusr);
                force_sig(SIGSEGV, current);
                return;
-       } else {
-#if 0 /* stale ATC entry??  Ignore it */
-
-#ifdef DEBUG
-               static volatile long tlong;
-#endif
-
-               printk ("weird insn access at %#lx from pc %#lx (ssw is %#x)\n",
-                       addr, fp->ptregs.pc, ssw);
-               asm volatile ("ptestr #1,%1@,#0\n\t"
-                             "pmove %/psr,%0@"
-                             : /* no outputs */
-                             : "a" (&temp), "a" (addr));
-               mmusr = temp;
-                     
-               printk ("level 0 mmusr is %#x\n", mmusr);
-#ifdef DEBUG
-               if (m68k_cputype & CPU_68030) {
-                       asm volatile ("pmove %/tt0,%0@"
-                                     : /* no outputs */
-                                     : "a" (&tlong));
-                       printk ("tt0 is %#lx, ", tlong);
-                       asm volatile ("pmove %/tt1,%0@"
-                                     : /* no outputs */
-                                     : "a" (&tlong));
-                       printk ("tt1 is %#lx\n", tlong);
-               }
-
-#endif
-
-#if DEBUG
-               printk("Unknown SIGSEGV - 3\n");
-#endif
-               die_if_kernel("Oops",&fp->ptregs,mmusr);
-               force_sig(SIGSEGV, current);
-               return;
-#endif
        }
 
 create_atc_entry:
@@ -990,3 +915,16 @@ asmlinkage void fpsp040_die(void)
 {
        do_exit(SIGSEGV);
 }
+
+#ifdef CONFIG_M68KFPU_EMU
+asmlinkage void fpemu_signal(int signal, int code, void *addr)
+{
+       siginfo_t info;
+
+       info.si_signo = signal;
+       info.si_errno = 0;
+       info.si_code = code;
+       info.si_addr = addr;
+       force_sig_info(signal, &info, current);
+}
+#endif
diff --git a/arch/m68k/math-emu/Makefile b/arch/m68k/math-emu/Makefile
new file mode 100644 (file)
index 0000000..fe379cb
--- /dev/null
@@ -0,0 +1,19 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+.S.o:
+       $(CC) $(EXTRA_CFLAGS) -D__ASSEMBLY__ -traditional -c $< -o $*.o
+
+#EXTRA_CFLAGS=-DFPU_EMU_DEBUG
+
+O_TARGET := mathemu.o
+O_OBJS := fp_entry.o fp_scan.o fp_util.o fp_move.o fp_movem.o \
+         fp_cond.o fp_arith.o fp_log.o fp_trig.o
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/m68k/math-emu/fp_arith.c b/arch/m68k/math-emu/fp_arith.c
new file mode 100644 (file)
index 0000000..c494b1d
--- /dev/null
@@ -0,0 +1,700 @@
+/*
+
+   fp_arith.c: floating-point math routines for the Linux-m68k
+   floating point emulator.
+
+   Copyright (c) 1998-1999 David Huggins-Daines.
+
+   Somewhat based on the AlphaLinux floating point emulator, by David
+   Mosberger-Tang.
+
+   You may copy, modify, and redistribute this file under the terms of
+   the GNU General Public License, version 2, or any later version, at
+   your convenience.
+ */
+
+#include "fp_emu.h"
+#include "multi_arith.h"
+#include "fp_arith.h"
+
+const struct fp_ext fp_QNaN =
+{
+       0, 0, 0x7fff, { ~0 }
+};
+
+const struct fp_ext fp_Inf =
+{
+       0, 0, 0x7fff, { 0 }
+};
+
+/* let's start with the easy ones */
+
+struct fp_ext *
+fp_fabs(struct fp_ext *dest, struct fp_ext *src)
+{
+       dprint(PINSTR, "fabs\n");
+
+       fp_monadic_check(dest, src);
+
+       dest->sign = 0;
+
+       return dest;
+}
+
+struct fp_ext *
+fp_fneg(struct fp_ext *dest, struct fp_ext *src)
+{
+       dprint(PINSTR, "fneg\n");
+
+       fp_monadic_check(dest, src);
+
+       dest->sign = !dest->sign;
+
+       return dest;
+}
+
+/* Now, the slightly harder ones */
+
+/* fp_fadd: Implements the kernel of the FADD, FSADD, FDADD, FSUB,
+   FDSUB, and FCMP instructions. */
+
+struct fp_ext *
+fp_fadd(struct fp_ext *dest, struct fp_ext *src)
+{
+       int diff;
+
+       dprint(PINSTR, "fadd\n");
+
+       fp_dyadic_check(dest, src);
+
+       if (IS_INF(dest)) {
+               /* infinity - infinity == NaN */
+               if (IS_INF(src) && (src->sign != dest->sign))
+                       fp_set_nan(dest);
+               return dest;
+       }
+       if (IS_INF(src)) {
+               fp_copy_ext(dest, src);
+               return dest;
+       }
+
+       if (IS_ZERO(dest)) {
+               if (IS_ZERO(src)) {
+                       if (src->sign != dest->sign) {
+                               if (FPDATA->rnd == FPCR_ROUND_RM)
+                                       dest->sign = 1;
+                               else
+                                       dest->sign = 0;
+                       }
+               } else
+                       fp_copy_ext(dest, src);
+               return dest;
+       }
+
+       dest->lowmant = src->lowmant = 0;
+
+       if ((diff = dest->exp - src->exp) > 0)
+               fp_denormalize(src, diff);
+       else if ((diff = -diff) > 0)
+               fp_denormalize(dest, diff);
+
+       if (dest->sign == src->sign) {
+               if (fp_addmant(dest, src))
+                       if (!fp_addcarry(dest))
+                               return dest;
+       } else {
+               if (dest->mant.m64 < src->mant.m64) {
+                       fp_submant(dest, src, dest);
+                       dest->sign = !dest->sign;
+               } else
+                       fp_submant(dest, dest, src);
+       }
+
+       return dest;
+}
+
+/* fp_fsub: Implementes the kernel of the FSUB, FSSUB, and FDSUB
+   instructions.
+
+   Remember that the arguments are in assembler-syntax order! */
+
+struct fp_ext *
+fp_fsub(struct fp_ext *dest, struct fp_ext *src)
+{
+       dprint(PINSTR, "fsub ");
+
+       src->sign = !src->sign;
+       return fp_fadd(dest, src);
+}
+
+
+struct fp_ext *
+fp_fcmp(struct fp_ext *dest, struct fp_ext *src)
+{
+       dprint(PINSTR, "fcmp ");
+
+       FPDATA->temp[1] = *dest;
+       src->sign = !src->sign;
+       return fp_fadd(&FPDATA->temp[1], src);
+}
+
+struct fp_ext *
+fp_ftst(struct fp_ext *dest, struct fp_ext *src)
+{
+       dprint(PINSTR, "ftst\n");
+
+       (void)dest;
+
+       return src;
+}
+
+struct fp_ext *
+fp_fmul(struct fp_ext *dest, struct fp_ext *src)
+{
+       union fp_mant128 temp;
+       int exp;
+
+       dprint(PINSTR, "fmul\n");
+
+       fp_dyadic_check(dest, src);
+
+       /* calculate the correct sign now, as it's necessary for infinities */
+       dest->sign = src->sign ^ dest->sign;
+
+       /* Handle infinities */
+       if (IS_INF(dest)) {
+               if (IS_ZERO(src))
+                       fp_set_nan(dest);
+               return dest;
+       }
+       if (IS_INF(src)) {
+               if (IS_ZERO(dest))
+                       fp_set_nan(dest);
+               else
+                       fp_copy_ext(dest, src);
+               return dest;
+       }
+
+       /* Of course, as we all know, zero * anything = zero.  You may
+          not have known that it might be a positive or negative
+          zero... */
+       if (IS_ZERO(dest) || IS_ZERO(src)) {
+               dest->exp = 0;
+               dest->mant.m64 = 0;
+               dest->lowmant = 0;
+
+               return dest;
+       }
+
+       exp = dest->exp + src->exp - 0x3ffe;
+
+       /* shift up the mantissa for denormalized numbers,
+          so that the highest bit is set, this makes the
+          shift of the result below easier */
+       if ((long)dest->mant.m32[0] >= 0)
+               exp -= fp_overnormalize(dest);
+       if ((long)src->mant.m32[0] >= 0)
+               exp -= fp_overnormalize(src);
+
+       /* now, do a 64-bit multiply with expansion */
+       fp_multiplymant(&temp, dest, src);
+
+       /* normalize it back to 64 bits and stuff it back into the
+          destination struct */
+       if ((long)temp.m32[0] > 0) {
+               exp--;
+               fp_putmant128(dest, &temp, 1);
+       } else
+               fp_putmant128(dest, &temp, 0);
+
+       if (exp >= 0x7fff) {
+               fp_set_ovrflw(dest);
+               return dest;
+       }
+       dest->exp = exp;
+       if (exp < 0) {
+               fp_set_sr(FPSR_EXC_UNFL);
+               fp_denormalize(dest, -exp);
+       }
+
+       return dest;
+}
+
+/* fp_fdiv: Implements the "kernel" of the FDIV, FSDIV, FDDIV and
+   FSGLDIV instructions.
+
+   Note that the order of the operands is counter-intuitive: instead
+   of src / dest, the result is actually dest / src. */
+
+struct fp_ext *
+fp_fdiv(struct fp_ext *dest, struct fp_ext *src)
+{
+       union fp_mant128 temp;
+       int exp;
+
+       dprint(PINSTR, "fdiv\n");
+
+       fp_dyadic_check(dest, src);
+
+       /* calculate the correct sign now, as it's necessary for infinities */
+       dest->sign = src->sign ^ dest->sign;
+
+       /* Handle infinities */
+       if (IS_INF(dest)) {
+               /* infinity / infinity = NaN (quiet, as always) */
+               if (IS_INF(src))
+                       fp_set_nan(dest);
+               /* infinity / anything else = infinity (with approprate sign) */
+               return dest;
+       }
+       if (IS_INF(src)) {
+               /* anything / infinity = zero (with appropriate sign) */
+               dest->exp = 0;
+               dest->mant.m64 = 0;
+               dest->lowmant = 0;
+
+               return dest;
+       }
+
+       /* zeroes */
+       if (IS_ZERO(dest)) {
+               /* zero / zero = NaN */
+               if (IS_ZERO(src))
+                       fp_set_nan(dest);
+               /* zero / anything else = zero */
+               return dest;
+       }
+       if (IS_ZERO(src)) {
+               /* anything / zero = infinity (with appropriate sign) */
+               fp_set_sr(FPSR_EXC_DZ);
+               dest->exp = 0x7fff;
+               dest->mant.m64 = 0;
+
+               return dest;
+       }
+
+       exp = dest->exp - src->exp + 0x3fff;
+
+       /* shift up the mantissa for denormalized numbers,
+          so that the highest bit is set, this makes lots
+          of things below easier */
+       if ((long)dest->mant.m32[0] >= 0)
+               exp -= fp_overnormalize(dest);
+       if ((long)src->mant.m32[0] >= 0)
+               exp -= fp_overnormalize(src);
+
+       /* now, do the 64-bit divide */
+       fp_dividemant(&temp, dest, src);
+
+       /* normalize it back to 64 bits and stuff it back into the
+          destination struct */
+       if (!temp.m32[0]) {
+               exp--;
+               fp_putmant128(dest, &temp, 32);
+       } else
+               fp_putmant128(dest, &temp, 31);
+
+       if (exp >= 0x7fff) {
+               fp_set_ovrflw(dest);
+               return dest;
+       }
+       dest->exp = exp;
+       if (exp < 0) {
+               fp_set_sr(FPSR_EXC_UNFL);
+               fp_denormalize(dest, -exp);
+       }
+
+       return dest;
+}
+
+struct fp_ext *
+fp_fsglmul(struct fp_ext *dest, struct fp_ext *src)
+{
+       int exp;
+
+       dprint(PINSTR, "fsglmul\n");
+
+       fp_dyadic_check(dest, src);
+
+       /* calculate the correct sign now, as it's necessary for infinities */
+       dest->sign = src->sign ^ dest->sign;
+
+       /* Handle infinities */
+       if (IS_INF(dest)) {
+               if (IS_ZERO(src))
+                       fp_set_nan(dest);
+               return dest;
+       }
+       if (IS_INF(src)) {
+               if (IS_ZERO(dest))
+                       fp_set_nan(dest);
+               else
+                       fp_copy_ext(dest, src);
+               return dest;
+       }
+
+       /* Of course, as we all know, zero * anything = zero.  You may
+          not have known that it might be a positive or negative
+          zero... */
+       if (IS_ZERO(dest) || IS_ZERO(src)) {
+               dest->exp = 0;
+               dest->mant.m64 = 0;
+               dest->lowmant = 0;
+
+               return dest;
+       }
+
+       exp = dest->exp + src->exp - 0x3ffe;
+
+       /* do a 32-bit multiply */
+       fp_mul64(dest->mant.m32[0], dest->mant.m32[1],
+                dest->mant.m32[0] & 0xffffff00,
+                src->mant.m32[0] & 0xffffff00);
+
+       if (exp >= 0x7fff) {
+               fp_set_ovrflw(dest);
+               return dest;
+       }
+       dest->exp = exp;
+       if (exp < 0) {
+               fp_set_sr(FPSR_EXC_UNFL);
+               fp_denormalize(dest, -exp);
+       }
+
+       return dest;
+}
+
+struct fp_ext *
+fp_fsgldiv(struct fp_ext *dest, struct fp_ext *src)
+{
+       int exp;
+       unsigned long quot, rem;
+
+       dprint(PINSTR, "fsgldiv\n");
+
+       fp_dyadic_check(dest, src);
+
+       /* calculate the correct sign now, as it's necessary for infinities */
+       dest->sign = src->sign ^ dest->sign;
+
+       /* Handle infinities */
+       if (IS_INF(dest)) {
+               /* infinity / infinity = NaN (quiet, as always) */
+               if (IS_INF(src))
+                       fp_set_nan(dest);
+               /* infinity / anything else = infinity (with approprate sign) */
+               return dest;
+       }
+       if (IS_INF(src)) {
+               /* anything / infinity = zero (with appropriate sign) */
+               dest->exp = 0;
+               dest->mant.m64 = 0;
+               dest->lowmant = 0;
+
+               return dest;
+       }
+
+       /* zeroes */
+       if (IS_ZERO(dest)) {
+               /* zero / zero = NaN */
+               if (IS_ZERO(src))
+                       fp_set_nan(dest);
+               /* zero / anything else = zero */
+               return dest;
+       }
+       if (IS_ZERO(src)) {
+               /* anything / zero = infinity (with appropriate sign) */
+               fp_set_sr(FPSR_EXC_DZ);
+               dest->exp = 0x7fff;
+               dest->mant.m64 = 0;
+
+               return dest;
+       }
+
+       exp = dest->exp - src->exp + 0x3fff;
+
+       dest->mant.m32[0] &= 0xffffff00;
+       src->mant.m32[0] &= 0xffffff00;
+
+       /* do the 32-bit divide */
+       if (dest->mant.m32[0] >= src->mant.m32[0]) {
+               fp_sub64(dest->mant, src->mant);
+               fp_div64(quot, rem, dest->mant.m32[0], 0, src->mant.m32[0]);
+               dest->mant.m32[0] = 0x80000000 | (quot >> 1);
+               dest->mant.m32[1] = (quot & 1) | rem;   /* only for rounding */
+       } else {
+               fp_div64(quot, rem, dest->mant.m32[0], 0, src->mant.m32[0]);
+               dest->mant.m32[0] = quot;
+               dest->mant.m32[1] = rem;                /* only for rounding */
+               exp--;
+       }
+
+       if (exp >= 0x7fff) {
+               fp_set_ovrflw(dest);
+               return dest;
+       }
+       dest->exp = exp;
+       if (exp < 0) {
+               fp_set_sr(FPSR_EXC_UNFL);
+               fp_denormalize(dest, -exp);
+       }
+
+       return dest;
+}
+
+/* fp_roundint: Internal rounding function for use by several of these
+   emulated instructions.
+
+   This one rounds off the fractional part using the rounding mode
+   specified. */
+
+static void fp_roundint(struct fp_ext *dest, int mode)
+{
+       union fp_mant64 oldmant;
+       unsigned long mask;
+
+       if (!fp_normalize_ext(dest))
+               return;
+
+       /* infinities and zeroes */
+       if (IS_INF(dest) || IS_ZERO(dest)) 
+               return;
+
+       /* first truncate the lower bits */
+       oldmant = dest->mant;
+       switch (dest->exp) {
+       case 0 ... 0x3ffe:
+               dest->mant.m64 = 0;
+               break;
+       case 0x3fff ... 0x401e:
+               dest->mant.m32[0] &= 0xffffffffU << (0x401e - dest->exp);
+               dest->mant.m32[1] = 0;
+               if (oldmant.m64 == dest->mant.m64)
+                       return;
+               break;
+       case 0x401f ... 0x403e:
+               dest->mant.m32[1] &= 0xffffffffU << (0x403e - dest->exp);
+               if (oldmant.m32[1] == dest->mant.m32[1])
+                       return;
+               break;
+       default:
+               return;
+       }
+       fp_set_sr(FPSR_EXC_INEX2);
+
+       /* We might want to normalize upwards here... however, since
+          we know that this is only called on the output of fp_fdiv,
+          or with the input to fp_fint or fp_fintrz, and the inputs
+          to all these functions are either normal or denormalized
+          (no subnormals allowed!), there's really no need.
+
+          In the case of fp_fdiv, observe that 0x80000000 / 0xffff =
+          0xffff8000, and the same holds for 128-bit / 64-bit. (i.e. the
+          smallest possible normal dividend and the largest possible normal
+          divisor will still produce a normal quotient, therefore, (normal
+          << 64) / normal is normal in all cases) */
+
+       switch (mode) {
+       case FPCR_ROUND_RN:
+               switch (dest->exp) {
+               case 0 ... 0x3ffd:
+                       return;
+               case 0x3ffe:
+                       /* As noted above, the input is always normal, so the
+                          guard bit (bit 63) is always set.  therefore, the
+                          only case in which we will NOT round to 1.0 is when
+                          the input is exactly 0.5. */
+                       if (oldmant.m64 == (1ULL << 63))
+                               return;
+                       break;
+               case 0x3fff ... 0x401d:
+                       mask = 1 << (0x401d - dest->exp);
+                       if (!(oldmant.m32[0] & mask))
+                               return;
+                       if (oldmant.m32[0] & (mask << 1))
+                               break;
+                       if (!(oldmant.m32[0] << (dest->exp - 0x3ffd)) &&
+                                       !oldmant.m32[1])
+                               return;
+                       break;
+               case 0x401e:
+                       if (!(oldmant.m32[1] >= 0))
+                               return;
+                       if (oldmant.m32[0] & 1)
+                               break;
+                       if (!(oldmant.m32[1] << 1))
+                               return;
+                       break;
+               case 0x401f ... 0x403d:
+                       mask = 1 << (0x403d - dest->exp);
+                       if (!(oldmant.m32[1] & mask))
+                               return;
+                       if (oldmant.m32[1] & (mask << 1))
+                               break;
+                       if (!(oldmant.m32[1] << (dest->exp - 0x401d)))
+                               return;
+                       break;
+               default:
+                       return;
+               }
+               break;
+       case FPCR_ROUND_RZ:
+               return;
+       default:
+               if (dest->sign ^ (mode - FPCR_ROUND_RM))
+                       break;
+               return;
+       }
+
+       switch (dest->exp) {
+       case 0 ... 0x3ffe:
+               dest->exp = 0x3fff;
+               dest->mant.m64 = 1ULL << 63;
+               break;
+       case 0x3fff ... 0x401e:
+               mask = 1 << (0x401e - dest->exp);
+               if (dest->mant.m32[0] += mask)
+                       break;
+               dest->mant.m32[0] = 0x80000000;
+               dest->exp++;
+               break;
+       case 0x401f ... 0x403e:
+               mask = 1 << (0x403e - dest->exp);
+               if (dest->mant.m32[1] += mask)
+                       break;
+               if (dest->mant.m32[0] += 1)
+                        break;
+               dest->mant.m32[0] = 0x80000000;
+                dest->exp++;
+               break;
+       }
+}
+
+/* modrem_kernel: Implementation of the FREM and FMOD instructions
+   (which are exactly the same, except for the rounding used on the
+   intermediate value) */
+
+static struct fp_ext *
+modrem_kernel(struct fp_ext *dest, struct fp_ext *src, int mode)
+{
+       struct fp_ext tmp;
+
+       fp_dyadic_check(dest, src);
+
+       /* Infinities and zeros */
+       if (IS_INF(dest) || IS_ZERO(src)) {
+               fp_set_nan(dest);
+               return dest;
+       }
+       if (IS_ZERO(dest) || IS_INF(src))
+               return dest;
+
+       /* FIXME: there is almost certainly a smarter way to do this */
+       fp_copy_ext(&tmp, dest);
+       fp_fdiv(&tmp, src);             /* NOTE: src might be modified */
+       fp_roundint(&tmp, mode);
+       fp_fmul(&tmp, src);
+       fp_fsub(dest, &tmp);
+
+       /* set the quotient byte */
+       fp_set_quotient((dest->mant.m64 & 0x7f) | (dest->sign << 7));
+       return dest;
+}
+
+/* fp_fmod: Implements the kernel of the FMOD instruction.
+
+   Again, the argument order is backwards.  The result, as defined in
+   the Motorola manuals, is:
+
+   fmod(src,dest) = (dest - (src * floor(dest / src))) */
+
+struct fp_ext *
+fp_fmod(struct fp_ext *dest, struct fp_ext *src)
+{
+       dprint(PINSTR, "fmod\n");
+       return modrem_kernel(dest, src, FPCR_ROUND_RZ);
+}
+
+/* fp_frem: Implements the kernel of the FREM instruction.
+
+   frem(src,dest) = (dest - (src * round(dest / src)))
+ */
+
+struct fp_ext *
+fp_frem(struct fp_ext *dest, struct fp_ext *src)
+{
+       dprint(PINSTR, "frem\n");
+       return modrem_kernel(dest, src, FPCR_ROUND_RN);
+}
+
+struct fp_ext *
+fp_fint(struct fp_ext *dest, struct fp_ext *src)
+{
+       dprint(PINSTR, "fint\n");
+
+       fp_copy_ext(dest, src);
+
+       fp_roundint(dest, FPDATA->rnd);
+
+       return dest;
+}
+
+struct fp_ext *
+fp_fintrz(struct fp_ext *dest, struct fp_ext *src)
+{
+       dprint(PINSTR, "fintrz\n");
+
+       fp_copy_ext(dest, src);
+
+       fp_roundint(dest, FPCR_ROUND_RZ);
+
+       return dest;
+}
+
+struct fp_ext *
+fp_fscale(struct fp_ext *dest, struct fp_ext *src)
+{
+       int scale, oldround;
+
+       dprint(PINSTR, "fscale\n");
+
+       fp_dyadic_check(dest, src);
+
+       /* Infinities */
+       if (IS_INF(src)) {
+               fp_set_nan(dest);
+               return dest;
+       }
+       if (IS_INF(dest))
+               return dest;
+
+       /* zeroes */
+       if (IS_ZERO(src) || IS_ZERO(dest))
+               return dest;
+
+       /* Source exponent out of range */
+       if (src->exp >= 0x400c) {
+               fp_set_ovrflw(dest);
+               return dest;
+       }
+
+       /* src must be rounded with round to zero. */
+       oldround = FPDATA->rnd;
+       FPDATA->rnd = FPCR_ROUND_RZ;
+       scale = fp_conv_ext2long(src);
+       FPDATA->rnd = oldround;
+
+       /* new exponent */
+       scale += dest->exp;
+
+       if (scale >= 0x7fff) {
+               fp_set_ovrflw(dest);
+       } else if (scale <= 0) {
+               fp_set_sr(FPSR_EXC_UNFL);
+               fp_denormalize(dest, -scale);
+       } else
+               dest->exp = scale;
+
+       return dest;
+}
+
diff --git a/arch/m68k/math-emu/fp_arith.h b/arch/m68k/math-emu/fp_arith.h
new file mode 100644 (file)
index 0000000..2cc3f84
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+
+   fp_arith.h: floating-point math routines for the Linux-m68k
+   floating point emulator.
+
+   Copyright (c) 1998 David Huggins-Daines.
+
+   Somewhat based on the AlphaLinux floating point emulator, by David
+   Mosberger-Tang.
+
+   You may copy, modify, and redistribute this file under the terms of
+   the GNU General Public License, version 2, or any later version, at
+   your convenience.
+
+ */
+
+#ifndef FP_ARITH_H
+#define FP_ARITH_H
+
+/* easy ones */
+struct fp_ext *
+fp_fabs(struct fp_ext *dest, struct fp_ext *src);
+struct fp_ext *
+fp_fneg(struct fp_ext *dest, struct fp_ext *src);
+
+/* straightforward arithmetic */
+struct fp_ext *
+fp_fadd(struct fp_ext *dest, struct fp_ext *src);
+struct fp_ext *
+fp_fsub(struct fp_ext *dest, struct fp_ext *src);
+struct fp_ext *
+fp_fcmp(struct fp_ext *dest, struct fp_ext *src);
+struct fp_ext *
+fp_ftst(struct fp_ext *dest, struct fp_ext *src);
+struct fp_ext *
+fp_fmul(struct fp_ext *dest, struct fp_ext *src);
+struct fp_ext *
+fp_fdiv(struct fp_ext *dest, struct fp_ext *src);
+
+/* ones that do rounding and integer conversions */
+struct fp_ext *
+fp_fmod(struct fp_ext *dest, struct fp_ext *src);
+struct fp_ext *
+fp_frem(struct fp_ext *dest, struct fp_ext *src);
+struct fp_ext *
+fp_fint(struct fp_ext *dest, struct fp_ext *src);
+struct fp_ext *
+fp_fintrz(struct fp_ext *dest, struct fp_ext *src);
+struct fp_ext *
+fp_fscale(struct fp_ext *dest, struct fp_ext *src);
+
+#endif /* FP_ARITH__H */
diff --git a/arch/m68k/math-emu/fp_cond.S b/arch/m68k/math-emu/fp_cond.S
new file mode 100644 (file)
index 0000000..d9981d6
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * fp_cond.S
+ *
+ * Copyright Roman Zippel, 1997.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions.  (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fp_emu.h"
+#include "fp_decode.h"
+
+       .globl  fp_fscc, fp_fbccw, fp_fbccl
+
+#ifdef FPU_EMU_DEBUG
+fp_fnop:
+       printf  PDECODE,"fnop\n"
+       jra     fp_end
+#else
+#define fp_fnop fp_end
+#endif
+
+fp_fbccw:
+       tst.w   %d2
+       jeq     fp_fnop
+       printf  PDECODE,"fbccw "
+       fp_get_pc %a0
+       lea     (-2,%a0,%d2.w),%a0
+       jra     1f
+
+fp_fbccl:
+       printf  PDECODE,"fbccl "
+       fp_get_pc %a0
+       move.l  %d2,%d0
+       swap    %d0
+       fp_get_instr_word %d0,fp_err_ua1
+       lea     (-2,%a0,%d0.l),%a0
+1:     printf  PDECODE,"%x",1,%a0
+       move.l  %d2,%d0
+       swap    %d0
+       jsr     fp_compute_cond
+       tst.l   %d0
+       jeq     1f
+       fp_put_pc %a0,1
+1:     printf  PDECODE,"\n"
+       jra     fp_end
+
+fp_fdbcc:
+       printf  PDECODE,"fdbcc "
+       fp_get_pc %a1                           | calculate new pc
+       fp_get_instr_word %d0,fp_err_ua1
+       add.w   %d0,%a1
+       fp_decode_addr_reg
+       printf  PDECODE,"d%d,%x\n",2,%d0,%a1
+       swap    %d1                             | test condition in %d1
+       tst.w   %d1
+       jne     2f
+       move.l  %d0,%d1
+       jsr     fp_get_data_reg
+       subq.w  #1,%d0
+       jcs     1f
+       fp_put_pc %a1,1
+1:     jsr     fp_put_data_reg
+2:     jra     fp_end
+
+| set flags for decode macros for fs<cc>
+do_fscc=1
+do_no_pc_mode=1
+
+fp_fscc:
+       printf  PDECODE,"fscc "
+       move.l  %d2,%d0
+       jsr     fp_compute_cond
+       move.w  %d0,%d1
+       swap    %d1
+
+       | decode addressing mode
+       fp_decode_addr_mode
+
+       .long   fp_data, fp_fdbcc
+       .long   fp_indirect, fp_postinc
+       .long   fp_predecr, fp_disp16
+       .long   fp_extmode0, fp_extmode1
+
+       | addressing mode: data register direct
+fp_data:
+       fp_mode_data_direct
+       move.w  %d0,%d1                 | save register nr
+       jsr     fp_get_data_reg
+       swap    %d1
+       move.b  %d1,%d0
+       swap    %d1
+       jsr     fp_put_data_reg
+       printf  PDECODE,"\n"
+       jra     fp_end
+
+fp_indirect:
+       fp_mode_addr_indirect
+       jra     fp_do_scc
+
+fp_postinc:
+       fp_mode_addr_indirect_postinc
+       jra     fp_do_scc
+
+fp_predecr:
+       fp_mode_addr_indirect_predec
+       jra     fp_do_scc
+
+fp_disp16:
+       fp_mode_addr_indirect_disp16
+       jra     fp_do_scc
+
+fp_extmode0:
+       fp_mode_addr_indirect_extmode0
+       jra     fp_do_scc
+
+fp_extmode1:
+       bfextu  %d2{#13,#3},%d0
+       jmp     ([0f:w,%pc,%d0*4])
+
+       .align  4
+0:
+       .long   fp_absolute_short, fp_absolute_long
+       .long   fp_ill, fp_ill          | NOTE: jump here to ftrap.x
+       .long   fp_ill, fp_ill
+       .long   fp_ill, fp_ill
+
+fp_absolute_short:
+       fp_mode_abs_short
+       jra     fp_do_scc
+
+fp_absolute_long:
+       fp_mode_abs_long
+|      jra     fp_do_scc
+
+fp_do_scc:
+       swap    %d1
+       putuser.b %d1,(%a0),fp_err_ua1,%a0
+       printf  PDECODE,"\n"
+       jra     fp_end
+
+
+#define tst_NAN        btst #24,%d1
+#define tst_Z  btst #26,%d1
+#define tst_N  btst #27,%d1
+
+fp_compute_cond:
+       move.l  (FPD_FPSR,FPDATA),%d1
+       btst    #4,%d0
+       jeq     1f
+       tst_NAN
+       jeq     1f
+       bset    #15,%d1
+       bset    #7,%d1
+       move.l  %d1,(FPD_FPSR,FPDATA)
+1:     and.w   #0xf,%d0
+       jmp     ([0f:w,%pc,%d0.w*4])
+
+       .align  4
+0:
+       .long   fp_f  , fp_eq , fp_ogt, fp_oge
+       .long   fp_olt, fp_ole, fp_ogl, fp_or
+       .long   fp_un , fp_ueq, fp_ugt, fp_uge
+       .long   fp_ult, fp_ule, fp_ne , fp_t
+
+fp_f:
+       moveq   #0,%d0
+       rts
+
+fp_eq:
+       moveq   #0,%d0
+       tst_Z
+       jeq     1f
+       moveq   #-1,%d0
+1:     rts
+
+fp_ogt:
+       moveq   #0,%d0
+       tst_NAN
+       jne     1f
+       tst_Z
+       jne     1f
+       tst_N
+       jne     1f
+       moveq   #-1,%d0
+1:     rts
+
+fp_oge:
+       moveq   #-1,%d0
+       tst_Z
+       jne     2f
+       tst_NAN
+       jne     1f
+       tst_N
+       jeq     2f
+1:     moveq   #0,%d0
+2:     rts
+
+fp_olt:
+       moveq   #0,%d0
+       tst_NAN
+       jne     1f
+       tst_Z
+       jne     1f
+       tst_N
+       jeq     1f
+       moveq   #-1,%d0
+1:     rts
+
+fp_ole:
+       moveq   #-1,%d0
+       tst_Z
+       jne     2f
+       tst_NAN
+       jne     1f
+       tst_N
+       jne     2f
+1:     moveq   #0,%d0
+2:     rts
+
+fp_ogl:
+       moveq   #0,%d0
+       tst_NAN
+       jne     1f
+       tst_Z
+       jne     1f
+       moveq   #-1,%d0
+1:     rts
+
+fp_or:
+       moveq   #0,%d0
+       tst_NAN
+       jne     1f
+       moveq   #-1,%d0
+1:     rts
+
+fp_un:
+       moveq   #0,%d0
+       tst_NAN
+       jeq     1f
+       moveq   #-1,%d0
+       rts
+
+fp_ueq:
+       moveq   #-1,%d0
+       tst_NAN
+       jne     1f
+       tst_Z
+       jne     1f
+       moveq   #0,%d0
+1:     rts
+
+fp_ugt:
+       moveq   #-1,%d0
+       tst_NAN
+       jne     2f
+       tst_N
+       jne     1f
+       tst_Z
+       jeq     2f
+1:     moveq   #0,%d0
+2:     rts
+
+fp_uge:
+       moveq   #-1,%d0
+       tst_NAN
+       jne     1f
+       tst_Z
+       jne     1f
+       tst_N
+       jeq     1f
+       moveq   #0,%d0
+1:     rts
+
+fp_ult:
+       moveq   #-1,%d0
+       tst_NAN
+       jne     2f
+       tst_Z
+       jne     1f
+       tst_N
+       jne     2f
+1:     moveq   #0,%d0
+2:     rts
+
+fp_ule:
+       moveq   #-1,%d0
+       tst_NAN
+       jne     1f
+       tst_Z
+       jne     1f
+       tst_N
+       jne     1f
+       moveq   #0,%d0
+1:     rts
+
+fp_ne:
+       moveq   #0,%d0
+       tst_Z
+       jne     1f
+       moveq   #-1,%d0
+1:     rts
+
+fp_t:
+       moveq   #-1,%d0
+       rts
diff --git a/arch/m68k/math-emu/fp_decode.h b/arch/m68k/math-emu/fp_decode.h
new file mode 100644 (file)
index 0000000..2332694
--- /dev/null
@@ -0,0 +1,417 @@
+/*
+ * fp_decode.h
+ *
+ * Copyright Roman Zippel, 1997.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions.  (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FP_DECODE_H
+#define _FP_DECODE_H
+
+/* These macros do the dirty work of the instr decoding, several variables
+ * can be defined in the source file to modify the work of these macros,
+ * currently the following variables are used:
+ * ...
+ * The register usage:
+ * d0 - will contain source operand for data direct mode,
+ *     otherwise scratch register
+ * d1 - upper 16bit are reserved for caller
+ *     lower 16bit may contain further arguments,
+ *     is destroyed during decoding
+ * d2 - contains first two instruction words,
+ *     first word will be used for extension word
+ * a0 - will point to source/dest operand for any indirect mode
+ *     otherwise scratch register
+ * a1 - scratch register
+ * a2 - base addr to the task structure
+ *
+ * the current implementation doesn't check for every disallowed
+ * addressing mode (e.g. pc relative modes as destination), as long
+ * as it only means a new addressing mode, which should not appear
+ * in a program and that doesn't crash the emulation, I think it's
+ * not a problem to allow these modes.
+ */
+
+do_fmovem=0
+do_fmovem_cr=0
+do_no_pc_mode=0
+do_fscc=0
+
+| first decoding of the instr type
+| this seperates the conditional instr
+.macro fp_decode_cond_instr_type
+       bfextu  %d2{#8,#2},%d0
+       jmp     ([0f:w,%pc,%d0*4])
+
+       .align  4
+0:
+|      .long   "f<op>","fscc/fdbcc"
+|      .long   "fbccw","fbccl"
+.endm
+
+| second decoding of the instr type
+| this seperates most move instr
+.macro fp_decode_move_instr_type
+       bfextu  %d2{#16,#3},%d0
+       jmp     ([0f:w,%pc,%d0*4])
+
+       .align  4
+0:
+|      .long   "f<op> fpx,fpx","invalid instr"
+|      .long   "f<op> <ea>,fpx","fmove fpx,<ea>"
+|      .long   "fmovem <ea>,fpcr","fmovem <ea>,fpx"
+|      .long   "fmovem fpcr,<ea>","fmovem fpx,<ea>"
+.endm
+
+| extract the source specifier, specifies
+| either source fp register or data format
+.macro fp_decode_sourcespec
+       bfextu  %d2{#19,#3},%d0
+.endm
+
+| decode destination format for fmove reg,ea
+.macro fp_decode_dest_format
+       bfextu  %d2{#19,#3},%d0
+.endm
+
+| decode source register for fmove reg,ea
+.macro fp_decode_src_reg
+       bfextu  %d2{#22,#3},%d0
+.endm
+
+| extract the addressing mode
+| it depends on the instr which of the modes is valid
+.macro fp_decode_addr_mode
+       bfextu  %d2{#10,#3},%d0
+       jmp     ([0f:w,%pc,%d0*4])
+
+       .align  4
+0:
+|      .long   "data register direct","addr register direct"
+|      .long   "addr register indirect"
+|      .long   "addr register indirect postincrement"
+|      .long   "addr register indirect predecrement"
+|      .long   "addr register + index16"
+|      .long   "extension mode1","extension mode2"
+.endm
+
+| extract the register for the addressing mode
+.macro fp_decode_addr_reg
+       bfextu  %d2{#13,#3},%d0
+.endm
+
+| decode the 8bit diplacement from the brief extension word
+.macro fp_decode_disp8
+       move.b  %d2,%d0
+       ext.w   %d0
+.endm
+
+| decode the index of the brief/full extension word
+.macro fp_decode_index
+       bfextu  %d2{#17,#3},%d0         | get the register nr
+       btst    #15,%d2                 | test for data/addr register
+       jne     1\@f
+       printf  PDECODE,"d%d",1,%d0
+       jsr     fp_get_data_reg
+       jra     2\@f
+1\@:   printf  PDECODE,"a%d",1,%d0
+       jsr     fp_get_addr_reg
+       move.l  %a0,%d0
+2\@:
+debug  lea     "'l'.w,%a0"
+       btst    #11,%d2                 | 16/32 bit size?
+       jne     3\@f
+debug  lea     "'w'.w,%a0"
+       ext.l   %d0
+3\@:   printf  PDECODE,":%c",1,%a0
+       move.w  %d2,%d1                 | scale factor
+       rol.w   #7,%d1
+       and.w   #3,%d1
+debug  move.l  "%d1,-(%sp)"
+debug  ext.l   "%d1"
+       printf  PDECODE,":%d",1,%d1
+debug  move.l  "(%sp)+,%d1"
+       lsl.l   %d1,%d0
+.endm
+
+| decode the base displacement size
+.macro fp_decode_basedisp
+       bfextu  %d2{#26,#2},%d0
+       jmp     ([0f:w,%pc,%d0*4])
+
+       .align  4
+0:
+|      .long   "reserved","null displacement"
+|      .long   "word displacement","long displacement"
+.endm
+
+.macro fp_decode_outerdisp
+       bfextu  %d2{#30,#2},%d0
+       jmp     ([0f:w,%pc,%d0*4])
+
+       .align  4
+0:
+|      .long   "no memory indirect action/reserved","null outer displacement"
+|      .long   "word outer displacement","long outer displacement"
+.endm
+
+| get the extension word and test for brief or full extension type
+.macro fp_get_test_extword label
+       fp_get_instr_word %d2,fp_err_ua1
+       btst    #8,%d2
+       jne     \label
+.endm
+
+
+| test if %pc is the base register for the indirect addr mode
+.macro fp_test_basereg_d16     label
+       btst    #20,%d2
+       jeq     \label
+.endm
+
+| test if %pc is the base register for one of the extended modes
+.macro fp_test_basereg_ext     label
+       btst    #19,%d2
+       jeq     \label
+.endm
+
+.macro fp_test_suppr_index label
+       btst    #6,%d2
+       jne     \label
+.endm
+
+
+| addressing mode: data register direct
+.macro fp_mode_data_direct
+       fp_decode_addr_reg
+       printf  PDECODE,"d%d",1,%d0
+.endm
+
+| addressing mode: address register indirect
+.macro fp_mode_addr_indirect
+       fp_decode_addr_reg
+       printf  PDECODE,"(a%d)",1,%d0
+       jsr     fp_get_addr_reg
+.endm
+
+| adjust stack for byte moves from/to stack
+.macro fp_test_sp_byte_move
+       .if     !do_fmovem
+       .if     do_fscc
+       move.w  #6,%d1
+       .endif
+       cmp.w   #7,%d0
+       jne     1\@f
+       .if     !do_fscc
+       cmp.w   #6,%d1
+       jne     1\@f
+       .endif
+       move.w  #4,%d1
+1\@:
+       .endif
+.endm
+
+| addressing mode: address register indirect with postincrement
+.macro fp_mode_addr_indirect_postinc
+       fp_decode_addr_reg
+       printf  PDECODE,"(a%d)+",1,%d0
+       fp_test_sp_byte_move
+       jsr     fp_get_addr_reg
+       move.l  %a0,%a1                 | save addr
+       .if     do_fmovem
+       lea     (%a0,%d1.w*4),%a0
+       .if     !do_fmovem_cr
+       lea     (%a0,%d1.w*8),%a0
+       .endif
+       .else
+       add.w   (fp_datasize,%d1.w*2),%a0
+       .endif
+       jsr     fp_put_addr_reg
+       move.l  %a1,%a0
+.endm
+
+| addressing mode: address register indirect with predecrement
+.macro fp_mode_addr_indirect_predec
+       fp_decode_addr_reg
+       printf  PDECODE,"-(a%d)",1,%d0
+       fp_test_sp_byte_move
+       jsr     fp_get_addr_reg
+       .if     do_fmovem
+       .if     !do_fmovem_cr
+       lea     (-12,%a0),%a1           | setup to addr of 1st reg to move
+       neg.w   %d1
+       lea     (%a0,%d1.w*4),%a0
+       add.w   %d1,%d1
+       lea     (%a0,%d1.w*4),%a0
+       jsr     fp_put_addr_reg
+       move.l  %a1,%a0
+       .else
+       neg.w   %d1
+       lea     (%a0,%d1.w*4),%a0
+       jsr     fp_put_addr_reg
+       .endif
+       .else
+       sub.w   (fp_datasize,%d1.w*2),%a0
+       jsr     fp_put_addr_reg
+       .endif
+.endm
+
+| addressing mode: address register/programm counter indirect
+|                 with 16bit displacement
+.macro fp_mode_addr_indirect_disp16
+       .if     !do_no_pc_mode
+       fp_test_basereg_d16 1f
+       printf  PDECODE,"pc"
+       fp_get_pc %a0
+       jra     2f
+       .endif
+1:     fp_decode_addr_reg
+       printf  PDECODE,"a%d",1,%d0
+       jsr     fp_get_addr_reg
+2:     fp_get_instr_word %a1,fp_err_ua1
+       printf  PDECODE,"@(%x)",1,%a1
+       add.l   %a1,%a0
+.endm
+
+| perform preindex (if I/IS == 0xx and xx != 00)
+.macro fp_do_preindex
+       moveq   #3,%d0
+       and.w   %d2,%d0
+       jeq     1f
+       btst    #2,%d2
+       jne     1f
+       printf  PDECODE,")@("
+       getuser.l (%a1),%a1,fp_err_ua1,%a1
+debug  jra     "2f"
+1:     printf  PDECODE,","
+2:
+.endm
+
+| perform postindex (if I/IS == 1xx)
+.macro fp_do_postindex
+       btst    #2,%d2
+       jeq     1f
+       printf  PDECODE,")@("
+       getuser.l (%a1),%a1,fp_err_ua1,%a1
+debug  jra     "2f"
+1:     printf  PDECODE,","
+2:
+.endm
+
+| all other indirect addressing modes will finally end up here
+.macro fp_mode_addr_indirect_extmode0
+       .if     !do_no_pc_mode
+       fp_test_basereg_ext 1f
+       printf  PDECODE,"pc"
+       fp_get_pc %a0
+       jra     2f
+       .endif
+1:     fp_decode_addr_reg
+       printf  PDECODE,"a%d",1,%d0
+       jsr     fp_get_addr_reg
+2:     move.l  %a0,%a1
+       swap    %d2
+       fp_get_test_extword 3f
+       | addressing mode: address register/programm counter indirect
+       |                  with index and 8bit displacement
+       fp_decode_disp8
+debug  ext.l   "%d0"
+       printf  PDECODE,"@(%x,",1,%d0
+       add.w   %d0,%a1
+       fp_decode_index
+       add.l   %d0,%a1
+       printf  PDECODE,")"
+       jra     9f
+3:     | addressing mode: address register/programm counter memory indirect
+       |                  with base and/or outer displacement
+       btst    #7,%d2                  | base register suppressed?
+       jeq     1f
+       printf  PDECODE,"!"
+       sub.l   %a1,%a1
+1:     printf  PDECODE,"@("
+       fp_decode_basedisp
+
+       .long   fp_ill,1f
+       .long   2f,3f
+
+#ifdef FPU_EMU_DEBUG
+1:     printf  PDECODE,"0"             | null base displacement
+       jra     1f
+#endif
+2:     fp_get_instr_word %a0,fp_err_ua1 | 16bit base displacement
+       printf  PDECODE,"%x:w",1,%a0
+       jra     4f
+3:     fp_get_instr_long %a0,fp_err_ua1 | 32bit base displacement
+       printf  PDECODE,"%x:l",1,%a0
+4:     add.l   %a0,%a1
+1:
+       fp_do_postindex
+       fp_test_suppr_index 1f
+       fp_decode_index
+       add.l   %d0,%a1
+1:     fp_do_preindex
+
+       fp_decode_outerdisp
+
+       .long   5f,1f
+       .long   2f,3f
+
+#ifdef FPU_EMU_DEBUG
+1:     printf  PDECODE,"0"             | null outer displacement
+       jra     1f
+#endif
+2:     fp_get_instr_word %a0,fp_err_ua1 | 16bit outer displacement
+       printf  PDECODE,"%x:w",1,%a0
+       jra     4f
+3:     fp_get_instr_long %a0,fp_err_ua1 | 32bit outer displacement
+       printf  PDECODE,"%x:l",1,%a0
+4:     add.l   %a0,%a1
+1:
+5:     printf  PDECODE,")"
+9:     move.l  %a1,%a0
+       swap    %d2
+.endm
+
+| get the absolute short address from user space
+.macro fp_mode_abs_short
+       fp_get_instr_word %a0,fp_err_ua1
+       printf  PDECODE,"%x.w",1,%a0
+.endm
+
+| get the absolute long address from user space
+.macro fp_mode_abs_long
+       fp_get_instr_long %a0,fp_err_ua1
+       printf  PDECODE,"%x.l",1,%a0
+.endm
+
+#endif /* _FP_DECODE_H */
diff --git a/arch/m68k/math-emu/fp_emu.h b/arch/m68k/math-emu/fp_emu.h
new file mode 100644 (file)
index 0000000..9344b93
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * fp_emu.h
+ *
+ * Copyright Roman Zippel, 1997.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions.  (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FP_EMU_H
+#define _FP_EMU_H
+
+#ifndef __ASSEMBLY__
+
+#include <asm/math-emu.h>
+
+#define IS_INF(a) ((a)->exp == 0x7fff)
+#define IS_ZERO(a) ((a)->mant.m64 == 0)
+
+
+#define fp_set_sr(bit) ({                                      \
+       FPDATA->fpsr |= 1 << (bit);                             \
+})
+
+#define fp_set_quotient(quotient) ({                           \
+       FPDATA->fpsr &= 0xff00ffff;                             \
+       FPDATA->fpsr |= ((quotient) & 0xff) << 16;              \
+})
+
+/* linkage for several useful functions */
+
+/* Normalize the extended struct, return 0 for a NaN */
+#define fp_normalize_ext(fpreg) ({                             \
+       register struct fp_ext *reg asm ("a0") = fpreg;         \
+       register int res asm ("d0");                            \
+                                                               \
+       asm volatile ("jsr fp_conv_ext2ext"                     \
+                       : "=d" (res) : "a" (reg)                \
+                       : "a1", "d1", "d2", "memory");          \
+       res;                                                    \
+})
+
+#define fp_copy_ext(dest, src) ({                              \
+       *dest = *src;                                           \
+})
+
+#define fp_monadic_check(dest, src) ({                         \
+       fp_copy_ext(dest, src);                                 \
+       if (!fp_normalize_ext(dest))                            \
+               return dest;                                    \
+})
+
+#define fp_dyadic_check(dest, src) ({                          \
+       if (!fp_normalize_ext(dest))                            \
+               return dest;                                    \
+       if (!fp_normalize_ext(src)) {                           \
+               fp_copy_ext(dest, src);                         \
+               return dest;                                    \
+       }                                                       \
+})
+
+extern const struct fp_ext fp_QNaN;
+extern const struct fp_ext fp_Inf;
+
+#define fp_set_nan(dest) ({                                    \
+       fp_set_sr(FPSR_EXC_OPERR);                              \
+       *dest = fp_QNaN;                                        \
+})
+
+/* TODO check rounding mode? */
+#define fp_set_ovrflw(dest) ({                                 \
+       fp_set_sr(FPSR_EXC_OVFL);                               \
+       dest->exp = 0x7fff;                                     \
+       dest->mant.m64 = 0;                                     \
+})
+
+#define fp_conv_ext2long(src) ({                               \
+       register struct fp_ext *__src asm ("a0") = src;         \
+       register int __res asm ("d0");                          \
+                                                               \
+       asm volatile ("jsr fp_conv_ext2long"                    \
+                       : "=d" (__res) : "a" (__src)            \
+                       : "a1", "d1", "d2", "memory");          \
+       __res;                                                  \
+})
+
+#else /* __ASSEMBLY__ */
+
+#include "../kernel/m68k_defs.h"
+#include <asm/math-emu.h>
+
+/*
+ * set, reset or clear a bit in the fp status register
+ */
+.macro fp_set_sr       bit
+       bset    #(\bit&7),(FPD_FPSR+3-(\bit/8),FPDATA)
+.endm
+
+.macro fp_clr_sr       bit
+       bclr    #(\bit&7),(FPD_FPSR+3-(\bit/8),FPDATA)
+.endm
+
+.macro fp_tst_sr       bit
+       btst    #(\bit&7),(FPD_FPSR+3-(\bit/8),FPDATA)
+.endm
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _FP_EMU_H */
diff --git a/arch/m68k/math-emu/fp_entry.S b/arch/m68k/math-emu/fp_entry.S
new file mode 100644 (file)
index 0000000..55088e8
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * fp_emu.S
+ *
+ * Copyright Roman Zippel, 1997.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions.  (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/entry.h>
+
+#include "fp_emu.h"
+
+       .globl  SYMBOL_NAME(fpu_emu)
+       .globl  fp_debugprint
+       .globl  fp_err_ua1,fp_err_ua2
+
+       .text
+SYMBOL_NAME_LABEL(fpu_emu)
+       SAVE_ALL_INT
+       GET_CURRENT(%d0)
+
+#if defined(CPU_M68020_OR_M68030) && defined(CPU_M68040_OR_M68060)
+        tst.l  SYMBOL_NAME(m68k_is040or060)
+        jeq    1f
+#endif
+#if defined(CPU_M68040_OR_M68060)
+       move.l  (FPS_PC2,%sp),(FPS_PC,%sp)
+#endif
+1:
+       | emulate the instruction
+       jsr     fp_scan
+
+#if defined(CONFIG_M68060)
+#if !defined(CPU_M68060_ONLY)
+       btst    #3,SYMBOL_NAME(m68k_cputype)+3
+       jeq     1f
+#endif
+       btst    #7,(FPS_SR,%sp)
+       jne     fp_sendtrace060
+#endif
+1:
+       | emulation successful?
+       tst.l   %d0
+       jeq     SYMBOL_NAME(ret_from_exception)
+
+       | send some signal to program here
+
+       jra     SYMBOL_NAME(ret_from_exception)
+
+       | we jump here after an access error while trying to access
+       | user space, we correct stackpointer and send a SIGSEGV to
+       | the user process
+fp_err_ua2:
+       addq.l  #4,%sp
+fp_err_ua1:
+       addq.l  #4,%sp
+       move.l  %a0,-(%sp)
+       pea     SEGV_MAPERR
+       pea     SIGSEGV
+       jsr     SYMBOL_NAME(fpemu_signal)
+       add.w   #12,%sp
+       jra     SYMBOL_NAME(ret_from_exception)
+
+#if defined(CONFIG_M68060)
+       | send a trace signal if we are debugged
+       | it does not really belong here, but...
+fp_sendtrace060:
+       move.l  (FPS_PC,%sp),-(%sp)
+       pea     TRAP_TRACE
+       pea     SIGTRAP
+       jsr     SYMBOL_NAME(fpemu_signal)
+       add.w   #12,%sp
+       jra     SYMBOL_NAME(ret_from_exception)
+#endif
+
+       .globl  fp_get_data_reg, fp_put_data_reg
+       .globl  fp_get_addr_reg, fp_put_addr_reg
+
+       | Entry points to get/put a register. Some of them can be get/put
+       | directly, others are on the stack, as we read/write the stack
+       | directly here, these function may only be called from within
+       | instruction decoding, otherwise the stack pointer is incorrect
+       | and the stack gets corrupted.
+fp_get_data_reg:
+       jmp     ([0f:w,%pc,%d0.w*4])
+
+       .align  4
+0:
+       .long   fp_get_d0, fp_get_d1
+       .long   fp_get_d2, fp_get_d3
+       .long   fp_get_d4, fp_get_d5
+       .long   fp_get_d6, fp_get_d7
+
+fp_get_d0:
+       move.l  (PT_D0+8,%sp),%d0
+       printf  PREGISTER,"{d0->%08x}",1,%d0
+       rts
+
+fp_get_d1:
+       move.l  (PT_D1+8,%sp),%d0
+       printf  PREGISTER,"{d1->%08x}",1,%d0
+       rts
+
+fp_get_d2:
+       move.l  (PT_D2+8,%sp),%d0
+       printf  PREGISTER,"{d2->%08x}",1,%d0
+       rts
+
+fp_get_d3:
+       move.l  %d3,%d0
+       printf  PREGISTER,"{d3->%08x}",1,%d0
+       rts
+
+fp_get_d4:
+       move.l  %d4,%d0
+       printf  PREGISTER,"{d4->%08x}",1,%d0
+       rts
+
+fp_get_d5:
+       move.l  %d5,%d0
+       printf  PREGISTER,"{d5->%08x}",1,%d0
+       rts
+
+fp_get_d6:
+       move.l  %d6,%d0
+       printf  PREGISTER,"{d6->%08x}",1,%d0
+       rts
+
+fp_get_d7:
+       move.l  %d7,%d0
+       printf  PREGISTER,"{d7->%08x}",1,%d0
+       rts
+
+fp_put_data_reg:
+       jmp     ([0f:w,%pc,%d1.w*4])
+
+       .align  4
+0:
+       .long   fp_put_d0, fp_put_d1
+       .long   fp_put_d2, fp_put_d3
+       .long   fp_put_d4, fp_put_d5
+       .long   fp_put_d6, fp_put_d7
+
+fp_put_d0:
+       printf  PREGISTER,"{d0<-%08x}",1,%d0
+       move.l  %d0,(PT_D0+8,%sp)
+       rts
+
+fp_put_d1:
+       printf  PREGISTER,"{d1<-%08x}",1,%d0
+       move.l  %d0,(PT_D1+8,%sp)
+       rts
+
+fp_put_d2:
+       printf  PREGISTER,"{d2<-%08x}",1,%d0
+       move.l  %d0,(PT_D2+8,%sp)
+       rts
+
+fp_put_d3:
+       printf  PREGISTER,"{d3<-%08x}",1,%d0
+|      move.l  %d0,%d3
+       move.l  %d0,(PT_D3+8,%sp)
+       rts
+
+fp_put_d4:
+       printf  PREGISTER,"{d4<-%08x}",1,%d0
+|      move.l  %d0,%d4
+       move.l  %d0,(PT_D4+8,%sp)
+       rts
+
+fp_put_d5:
+       printf  PREGISTER,"{d5<-%08x}",1,%d0
+|      move.l  %d0,%d5
+       move.l  %d0,(PT_D5+8,%sp)
+       rts
+
+fp_put_d6:
+       printf  PREGISTER,"{d6<-%08x}",1,%d0
+       move.l  %d0,%d6
+       rts
+
+fp_put_d7:
+       printf  PREGISTER,"{d7<-%08x}",1,%d0
+       move.l  %d0,%d7
+       rts
+
+fp_get_addr_reg:
+       jmp     ([0f:w,%pc,%d0.w*4])
+
+       .align  4
+0:
+       .long   fp_get_a0, fp_get_a1
+       .long   fp_get_a2, fp_get_a3
+       .long   fp_get_a4, fp_get_a5
+       .long   fp_get_a6, fp_get_a7
+
+fp_get_a0:
+       move.l  (PT_A0+8,%sp),%a0
+       printf  PREGISTER,"{a0->%08x}",1,%a0
+       rts
+
+fp_get_a1:
+       move.l  (PT_A1+8,%sp),%a0
+       printf  PREGISTER,"{a1->%08x}",1,%a0
+       rts
+
+fp_get_a2:
+       move.l  (PT_A2+8,%sp),%a0
+       printf  PREGISTER,"{a2->%08x}",1,%a0
+       rts
+
+fp_get_a3:
+       move.l  %a3,%a0
+       printf  PREGISTER,"{a3->%08x}",1,%a0
+       rts
+
+fp_get_a4:
+       move.l  %a4,%a0
+       printf  PREGISTER,"{a4->%08x}",1,%a0
+       rts
+
+fp_get_a5:
+       move.l  %a5,%a0
+       printf  PREGISTER,"{a5->%08x}",1,%a0
+       rts
+
+fp_get_a6:
+       move.l  %a6,%a0
+       printf  PREGISTER,"{a6->%08x}",1,%a0
+       rts
+
+fp_get_a7:
+       move.l  %usp,%a0
+       printf  PREGISTER,"{a7->%08x}",1,%a0
+       rts
+
+fp_put_addr_reg:
+       jmp     ([0f:w,%pc,%d0.w*4])
+
+       .align  4
+0:
+       .long   fp_put_a0, fp_put_a1
+       .long   fp_put_a2, fp_put_a3
+       .long   fp_put_a4, fp_put_a5
+       .long   fp_put_a6, fp_put_a7
+
+fp_put_a0:
+       printf  PREGISTER,"{a0<-%08x}",1,%a0
+       move.l  %a0,(PT_A0+8,%sp)
+       rts
+
+fp_put_a1:
+       printf  PREGISTER,"{a1<-%08x}",1,%a0
+       move.l  %a0,(PT_A1+8,%sp)
+       rts
+
+fp_put_a2:
+       printf  PREGISTER,"{a2<-%08x}",1,%a0
+       move.l  %a0,(PT_A2+8,%sp)
+       rts
+
+fp_put_a3:
+       printf  PREGISTER,"{a3<-%08x}",1,%a0
+       move.l  %a0,%a3
+       rts
+
+fp_put_a4:
+       printf  PREGISTER,"{a4<-%08x}",1,%a0
+       move.l  %a0,%a4
+       rts
+
+fp_put_a5:
+       printf  PREGISTER,"{a5<-%08x}",1,%a0
+       move.l  %a0,%a5
+       rts
+
+fp_put_a6:
+       printf  PREGISTER,"{a6<-%08x}",1,%a0
+       move.l  %a0,%a6
+       rts
+
+fp_put_a7:
+       printf  PREGISTER,"{a7<-%08x}",1,%a0
+       move.l  %a0,%usp
+       rts
+
+       .data
+       .align  4
+
+fp_debugprint:
+|      .long   PMDECODE
+       .long   PMINSTR+PMDECODE+PMCONV+PMNORM
+|      .long   PMCONV+PMNORM+PMINSTR
+|      .long   0
diff --git a/arch/m68k/math-emu/fp_log.c b/arch/m68k/math-emu/fp_log.c
new file mode 100644 (file)
index 0000000..8e1c964
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+
+  fp_trig.c: floating-point math routines for the Linux-m68k
+  floating point emulator.
+
+  Copyright (c) 1998-1999 David Huggins-Daines / Roman Zippel.
+
+  I hereby give permission, free of charge, to copy, modify, and
+  redistribute this software, in source or binary form, provided that
+  the above copyright notice and the following disclaimer are included
+  in all such copies.
+
+  THIS SOFTWARE IS PROVIDED "AS IS", WITH ABSOLUTELY NO WARRANTY, REAL
+  OR IMPLIED.
+
+*/
+
+#include "fp_emu.h"
+
+struct fp_ext *
+fp_fsqrt(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("fsqrt\n");
+
+       fp_monadic_check(dest, src);
+
+       if (IS_ZERO(dest))
+               return dest;
+
+       if (dest->sign) {
+               fp_set_nan(dest);
+               return dest;
+       }
+       if (IS_INF(dest))
+               return dest;
+
+       return dest;
+}
+
+struct fp_ext *
+fp_fetoxm1(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("fetoxm1\n");
+
+       fp_monadic_check(dest, src);
+
+       if (IS_ZERO(dest))
+               return dest;
+
+       return dest;
+}
+
+struct fp_ext *
+fp_fetox(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("fetox\n");
+
+       fp_monadic_check(dest, src);
+
+       return dest;
+}
+
+struct fp_ext *
+fp_ftwotox(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("ftwotox\n");
+
+       fp_monadic_check(dest, src);
+
+       return dest;
+}
+
+struct fp_ext *
+fp_ftentox(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("ftentox\n");
+
+       fp_monadic_check(dest, src);
+
+       return dest;
+}
+
+struct fp_ext *
+fp_flogn(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("flogn\n");
+
+       fp_monadic_check(dest, src);
+
+       return dest;
+}
+
+struct fp_ext *
+fp_flognp1(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("flognp1\n");
+
+       fp_monadic_check(dest, src);
+
+       return dest;
+}
+
+struct fp_ext *
+fp_flog10(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("flog10\n");
+
+       fp_monadic_check(dest, src);
+
+       return dest;
+}
+
+struct fp_ext *
+fp_flog2(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("flog2\n");
+
+       fp_monadic_check(dest, src);
+
+       return dest;
+}
+
+struct fp_ext *
+fp_fgetexp(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("fgetexp\n");
+
+       fp_monadic_check(dest, src);
+
+       return dest;
+}
+
+struct fp_ext *
+fp_fgetman(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("fgetman\n");
+
+       fp_monadic_check(dest, src);
+
+       return dest;
+}
+
diff --git a/arch/m68k/math-emu/fp_move.S b/arch/m68k/math-emu/fp_move.S
new file mode 100644 (file)
index 0000000..45fb02b
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * fp_move.S
+ *
+ * Copyright Roman Zippel, 1997.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions.  (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fp_emu.h"
+#include "fp_decode.h"
+
+do_no_pc_mode=1
+
+       .globl  fp_fmove_fp2mem
+
+fp_fmove_fp2mem:
+       clr.b   (2+FPD_FPSR,FPDATA)
+       fp_decode_dest_format
+       move.w  %d0,%d1                 | store data size twice in %d1
+       swap    %d1                     | one can be trashed below
+       move.w  %d0,%d1
+#ifdef FPU_EMU_DEBUG
+       lea     0f,%a0
+       clr.l   %d0
+       move.b  (%a0,%d1.w),%d0
+       printf  PDECODE,"fmove.%c ",1,%d0
+       fp_decode_src_reg
+       printf  PDECODE,"fp%d,",1,%d0
+
+       .data
+0:     .byte   'l','s','x','p','w','d','b','p'
+       .previous
+#endif
+
+       | encode addressing mode for dest
+       fp_decode_addr_mode
+
+       .long   fp_data, fp_ill
+       .long   fp_indirect, fp_postinc
+       .long   fp_predecr, fp_disp16
+       .long   fp_extmode0, fp_extmode1
+
+       | addressing mode: data register direct
+fp_data:
+       fp_mode_data_direct
+       move.w  %d0,%d1
+       fp_decode_src_reg
+       fp_get_fp_reg
+       lea     (FPD_TEMPFP1,FPDATA),%a1
+       move.l  (%a0)+,(%a1)+
+       move.l  (%a0)+,(%a1)+
+       move.l  (%a0),(%a1)
+       lea     (-8,%a1),%a0
+       swap    %d1
+       move.l  %d1,%d2
+       printf  PDECODE,"\n"
+       jmp     ([0f:w,%pc,%d1.w*4])
+
+       .align  4
+0:
+       .long   fp_data_long, fp_data_single
+       .long   fp_ill, fp_ill
+       .long   fp_data_word, fp_ill
+       .long   fp_data_byte, fp_ill
+
+fp_data_byte:
+       jsr     fp_normalize_ext
+       jsr     fp_conv_ext2byte
+       move.l  %d0,%d1
+       swap    %d2
+       move.w  %d2,%d0
+       jsr     fp_get_data_reg
+       move.b  %d1,%d0
+       move.w  %d2,%d1
+       jsr     fp_put_data_reg
+       jra     fp_final
+
+fp_data_word:
+       jsr     fp_normalize_ext
+       jsr     fp_conv_ext2short
+       move.l  %d0,%d1
+       swap    %d2
+       move.w  %d2,%d0
+       jsr     fp_get_data_reg
+       move.w  %d1,%d0
+       move.l  %d2,%d1
+       jsr     fp_put_data_reg
+       jra     fp_final
+
+fp_data_long:
+       jsr     fp_normalize_ext
+       jsr     fp_conv_ext2long
+       swap    %d2
+       move.w  %d2,%d1
+       jsr     fp_put_data_reg
+       jra     fp_final
+
+fp_data_single:
+       jsr     fp_normalize_ext
+       jsr     fp_conv_ext2single
+       swap    %d2
+       move.w  %d2,%d1
+       jsr     fp_put_data_reg
+       jra     fp_final
+
+       | addressing mode: address register indirect
+fp_indirect:
+       fp_mode_addr_indirect
+       jra     fp_putdest
+
+       | addressing mode: address register indirect with postincrement
+fp_postinc:
+       fp_mode_addr_indirect_postinc
+       jra     fp_putdest
+
+       | addressing mode: address register indirect with predecrement
+fp_predecr:
+       fp_mode_addr_indirect_predec
+       jra     fp_putdest
+
+       | addressing mode: address register indirect with 16bit displacement
+fp_disp16:
+       fp_mode_addr_indirect_disp16
+       jra     fp_putdest
+
+fp_extmode0:
+       fp_mode_addr_indirect_extmode0
+       jra     fp_putdest
+
+fp_extmode1:
+       fp_decode_addr_reg
+       jmp     ([0f:w,%pc,%d0*4])
+
+       .align  4
+0:
+       .long   fp_abs_short, fp_abs_long
+       .long   fp_ill, fp_ill
+       .long   fp_ill, fp_ill
+       .long   fp_ill, fp_ill
+
+fp_abs_short:
+       fp_mode_abs_short
+       jra     fp_putdest
+
+fp_abs_long:
+       fp_mode_abs_long
+       jra     fp_putdest
+
+fp_putdest:
+       move.l  %a0,%a1
+       fp_decode_src_reg
+       move.l  %d1,%d2                 | save size
+       fp_get_fp_reg
+       printf  PDECODE,"\n"
+       addq.l  #8,%a0
+       move.l  (%a0),-(%sp)
+       move.l  -(%a0),-(%sp)
+       move.l  -(%a0),-(%sp)
+       move.l  %sp,%a0
+       jsr     fp_normalize_ext
+
+       swap    %d2
+       jmp     ([0f:w,%pc,%d2.w*4])
+
+       .align  4
+0:
+       .long   fp_format_long, fp_format_single
+       .long   fp_format_extended, fp_format_packed
+       .long   fp_format_word, fp_format_double
+       .long   fp_format_byte, fp_format_packed
+
+fp_format_long:
+       jsr     fp_conv_ext2long
+       putuser.l %d0,(%a1),fp_err_ua1,%a1
+       jra     fp_finish_move
+
+fp_format_single:
+       jsr     fp_conv_ext2single
+       putuser.l %d0,(%a1),fp_err_ua1,%a1
+       jra     fp_finish_move
+
+fp_format_extended:
+       move.l  (%a0)+,%d0
+       lsl.w   #1,%d0
+       lsl.l   #7,%d0
+       lsl.l   #8,%d0
+       putuser.l %d0,(%a1)+,fp_err_ua1,%a1
+       move.l  (%a0)+,%d0
+       putuser.l %d0,(%a1)+,fp_err_ua1,%a1
+       move.l  (%a0),%d0
+       putuser.l %d0,(%a1),fp_err_ua1,%a1
+       jra     fp_finish_move
+
+fp_format_packed:
+       /* not supported yet */
+       lea     (12,%sp),%sp
+       jra     fp_ill
+
+fp_format_word:
+       jsr     fp_conv_ext2short
+       putuser.w %d0,(%a1),fp_err_ua1,%a1
+       jra     fp_finish_move
+
+fp_format_double:
+       jsr     fp_conv_ext2double
+       jra     fp_finish_move
+
+fp_format_byte:
+       jsr     fp_conv_ext2byte
+       putuser.b %d0,(%a1),fp_err_ua1,%a1
+|      jra     fp_finish_move
+
+fp_finish_move:
+       lea     (12,%sp),%sp
+       jra     fp_final
diff --git a/arch/m68k/math-emu/fp_movem.S b/arch/m68k/math-emu/fp_movem.S
new file mode 100644 (file)
index 0000000..01058b3
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ * fp_movem.S
+ *
+ * Copyright Roman Zippel, 1997.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions.  (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fp_emu.h"
+#include "fp_decode.h"
+
+| set flags for decode macros for fmovem
+do_fmovem=1
+
+       .globl  fp_fmovem_fp, fp_fmovem_cr
+
+| %d1 contains the mask and count of the register list
+| for other register usage see fp_decode.h
+
+fp_fmovem_fp:
+       printf  PDECODE,"fmovem.x "
+       | get register list and count them
+       btst    #11,%d2
+       jne     1f
+       bfextu  %d2{#24,#8},%d0         | static register list
+       jra     2f
+1:     bfextu  %d2{#25,#3},%d0         | dynamic register list
+       jsr     fp_get_data_reg
+2:     move.l  %d0,%d1
+       swap    %d1
+       jra     2f
+1:     addq.w  #1,%d1                  | count the # of registers in
+2:     lsr.b   #1,%d0                  | register list and keep it in %d1
+       jcs     1b
+       jne     2b
+       printf  PDECODE,"#%08x",1,%d1
+#ifdef FPU_EMU_DEBUG
+       btst    #12,%d2
+       jne     1f
+       printf  PDECODE,"-"             | decremental move
+       jra     2f
+1:     printf  PDECODE,"+"             | incremental move
+2:     btst    #13,%d2
+       jeq     1f
+       printf  PDECODE,"->"            | fpu -> cpu
+       jra     2f
+1:     printf  PDECODE,"<-"            | fpu <- cpu
+2:
+#endif
+
+       | decode address mode
+       fp_decode_addr_mode
+
+       .long   fp_ill, fp_ill
+       .long   fpr_indirect, fpr_postinc
+       .long   fpr_predecr, fpr_disp16
+       .long   fpr_extmode0, fpr_extmode1
+
+       | addressing mode: address register indirect
+fpr_indirect:
+       fp_mode_addr_indirect
+       jra     fpr_do_movem
+
+       | addressing mode: address register indirect with postincrement
+fpr_postinc:
+       fp_mode_addr_indirect_postinc
+       jra     fpr_do_movem
+
+fpr_predecr:
+       fp_mode_addr_indirect_predec
+       jra     fpr_do_movem
+
+       | addressing mode: address register/programm counter indirect
+       |                  with 16bit displacement
+fpr_disp16:
+       fp_mode_addr_indirect_disp16
+       jra     fpr_do_movem
+
+fpr_extmode0:
+       fp_mode_addr_indirect_extmode0
+       jra     fpr_do_movem
+
+fpr_extmode1:
+       fp_decode_addr_reg
+       jmp     ([0f:w,%pc,%d0*4])
+
+       .align  4
+0:
+       .long   fpr_absolute_short, fpr_absolute_long
+       .long   fpr_disp16, fpr_extmode0
+       .long   fp_ill, fp_ill
+       .long   fp_ill, fp_ill
+
+fpr_absolute_short:
+       fp_mode_abs_short
+       jra     fpr_do_movem
+
+fpr_absolute_long:
+       fp_mode_abs_long
+|      jra     fpr_do_movem
+
+fpr_do_movem:
+       swap    %d1                     | get fpu register list
+       lea     (FPD_FPREG,FPDATA),%a1
+       moveq   #12,%d0
+       btst    #12,%d2
+       jne     1f
+       lea     (-12,%a1,%d0*8),%a1
+       neg.l   %d0
+1:     btst    #13,%d2
+       jne     4f
+       | move register from memory into fpu
+       jra     3f
+1:     printf  PMOVEM,"(%p>%p)",2,%a0,%a1
+       getuser.l (%a0)+,%d2,fp_err_ua1,%a0
+       lsr.l   #8,%d2
+       lsr.l   #7,%d2
+       lsr.w   #1,%d2
+       move.l  %d2,(%a1)+
+       getuser.l (%a0)+,%d2,fp_err_ua1,%a0
+       move.l  %d2,(%a1)+
+       getuser.l (%a0),%d2,fp_err_ua1,%a0
+       move.l  %d2,(%a1)
+       subq.l  #8,%a0
+       subq.l  #8,%a1
+       add.l   %d0,%a0
+2:     add.l   %d0,%a1
+3:     lsl.b   #1,%d1
+       jcs     1b
+       jne     2b
+       jra     5f
+       | move register from fpu into memory
+1:     printf  PMOVEM,"(%p>%p)",2,%a1,%a0
+       move.l  (%a1)+,%d2
+       lsl.w   #1,%d2
+       lsl.l   #7,%d2
+       lsl.l   #8,%d2
+       putuser.l %d2,(%a0)+,fp_err_ua1,%a0
+       move.l  (%a1)+,%d2
+       putuser.l %d2,(%a0)+,fp_err_ua1,%a0
+       move.l  (%a1),%d2
+       putuser.l %d2,(%a0),fp_err_ua1,%a0
+       subq.l  #8,%a1
+       subq.l  #8,%a0
+       add.l   %d0,%a0
+2:     add.l   %d0,%a1
+4:     lsl.b   #1,%d1
+       jcs     1b
+       jne     2b
+5:
+       printf  PDECODE,"\n"
+#if 0
+       lea     (FPD_FPREG,FPDATA),%a0
+       printf  PMOVEM,"fp:"
+       printx  PMOVEM,%a0@(0)
+       printx  PMOVEM,%a0@(12)
+       printf  PMOVEM,"\n   "
+       printx  PMOVEM,%a0@(24)
+       printx  PMOVEM,%a0@(36)
+       printf  PMOVEM,"\n   "
+       printx  PMOVEM,%a0@(48)
+       printx  PMOVEM,%a0@(60)
+       printf  PMOVEM,"\n   "
+       printx  PMOVEM,%a0@(72)
+       printx  PMOVEM,%a0@(84)
+       printf  PMOVEM,"\n"
+#endif
+       jra     fp_end
+
+| set flags for decode macros for fmovem control register
+do_fmovem=1
+do_fmovem_cr=1
+
+fp_fmovem_cr:
+       printf  PDECODE,"fmovem.cr "
+       | get register list and count them
+       bfextu  %d2{#19,#3},%d0
+       move.l  %d0,%d1
+       swap    %d1
+       jra     2f
+1:     addq.w  #1,%d1
+2:     lsr.l   #1,%d0
+       jcs     1b
+       jne     2b
+       printf  PDECODE,"#%08x",1,%d1
+#ifdef FPU_EMU_DEBUG
+       btst    #13,%d2
+       jeq     1f
+       printf  PDECODE,"->"            | fpu -> cpu
+       jra     2f
+1:     printf  PDECODE,"<-"            | fpu <- cpu
+2:
+#endif
+
+       | decode address mode
+       fp_decode_addr_mode
+
+       .long   fpc_data, fpc_addr
+       .long   fpc_indirect, fpc_postinc
+       .long   fpc_predecr, fpc_disp16
+       .long   fpc_extmode0, fpc_extmode1
+
+fpc_data:
+       fp_mode_data_direct
+       move.w  %d0,%d1
+       bfffo   %d2{#19,#3},%d0
+       sub.w   #19,%d0
+       lea     (FPD_FPCR,FPDATA,%d0.w*4),%a1
+       btst    #13,%d2
+       jne     1f
+       move.w  %d1,%d0
+       jsr     fp_get_data_reg
+       move.l  %d0,(%a1)
+       jra     fpc_movem_fin
+1:     move.l  (%a1),%d0
+       jsr     fp_put_data_reg
+       jra     fpc_movem_fin
+
+fpc_addr:
+       fp_decode_addr_reg
+       printf  PDECODE,"a%d",1,%d0
+       btst    #13,%d2
+       jne     1f
+       jsr     fp_get_addr_reg
+       move.l  %a0,(FPD_FPIAR,FPDATA)
+       jra     fpc_movem_fin
+1:     move.l  (FPD_FPIAR,FPDATA),%a0
+       jsr     fp_put_addr_reg
+       jra     fpc_movem_fin
+
+fpc_indirect:
+       fp_mode_addr_indirect
+       jra     fpc_do_movem
+
+fpc_postinc:
+       fp_mode_addr_indirect_postinc
+       jra     fpc_do_movem
+
+fpc_predecr:
+       fp_mode_addr_indirect_predec
+       jra     fpc_do_movem
+
+fpc_disp16:
+       fp_mode_addr_indirect_disp16
+       jra     fpc_do_movem
+
+fpc_extmode0:
+       fp_mode_addr_indirect_extmode0
+       jra     fpc_do_movem
+
+fpc_extmode1:
+       fp_decode_addr_reg
+       jmp     ([0f:w,%pc,%d0*4])
+
+       .align  4
+0:
+       .long   fpc_absolute_short, fpc_absolute_long
+       .long   fpc_disp16, fpc_extmode0
+       .long   fpc_immediate, fp_ill
+       .long   fp_ill, fp_ill
+
+fpc_absolute_short:
+       fp_mode_abs_short
+       jra     fpc_do_movem
+
+fpc_absolute_long:
+       fp_mode_abs_long
+       jra     fpc_do_movem
+
+fpc_immediate:
+       fp_get_pc %a0
+       lea     (%a0,%d1.w*4),%a1
+       fp_put_pc %a1
+       printf  PDECODE,"#imm"
+|      jra     fpc_do_movem
+#if 0
+       swap    %d1
+       lsl.l   #5,%d1
+       lea     (FPD_FPCR,FPDATA),%a0
+       jra     3f
+1:     move.l  %d0,(%a0)
+2:     addq.l  #4,%a0
+3:     lsl.b   #1,%d1
+       jcs     1b
+       jne     2b
+       jra     fpc_movem_fin
+#endif
+
+fpc_do_movem:
+       swap    %d1                     | get fpu register list
+       lsl.l   #5,%d1
+       lea     (FPD_FPCR,FPDATA),%a1
+1:     btst    #13,%d2
+       jne     4f
+
+       | move register from memory into fpu
+       jra     3f
+1:     printf  PMOVEM,"(%p>%p)",2,%a0,%a1
+       getuser.l (%a0)+,%d0,fp_err_ua1,%a0
+       move.l  %d0,(%a1)
+2:     addq.l  #4,%a1
+3:     lsl.b   #1,%d1
+       jcs     1b
+       jne     2b
+       jra     fpc_movem_fin
+
+       | move register from fpu into memory
+1:     printf  PMOVEM,"(%p>%p)",2,%a1,%a0
+       move.l  (%a1),%d0
+       putuser.l %d0,(%a0)+,fp_err_ua1,%a0
+2:     addq.l  #4,%a1
+4:     lsl.b   #1,%d1
+       jcs     1b
+       jne     2b
+
+fpc_movem_fin:
+       and.l   #0x0000fff0,(FPD_FPCR,FPDATA)
+       and.l   #0x0ffffff8,(FPD_FPSR,FPDATA)
+       move.l  (FPD_FPCR,FPDATA),%d0
+       lsr.l   #4,%d0
+       moveq   #3,%d1
+       and.l   %d0,%d1
+       move.w  %d1,(FPD_RND,FPDATA)
+       lsr.l   #2,%d0
+       moveq   #3,%d1
+       and.l   %d0,%d1
+       move.w  %d1,(FPD_PREC,FPDATA)
+       printf  PDECODE,"\n"
+#if 0
+       printf  PMOVEM,"fpcr : %08x\n",1,FPDATA@(FPD_FPCR)
+       printf  PMOVEM,"fpsr : %08x\n",1,FPDATA@(FPD_FPSR)
+       printf  PMOVEM,"fpiar: %08x\n",1,FPDATA@(FPD_FPIAR)
+       clr.l   %d0
+       move.w  (FPD_PREC,FPDATA),%d0
+       printf  PMOVEM,"prec : %04x\n",1,%d0
+       move.w  (FPD_RND,FPDATA),%d0
+       printf  PMOVEM,"rnd  : %04x\n",1,%d0
+#endif
+       jra     fp_end
diff --git a/arch/m68k/math-emu/fp_scan.S b/arch/m68k/math-emu/fp_scan.S
new file mode 100644 (file)
index 0000000..4f40491
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+ * fp_scan.S
+ *
+ * Copyright Roman Zippel, 1997.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions.  (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fp_emu.h"
+#include "fp_decode.h"
+
+       .globl  fp_scan, fp_datasize
+
+       .data
+
+| %d2 - first two instr words
+| %d1 - operand size
+
+/* operand formats are:
+
+       Long = 0,               i.e. fmove.l
+       Single,                 i.e. fmove.s
+       Extended,               i.e. fmove.x
+       Packed-BCD,             i.e. fmove.p
+       Word,                   i.e. fmove.w
+       Double,                 i.e. fmove.d
+*/
+
+       .text
+
+| On entry:
+| FPDATA - base of emulated FPU registers
+
+fp_scan:
+| normal fpu instruction? (this excludes fsave/frestore)
+       fp_get_pc %a0
+       printf  PDECODE,"%08x: ",1,%a0
+       getuser.b (%a0),%d0,fp_err_ua1,%a0
+#if 1
+       cmp.b   #0xf2,%d0               | cpid = 1
+#else
+       cmp.b   #0xfc,%d0               | cpid = 6
+#endif
+       jne     fp_nonstd
+| first two instruction words are kept in %d2
+       getuser.l (%a0)+,%d2,fp_err_ua1,%a0
+       fp_put_pc %a0
+fp_decode_cond:                                | seperate conditional instr
+       fp_decode_cond_instr_type
+
+       .long   fp_decode_move, fp_fscc
+       .long   fp_fbccw, fp_fbccl
+
+fp_decode_move:                                | seperate move instr
+       fp_decode_move_instr_type
+
+       .long   fp_fgen_fp, fp_ill
+       .long   fp_fgen_ea, fp_fmove_fp2mem
+       .long   fp_fmovem_cr, fp_fmovem_cr
+       .long   fp_fmovem_fp, fp_fmovem_fp
+
+| now all arithmetic instr and a few move instr are left
+fp_fgen_fp:                            | source is a fpu register
+       clr.b   (FPD_FPSR+2,FPDATA)     | clear the exception byte
+       fp_decode_sourcespec
+       printf  PDECODE,"f<op>.x fp%d",1,%d0
+       fp_get_fp_reg
+       lea     (FPD_TEMPFP1,FPDATA),%a1 | copy src into a temp location
+       move.l  (%a0)+,(%a1)+
+       move.l  (%a0)+,(%a1)+
+       move.l  (%a0),(%a1)
+       lea     (-8,%a1),%a0
+       jra     fp_getdest
+
+fp_fgen_ea:                            | source is <ea>
+       clr.b   (FPD_FPSR+2,FPDATA)     | clear the exception byte
+       | sort out fmovecr, keep data size in %d1
+       fp_decode_sourcespec
+       cmp.w   #7,%d0
+       jeq     fp_fmovecr
+       move.w  %d0,%d1                 | store data size twice in %d1
+       swap    %d1                     | one can be trashed below
+       move.w  %d0,%d1
+#ifdef FPU_EMU_DEBUG
+       lea     0f,%a0
+       clr.l   %d0
+       move.b  (%a0,%d1.w),%d0
+       printf  PDECODE,"f<op>.%c ",1,%d0
+
+       .data
+0:     .byte   'l','s','x','p','w','d','b',0
+       .previous
+#endif
+
+/*
+       fp_getsource, fp_getdest
+
+       basically, we end up with a pointer to the source operand in
+       %a1, and a pointer to the destination operand in %a0.  both
+       are, of course, 96-bit extended floating point numbers.
+*/
+
+fp_getsource:
+       | decode addressing mode for source
+       fp_decode_addr_mode
+
+       .long   fp_data, fp_ill
+       .long   fp_indirect, fp_postinc
+       .long   fp_predecr, fp_disp16
+       .long   fp_extmode0, fp_extmode1
+
+       | addressing mode: data register direct
+fp_data:
+       fp_mode_data_direct
+       jsr     fp_get_data_reg
+       lea     (FPD_TEMPFP1,FPDATA),%a0
+       jmp     ([0f:w,%pc,%d1.w*4])
+
+       .align  4
+0:
+       .long   fp_data_long, fp_data_single
+       .long   fp_ill, fp_ill
+       .long   fp_data_word, fp_ill
+       .long   fp_data_byte, fp_ill
+
+       | data types that fit in an integer data register
+fp_data_byte:
+       extb.l  %d0
+       jra     fp_data_long
+
+fp_data_word:
+       ext.l   %d0
+
+fp_data_long:
+       jsr     fp_conv_long2ext
+       jra     fp_getdest
+
+fp_data_single:
+       jsr     fp_conv_single2ext
+       jra     fp_getdest
+
+       | addressing mode: address register indirect
+fp_indirect:
+       fp_mode_addr_indirect
+       jra     fp_fetchsource
+
+       | addressing mode: address register indirect with postincrement
+fp_postinc:
+       fp_mode_addr_indirect_postinc
+       jra     fp_fetchsource
+
+       | addressing mode: address register indirect with predecrement
+fp_predecr:
+       fp_mode_addr_indirect_predec
+       jra     fp_fetchsource
+
+       | addressing mode: address register/programm counter indirect
+       |                  with 16bit displacement
+fp_disp16:
+       fp_mode_addr_indirect_disp16
+       jra     fp_fetchsource
+
+       | all other indirect addressing modes will finally end up here
+fp_extmode0:
+       fp_mode_addr_indirect_extmode0
+       jra     fp_fetchsource
+
+| all pc relative addressing modes and immediate/absolute modes end up here
+| the first ones are sent to fp_extmode0 or fp_disp16
+| and only the latter are handled here
+fp_extmode1:
+       fp_decode_addr_reg
+       jmp     ([0f:w,%pc,%d0*4])
+
+       .align  4
+0:
+       .long   fp_abs_short, fp_abs_long
+       .long   fp_disp16, fp_extmode0
+       .long   fp_immediate, fp_ill
+       .long   fp_ill, fp_ill
+
+       | addressing mode: absolute short
+fp_abs_short:
+       fp_mode_abs_short
+       jra     fp_fetchsource
+
+       | addressing mode: absolute long
+fp_abs_long:
+       fp_mode_abs_long
+       jra     fp_fetchsource
+
+       | addressing mode: immediate data
+fp_immediate:
+       printf  PDECODE,"#"
+       fp_get_pc %a0
+       move.w  (fp_datasize,%d1.w*2),%d0
+       addq.w  #1,%d0
+       and.w   #-2,%d0
+#ifdef FPU_EMU_DEBUG
+       movem.l %d0/%d1,-(%sp)
+       movel   %a0,%a1
+       clr.l   %d1
+       jra     2f
+1:     getuser.b (%a1)+,%d1,fp_err_ua1,%a1
+       printf  PDECODE,"%02x",1,%d1
+2:     dbra    %d0,1b
+       movem.l (%sp)+,%d0/%d1
+#endif
+       lea     (%a0,%d0.w),%a1
+       fp_put_pc %a1
+|      jra     fp_fetchsource
+
+fp_fetchsource:
+       move.l  %a0,%a1
+       swap    %d1
+       lea     (FPD_TEMPFP1,FPDATA),%a0
+       jmp     ([0f:w,%pc,%d1.w*4])
+
+       .align  4
+0:     .long   fp_long, fp_single
+       .long   fp_ext, fp_pack
+       .long   fp_word, fp_double
+       .long   fp_byte, fp_ill
+
+fp_long:
+       getuser.l (%a1),%d0,fp_err_ua1,%a1
+       jsr     fp_conv_long2ext
+       jra     fp_getdest
+
+fp_single:
+       getuser.l (%a1),%d0,fp_err_ua1,%a1
+       jsr     fp_conv_single2ext
+       jra     fp_getdest
+
+fp_ext:
+       getuser.l (%a1)+,%d0,fp_err_ua1,%a1
+       lsr.l   #8,%d0
+       lsr.l   #7,%d0
+       lsr.w   #1,%d0
+       move.l  %d0,(%a0)+
+       getuser.l (%a1)+,%d0,fp_err_ua1,%a1
+       move.l  %d0,(%a0)+
+       getuser.l (%a1),%d0,fp_err_ua1,%a1
+       move.l  %d0,(%a0)
+       subq.l  #8,%a0
+       jra     fp_getdest
+
+fp_pack:
+       /* not supported yet */
+       jra     fp_ill
+
+fp_word:
+       getuser.w (%a1),%d0,fp_err_ua1,%a1
+       ext.l   %d0
+       jsr     fp_conv_long2ext
+       jra     fp_getdest
+
+fp_double:
+       jsr     fp_conv_double2ext
+       jra     fp_getdest
+
+fp_byte:
+       getuser.b (%a1),%d0,fp_err_ua1,%a1
+       extb.l  %d0
+       jsr     fp_conv_long2ext
+|      jra     fp_getdest
+
+fp_getdest:
+       move.l  %a0,%a1
+       bfextu  %d2{#22,#3},%d0
+       printf  PDECODE,",fp%d\n",1,%d0
+       fp_get_fp_reg
+       movem.l %a0/%a1,-(%sp)
+       pea     fp_finalrounding
+       bfextu  %d2{#25,#7},%d0
+       jmp     ([0f:w,%pc,%d0*4])
+
+       .align  4
+0:
+       .long   fp_fmove_mem2fp, fp_fint, fp_fsinh, fp_fintrz
+       .long   fp_fsqrt, fp_ill, fp_flognp1, fp_ill
+       .long   fp_fetoxm1, fp_ftanh, fp_fatan, fp_ill
+       .long   fp_fasin, fp_fatanh, fp_fsin, fp_ftan
+       .long   fp_fetox, fp_ftwotox, fp_ftentox, fp_ill
+       .long   fp_flogn, fp_flog10, fp_flog2, fp_ill
+       .long   fp_fabs, fp_fcosh, fp_fneg, fp_ill
+       .long   fp_facos, fp_fcos, fp_fgetexp, fp_fgetman
+       .long   fp_fdiv, fp_fmod, fp_fadd, fp_fmul
+       .long   fpa_fsgldiv, fp_frem, fp_fscale, fpa_fsglmul
+       .long   fp_fsub, fp_ill, fp_ill, fp_ill
+       .long   fp_ill, fp_ill, fp_ill, fp_ill
+       .long   fp_fsincos0, fp_fsincos1, fp_fsincos2, fp_fsincos3
+       .long   fp_fsincos4, fp_fsincos5, fp_fsincos6, fp_fsincos7
+       .long   fp_fcmp, fp_ill, fp_ftst, fp_ill
+       .long   fp_ill, fp_ill, fp_ill, fp_ill
+       .long   fp_fsmove, fp_fssqrt, fp_ill, fp_ill
+       .long   fp_fdmove, fp_fdsqrt, fp_ill, fp_ill
+       .long   fp_ill, fp_ill, fp_ill, fp_ill
+       .long   fp_ill, fp_ill, fp_ill, fp_ill
+       .long   fp_ill, fp_ill, fp_ill, fp_ill
+       .long   fp_ill, fp_ill, fp_ill, fp_ill
+       .long   fp_fsabs, fp_ill, fp_fsneg, fp_ill
+       .long   fp_fdabs, fp_ill, fp_fdneg, fp_ill
+       .long   fp_fsdiv, fp_ill, fp_fsadd, fp_fsmul
+       .long   fp_fddiv, fp_ill, fp_fdadd, fp_fdmul
+       .long   fp_fssub, fp_ill, fp_ill, fp_ill
+       .long   fp_fdsub, fp_ill, fp_ill, fp_ill
+       .long   fp_ill, fp_ill, fp_ill, fp_ill
+       .long   fp_ill, fp_ill, fp_ill, fp_ill
+       .long   fp_ill, fp_ill, fp_ill, fp_ill
+       .long   fp_ill, fp_ill, fp_ill, fp_ill
+
+       | Instructions follow
+
+       | Move an (emulated) ROM constant
+fp_fmovecr:
+       bfextu  %d2{#27,#5},%d0
+       printf  PINSTR,"fp_fmovecr #%d",1,%d0
+       move.l  %d0,%d1
+       add.l   %d0,%d0
+       add.l   %d1,%d0
+       lea     (fp_constants,%d0*4),%a0
+       move.l  #0x801cc0ff,%d0
+       addq.l  #1,%d1
+       lsl.l   %d1,%d0
+       jcc     1f
+       fp_set_sr FPSR_EXC_INEX2                        | INEX2 exception
+1:     moveq   #-128,%d0                               | continue with fmove
+       and.l   %d0,%d2
+       jra     fp_getdest
+
+       .data
+       .align  4
+fp_constants:
+       .long   0x00004000,0xc90fdaa2,0x2168c235        | pi
+       .extend 0,0,0,0,0,0,0,0,0,0
+       .long   0x00003ffd,0x9a209a84,0xfbcff798        | log10(2)
+       .long   0x00004000,0xadf85458,0xa2bb4a9a        | e
+       .long   0x00003fff,0xb8aa3b29,0x5c17f0bc        | log2(e)
+       .long   0x00003ffd,0xde5bd8a9,0x37287195        | log10(e)
+       .long   0x00000000,0x00000000,0x00000000        | 0.0
+       .long   0x00003ffe,0xb17217f7,0xd1cf79ac        | 1n(2)
+       .long   0x00004000,0x935d8ddd,0xaaa8ac17        | 1n(10)
+       | read this as "1.0 * 2^0" - note the high bit in the mantissa
+       .long   0x00003fff,0x80000000,0x00000000        | 10^0
+       .long   0x00004002,0xa0000000,0x00000000        | 10^1
+       .long   0x00004005,0xc8000000,0x00000000        | 10^2
+       .long   0x0000400c,0x9c400000,0x00000000        | 10^4
+       .long   0x00004019,0xbebc2000,0x00000000        | 10^8
+       .long   0x00004034,0x8e1bc9bf,0x04000000        | 10^16
+       .long   0x00004069,0x9dc5ada8,0x2b70b59e        | 10^32
+       .long   0x000040d3,0xc2781f49,0xffcfa6d5        | 10^64
+       .long   0x000041a8,0x93ba47c9,0x80e98ce0        | 10^128
+       .long   0x00004351,0xaa7eebfb,0x9df9de8e        | 10^256
+       .long   0x000046a3,0xe319a0ae,0xa60e91c7        | 10^512
+       .long   0x00004d48,0xc9767586,0x81750c17        | 10^1024
+       .long   0x00005a92,0x9e8b3b5d,0xc53d5de5        | 10^2048
+       .long   0x00007525,0xc4605202,0x8a20979b        | 10^4096
+       .previous
+
+fp_fmove_mem2fp:
+       printf  PINSTR,"fmove %p,%p\n",2,%a0,%a1
+       move.l  (%a1)+,(%a0)+
+       move.l  (%a1)+,(%a0)+
+       move.l  (%a1),(%a0)
+       subq.l  #8,%a0
+       rts
+
+fpa_fsglmul:
+       move.l  #fp_finalrounding_single_fast,(%sp)
+       jra     fp_fsglmul
+
+fpa_fsgldiv:
+       move.l  #fp_finalrounding_single_fast,(%sp)
+       jra     fp_fsgldiv
+
+.macro fp_dosingleprec instr
+       printf  PINSTR,"single "
+       move.l  #fp_finalrounding_single,(%sp)
+       jra     \instr
+.endm
+
+.macro fp_dodoubleprec instr
+       printf  PINSTR,"double "
+       move.l  #fp_finalrounding_double,(%sp)
+       jra     \instr
+.endm
+
+fp_fsmove:
+       fp_dosingleprec fp_fmove_mem2fp
+
+fp_fssqrt:
+       fp_dosingleprec fp_fsqrt
+
+fp_fdmove:
+       fp_dodoubleprec fp_fmove_mem2fp
+
+fp_fdsqrt:
+       fp_dodoubleprec fp_fsqrt
+
+fp_fsabs:
+       fp_dosingleprec fp_fabs
+
+fp_fsneg:
+       fp_dosingleprec fp_fneg
+
+fp_fdabs:
+       fp_dodoubleprec fp_fabs
+
+fp_fdneg:
+       fp_dodoubleprec fp_fneg
+
+fp_fsdiv:
+       fp_dosingleprec fp_fdiv
+
+fp_fsadd:
+       fp_dosingleprec fp_fadd
+
+fp_fsmul:
+       fp_dosingleprec fp_fmul
+
+fp_fddiv:
+       fp_dodoubleprec fp_fdiv
+
+fp_fdadd:
+       fp_dodoubleprec fp_fadd
+
+fp_fdmul:
+       fp_dodoubleprec fp_fmul
+
+fp_fssub:
+       fp_dosingleprec fp_fsub
+
+fp_fdsub:
+       fp_dodoubleprec fp_fsub
+
+fp_nonstd:
+       fp_get_pc %a0
+       getuser.l (%a0),%d0,fp_err_ua1,%a0
+       printf  ,"nonstd ((%08x)=%08x)\n",2,%a0,%d0
+       moveq   #-1,%d0
+       rts
+
+       .data
+       .align  4
+
+       | data sizes corresponding to the operand formats
+fp_datasize:
+       .word   4, 4, 12, 12, 2, 8, 1, 0
diff --git a/arch/m68k/math-emu/fp_trig.c b/arch/m68k/math-emu/fp_trig.c
new file mode 100644 (file)
index 0000000..6361d07
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+
+  fp_trig.c: floating-point math routines for the Linux-m68k
+  floating point emulator.
+
+  Copyright (c) 1998-1999 David Huggins-Daines / Roman Zippel.
+
+  I hereby give permission, free of charge, to copy, modify, and
+  redistribute this software, in source or binary form, provided that
+  the above copyright notice and the following disclaimer are included
+  in all such copies.
+
+  THIS SOFTWARE IS PROVIDED "AS IS", WITH ABSOLUTELY NO WARRANTY, REAL
+  OR IMPLIED.
+
+*/
+
+#include "fp_emu.h"
+#include "fp_trig.h"
+
+struct fp_ext *
+fp_fsin(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("fsin\n");
+
+       fp_monadic_check(dest, src);
+
+       return dest;
+}
+
+struct fp_ext *
+fp_fcos(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("fcos\n");
+
+       fp_monadic_check(dest, src);
+
+       return dest;
+}
+
+struct fp_ext *
+fp_ftan(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("ftan\n");
+
+       fp_monadic_check(dest, src);
+
+       return dest;
+}
+
+struct fp_ext *
+fp_fasin(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("fasin\n");
+
+       fp_monadic_check(dest, src);
+
+       return dest;
+}
+
+struct fp_ext *
+fp_facos(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("facos\n");
+
+       fp_monadic_check(dest, src);
+
+       return dest;
+}
+
+struct fp_ext *
+fp_fatan(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("fatan\n");
+
+       fp_monadic_check(dest, src);
+
+       return dest;
+}
+
+struct fp_ext *
+fp_fsinh(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("fsinh\n");
+
+       fp_monadic_check(dest, src);
+
+       return dest;
+}
+
+struct fp_ext *
+fp_fcosh(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("fcosh\n");
+
+       fp_monadic_check(dest, src);
+
+       return dest;
+}
+
+struct fp_ext *
+fp_ftanh(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("ftanh\n");
+
+       fp_monadic_check(dest, src);
+
+       return dest;
+}
+
+struct fp_ext *
+fp_fatanh(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("fatanh\n");
+
+       fp_monadic_check(dest, src);
+
+       return dest;
+}
+
+struct fp_ext *
+fp_fsincos0(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("fsincos0\n");
+
+       return dest;
+}
+
+struct fp_ext *
+fp_fsincos1(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("fsincos1\n");
+
+       return dest;
+}
+
+struct fp_ext *
+fp_fsincos2(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("fsincos2\n");
+
+       return dest;
+}
+
+struct fp_ext *
+fp_fsincos3(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("fsincos3\n");
+
+       return dest;
+}
+
+struct fp_ext *
+fp_fsincos4(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("fsincos4\n");
+
+       return dest;
+}
+
+struct fp_ext *
+fp_fsincos5(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("fsincos5\n");
+
+       return dest;
+}
+
+struct fp_ext *
+fp_fsincos6(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("fsincos6\n");
+
+       return dest;
+}
+
+struct fp_ext *
+fp_fsincos7(struct fp_ext *dest, struct fp_ext *src)
+{
+       uprint("fsincos7\n");
+
+       return dest;
+}
diff --git a/arch/m68k/math-emu/fp_trig.h b/arch/m68k/math-emu/fp_trig.h
new file mode 100644 (file)
index 0000000..af8b247
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+
+  fp_trig.h: floating-point math routines for the Linux-m68k
+  floating point emulator.
+
+  Copyright (c) 1998 David Huggins-Daines.
+
+  I hereby give permission, free of charge, to copy, modify, and
+  redistribute this software, in source or binary form, provided that
+  the above copyright notice and the following disclaimer are included
+  in all such copies.
+
+  THIS SOFTWARE IS PROVIDED "AS IS", WITH ABSOLUTELY NO WARRANTY, REAL
+  OR IMPLIED.
+
+*/
+
+#ifndef FP_TRIG_H
+#define FP_TRIG_H
+
+#include "fp_emu.h"
+
+/* floating point trigonometric instructions:
+
+   the arguments to these are in the "internal" extended format, that
+   is, an "exploded" version of the 96-bit extended fp format used by
+   the 68881.
+
+   they return a status code, which should end up in %d0, if all goes
+   well.  */
+
+#endif /* FP_TRIG__H */
diff --git a/arch/m68k/math-emu/fp_util.S b/arch/m68k/math-emu/fp_util.S
new file mode 100644 (file)
index 0000000..eeea869
--- /dev/null
@@ -0,0 +1,1456 @@
+/*
+ * fp_util.S
+ *
+ * Copyright Roman Zippel, 1997.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions.  (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/config.h>
+
+#include "fp_emu.h"
+
+/*
+ * Here are lots of conversion and normalization functions mainly
+ * used by fp_scan.S
+ * Note that these functions are optimized for "normal" numbers,
+ * these are handled first and exit as fast as possible, this is
+ * especially important for fp_normalize_ext/fp_conv_ext2ext, as
+ * it's called very often.
+ * The register usage is optimized for fp_scan.S and which register
+ * is currently at that time unused, be careful if you want change
+ * something here. %d0 and %d1 is always usable, sometimes %d2 (or
+ * only the lower half) most function have to return the %a0
+ * unmodified, so that the caller can immediatly reuse it.
+ */
+
+       .globl  fp_ill, fp_end
+
+       | exits from fp_scan:
+       | illegal instruction
+fp_ill:
+       printf  ,"fp_illegal\n"
+       rts
+       | completed instruction
+fp_end:
+       tst.l   (TASK_MM-8,%a2)
+       jmi     1f
+       tst.l   (TASK_MM-4,%a2)
+       jmi     1f
+       tst.l   (TASK_MM,%a2)
+       jpl     2f
+1:     printf  ,"oops:%p,%p,%p\n",3,%a2@(TASK_MM-8),%a2@(TASK_MM-4),%a2@(TASK_MM)
+2:     clr.l   %d0
+       rts
+
+       .globl  fp_conv_long2ext, fp_conv_single2ext
+       .globl  fp_conv_double2ext, fp_conv_ext2ext
+       .globl  fp_normalize_ext, fp_normalize_double
+       .globl  fp_normalize_single, fp_normalize_single_fast
+       .globl  fp_conv_ext2double, fp_conv_ext2single
+       .globl  fp_conv_ext2long, fp_conv_ext2short
+       .globl  fp_conv_ext2byte
+       .globl  fp_finalrounding_single, fp_finalrounding_single_fast
+       .globl  fp_finalrounding_double
+       .globl  fp_finalrounding, fp_finaltest, fp_final
+
+/*
+ * First several conversion functions from a source operand
+ * into the extended format. Note, that only fp_conv_ext2ext
+ * normalizes the number and is always called after the other
+ * conversion functions, which only move the information into
+ * fp_ext structure.
+ */
+
+       | fp_conv_long2ext:
+       |
+       | args: %d0 = source (32-bit long)
+       |       %a0 = destination (ptr to struct fp_ext)
+
+fp_conv_long2ext:
+       printf  PCONV,"l2e: %p -> %p(",2,%d0,%a0
+       clr.l   %d1                     | sign defaults to zero
+       tst.l   %d0
+       jeq     fp_l2e_zero             | is source zero?
+       jpl     1f                      | positive?
+       moveq   #1,%d1
+       neg.l   %d0
+1:     swap    %d1
+       move.w  #0x3fff+31,%d1
+       move.l  %d1,(%a0)+              | set sign / exp
+       move.l  %d0,(%a0)+              | set mantissa
+       clr.l   (%a0)
+       subq.l  #8,%a0                  | restore %a0
+       printx  PCONV,%a0@
+       printf  PCONV,")\n"
+       rts
+       | source is zero
+fp_l2e_zero:
+       clr.l   (%a0)+
+       clr.l   (%a0)+
+       clr.l   (%a0)
+       subq.l  #8,%a0
+       printx  PCONV,%a0@
+       printf  PCONV,")\n"
+       rts
+
+       | fp_conv_single2ext
+       | args: %d0 = source (single-precision fp value)
+       |       %a0 = dest (struct fp_ext *)
+
+fp_conv_single2ext:
+       printf  PCONV,"s2e: %p -> %p(",2,%d0,%a0
+       move.l  %d0,%d1
+       lsl.l   #8,%d0                  | shift mantissa
+       lsr.l   #8,%d1                  | exponent / sign
+       lsr.l   #7,%d1
+       lsr.w   #8,%d1
+       jeq     fp_s2e_small            | zero / denormal?
+       cmp.w   #0xff,%d1               | NaN / Inf?
+       jeq     fp_s2e_large
+       bset    #31,%d0                 | set explizit bit
+       add.w   #0x3fff-0x7f,%d1        | re-bias the exponent.
+9:     move.l  %d1,(%a0)+              | fp_ext.sign, fp_ext.exp
+       move.l  %d0,(%a0)+              | high lword of fp_ext.mant
+       clr.l   (%a0)                   | low lword = 0
+       subq.l  #8,%a0
+       printx  PCONV,%a0@
+       printf  PCONV,")\n"
+       rts
+       | zeros and denormalized
+fp_s2e_small:
+       | exponent is zero, so explizit bit is already zero too
+       tst.l   %d0
+       jeq     9b
+       move.w  #0x4000-0x7f,%d1
+       jra     9b
+       | infinities and NAN
+fp_s2e_large:
+       bclr    #31,%d0                 | clear explizit bit
+       move.w  #0x7fff,%d1
+       jra     9b
+
+fp_conv_double2ext:
+#ifdef FPU_EMU_DEBUG
+       getuser.l %a1@(0),%d0,fp_err_ua2,%a1
+       getuser.l %a1@(4),%d1,fp_err_ua2,%a1
+       printf  PCONV,"d2e: %p%p -> %p(",3,%d0,%d1,%a0
+#endif
+       getuser.l (%a1)+,%d0,fp_err_ua2,%a1
+       move.l  %d0,%d1
+       lsl.l   #8,%d0                  | shift high mantissa
+       lsl.l   #3,%d0
+       lsr.l   #8,%d1                  | exponent / sign
+       lsr.l   #7,%d1
+       lsr.w   #5,%d1
+       jeq     fp_d2e_small            | zero / denormal?
+       cmp.w   #0x7ff,%d1              | NaN / Inf?
+       jeq     fp_d2e_large
+       bset    #31,%d0                 | set explizit bit
+       add.w   #0x3fff-0x3ff,%d1       | re-bias the exponent.
+9:     move.l  %d1,(%a0)+              | fp_ext.sign, fp_ext.exp
+       move.l  %d0,(%a0)+
+       getuser.l (%a1)+,%d0,fp_err_ua2,%a1
+       move.l  %d0,%d1
+       lsl.l   #8,%d0
+       lsl.l   #3,%d0
+       move.l  %d0,(%a0)
+       moveq   #21,%d0
+       lsr.l   %d0,%d1
+       or.l    %d1,-(%a0)
+       subq.l  #4,%a0
+       printx  PCONV,%a0@
+       printf  PCONV,")\n"
+       rts
+       | zeros and denormalized
+fp_d2e_small:
+       | exponent is zero, so explizit bit is already zero too
+       tst.l   %d0
+       jeq     9b
+       move.w  #0x4000-0x3ff,%d1
+       jra     9b
+       | infinities and NAN
+fp_d2e_large:
+       bclr    #31,%d0                 | clear explizit bit
+       move.w  #0x7fff,%d1
+       jra     9b
+
+       | fp_conv_ext2ext:
+       | originally used to get longdouble from userspace, now it's
+       | called before arithmetic operations to make sure the number
+       | is normalized [maybe rename it?].
+       | args: %a0 = dest (struct fp_ext *)
+       | returns 0 in %d0 for a NaN, otherwise 1
+
+fp_conv_ext2ext:
+       printf  PCONV,"e2e: %p(",1,%a0
+       printx  PCONV,%a0@
+       printf  PCONV,"), "
+       move.l  (%a0)+,%d0
+       cmp.w   #0x7fff,%d0             | Inf / NaN?
+       jeq     fp_e2e_large
+       move.l  (%a0),%d0
+       jpl     fp_e2e_small            | zero / denorm?
+       | The high bit is set, so normalization is irrelevant.
+fp_e2e_checkround:
+       subq.l  #4,%a0
+#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
+       move.b  (%a0),%d0
+       jne     fp_e2e_round
+#endif
+       printf  PCONV,"%p(",1,%a0
+       printx  PCONV,%a0@
+       printf  PCONV,")\n"
+       moveq   #1,%d0
+       rts
+#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
+fp_e2e_round:
+       fp_set_sr FPSR_EXC_INEX2
+       clr.b   (%a0)
+       move.w  (FPD_RND,FPDATA),%d2
+       jne     fp_e2e_roundother       | %d2 == 0, round to nearest
+       tst.b   %d0                     | test guard bit
+       jpl     9f                      | zero is closer
+       btst    #0,(11,%a0)             | test lsb bit
+       jne     fp_e2e_doroundup        | round to infinity
+       lsl.b   #1,%d0                  | check low bits
+       jeq     9f                      | round to zero
+fp_e2e_doroundup:
+       addq.l  #1,(8,%a0)
+       jcc     9f
+       addq.l  #1,(4,%a0)
+       jcc     9f
+       move.w  #0x8000,(4,%a0)
+       addq.w  #1,(2,%a0)
+9:     printf  PNORM,"%p(",1,%a0
+       printx  PNORM,%a0@
+       printf  PNORM,")\n"
+       rts
+fp_e2e_roundother:
+       subq.w  #2,%d2
+       jcs     9b                      | %d2 < 2, round to zero
+       jhi     1f                      | %d2 > 2, round to +infinity
+       tst.b   (1,%a0)                 | to -inf
+       jne     fp_e2e_doroundup        | negative, round to infinity
+       jra     9b                      | positive, round to zero
+1:     tst.b   (1,%a0)                 | to +inf
+       jeq     fp_e2e_doroundup        | positive, round to infinity
+       jra     9b                      | negative, round to zero
+#endif
+       | zeros and subnormals:
+       | try to normalize these anyway.
+fp_e2e_small:
+       jne     fp_e2e_small1           | high lword zero?
+       move.l  (4,%a0),%d0
+       jne     fp_e2e_small2
+#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
+       clr.l   %d0
+       move.b  (-4,%a0),%d0
+       jne     fp_e2e_small3
+#endif
+       | Genuine zero.
+       clr.w   -(%a0)
+       subq.l  #2,%a0
+       printf  PNORM,"%p(",1,%a0
+       printx  PNORM,%a0@
+       printf  PNORM,")\n"
+       moveq   #1,%d0
+       rts
+       | definitely subnormal, need to shift all 64 bits
+fp_e2e_small1:
+       bfffo   %d0{#0,#32},%d1
+       move.w  -(%a0),%d2
+       sub.w   %d1,%d2
+       jcc     1f
+       | Pathologically small, denormalize.
+       add.w   %d2,%d1
+       clr.w   %d2
+1:     move.w  %d2,(%a0)+
+       move.w  %d1,%d2
+       jeq     fp_e2e_checkround
+       | fancy 64-bit double-shift begins here
+       lsl.l   %d2,%d0
+       move.l  %d0,(%a0)+
+       move.l  (%a0),%d0
+       move.l  %d0,%d1
+       lsl.l   %d2,%d0
+       move.l  %d0,(%a0)
+       neg.w   %d2
+       and.w   #0x1f,%d2
+       lsr.l   %d2,%d1
+       or.l    %d1,-(%a0)
+#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
+fp_e2e_extra1:
+       clr.l   %d0
+       move.b  (-4,%a0),%d0
+       neg.w   %d2
+       add.w   #24,%d2
+       jcc     1f
+       clr.b   (-4,%a0)
+       lsl.l   %d2,%d0
+       or.l    %d0,(4,%a0)
+       jra     fp_e2e_checkround
+1:     addq.w  #8,%d2
+       lsl.l   %d2,%d0
+       move.b  %d0,(-4,%a0)
+       lsr.l   #8,%d0
+       or.l    %d0,(4,%a0)
+#endif
+       jra     fp_e2e_checkround
+       | pathologically small subnormal
+fp_e2e_small2:
+       bfffo   %d0{#0,#32},%d1
+       add.w   #32,%d1
+       move.w  -(%a0),%d2
+       sub.w   %d1,%d2
+       jcc     1f
+       | Beyond pathologically small, denormalize.
+       add.w   %d2,%d1
+       clr.w   %d2
+1:     move.w  %d2,(%a0)+
+       ext.l   %d1
+       jeq     fp_e2e_checkround
+       clr.l   (4,%a0)
+       sub.w   #32,%d2
+       jcs     1f
+       lsl.l   %d1,%d0                 | lower lword needs only to be shifted
+       move.l  %d0,(%a0)               | into the higher lword
+#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
+       clr.l   %d0
+       move.b  (-4,%a0),%d0
+       clr.b   (-4,%a0)
+       neg.w   %d1
+       add.w   #32,%d1
+       bfins   %d0,(%a0){%d1,#8}
+#endif
+       jra     fp_e2e_checkround
+1:     neg.w   %d1                     | lower lword is splitted between
+       bfins   %d0,(%a0){%d1,#32}      | higher and lower lword
+#ifndef CONFIG_M68KFPU_EMU_EXTRAPREC
+       jra     fp_e2e_checkround
+#else
+       move.w  %d1,%d2
+       jra     fp_e2e_extra1
+       | These are extremely small numbers, that will mostly end up as zero
+       | anyway, so this is only important for correct rounding.
+fp_e2e_small3:
+       bfffo   %d0{#24,#8},%d1
+       add.w   #40,%d1
+       move.w  -(%a0),%d2
+       sub.w   %d1,%d2
+       jcc     1f
+       | Pathologically small, denormalize.
+       add.w   %d2,%d1
+       clr.w   %d2
+1:     move.w  %d2,(%a0)+
+       ext.l   %d1
+       jeq     fp_e2e_checkround
+       cmp.w   #8,%d1
+       jcs     2f
+1:     clr.b   (-4,%a0)
+       sub.w   #64,%d1
+       jcs     1f
+       add.w   #24,%d1
+       lsl.l   %d1,%d0
+       move.l  %d0,(%a0)
+       jra     fp_e2e_checkround
+1:     neg.w   %d1
+       bfins   %d0,(%a0){%d1,#8}
+       jra     fp_e2e_checkround
+2:     lsl.l   %d1,%d0
+       move.b  %d0,(-4,%a0)
+       lsr.l   #8,%d0
+       move.b  %d0,(7,%a0)
+       jra     fp_e2e_checkround
+#endif
+1:     move.l  %d0,%d1                 | lower lword is splitted between
+       lsl.l   %d2,%d0                 | higher and lower lword
+       move.l  %d0,(%a0)
+       move.l  %d1,%d0
+       neg.w   %d2
+       add.w   #32,%d2
+       lsr.l   %d2,%d0
+       move.l  %d0,-(%a0)
+       jra     fp_e2e_checkround
+       | Infinities and NaNs
+fp_e2e_large:
+       move.l  (%a0)+,%d0
+       jne     3f
+1:     tst.l   (%a0)
+       jne     4f
+       moveq   #1,%d0
+2:     subq.l  #8,%a0
+       printf  PCONV,"%p(",1,%a0
+       printx  PCONV,%a0@
+       printf  PCONV,")\n"
+       rts
+       | we have maybe a NaN, shift off the highest bit
+3:     lsl.l   #1,%d0
+       jeq     1b
+       | we have a NaN, clear the return value
+4:     clrl    %d0
+       jra     2b
+
+
+/*
+ * Normalization functions.  Call these on the output of general
+ * FP operators, and before any conversion into the destination
+ * formats. fp_normalize_ext has always to be called first, the
+ * following conversion functions expect an already normalized
+ * number.
+ */
+
+       | fp_normalize_ext:
+       | normalize an extended in extended (unpacked) format, basically
+       | it does the same as fp_conv_ext2ext, additionally it also does
+       | the necessary postprocessing checks.
+       | args: %a0 (struct fp_ext *)
+       | NOTE: it does _not_ modify %a0/%a1 and the upper word of %d2
+
+fp_normalize_ext:
+       printf  PNORM,"ne: %p(",1,%a0
+       printx  PNORM,%a0@
+       printf  PNORM,"), "
+       move.l  (%a0)+,%d0
+       cmp.w   #0x7fff,%d0             | Inf / NaN?
+       jeq     fp_ne_large
+       move.l  (%a0),%d0
+       jpl     fp_ne_small             | zero / denorm?
+       | The high bit is set, so normalization is irrelevant.
+fp_ne_checkround:
+       subq.l  #4,%a0
+#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
+       move.b  (%a0),%d0
+       jne     fp_ne_round
+#endif
+       printf  PNORM,"%p(",1,%a0
+       printx  PNORM,%a0@
+       printf  PNORM,")\n"
+       rts
+#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
+fp_ne_round:
+       fp_set_sr FPSR_EXC_INEX2
+       clr.b   (%a0)
+       move.w  (FPD_RND,FPDATA),%d2
+       jne     fp_ne_roundother        | %d2 == 0, round to nearest
+       tst.b   %d0                     | test guard bit
+       jpl     9f                      | zero is closer
+       btst    #0,(11,%a0)             | test lsb bit
+       jne     fp_ne_doroundup         | round to infinity
+       lsl.b   #1,%d0                  | check low bits
+       jeq     9f                      | round to zero
+fp_ne_doroundup:
+       addq.l  #1,(8,%a0)
+       jcc     9f
+       addq.l  #1,(4,%a0)
+       jcc     9f
+       addq.w  #1,(2,%a0)
+       move.w  #0x8000,(4,%a0)
+9:     printf  PNORM,"%p(",1,%a0
+       printx  PNORM,%a0@
+       printf  PNORM,")\n"
+       rts
+fp_ne_roundother:
+       subq.w  #2,%d2
+       jcs     9b                      | %d2 < 2, round to zero
+       jhi     1f                      | %d2 > 2, round to +infinity
+       tst.b   (1,%a0)                 | to -inf
+       jne     fp_ne_doroundup         | negative, round to infinity
+       jra     9b                      | positive, round to zero
+1:     tst.b   (1,%a0)                 | to +inf
+       jeq     fp_ne_doroundup         | positive, round to infinity
+       jra     9b                      | negative, round to zero
+#endif
+       | Zeros and subnormal numbers
+       | These are probably merely subnormal, rather than "denormalized"
+       |  numbers, so we will try to make them normal again.
+fp_ne_small:
+       jne     fp_ne_small1            | high lword zero?
+       move.l  (4,%a0),%d0
+       jne     fp_ne_small2
+#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
+       clr.l   %d0
+       move.b  (-4,%a0),%d0
+       jne     fp_ne_small3
+#endif
+       | Genuine zero.
+       clr.w   -(%a0)
+       subq.l  #2,%a0
+       printf  PNORM,"%p(",1,%a0
+       printx  PNORM,%a0@
+       printf  PNORM,")\n"
+       rts
+       | Subnormal.
+fp_ne_small1:
+       bfffo   %d0{#0,#32},%d1
+       move.w  -(%a0),%d2
+       sub.w   %d1,%d2
+       jcc     1f
+       | Pathologically small, denormalize.
+       add.w   %d2,%d1
+       clr.w   %d2
+       fp_set_sr FPSR_EXC_UNFL
+1:     move.w  %d2,(%a0)+
+       move.w  %d1,%d2
+       jeq     fp_ne_checkround
+       | This is exactly the same 64-bit double shift as seen above.
+       lsl.l   %d2,%d0
+       move.l  %d0,(%a0)+
+       move.l  (%a0),%d0
+       move.l  %d0,%d1
+       lsl.l   %d2,%d0
+       move.l  %d0,(%a0)
+       neg.w   %d2
+       and.w   #0x1f,%d2
+       lsr.l   %d2,%d1
+       or.l    %d1,-(%a0)
+#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
+fp_ne_extra1:
+       clr.l   %d0
+       move.b  (-4,%a0),%d0
+       neg.w   %d2
+       add.w   #24,%d2
+       jcc     1f
+       clr.b   (-4,%a0)
+       lsl.l   %d2,%d0
+       or.l    %d0,(4,%a0)
+       jra     fp_ne_checkround
+1:     addq.w  #8,%d2
+       lsl.l   %d2,%d0
+       move.b  %d0,(-4,%a0)
+       lsr.l   #8,%d0
+       or.l    %d0,(4,%a0)
+#endif
+       jra     fp_ne_checkround
+       | May or may not be subnormal, if so, only 32 bits to shift.
+fp_ne_small2:
+       bfffo   %d0{#0,#32},%d1
+       add.w   #32,%d1
+       move.w  -(%a0),%d2
+       sub.w   %d1,%d2
+       jcc     1f
+       | Beyond pathologically small, denormalize.
+       add.w   %d2,%d1
+       clr.w   %d2
+       fp_set_sr FPSR_EXC_UNFL
+1:     move.w  %d2,(%a0)+
+       ext.l   %d1
+       jeq     fp_ne_checkround
+       clr.l   (4,%a0)
+       sub.w   #32,%d1
+       jcs     1f
+       lsl.l   %d1,%d0                 | lower lword needs only to be shifted
+       move.l  %d0,(%a0)               | into the higher lword
+#ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
+       clr.l   %d0
+       move.b  (-4,%a0),%d0
+       clr.b   (-4,%a0)
+       neg.w   %d1
+       add.w   #32,%d1
+       bfins   %d0,(%a0){%d1,#8}
+#endif
+       jra     fp_ne_checkround
+1:     neg.w   %d1                     | lower lword is splitted between
+       bfins   %d0,(%a0){%d1,#32}      | higher and lower lword
+#ifndef CONFIG_M68KFPU_EMU_EXTRAPREC
+       jra     fp_ne_checkround
+#else
+       move.w  %d1,%d2
+       jra     fp_ne_extra1
+       | These are extremely small numbers, that will mostly end up as zero
+       | anyway, so this is only important for correct rounding.
+fp_ne_small3:
+       bfffo   %d0{#24,#8},%d1
+       add.w   #40,%d1
+       move.w  -(%a0),%d2
+       sub.w   %d1,%d2
+       jcc     1f
+       | Pathologically small, denormalize.
+       add.w   %d2,%d1
+       clr.w   %d2
+1:     move.w  %d2,(%a0)+
+       ext.l   %d1
+       jeq     fp_ne_checkround
+       cmp.w   #8,%d1
+       jcs     2f
+1:     clr.b   (-4,%a0)
+       sub.w   #64,%d1
+       jcs     1f
+       add.w   #24,%d1
+       lsl.l   %d1,%d0
+       move.l  %d0,(%a0)
+       jra     fp_ne_checkround
+1:     neg.w   %d1
+       bfins   %d0,(%a0){%d1,#8}
+       jra     fp_ne_checkround
+2:     lsl.l   %d1,%d0
+       move.b  %d0,(-4,%a0)
+       lsr.l   #8,%d0
+       move.b  %d0,(7,%a0)
+       jra     fp_ne_checkround
+#endif
+       | Infinities and NaNs, again, same as above.
+fp_ne_large:
+       move.l  (%a0)+,%d0
+       jne     3f
+1:     tst.l   (%a0)
+       jne     4f
+2:     subq.l  #8,%a0
+       printf  PNORM,"%p(",1,%a0
+       printx  PNORM,%a0@
+       printf  PNORM,")\n"
+       rts
+       | we have maybe a NaN, shift off the highest bit
+3:     move.l  %d0,%d1
+       lsl.l   #1,%d1
+       jne     4f
+       clr.l   (-4,%a0)
+       jra     1b
+       | we have a NaN, test if it is signaling
+4:     bset    #30,%d0
+       jne     2b
+       fp_set_sr FPSR_EXC_SNAN
+       move.l  %d0,(-4,%a0)
+       jra     2b
+
+       | these next two do rounding as per the IEEE standard.
+       | values for the rounding modes appear to be:
+       | 0:    Round to nearest
+       | 1:    Round to zero
+       | 2:    Round to -Infinity
+       | 3:    Round to +Infinity
+       | both functions expect that fp_normalize was already
+       | called (and extended argument is already normalized
+       | as far as possible), these are used if there is different
+       | rounding precision is selected and before converting
+       | into single/double
+
+       | fp_normalize_double:
+       | normalize an extended with double (52-bit) precision
+       | args:  %a0 (struct fp_ext *)
+
+fp_normalize_double:
+       printf  PNORM,"nd: %p(",1,%a0
+       printx  PNORM,%a0@
+       printf  PNORM,"), "
+       move.l  (%a0)+,%d2
+       tst.w   %d2
+       jeq     fp_nd_zero              | zero / denormalized
+       cmp.w   #0x7fff,%d2
+       jeq     fp_nd_huge              | NaN / infinitive.
+       sub.w   #0x4000-0x3ff,%d2       | will the exponent fit?
+       jcs     fp_nd_small             | too small.
+       cmp.w   #0x7fe,%d2
+       jcc     fp_nd_large             | too big.
+       addq.l  #4,%a0
+       move.l  (%a0),%d0               | low lword of mantissa
+       | now, round off the low 11 bits.
+fp_nd_round:
+       moveq   #21,%d1
+       lsl.l   %d1,%d0                 | keep 11 low bits.
+       jne     fp_nd_checkround        | Are they non-zero?
+       | nothing to do here
+9:     subq.l  #8,%a0
+       printf  PNORM,"%p(",1,%a0
+       printx  PNORM,%a0@
+       printf  PNORM,")\n"
+       rts
+       | Be careful with the X bit! It contains the lsb
+       | from the shift above, it is needed for round to nearest.
+fp_nd_checkround:
+       fp_set_sr FPSR_EXC_INEX2        | INEX2 bit
+       and.w   #0xf800,(2,%a0)         | clear bits 0-10
+       move.w  (FPD_RND,FPDATA),%d2    | rounding mode
+       jne     2f                      | %d2 == 0, round to nearest
+       tst.l   %d0                     | test guard bit
+       jpl     9b                      | zero is closer
+       | here we test the X bit by adding it to %d2
+       clr.w   %d2                     | first set z bit, addx only clears it
+       addx.w  %d2,%d2                 | test lsb bit
+       | IEEE754-specified "round to even" behaviour.  If the guard
+       | bit is set, then the number is odd, so rounding works like
+       | in grade-school arithmetic (i.e. 1.5 rounds to 2.0)
+       | Otherwise, an equal distance rounds towards zero, so as not
+       | to produce an odd number.  This is strange, but it is what
+       | the standard says.
+       jne     fp_nd_doroundup         | round to infinity
+       lsl.l   #1,%d0                  | check low bits
+       jeq     9b                      | round to zero
+fp_nd_doroundup:
+       | round (the mantissa, that is) towards infinity
+       add.l   #0x800,(%a0)
+       jcc     9b                      | no overflow, good.
+       addq.l  #1,-(%a0)               | extend to high lword
+       jcc     1f                      | no overflow, good.
+       | Yow! we have managed to overflow the mantissa.  Since this
+       | only happens when %d1 was 0xfffff800, it is now zero, so
+       | reset the high bit, and increment the exponent.
+       move.w  #0x8000,(%a0)
+       addq.w  #1,-(%a0)
+       cmp.w   #0x43ff,(%a0)+          | exponent now overflown?
+       jeq     fp_nd_large             | yes, so make it infinity.
+1:     subq.l  #4,%a0
+       printf  PNORM,"%p(",1,%a0
+       printx  PNORM,%a0@
+       printf  PNORM,")\n"
+       rts
+2:     subq.w  #2,%d2
+       jcs     9b                      | %d2 < 2, round to zero
+       jhi     3f                      | %d2 > 2, round to +infinity
+       | Round to +Inf or -Inf.  High word of %d2 contains the
+       | sign of the number, by the way.
+       swap    %d2                     | to -inf
+       tst.b   %d2
+       jne     fp_nd_doroundup         | negative, round to infinity
+       jra     9b                      | positive, round to zero
+3:     swap    %d2                     | to +inf
+       tst.b   %d2
+       jeq     fp_nd_doroundup         | positive, round to infinity
+       jra     9b                      | negative, round to zero
+       | Exponent underflow.  Try to make a denormal, and set it to
+       | the smallest possible fraction if this fails.
+fp_nd_small:
+       fp_set_sr FPSR_EXC_UNFL         | set UNFL bit
+       move.w  #0x3c01,(-2,%a0)        | 2**-1022
+       neg.w   %d2                     | degree of underflow
+       cmp.w   #32,%d2                 | single or double shift?
+       jcc     1f
+       | Again, another 64-bit double shift.
+       move.l  (%a0),%d0
+       move.l  %d0,%d1
+       lsr.l   %d2,%d0
+       move.l  %d0,(%a0)+
+       move.l  (%a0),%d0
+       lsr.l   %d2,%d0
+       neg.w   %d2
+       add.w   #32,%d2
+       lsl.l   %d2,%d1
+       or.l    %d1,%d0
+       move.l  (%a0),%d1
+       move.l  %d0,(%a0)
+       | Check to see if we shifted off any significant bits
+       lsl.l   %d2,%d1
+       jeq     fp_nd_round             | Nope, round.
+       bset    #0,%d0                  | Yes, so set the "sticky bit".
+       jra     fp_nd_round             | Now, round.
+       | Another 64-bit single shift and store
+1:     sub.w   #32,%d2
+       cmp.w   #32,%d2                 | Do we really need to shift?
+       jcc     2f                      | No, the number is too small.
+       move.l  (%a0),%d0
+       clr.l   (%a0)+
+       move.l  %d0,%d1
+       lsr.l   %d2,%d0
+       neg.w   %d2
+       add.w   #32,%d2
+       | Again, check to see if we shifted off any significant bits.
+       tst.l   (%a0)
+       jeq     1f
+       bset    #0,%d0                  | Sticky bit.
+1:     move.l  %d0,(%a0)
+       lsl.l   %d2,%d1
+       jeq     fp_nd_round
+       bset    #0,%d0
+       jra     fp_nd_round
+       | Sorry, the number is just too small.
+2:     clr.l   (%a0)+
+       clr.l   (%a0)
+       moveq   #1,%d0                  | Smallest possible fraction,
+       jra     fp_nd_round             | round as desired.
+       | zero and denormalized
+fp_nd_zero:
+       tst.l   (%a0)+
+       jne     1f
+       tst.l   (%a0)
+       jne     1f
+       subq.l  #8,%a0
+       printf  PNORM,"%p(",1,%a0
+       printx  PNORM,%a0@
+       printf  PNORM,")\n"
+       rts                             | zero.  nothing to do.
+       | These are not merely subnormal numbers, but true denormals,
+       | i.e. pathologically small (exponent is 2**-16383) numbers.
+       | It is clearly impossible for even a normal extended number
+       | with that exponent to fit into double precision, so just
+       | write these ones off as "too darn small".
+1:     fp_set_sr FPSR_EXC_UNFL         | Set UNFL bit
+       clr.l   (%a0)
+       clr.l   -(%a0)
+       move.w  #0x3c01,-(%a0)          | i.e. 2**-1022
+       addq.l  #6,%a0
+       moveq   #1,%d0
+       jra     fp_nd_round             | round.
+       | Exponent overflow.  Just call it infinity.
+fp_nd_large:
+       move.w  #0x7ff,%d0
+       and.w   (6,%a0),%d0
+       jeq     1f
+       fp_set_sr FPSR_EXC_INEX2
+1:     fp_set_sr FPSR_EXC_OVFL
+       move.w  (FPD_RND,FPDATA),%d2
+       jne     3f                      | %d2 = 0 round to nearest
+1:     move.w  #0x7fff,(-2,%a0)
+       clr.l   (%a0)+
+       clr.l   (%a0)
+2:     subq.l  #8,%a0
+       printf  PNORM,"%p(",1,%a0
+       printx  PNORM,%a0@
+       printf  PNORM,")\n"
+       rts
+3:     subq.w  #2,%d2
+       jcs     5f                      | %d2 < 2, round to zero
+       jhi     4f                      | %d2 > 2, round to +infinity
+       tst.b   (-3,%a0)                | to -inf
+       jne     1b
+       jra     5f
+4:     tst.b   (-3,%a0)                | to +inf
+       jeq     1b
+5:     move.w  #0x43fe,(-2,%a0)
+       moveq   #-1,%d0
+       move.l  %d0,(%a0)+
+       move.w  #0xf800,%d0
+       move.l  %d0,(%a0)
+       jra     2b
+       | Infinities or NaNs
+fp_nd_huge:
+       subq.l  #4,%a0
+       printf  PNORM,"%p(",1,%a0
+       printx  PNORM,%a0@
+       printf  PNORM,")\n"
+       rts
+
+       | fp_normalize_single:
+       | normalize an extended with single (23-bit) precision
+       | args:  %a0 (struct fp_ext *)
+
+fp_normalize_single:
+       printf  PNORM,"ns: %p(",1,%a0
+       printx  PNORM,%a0@
+       printf  PNORM,") "
+       addq.l  #2,%a0
+       move.w  (%a0)+,%d2
+       jeq     fp_ns_zero              | zero / denormalized
+       cmp.w   #0x7fff,%d2
+       jeq     fp_ns_huge              | NaN / infinitive.
+       sub.w   #0x4000-0x7f,%d2        | will the exponent fit?
+       jcs     fp_ns_small             | too small.
+       cmp.w   #0xfe,%d2
+       jcc     fp_ns_large             | too big.
+       move.l  (%a0)+,%d0              | get high lword of mantissa
+fp_ns_round:
+       tst.l   (%a0)                   | check the low lword
+       jeq     1f
+       | Set a sticky bit if it is non-zero.  This should only
+       | affect the rounding in what would otherwise be equal-
+       | distance situations, which is what we want it to do.
+       bset    #0,%d0
+1:     clr.l   (%a0)                   | zap it from memory.
+       | now, round off the low 8 bits of the hi lword.
+       tst.b   %d0                     | 8 low bits.
+       jne     fp_ns_checkround        | Are they non-zero?
+       | nothing to do here
+       subq.l  #8,%a0
+       printf  PNORM,"%p(",1,%a0
+       printx  PNORM,%a0@
+       printf  PNORM,")\n"
+       rts
+fp_ns_checkround:
+       fp_set_sr FPSR_EXC_INEX2        | INEX2 bit
+       clr.b   -(%a0)                  | clear low byte of high lword
+       subq.l  #3,%a0
+       move.w  (FPD_RND,FPDATA),%d2    | rounding mode
+       jne     2f                      | %d2 == 0, round to nearest
+       tst.b   %d0                     | test guard bit
+       jpl     9f                      | zero is closer
+       btst    #8,%d0                  | test lsb bit
+       | round to even behaviour, see above.
+       jne     fp_ns_doroundup         | round to infinity
+       lsl.b   #1,%d0                  | check low bits
+       jeq     9f                      | round to zero
+fp_ns_doroundup:
+       | round (the mantissa, that is) towards infinity
+       add.l   #0x100,(%a0)
+       jcc     9f                      | no overflow, good.
+       | Overflow.  This means that the %d1 was 0xffffff00, so it
+       | is now zero.  We will set the mantissa to reflect this, and
+       | increment the exponent (checking for overflow there too)
+       move.w  #0x8000,(%a0)
+       addq.w  #1,-(%a0)
+       cmp.w   #0x407f,(%a0)+          | exponent now overflown?
+       jeq     fp_ns_large             | yes, so make it infinity.
+9:     subq.l  #4,%a0
+       printf  PNORM,"%p(",1,%a0
+       printx  PNORM,%a0@
+       printf  PNORM,")\n"
+       rts
+       | check nondefault rounding modes
+2:     subq.w  #2,%d2
+       jcs     9b                      | %d2 < 2, round to zero
+       jhi     3f                      | %d2 > 2, round to +infinity
+       tst.b   (-3,%a0)                | to -inf
+       jne     fp_ns_doroundup         | negative, round to infinity
+       jra     9b                      | positive, round to zero
+3:     tst.b   (-3,%a0)                | to +inf
+       jeq     fp_ns_doroundup         | positive, round to infinity
+       jra     9b                      | negative, round to zero
+       | Exponent underflow.  Try to make a denormal, and set it to
+       | the smallest possible fraction if this fails.
+fp_ns_small:
+       fp_set_sr FPSR_EXC_UNFL         | set UNFL bit
+       move.w  #0x3f81,(-2,%a0)        | 2**-126
+       neg.w   %d2                     | degree of underflow
+       cmp.w   #32,%d2                 | single or double shift?
+       jcc     2f
+       | a 32-bit shift.
+       move.l  (%a0),%d0
+       move.l  %d0,%d1
+       lsr.l   %d2,%d0
+       move.l  %d0,(%a0)+
+       | Check to see if we shifted off any significant bits.
+       neg.w   %d2
+       add.w   #32,%d2
+       lsl.l   %d2,%d1
+       jeq     1f
+       bset    #0,%d0                  | Sticky bit.
+       | Check the lower lword
+1:     tst.l   (%a0)
+       jeq     fp_ns_round
+       clr     (%a0)
+       bset    #0,%d0                  | Sticky bit.
+       jra     fp_ns_round
+       | Sorry, the number is just too small.
+2:     clr.l   (%a0)+
+       clr.l   (%a0)
+       moveq   #1,%d0                  | Smallest possible fraction,
+       jra     fp_ns_round             | round as desired.
+       | Exponent overflow.  Just call it infinity.
+fp_ns_large:
+       tst.b   (3,%a0)
+       jeq     1f
+       fp_set_sr FPSR_EXC_INEX2
+1:     fp_set_sr FPSR_EXC_OVFL
+       move.w  (FPD_RND,FPDATA),%d2
+       jne     3f                      | %d2 = 0 round to nearest
+1:     move.w  #0x7fff,(-2,%a0)
+       clr.l   (%a0)+
+       clr.l   (%a0)
+2:     subq.l  #8,%a0
+       printf  PNORM,"%p(",1,%a0
+       printx  PNORM,%a0@
+       printf  PNORM,")\n"
+       rts
+3:     subq.w  #2,%d2
+       jcs     5f                      | %d2 < 2, round to zero
+       jhi     4f                      | %d2 > 2, round to +infinity
+       tst.b   (-3,%a0)                | to -inf
+       jne     1b
+       jra     5f
+4:     tst.b   (-3,%a0)                | to +inf
+       jeq     1b
+5:     move.w  #0x407e,(-2,%a0)
+       move.l  #0xffffff00,(%a0)+
+       clr.l   (%a0)
+       jra     2b
+       | zero and denormalized
+fp_ns_zero:
+       tst.l   (%a0)+
+       jne     1f
+       tst.l   (%a0)
+       jne     1f
+       subq.l  #8,%a0
+       printf  PNORM,"%p(",1,%a0
+       printx  PNORM,%a0@
+       printf  PNORM,")\n"
+       rts                             | zero.  nothing to do.
+       | These are not merely subnormal numbers, but true denormals,
+       | i.e. pathologically small (exponent is 2**-16383) numbers.
+       | It is clearly impossible for even a normal extended number
+       | with that exponent to fit into single precision, so just
+       | write these ones off as "too darn small".
+1:     fp_set_sr FPSR_EXC_UNFL         | Set UNFL bit
+       clr.l   (%a0)
+       clr.l   -(%a0)
+       move.w  #0x3f81,-(%a0)          | i.e. 2**-126
+       addq.l  #6,%a0
+       moveq   #1,%d0
+       jra     fp_ns_round             | round.
+       | Infinities or NaNs
+fp_ns_huge:
+       subq.l  #4,%a0
+       printf  PNORM,"%p(",1,%a0
+       printx  PNORM,%a0@
+       printf  PNORM,")\n"
+       rts
+
+       | fp_normalize_single_fast:
+       | normalize an extended with single (23-bit) precision
+       | this is only used by fsgldiv/fsgdlmul, where the
+       | operand is not completly normalized.
+       | args:  %a0 (struct fp_ext *)
+
+fp_normalize_single_fast:
+       printf  PNORM,"nsf: %p(",1,%a0
+       printx  PNORM,%a0@
+       printf  PNORM,") "
+       addq.l  #2,%a0
+       move.w  (%a0)+,%d2
+       cmp.w   #0x7fff,%d2
+       jeq     fp_nsf_huge             | NaN / infinitive.
+       move.l  (%a0)+,%d0              | get high lword of mantissa
+fp_nsf_round:
+       tst.l   (%a0)                   | check the low lword
+       jeq     1f
+       | Set a sticky bit if it is non-zero.  This should only
+       | affect the rounding in what would otherwise be equal-
+       | distance situations, which is what we want it to do.
+       bset    #0,%d0
+1:     clr.l   (%a0)                   | zap it from memory.
+       | now, round off the low 8 bits of the hi lword.
+       tst.b   %d0                     | 8 low bits.
+       jne     fp_nsf_checkround       | Are they non-zero?
+       | nothing to do here
+       subq.l  #8,%a0
+       printf  PNORM,"%p(",1,%a0
+       printx  PNORM,%a0@
+       printf  PNORM,")\n"
+       rts
+fp_nsf_checkround:
+       fp_set_sr FPSR_EXC_INEX2        | INEX2 bit
+       clr.b   -(%a0)                  | clear low byte of high lword
+       subq.l  #3,%a0
+       move.w  (FPD_RND,FPDATA),%d2    | rounding mode
+       jne     2f                      | %d2 == 0, round to nearest
+       tst.b   %d0                     | test guard bit
+       jpl     9f                      | zero is closer
+       btst    #8,%d0                  | test lsb bit
+       | round to even behaviour, see above.
+       jne     fp_nsf_doroundup                | round to infinity
+       lsl.b   #1,%d0                  | check low bits
+       jeq     9f                      | round to zero
+fp_nsf_doroundup:
+       | round (the mantissa, that is) towards infinity
+       add.l   #0x100,(%a0)
+       jcc     9f                      | no overflow, good.
+       | Overflow.  This means that the %d1 was 0xffffff00, so it
+       | is now zero.  We will set the mantissa to reflect this, and
+       | increment the exponent (checking for overflow there too)
+       move.w  #0x8000,(%a0)
+       addq.w  #1,-(%a0)
+       cmp.w   #0x407f,(%a0)+          | exponent now overflown?
+       jeq     fp_nsf_large            | yes, so make it infinity.
+9:     subq.l  #4,%a0
+       printf  PNORM,"%p(",1,%a0
+       printx  PNORM,%a0@
+       printf  PNORM,")\n"
+       rts
+       | check nondefault rounding modes
+2:     subq.w  #2,%d2
+       jcs     9b                      | %d2 < 2, round to zero
+       jhi     3f                      | %d2 > 2, round to +infinity
+       tst.b   (-3,%a0)                | to -inf
+       jne     fp_nsf_doroundup        | negative, round to infinity
+       jra     9b                      | positive, round to zero
+3:     tst.b   (-3,%a0)                | to +inf
+       jeq     fp_nsf_doroundup                | positive, round to infinity
+       jra     9b                      | negative, round to zero
+       | Exponent overflow.  Just call it infinity.
+fp_nsf_large:
+       tst.b   (3,%a0)
+       jeq     1f
+       fp_set_sr FPSR_EXC_INEX2
+1:     fp_set_sr FPSR_EXC_OVFL
+       move.w  (FPD_RND,FPDATA),%d2
+       jne     3f                      | %d2 = 0 round to nearest
+1:     move.w  #0x7fff,(-2,%a0)
+       clr.l   (%a0)+
+       clr.l   (%a0)
+2:     subq.l  #8,%a0
+       printf  PNORM,"%p(",1,%a0
+       printx  PNORM,%a0@
+       printf  PNORM,")\n"
+       rts
+3:     subq.w  #2,%d2
+       jcs     5f                      | %d2 < 2, round to zero
+       jhi     4f                      | %d2 > 2, round to +infinity
+       tst.b   (-3,%a0)                | to -inf
+       jne     1b
+       jra     5f
+4:     tst.b   (-3,%a0)                | to +inf
+       jeq     1b
+5:     move.w  #0x407e,(-2,%a0)
+       move.l  #0xffffff00,(%a0)+
+       clr.l   (%a0)
+       jra     2b
+       | Infinities or NaNs
+fp_nsf_huge:
+       subq.l  #4,%a0
+       printf  PNORM,"%p(",1,%a0
+       printx  PNORM,%a0@
+       printf  PNORM,")\n"
+       rts
+
+       | conv_ext2int (macro):
+       | Generates a subroutine that converts an extended value to an
+       | integer of a given size, again, with the appropriate type of
+       | rounding.
+
+       | Macro arguments:
+       | s:    size, as given in an assembly instruction.
+       | b:    number of bits in that size.
+
+       | Subroutine arguments:
+       | %a0:  source (struct fp_ext *)
+
+       | Returns the integer in %d0 (like it should)
+
+.macro conv_ext2int s,b
+       .set    inf,(1<<(\b-1))-1       | i.e. MAXINT
+       printf  PCONV,"e2i%d: %p(",2,#\b,%a0
+       printx  PCONV,%a0@
+       printf  PCONV,") "
+       addq.l  #2,%a0
+       move.w  (%a0)+,%d2              | exponent
+       jeq     fp_e2i_zero\b           | zero / denorm (== 0, here)
+       cmp.w   #0x7fff,%d2
+       jeq     fp_e2i_huge\b           | Inf / NaN
+       sub.w   #0x3ffe,%d2
+       jcs     fp_e2i_small\b
+       cmp.w   #\b,%d2
+       jhi     fp_e2i_large\b
+       move.l  (%a0),%d0
+       move.l  %d0,%d1
+       lsl.l   %d2,%d1
+       jne     fp_e2i_round\b
+       tst.l   (4,%a0)
+       jne     fp_e2i_round\b
+       neg.w   %d2
+       add.w   #32,%d2
+       lsr.l   %d2,%d0
+9:     tst.w   (-4,%a0)
+       jne     1f
+       tst.\s  %d0
+       jmi     fp_e2i_large\b
+       printf  PCONV,"-> %p\n",1,%d0
+       rts
+1:     neg.\s  %d0
+       jeq     1f
+       jpl     fp_e2i_large\b
+1:     printf  PCONV,"-> %p\n",1,%d0
+       rts
+fp_e2i_round\b:
+       fp_set_sr FPSR_EXC_INEX2        | INEX2 bit
+       neg.w   %d2
+       add.w   #32,%d2
+       .if     \b>16
+       jeq     5f
+       .endif
+       lsr.l   %d2,%d0
+       move.w  (FPD_RND,FPDATA),%d2    | rounding mode
+       jne     2f                      | %d2 == 0, round to nearest
+       tst.l   %d1                     | test guard bit
+       jpl     9b                      | zero is closer
+       btst    %d2,%d0                 | test lsb bit (%d2 still 0)
+       jne     fp_e2i_doroundup\b
+       lsl.l   #1,%d1                  | check low bits
+       jne     fp_e2i_doroundup\b
+       tst.l   (4,%a0)
+       jeq     9b
+fp_e2i_doroundup\b:
+       addq.l  #1,%d0
+       jra     9b
+       | check nondefault rounding modes
+2:     subq.w  #2,%d2
+       jcs     9b                      | %d2 < 2, round to zero
+       jhi     3f                      | %d2 > 2, round to +infinity
+       tst.w   (-4,%a0)                | to -inf
+       jne     fp_e2i_doroundup\b      | negative, round to infinity
+       jra     9b                      | positive, round to zero
+3:     tst.w   (-4,%a0)                | to +inf
+       jeq     fp_e2i_doroundup\b      | positive, round to infinity
+       jra     9b      | negative, round to zero
+       | we are only want -2**127 get correctly rounded here,
+       | since the guard bit is in the lower lword.
+       | everything else ends up anyway as overflow.
+       .if     \b>16
+5:     move.w  (FPD_RND,FPDATA),%d2    | rounding mode
+       jne     2b                      | %d2 == 0, round to nearest
+       move.l  (4,%a0),%d1             | test guard bit
+       jpl     9b                      | zero is closer
+       lsl.l   #1,%d1                  | check low bits
+       jne     fp_e2i_doroundup\b
+       jra     9b
+       .endif
+fp_e2i_zero\b:
+       clr.l   %d0
+       tst.l   (%a0)+
+       jne     1f
+       tst.l   (%a0)
+       jeq     3f
+1:     subq.l  #4,%a0
+       fp_clr_sr FPSR_EXC_UNFL         | fp_normalize_ext has set this bit
+fp_e2i_small\b:
+       fp_set_sr FPSR_EXC_INEX2
+       clr.l   %d0
+       move.w  (FPD_RND,FPDATA),%d2    | rounding mode
+       subq.w  #2,%d2
+       jcs     3f                      | %d2 < 2, round to nearest/zero
+       jhi     2f                      | %d2 > 2, round to +infinity
+       tst.w   (-4,%a0)                | to -inf
+       jeq     3f
+       subq.\s #1,%d0
+       jra     3f
+2:     tst.w   (-4,%a0)                | to +inf
+       jne     3f
+       addq.\s #1,%d0
+3:     printf  PCONV,"-> %p\n",1,%d0
+       rts
+fp_e2i_large\b:
+       fp_set_sr FPSR_EXC_OPERR
+       move.\s #inf,%d0
+       tst.w   (-4,%a0)
+       jeq     1f
+       addq.\s #1,%d0
+1:     printf  PCONV,"-> %p\n",1,%d0
+       rts
+fp_e2i_huge\b:
+       move.\s (%a0),%d0
+       tst.l   (%a0)
+       jne     1f
+       tst.l   (%a0)
+       jeq     fp_e2i_large\b
+       | fp_normalize_ext has set this bit already
+       | and made the number nonsignaling
+1:     fp_tst_sr FPSR_EXC_SNAN
+       jne     1f
+       fp_set_sr FPSR_EXC_OPERR
+1:     printf  PCONV,"-> %p\n",1,%d0
+       rts
+.endm
+
+fp_conv_ext2long:
+       conv_ext2int l,32
+
+fp_conv_ext2short:
+       conv_ext2int w,16
+
+fp_conv_ext2byte:
+       conv_ext2int b,8
+
+fp_conv_ext2double:
+       jsr     fp_normalize_double
+       printf  PCONV,"e2d: %p(",1,%a0
+       printx  PCONV,%a0@
+       printf  PCONV,"), "
+       move.l  (%a0)+,%d2
+       cmp.w   #0x7fff,%d2
+       jne     1f
+       move.w  #0x7ff,%d2
+       move.l  (%a0)+,%d0
+       jra     2f
+1:     sub.w   #0x3fff-0x3ff,%d2
+       move.l  (%a0)+,%d0
+       jmi     2f
+       clr.w   %d2
+2:     lsl.w   #5,%d2
+       lsl.l   #7,%d2
+       lsl.l   #8,%d2
+       move.l  %d0,%d1
+       lsl.l   #1,%d0
+       lsr.l   #4,%d0
+       lsr.l   #8,%d0
+       or.l    %d2,%d0
+       putuser.l %d0,(%a1)+,fp_err_ua2,%a1
+       moveq   #21,%d0
+       lsl.l   %d0,%d1
+       move.l  (%a0),%d0
+       lsr.l   #4,%d0
+       lsr.l   #7,%d0
+       or.l    %d1,%d0
+       putuser.l %d0,(%a1),fp_err_ua2,%a1
+#ifdef FPU_EMU_DEBUG
+       getuser.l %a1@(-4),%d0,fp_err_ua2,%a1
+       getuser.l %a1@(0),%d1,fp_err_ua2,%a1
+       printf  PCONV,"%p(%08x%08x)\n",3,%a1,%d0,%d1
+#endif
+       rts
+
+fp_conv_ext2single:
+       jsr     fp_normalize_single
+       printf  PCONV,"e2s: %p(",1,%a0
+       printx  PCONV,%a0@
+       printf  PCONV,"), "
+       move.l  (%a0)+,%d1
+       cmp.w   #0x7fff,%d1
+       jne     1f
+       move.w  #0xff,%d1
+       move.l  (%a0)+,%d0
+       jra     2f
+1:     sub.w   #0x3fff-0x7f,%d1
+       move.l  (%a0)+,%d0
+       jmi     2f
+       clr.w   %d1
+2:     lsl.w   #8,%d1
+       lsl.l   #7,%d1
+       lsl.l   #8,%d1
+       bclr    #31,%d0
+       lsr.l   #8,%d0
+       or.l    %d1,%d0
+       printf  PCONV,"%08x\n",1,%d0
+       rts
+
+       | special return addresses for instr that
+       | encode the rounding precision in the opcode
+       | (e.g. fsmove,fdmove)
+
+fp_finalrounding_single:
+       addq.l  #8,%sp
+       jsr     fp_normalize_ext
+       jsr     fp_normalize_single
+       jra     fp_finaltest
+
+fp_finalrounding_single_fast:
+       addq.l  #8,%sp 
+       jsr     fp_normalize_ext
+       jsr     fp_normalize_single_fast
+       jra     fp_finaltest
+
+fp_finalrounding_double:
+       addq.l  #8,%sp
+       jsr     fp_normalize_ext
+       jsr     fp_normalize_double
+       jra     fp_finaltest
+
+       | fp_finaltest:
+       | set the emulated status register based on the outcome of an
+       | emulated instruction.
+
+fp_finalrounding:
+       addq.l  #8,%sp
+|      printf  ,"f: %p\n",1,%a0
+       jsr     fp_normalize_ext
+       move.w  (FPD_PREC,FPDATA),%d0
+       subq.w  #1,%d0
+       jcs     fp_finaltest
+       jne     1f
+       jsr     fp_normalize_single
+       jra     2f
+1:     jsr     fp_normalize_double
+2:|    printf  ,"f: %p\n",1,%a0
+fp_finaltest:
+       | First, we do some of the obvious tests for the exception
+       | status byte and condition code bytes of fp_sr here, so that
+       | they do not have to be handled individually by every
+       | emulated instruction.
+       clr.l   %d0
+       addq.l  #1,%a0
+       tst.b   (%a0)+                  | sign
+       jeq     1f
+       bset    #FPSR_CC_NEG-24,%d0     | N bit
+1:     cmp.w   #0x7fff,(%a0)+          | exponent
+       jeq     2f
+       | test for zero
+       moveq   #FPSR_CC_Z-24,%d1
+       tst.l   (%a0)+
+       jne     9f
+       tst.l   (%a0)
+       jne     9f
+       jra     8f
+       | infinitiv and NAN
+2:     moveq   #FPSR_CC_NAN-24,%d1
+       move.l  (%a0)+,%d2
+       lsl.l   #1,%d2                  | ignore high bit
+       jne     8f
+       tst.l   (%a0)
+       jne     8f
+       moveq   #FPSR_CC_INF-24,%d1
+8:     bset    %d1,%d0
+9:     move.b  %d0,(FPD_FPSR+0,FPDATA) | set condition test result
+       | move instructions enter here
+       | Here, we test things in the exception status byte, and set
+       | other things in the accrued exception byte accordingly.
+       | Emulated instructions can set various things in the former,
+       | as defined in fp_emu.h.
+fp_final:
+       move.l  (FPD_FPSR,FPDATA),%d0
+#if 0
+       btst    #FPSR_EXC_SNAN,%d0      | EXC_SNAN
+       jne     1f
+       btst    #FPSR_EXC_OPERR,%d0     | EXC_OPERR
+       jeq     2f
+1:     bset    #FPSR_AEXC_IOP,%d0      | set IOP bit
+2:     btst    #FPSR_EXC_OVFL,%d0      | EXC_OVFL
+       jeq     1f
+       bset    #FPSR_AEXC_OVFL,%d0     | set OVFL bit
+1:     btst    #FPSR_EXC_UNFL,%d0      | EXC_UNFL
+       jeq     1f
+       btst    #FPSR_EXC_INEX2,%d0     | EXC_INEX2
+       jeq     1f
+       bset    #FPSR_AEXC_UNFL,%d0     | set UNFL bit
+1:     btst    #FPSR_EXC_DZ,%d0        | EXC_INEX1
+       jeq     1f
+       bset    #FPSR_AEXC_DZ,%d0       | set DZ bit
+1:     btst    #FPSR_EXC_OVFL,%d0      | EXC_OVFL
+       jne     1f
+       btst    #FPSR_EXC_INEX2,%d0     | EXC_INEX2
+       jne     1f
+       btst    #FPSR_EXC_INEX1,%d0     | EXC_INEX1
+       jeq     2f
+1:     bset    #FPSR_AEXC_INEX,%d0     | set INEX bit
+2:     move.l  %d0,(FPD_FPSR,FPDATA)
+#else
+       | same as above, greatly optimized, but untested (yet)
+       move.l  %d0,%d2
+       lsr.l   #5,%d0
+       move.l  %d0,%d1
+       lsr.l   #4,%d1
+       or.l    %d0,%d1
+       and.b   #0x08,%d1
+       move.l  %d2,%d0
+       lsr.l   #6,%d0
+       or.l    %d1,%d0
+       move.l  %d2,%d1
+       lsr.l   #4,%d1
+       or.b    #0xdf,%d1
+       and.b   %d1,%d0
+       move.l  %d2,%d1
+       lsr.l   #7,%d1
+       and.b   #0x80,%d1
+       or.b    %d1,%d0
+       and.b   #0xf8,%d0
+       or.b    %d0,%d2
+       move.l  %d2,(FPD_FPSR,FPDATA)
+#endif
+       move.b  (FPD_FPSR+2,FPDATA),%d0
+       and.b   (FPD_FPCR+2,FPDATA),%d0
+       jeq     1f
+       printf  ,"send signal!!!\n"
+1:     jra     fp_end
diff --git a/arch/m68k/math-emu/multi_arith.h b/arch/m68k/math-emu/multi_arith.h
new file mode 100644 (file)
index 0000000..2b9b9e2
--- /dev/null
@@ -0,0 +1,822 @@
+/* multi_arith.h: multi-precision integer arithmetic functions, needed
+   to do extended-precision floating point.
+
+   (c) 1998 David Huggins-Daines.
+
+   Somewhat based on arch/alpha/math-emu/ieee-math.c, which is (c)
+   David Mosberger-Tang.
+
+   You may copy, modify, and redistribute this file under the terms of
+   the GNU General Public License, version 2, or any later version, at
+   your convenience. */
+
+/* Note:
+
+   These are not general multi-precision math routines.  Rather, they
+   implement the subset of integer arithmetic that we need in order to
+   multiply, divide, and normalize 128-bit unsigned mantissae.  */
+
+#ifndef MULTI_ARITH_H
+#define MULTI_ARITH_H
+
+#if 0  /* old code... */
+
+/* Unsigned only, because we don't need signs to multiply and divide. */
+typedef unsigned int int128[4];
+
+/* Word order */
+enum {
+       MSW128,
+       NMSW128,
+       NLSW128,
+       LSW128
+};
+
+/* big-endian */
+#define LO_WORD(ll) (((unsigned int *) &ll)[1])
+#define HI_WORD(ll) (((unsigned int *) &ll)[0])
+
+/* Convenience functions to stuff various integer values into int128s */
+
+extern inline void zero128(int128 a)
+{
+       a[LSW128] = a[NLSW128] = a[NMSW128] = a[MSW128] = 0;
+}
+
+/* Human-readable word order in the arguments */
+extern inline void set128(unsigned int i3,
+                         unsigned int i2,
+                         unsigned int i1,
+                         unsigned int i0,
+                         int128 a)
+{
+       a[LSW128] = i0;
+       a[NLSW128] = i1;
+       a[NMSW128] = i2;
+       a[MSW128] = i3;
+}
+
+/* Convenience functions (for testing as well) */
+extern inline void int64_to_128(unsigned long long src,
+                               int128 dest)
+{
+       dest[LSW128] = (unsigned int) src;
+       dest[NLSW128] = src >> 32;
+       dest[NMSW128] = dest[MSW128] = 0;
+}
+
+extern inline void int128_to_64(const int128 src,
+                               unsigned long long *dest)
+{
+       *dest = src[LSW128] | (long long) src[NLSW128] << 32;
+}
+
+extern inline void put_i128(const int128 a)
+{
+       printk("%08x %08x %08x %08x\n", a[MSW128], a[NMSW128],
+              a[NLSW128], a[LSW128]);
+}
+
+/* Internal shifters:
+
+   Note that these are only good for 0 < count < 32.
+ */
+
+extern inline void _lsl128(unsigned int count, int128 a)
+{
+       a[MSW128] = (a[MSW128] << count) | (a[NMSW128] >> (32 - count));
+       a[NMSW128] = (a[NMSW128] << count) | (a[NLSW128] >> (32 - count));
+       a[NLSW128] = (a[NLSW128] << count) | (a[LSW128] >> (32 - count));
+       a[LSW128] <<= count;
+}
+
+extern inline void _lsr128(unsigned int count, int128 a)
+{
+       a[LSW128] = (a[LSW128] >> count) | (a[NLSW128] << (32 - count));
+       a[NLSW128] = (a[NLSW128] >> count) | (a[NMSW128] << (32 - count));
+       a[NMSW128] = (a[NMSW128] >> count) | (a[MSW128] << (32 - count));
+       a[MSW128] >>= count;
+}
+
+/* Should be faster, one would hope */
+
+extern inline void lslone128(int128 a)
+{
+       asm volatile ("lsl.l #1,%0\n"
+                     "roxl.l #1,%1\n"
+                     "roxl.l #1,%2\n"
+                     "roxl.l #1,%3\n"
+                     :
+                     "=d" (a[LSW128]),
+                     "=d"(a[NLSW128]),
+                     "=d"(a[NMSW128]),
+                     "=d"(a[MSW128])
+                     :
+                     "0"(a[LSW128]),
+                     "1"(a[NLSW128]),
+                     "2"(a[NMSW128]),
+                     "3"(a[MSW128]));
+}
+
+extern inline void lsrone128(int128 a)
+{
+       asm volatile ("lsr.l #1,%0\n"
+                     "roxr.l #1,%1\n"
+                     "roxr.l #1,%2\n"
+                     "roxr.l #1,%3\n"
+                     :
+                     "=d" (a[MSW128]),
+                     "=d"(a[NMSW128]),
+                     "=d"(a[NLSW128]),
+                     "=d"(a[LSW128])
+                     :
+                     "0"(a[MSW128]),
+                     "1"(a[NMSW128]),
+                     "2"(a[NLSW128]),
+                     "3"(a[LSW128]));
+}
+
+/* Generalized 128-bit shifters:
+
+   These bit-shift to a multiple of 32, then move whole longwords.  */
+
+extern inline void lsl128(unsigned int count, int128 a)
+{
+       int wordcount, i;
+
+       if (count % 32)
+               _lsl128(count % 32, a);
+
+       if (0 == (wordcount = count / 32))
+               return;
+
+       /* argh, gak, endian-sensitive */
+       for (i = 0; i < 4 - wordcount; i++) {
+               a[i] = a[i + wordcount];
+       }
+       for (i = 3; i >= 4 - wordcount; --i) {
+               a[i] = 0;
+       }
+}
+
+extern inline void lsr128(unsigned int count, int128 a)
+{
+       int wordcount, i;
+
+       if (count % 32)
+               _lsr128(count % 32, a);
+
+       if (0 == (wordcount = count / 32))
+               return;
+
+       for (i = 3; i >= wordcount; --i) {
+               a[i] = a[i - wordcount];
+       }
+       for (i = 0; i < wordcount; i++) {
+               a[i] = 0;
+       }
+}
+
+extern inline int orl128(int a, int128 b)
+{
+       b[LSW128] |= a;
+}
+
+extern inline int btsthi128(const int128 a)
+{
+       return a[MSW128] & 0x80000000;
+}
+
+/* test bits (numbered from 0 = LSB) up to and including "top" */
+extern inline int bftestlo128(int top, const int128 a)
+{
+       int r = 0;
+
+       if (top > 31)
+               r |= a[LSW128];
+       if (top > 63)
+               r |= a[NLSW128];
+       if (top > 95)
+               r |= a[NMSW128];
+
+       r |= a[3 - (top / 32)] & ((1 << (top % 32 + 1)) - 1);
+
+       return (r != 0);
+}
+
+/* Aargh.  We need these because GCC is broken */
+/* FIXME: do them in assembly, for goodness' sake! */
+extern inline void mask64(int pos, unsigned long long *mask)
+{
+       *mask = 0;
+
+       if (pos < 32) {
+               LO_WORD(*mask) = (1 << pos) - 1;
+               return;
+       }
+       LO_WORD(*mask) = -1;
+       HI_WORD(*mask) = (1 << (pos - 32)) - 1;
+}
+
+extern inline void bset64(int pos, unsigned long long *dest)
+{
+       /* This conditional will be optimized away.  Thanks, GCC! */
+       if (pos < 32)
+               asm volatile ("bset %1,%0":"=m"
+                             (LO_WORD(*dest)):"id"(pos));
+       else
+               asm volatile ("bset %1,%0":"=m"
+                             (HI_WORD(*dest)):"id"(pos - 32));
+}
+
+extern inline int btst64(int pos, unsigned long long dest)
+{
+       if (pos < 32)
+               return (0 != (LO_WORD(dest) & (1 << pos)));
+       else
+               return (0 != (HI_WORD(dest) & (1 << (pos - 32))));
+}
+
+extern inline void lsl64(int count, unsigned long long *dest)
+{
+       if (count < 32) {
+               HI_WORD(*dest) = (HI_WORD(*dest) << count)
+                   | (LO_WORD(*dest) >> count);
+               LO_WORD(*dest) <<= count;
+               return;
+       }
+       count -= 32;
+       HI_WORD(*dest) = LO_WORD(*dest) << count;
+       LO_WORD(*dest) = 0;
+}
+
+extern inline void lsr64(int count, unsigned long long *dest)
+{
+       if (count < 32) {
+               LO_WORD(*dest) = (LO_WORD(*dest) >> count)
+                   | (HI_WORD(*dest) << (32 - count));
+               HI_WORD(*dest) >>= count;
+               return;
+       }
+       count -= 32;
+       LO_WORD(*dest) = HI_WORD(*dest) >> count;
+       HI_WORD(*dest) = 0;
+}
+#endif
+
+extern inline void fp_denormalize(struct fp_ext *reg, unsigned int cnt)
+{
+       reg->exp += cnt;
+
+       switch (cnt) {
+       case 0 ... 8:
+               reg->lowmant = reg->mant.m32[1] << (8 - cnt);
+               reg->mant.m32[1] = (reg->mant.m32[1] >> cnt) |
+                                  (reg->mant.m32[0] << (32 - cnt));
+               reg->mant.m32[0] = reg->mant.m32[0] >> cnt;
+               break;
+       case 9 ... 32:
+               reg->lowmant = reg->mant.m32[1] >> (cnt - 8);
+               if (reg->mant.m32[1] << (40 - cnt))
+                       reg->lowmant |= 1;
+               reg->mant.m32[1] = (reg->mant.m32[1] >> cnt) |
+                                  (reg->mant.m32[0] << (32 - cnt));
+               reg->mant.m32[0] = reg->mant.m32[0] >> cnt;
+               break;
+       case 33 ... 39:
+               asm volatile ("bfextu %1{%2,#8},%0" : "=d" (reg->lowmant)
+                       : "m" (reg->mant.m32[0]), "d" (64 - cnt));
+               if (reg->mant.m32[1] << (40 - cnt))
+                       reg->lowmant |= 1;
+               reg->mant.m32[1] = reg->mant.m32[0] >> (cnt - 32);
+               reg->mant.m32[0] = 0;
+               break;
+       case 40 ... 71:
+               reg->lowmant = reg->mant.m32[0] >> (cnt - 40);
+               if ((reg->mant.m32[0] << (72 - cnt)) || reg->mant.m32[1])
+                       reg->lowmant |= 1;
+               reg->mant.m32[1] = reg->mant.m32[0] >> (cnt - 32);
+               reg->mant.m32[0] = 0;
+               break;
+       default:
+               reg->lowmant = reg->mant.m32[0] || reg->mant.m32[1];
+               reg->mant.m32[0] = 0;
+               reg->mant.m32[1] = 0;
+               break;
+       }
+}
+
+extern inline int fp_overnormalize(struct fp_ext *reg)
+{
+       int shift;
+
+       if (reg->mant.m32[0]) {
+               asm ("bfffo %1{#0,#32},%0" : "=d" (shift) : "dm" (reg->mant.m32[0]));
+               reg->mant.m32[0] = (reg->mant.m32[0] << shift) | (reg->mant.m32[1] >> (32 - shift));
+               reg->mant.m32[1] = (reg->mant.m32[1] << shift);
+       } else {
+               asm ("bfffo %1{#0,#32},%0" : "=d" (shift) : "dm" (reg->mant.m32[1]));
+               reg->mant.m32[0] = (reg->mant.m32[1] << shift);
+               reg->mant.m32[1] = 0;
+               shift += 32;
+       }
+
+       return shift;
+}
+
+extern inline int fp_addmant(struct fp_ext *dest, struct fp_ext *src)
+{
+       int carry;
+
+       /* we assume here, gcc only insert move and a clr instr */
+       asm volatile ("add.b %1,%0" : "=d,=g" (dest->lowmant)
+               : "g,d" (src->lowmant), "0,0" (dest->lowmant));
+       asm volatile ("addx.l %1,%0" : "=d" (dest->mant.m32[1])
+               : "d" (src->mant.m32[1]), "0" (dest->mant.m32[1]));
+       asm volatile ("addx.l %1,%0" : "=d" (dest->mant.m32[0])
+               : "d" (src->mant.m32[0]), "0" (dest->mant.m32[0]));
+       asm volatile ("addx.l %0,%0" : "=d" (carry) : "0" (0));
+
+       return carry;
+}
+
+extern inline int fp_addcarry(struct fp_ext *reg)
+{
+       if (++reg->exp == 0x7fff) {
+               if (reg->mant.m64)
+                       fp_set_sr(FPSR_EXC_INEX2);
+               reg->mant.m64 = 0;
+               fp_set_sr(FPSR_EXC_OVFL);
+               return 0;
+       }
+       reg->lowmant = (reg->mant.m32[1] << 7) | (reg->lowmant ? 1 : 0);
+       reg->mant.m32[1] = (reg->mant.m32[1] >> 1) |
+                          (reg->mant.m32[0] << 31);
+       reg->mant.m32[0] = (reg->mant.m32[0] >> 1) | 0x80000000;
+
+       return 1;
+}
+
+extern inline void fp_submant(struct fp_ext *dest, struct fp_ext *src1, struct fp_ext *src2)
+{
+       /* we assume here, gcc only insert move and a clr instr */
+       asm volatile ("sub.b %1,%0" : "=d,=g" (dest->lowmant)
+               : "g,d" (src2->lowmant), "0,0" (src1->lowmant));
+       asm volatile ("subx.l %1,%0" : "=d" (dest->mant.m32[1])
+               : "d" (src2->mant.m32[1]), "0" (src1->mant.m32[1]));
+       asm volatile ("subx.l %1,%0" : "=d" (dest->mant.m32[0])
+               : "d" (src2->mant.m32[0]), "0" (src1->mant.m32[0]));
+}
+
+#define fp_mul64(desth, destl, src1, src2) ({                          \
+       asm ("mulu.l %2,%1:%0" : "=d" (destl), "=d" (desth)             \
+               : "g" (src1), "0" (src2));                              \
+})
+#define fp_div64(quot, rem, srch, srcl, div)                           \
+       asm ("divu.l %2,%1:%0" : "=d" (quot), "=d" (rem)                \
+               : "dm" (div), "1" (srch), "0" (srcl))
+#define fp_add64(dest1, dest2, src1, src2) ({                          \
+       asm ("add.l %1,%0" : "=d,=dm" (dest2)                           \
+               : "dm,d" (src2), "0,0" (dest2));                        \
+       asm ("addx.l %1,%0" : "=d" (dest1)                              \
+               : "d" (src1), "0" (dest1));                             \
+})
+#define fp_addx96(dest, src) ({                                                \
+       /* we assume here, gcc only insert move and a clr instr */      \
+       asm volatile ("add.l %1,%0" : "=d,=g" (dest->m32[2])            \
+               : "g,d" (temp.m32[1]), "0,0" (dest->m32[2]));           \
+       asm volatile ("addx.l %1,%0" : "=d" (dest->m32[1])              \
+               : "d" (temp.m32[0]), "0" (dest->m32[1]));               \
+       asm volatile ("addx.l %1,%0" : "=d" (dest->m32[0])              \
+               : "d" (0), "0" (dest->m32[0]));                         \
+})
+#define fp_sub64(dest, src) ({                                         \
+       asm ("sub.l %1,%0" : "=d,=dm" (dest.m32[1])                     \
+               : "dm,d" (src.m32[1]), "0,0" (dest.m32[1]));            \
+       asm ("subx.l %1,%0" : "=d" (dest.m32[0])                        \
+               : "d" (src.m32[0]), "0" (dest.m32[0]));                 \
+})
+#define fp_sub96c(dest, srch, srcm, srcl) ({                           \
+       char carry;                                                     \
+       asm ("sub.l %1,%0" : "=d,=dm" (dest.m32[2])                     \
+               : "dm,d" (srcl), "0,0" (dest.m32[2]));                  \
+       asm ("subx.l %1,%0" : "=d" (dest.m32[1])                        \
+               : "d" (srcm), "0" (dest.m32[1]));                       \
+       asm ("subx.l %2,%1; scs %0" : "=d" (carry), "=d" (dest.m32[0])  \
+               : "d" (srch), "1" (dest.m32[0]));                       \
+       carry;                                                          \
+})
+
+extern inline void fp_multiplymant(union fp_mant128 *dest, struct fp_ext *src1, struct fp_ext *src2)
+{
+       union fp_mant64 temp;
+
+       fp_mul64(dest->m32[0], dest->m32[1], src1->mant.m32[0], src2->mant.m32[0]);
+       fp_mul64(dest->m32[2], dest->m32[3], src1->mant.m32[1], src2->mant.m32[1]);
+
+       fp_mul64(temp.m32[0], temp.m32[1], src1->mant.m32[0], src2->mant.m32[1]);
+       fp_addx96(dest, temp);
+
+       fp_mul64(temp.m32[0], temp.m32[1], src1->mant.m32[1], src2->mant.m32[0]);
+       fp_addx96(dest, temp);
+}
+
+extern inline void fp_dividemant(union fp_mant128 *dest, struct fp_ext *src, struct fp_ext *div)
+{
+       union fp_mant128 tmp;
+       union fp_mant64 tmp64;
+       unsigned long *mantp = dest->m32;
+       unsigned long fix, rem, first, dummy;
+       int i;
+
+       /* the algorithm below requires dest to be smaller than div,
+          but both have the high bit set */
+       if (src->mant.m64 >= div->mant.m64) {
+               fp_sub64(src->mant, div->mant);
+               *mantp = 1;
+       } else
+               *mantp = 0;
+       mantp++;
+
+       /* basic idea behind this algorithm: we can't divide two 64bit numbers
+          (AB/CD) directly, but we can calculate AB/C0, but this means this
+          quotient is off by C0/CD, so we have to multiply the first result
+          to fix the result, after that we have nearly the correct result
+          and only a few corrections are needed. */
+
+       /* C0/CD can be precalculated, but it's an 64bit division again, but
+          we can make it a bit easier, by dividing first through C so we get
+          10/1D and now only a single shift and the value fits into 32bit. */
+       fix = 0x80000000;
+       dummy = div->mant.m32[1] / div->mant.m32[0] + 1;
+       dummy = (dummy >> 1) | fix;
+       fp_div64(fix, dummy, fix, 0, dummy);
+       fix--;
+
+       for (i = 0; i < 3; i++, mantp++) {
+               if (src->mant.m32[0] == div->mant.m32[0]) {
+                       fp_div64(first, rem, 0, src->mant.m32[1], div->mant.m32[0]);
+
+                       fp_mul64(*mantp, dummy, first, fix);
+                       *mantp += fix;
+               } else {
+                       fp_div64(first, rem, src->mant.m32[0], src->mant.m32[1], div->mant.m32[0]);
+
+                       fp_mul64(*mantp, dummy, first, fix);
+               }
+
+               fp_mul64(tmp.m32[0], tmp.m32[1], div->mant.m32[0], first - *mantp);
+               fp_add64(tmp.m32[0], tmp.m32[1], 0, rem);
+               tmp.m32[2] = 0;
+
+               fp_mul64(tmp64.m32[0], tmp64.m32[1], *mantp, div->mant.m32[1]);
+               fp_sub96c(tmp, 0, tmp64.m32[0], tmp64.m32[1]);
+
+               src->mant.m32[0] = tmp.m32[1];
+               src->mant.m32[1] = tmp.m32[2];
+
+               while (!fp_sub96c(tmp, 0, div->mant.m32[0], div->mant.m32[1])) {
+                       src->mant.m32[0] = tmp.m32[1];
+                       src->mant.m32[1] = tmp.m32[2];
+                       *mantp += 1;
+               }
+       }
+}
+
+#if 0
+extern inline unsigned int fp_fls128(union fp_mant128 *src)
+{
+       unsigned long data;
+       unsigned int res, off;
+
+       if ((data = src->m32[0]))
+               off = 0;
+       else if ((data = src->m32[1]))
+               off = 32;
+       else if ((data = src->m32[2]))
+               off = 64;
+       else if ((data = src->m32[3]))
+               off = 96;
+       else
+               return 128;
+
+       asm ("bfffo %1{#0,#32},%0" : "=d" (res) : "dm" (data));
+       return res + off;
+}
+
+extern inline void fp_shiftmant128(union fp_mant128 *src, int shift)
+{
+       unsigned long sticky;
+
+       switch (shift) {
+       case 0:
+               return;
+       case 1:
+               asm volatile ("lsl.l #1,%0"
+                       : "=d" (src->m32[3]) : "0" (src->m32[3]));
+               asm volatile ("roxl.l #1,%0"
+                       : "=d" (src->m32[2]) : "0" (src->m32[2]));
+               asm volatile ("roxl.l #1,%0"
+                       : "=d" (src->m32[1]) : "0" (src->m32[1]));
+               asm volatile ("roxl.l #1,%0"
+                       : "=d" (src->m32[0]) : "0" (src->m32[0]));
+               return;
+       case 2 ... 31:
+               src->m32[0] = (src->m32[0] << shift) | (src->m32[1] >> (32 - shift));
+               src->m32[1] = (src->m32[1] << shift) | (src->m32[2] >> (32 - shift));
+               src->m32[2] = (src->m32[2] << shift) | (src->m32[3] >> (32 - shift));
+               src->m32[3] = (src->m32[3] << shift);
+               return;
+       case 32 ... 63:
+               shift -= 32;
+               src->m32[0] = (src->m32[1] << shift) | (src->m32[2] >> (32 - shift));
+               src->m32[1] = (src->m32[2] << shift) | (src->m32[3] >> (32 - shift));
+               src->m32[2] = (src->m32[3] << shift);
+               src->m32[3] = 0;
+               return;
+       case 64 ... 95:
+               shift -= 64;
+               src->m32[0] = (src->m32[2] << shift) | (src->m32[3] >> (32 - shift));
+               src->m32[1] = (src->m32[3] << shift);
+               src->m32[2] = src->m32[3] = 0;
+               return;
+       case 96 ... 127:
+               shift -= 96;
+               src->m32[0] = (src->m32[3] << shift);
+               src->m32[1] = src->m32[2] = src->m32[3] = 0;
+               return;
+       case -31 ... -1:
+               shift = -shift;
+               sticky = 0;
+               if (src->m32[3] << (32 - shift))
+                       sticky = 1;
+               src->m32[3] = (src->m32[3] >> shift) | (src->m32[2] << (32 - shift)) | sticky;
+               src->m32[2] = (src->m32[2] >> shift) | (src->m32[1] << (32 - shift));
+               src->m32[1] = (src->m32[1] >> shift) | (src->m32[0] << (32 - shift));
+               src->m32[0] = (src->m32[0] >> shift);
+               return;
+       case -63 ... -32:
+               shift = -shift - 32;
+               sticky = 0;
+               if ((src->m32[2] << (32 - shift)) || src->m32[3])
+                       sticky = 1;
+               src->m32[3] = (src->m32[2] >> shift) | (src->m32[1] << (32 - shift)) | sticky;
+               src->m32[2] = (src->m32[1] >> shift) | (src->m32[0] << (32 - shift));
+               src->m32[1] = (src->m32[0] >> shift);
+               src->m32[0] = 0;
+               return;
+       case -95 ... -64:
+               shift = -shift - 64;
+               sticky = 0;
+               if ((src->m32[1] << (32 - shift)) || src->m32[2] || src->m32[3])
+                       sticky = 1;
+               src->m32[3] = (src->m32[1] >> shift) | (src->m32[0] << (32 - shift)) | sticky;
+               src->m32[2] = (src->m32[0] >> shift);
+               src->m32[1] = src->m32[0] = 0;
+               return;
+       case -127 ... -96:
+               shift = -shift - 96;
+               sticky = 0;
+               if ((src->m32[0] << (32 - shift)) || src->m32[1] || src->m32[2] || src->m32[3])
+                       sticky = 1;
+               src->m32[3] = (src->m32[0] >> shift) | sticky;
+               src->m32[2] = src->m32[1] = src->m32[0] = 0;
+               return;
+       }
+
+       if (shift < 0 && (src->m32[0] || src->m32[1] || src->m32[2] || src->m32[3]))
+               src->m32[3] = 1;
+       else
+               src->m32[3] = 0;
+       src->m32[2] = 0;
+       src->m32[1] = 0;
+       src->m32[0] = 0;
+}
+#endif
+
+extern inline void fp_putmant128(struct fp_ext *dest, union fp_mant128 *src, int shift)
+{
+       unsigned long tmp;
+
+       switch (shift) {
+       case 0:
+               dest->mant.m64 = src->m64[0];
+               dest->lowmant = src->m32[2] >> 24;
+               if (src->m32[3] || (src->m32[2] << 8))
+                       dest->lowmant |= 1;
+               break;
+       case 1:
+               asm volatile ("lsl.l #1,%0"
+                       : "=d" (tmp) : "0" (src->m32[2]));
+               asm volatile ("roxl.l #1,%0"
+                       : "=d" (dest->mant.m32[1]) : "0" (src->m32[1]));
+               asm volatile ("roxl.l #1,%0"
+                       : "=d" (dest->mant.m32[0]) : "0" (src->m32[0]));
+               dest->lowmant = tmp >> 24;
+               if (src->m32[3] || (tmp << 8))
+                       dest->lowmant |= 1;
+               break;
+       case 31:
+               asm volatile ("lsr.l #1,%1; roxr.l #1,%0"
+                       : "=d" (dest->mant.m32[0])
+                       : "d" (src->m32[0]), "0" (src->m32[1]));
+               asm volatile ("roxr.l #1,%0"
+                       : "=d" (dest->mant.m32[1]) : "0" (src->m32[2]));
+               asm volatile ("roxr.l #1,%0"
+                       : "=d" (tmp) : "0" (src->m32[3]));
+               dest->lowmant = tmp >> 24;
+               if (src->m32[3] << 7)
+                       dest->lowmant |= 1;
+               break;
+       case 32:
+               dest->mant.m32[0] = src->m32[1];
+               dest->mant.m32[1] = src->m32[2];
+               dest->lowmant = src->m32[3] >> 24;
+               if (src->m32[3] << 8)
+                       dest->lowmant |= 1;
+               break;
+       }
+}
+
+#if 0 /* old code... */
+extern inline int fls(unsigned int a)
+{
+       int r;
+
+       asm volatile ("bfffo %1{#0,#32},%0"
+                     : "=d" (r) : "md" (a));
+       return r;
+}
+
+/* fls = "find last set" (cf. ffs(3)) */
+extern inline int fls128(const int128 a)
+{
+       if (a[MSW128])
+               return fls(a[MSW128]);
+       if (a[NMSW128])
+               return fls(a[NMSW128]) + 32;
+       /* XXX: it probably never gets beyond this point in actual
+          use, but that's indicative of a more general problem in the
+          algorithm (i.e. as per the actual 68881 implementation, we
+          really only need at most 67 bits of precision [plus
+          overflow]) so I'm not going to fix it. */
+       if (a[NLSW128])
+               return fls(a[NLSW128]) + 64;
+       if (a[LSW128])
+               return fls(a[LSW128]) + 96;
+       else
+               return -1;
+}
+
+extern inline int zerop128(const int128 a)
+{
+       return !(a[LSW128] | a[NLSW128] | a[NMSW128] | a[MSW128]);
+}
+
+extern inline int nonzerop128(const int128 a)
+{
+       return (a[LSW128] | a[NLSW128] | a[NMSW128] | a[MSW128]);
+}
+
+/* Addition and subtraction */
+/* Do these in "pure" assembly, because "extended" asm is unmanageable
+   here */
+extern inline void add128(const int128 a, int128 b)
+{
+       /* rotating carry flags */
+       unsigned int carry[2];
+
+       carry[0] = a[LSW128] > (0xffffffff - b[LSW128]);
+       b[LSW128] += a[LSW128];
+
+       carry[1] = a[NLSW128] > (0xffffffff - b[NLSW128] - carry[0]);
+       b[NLSW128] = a[NLSW128] + b[NLSW128] + carry[0];
+
+       carry[0] = a[NMSW128] > (0xffffffff - b[NMSW128] - carry[1]);
+       b[NMSW128] = a[NMSW128] + b[NMSW128] + carry[1];
+
+       b[MSW128] = a[MSW128] + b[MSW128] + carry[0];
+}
+
+/* Note: assembler semantics: "b -= a" */
+extern inline void sub128(const int128 a, int128 b)
+{
+       /* rotating borrow flags */
+       unsigned int borrow[2];
+
+       borrow[0] = b[LSW128] < a[LSW128];
+       b[LSW128] -= a[LSW128];
+
+       borrow[1] = b[NLSW128] < a[NLSW128] + borrow[0];
+       b[NLSW128] = b[NLSW128] - a[NLSW128] - borrow[0];
+
+       borrow[0] = b[NMSW128] < a[NMSW128] + borrow[1];
+       b[NMSW128] = b[NMSW128] - a[NMSW128] - borrow[1];
+
+       b[MSW128] = b[MSW128] - a[MSW128] - borrow[0];
+}
+
+/* Poor man's 64-bit expanding multiply */
+extern inline void mul64(unsigned long long a,
+                 unsigned long long b,
+                 int128 c)
+{
+       unsigned long long acc;
+       int128 acc128;
+
+       zero128(acc128);
+       zero128(c);
+
+       /* first the low words */
+       if (LO_WORD(a) && LO_WORD(b)) {
+               acc = (long long) LO_WORD(a) * LO_WORD(b);
+               c[NLSW128] = HI_WORD(acc);
+               c[LSW128] = LO_WORD(acc);
+       }
+       /* Next the high words */
+       if (HI_WORD(a) && HI_WORD(b)) {
+               acc = (long long) HI_WORD(a) * HI_WORD(b);
+               c[MSW128] = HI_WORD(acc);
+               c[NMSW128] = LO_WORD(acc);
+       }
+       /* The middle words */
+       if (LO_WORD(a) && HI_WORD(b)) {
+               acc = (long long) LO_WORD(a) * HI_WORD(b);
+               acc128[NMSW128] = HI_WORD(acc);
+               acc128[NLSW128] = LO_WORD(acc);
+               add128(acc128, c);
+       }
+       /* The first and last words */
+       if (HI_WORD(a) && LO_WORD(b)) {
+               acc = (long long) HI_WORD(a) * LO_WORD(b);
+               acc128[NMSW128] = HI_WORD(acc);
+               acc128[NLSW128] = LO_WORD(acc);
+               add128(acc128, c);
+       }
+}
+
+/* Note: unsigned */
+extern inline int cmp128(int128 a, int128 b)
+{
+       if (a[MSW128] < b[MSW128])
+               return -1;
+       if (a[MSW128] > b[MSW128])
+               return 1;
+       if (a[NMSW128] < b[NMSW128])
+               return -1;
+       if (a[NMSW128] > b[NMSW128])
+               return 1;
+       if (a[NLSW128] < b[NLSW128])
+               return -1;
+       if (a[NLSW128] > b[NLSW128])
+               return 1;
+
+       return (signed) a[LSW128] - b[LSW128];
+}
+
+inline void div128(int128 a, int128 b, int128 c)
+{
+       int128 mask;
+
+       /* Algorithm:
+
+          Shift the divisor until it's at least as big as the
+          dividend, keeping track of the position to which we've
+          shifted it, i.e. the power of 2 which we've multiplied it
+          by.
+
+          Then, for this power of 2 (the mask), and every one smaller
+          than it, subtract the mask from the dividend and add it to
+          the quotient until the dividend is smaller than the raised
+          divisor.  At this point, divide the dividend and the mask
+          by 2 (i.e. shift one place to the right).  Lather, rinse,
+          and repeat, until there are no more powers of 2 left. */
+
+       /* FIXME: needless to say, there's room for improvement here too. */
+
+       /* Shift up */
+       /* XXX: since it just has to be "at least as big", we can
+          probably eliminate this horribly wasteful loop.  I will
+          have to prove this first, though */
+       set128(0, 0, 0, 1, mask);
+       while (cmp128(b, a) < 0 && !btsthi128(b)) {
+               lslone128(b);
+               lslone128(mask);
+       }
+
+       /* Shift down */
+       zero128(c);
+       do {
+               if (cmp128(a, b) >= 0) {
+                       sub128(b, a);
+                       add128(mask, c);
+               }
+               lsrone128(mask);
+               lsrone128(b);
+       } while (nonzerop128(mask));
+
+       /* The remainder is in a... */
+}
+#endif
+
+#endif /* MULTI_ARITH_H */
index 5433796cbc91acce53db2623d381a8115cbb854d..60134d9de5bb401c781085693da6fca287c4a6a2 100644 (file)
@@ -7,7 +7,7 @@ available from this place and ftp.uni-erlangen.de/linux/680x0/q40/
 and mirrors.
 
 Hints to documentation usually refer to the linux source tree in
-/usr/src/linux unless URL given.
+/usr/src/linux/Documentation unless URL given.
 
 It seems IRQ unmasking can't be safely done on a Q40. Autoprobing is 
 not yet implemented - do not try it! (See below)
@@ -18,8 +18,8 @@ particular device drivers.
 The floppy imposes a very high interrupt load on the CPU, approx 30K/s.
 When something blocks interrupts (HD) it will loose some of them, so far 
 this is not known to have caused any data loss. On hihgly loaded systems
-it can make the floppy very slow. Other Q40 OS' simply poll the floppy
-for this reason - something that can't be done in Linux.
+it can make the floppy very slow or practicaly stop. Other Q40 OS' simply 
+poll the floppy for this reason - something that can't be done in Linux.
 Only possible cure is getting a 82072 contoler with fifo instead of 
 the 8272A
 
@@ -48,7 +48,7 @@ Debugging
 Upon startup the kernel will usually output "ABCQGHIJ" into the SRAM, 
 preceded by the booter signature. This is a trace just in case something 
 went wrong during earliest setup stages. 
-*Changed* to preserve SRAM contents by default, this is only done when 
+**Changed** to preserve SRAM contents by default, this is only done when 
 requested - SRAM must start with '%LX$' signature to do this. '-d' option 
 to 'lxx' loader enables this.
 
@@ -92,12 +92,22 @@ Interrupts
 ==========
 
 q40 master chip handles only level triggered interrupts :-((
-further limitation is no disabling etc. Unless someone finds 
-some ingenious clue this means autoprobing will never work.
-Parallel port interrupts cause most trouble..
-
-IRQ sharing is not yet implemented.
-
+further limitation is no disabling etc. There is NO WAY to remove
+an ISA irq request other than serve the HW specific control register,
+the ISA irq lines are connected straight to the CPU ipl1 pin..
+
+IRQ sharing is not yet implemented but this should be only a minor
+problem..
+
+Linux has some requirements wrt interrupt architecture, these are
+to my knowledge:
+       (a) interrupt handler must not be reentered even when sti() is called
+       (b) working enable/disable_irq
+
+Luckily these requirements are only important for drivers shared
+with other architectures - ide,serial,parallel, ethernet..
+q40ints.c now contains a trivial hack for (a), however (b) could
+be only solved by driver-specific code
 
 Keyboard
 ========
index 889936243955a0e18f5686a0cc7fcbe34c536f95..178bef18c72408ea6aa5df4d6db4efb7d70e0f1c 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *  arch/m68k/q40/config.c
  *
+ *  Copyright (C) 1999 Richard Zidlicky
+ *
  * originally based on:
  *
  *  linux/bvme/config.c
  *
- *  Copyright (C) 1993 Hamish Macdonald
- *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file README.legal in the main directory of this archive
  * for more details.
@@ -23,6 +23,7 @@
 #include <linux/init.h>
 #include <linux/major.h>
 
+#include <asm/rtc.h>
 #include <asm/bootinfo.h>
 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -134,12 +135,11 @@ int q40_kbdrate (struct kbd_repeat *k)
 void q40_reset()
 {
 
-       printk ("\n\n*******************************************\n"
-                     "Called q40_reset : press the RESET button!! \n");
-       printk(     "*******************************************\n");
-
-       while(1)
-               ;
+        printk ("\n\n*******************************************\n"
+               "Called q40_reset : press the RESET button!! \n"
+               "*******************************************\n");
+       
+       while(1) ;
 }
 
 static void q40_get_model(char *model)
@@ -232,6 +232,9 @@ void q40_mksound(unsigned int hz, unsigned int ticks)
 }
 
 static void (*q40_timer_routine)(int, void *, struct pt_regs *);
+static short rtc_oldsecs=0;
+unsigned rtc_irq_flags=0;
+unsigned rtc_irq_ctrl=0;
 
 static void q40_timer_int (int irq, void *dev_id, struct pt_regs *fp)
 {
@@ -250,6 +253,14 @@ static void q40_timer_int (int irq, void *dev_id, struct pt_regs *fp)
        *DAC_LEFT=sval;
        *DAC_RIGHT=sval;
       }
+#ifdef CONFIG_Q40RTC
+    if (rtc_irq_ctrl && (rtc_oldsecs != RTC_SECS))
+      {
+       rtc_oldsecs = RTC_SECS;
+       rtc_irq_flags = RTC_UIE;
+       rtc_interrupt();
+      }
+#endif
     if (ql_ticks) return;
 #endif
     q40_timer_routine(irq, dev_id, fp);
index e9b5a5b1f0372bf43ae666b07d68511abfbd8d39..c6625aad8b09dd545d89714269c70ceaa411eaa0 100644 (file)
@@ -29,7 +29,7 @@
  *            3,4,5,6,7,10,11,14,15 : ISA dev IRQs
  *            16-31: reserved
  *            32   : keyboard int
- *            33   : frame int (50 Hz periodic timer)
+ *            33   : frame int (50/200 Hz periodic timer)
  *            34   : sample int (10/20 KHz periodic timer)
  *          
 */
@@ -45,20 +45,21 @@ extern void (*q40_sys_default_handler[]) (int, void *, struct pt_regs *);  /* ad
 static void q40_defhand (int irq, void *dev_id, struct pt_regs *fp);
 static void sys_default_handler(int lev, void *dev_id, struct pt_regs *regs);
 
-/*
- * This should ideally be 4 elements only, for speed.
- */
 
 #define DEVNAME_SIZE 24
 
-static struct {
+static struct q40_irq_node {
        void            (*handler)(int, void *, struct pt_regs *);
        unsigned long   flags;
        void            *dev_id;
+  /*        struct q40_irq_node *next;*/
         char           devname[DEVNAME_SIZE];
        unsigned        count;
+        unsigned short  state;
 } irq_tab[Q40_IRQ_MAX+1];
 
+short unsigned q40_ablecount[Q40_IRQ_MAX+1];
+
 /*
  * void q40_init_IRQ (void)
  *
@@ -78,8 +79,11 @@ void q40_init_IRQ (void)
                irq_tab[i].handler = q40_defhand;
                irq_tab[i].flags = IRQ_FLG_STD;
                irq_tab[i].dev_id = NULL;
+               /*              irq_tab[i].next = NULL;*/
                irq_tab[i].devname[0] = 0;
                irq_tab[i].count = 0;
+               irq_tab[i].state =0;
+               q40_ablecount[i]=0;   /* all enabled */
        }
 
        /* setup handler for ISA ints */
@@ -108,23 +112,20 @@ int q40_request_irq(unsigned int irq,
        }
 
        /* test for ISA ints not implemented by HW */
-       if (irq<15) 
+       switch (irq)
          {
-           switch (irq){
-           case 1: case 2: case 8: case 9:
-           case 12: case 13:
-             printk("%s: ISA IRQ %d from %s not implemented by HW\n", __FUNCTION__, irq, devname);
-             return -ENXIO;
-           default:
-           }
+         case 1: case 2: case 8: case 9:
+         case 12: case 13:
+           printk("%s: ISA IRQ %d from %s not implemented by HW\n", __FUNCTION__, irq, devname);
+           return -ENXIO;
+         case 11:            
+           printk("warning IRQ 10 and 11 not distinguishable\n");
+           irq=10;
+         default:
          }
 
        if (irq<Q40_IRQ_TIMER)
          {
-           if (irq==11) {
-             printk("warning IRQ 10 and 11 not distinguishable\n");
-             irq=10;
-           }
            if (!(irq_tab[irq].flags & IRQ_FLG_STD)) 
              {
                if (irq_tab[irq].flags & IRQ_FLG_LOCK) 
@@ -145,6 +146,7 @@ int q40_request_irq(unsigned int irq,
            irq_tab[irq].flags   = flags;
            irq_tab[irq].dev_id  = dev_id;
            strncpy(irq_tab[irq].devname,devname,DEVNAME_SIZE);
+           irq_tab[irq].state = 0;
            return 0;
          }
        else {
@@ -163,30 +165,33 @@ void q40_free_irq(unsigned int irq, void *dev_id)
        }
 
        /* test for ISA ints not implemented by HW */
-       if (irq<15) {
-         switch (irq){
+       switch (irq)
+         {
          case 1: case 2: case 8: case 9:
          case 12: case 13:
-               printk("%s: ISA IRQ %d from %x illegal\n", __FUNCTION__, irq, (unsigned)dev_id);
-               return;
+           printk("%s: ISA IRQ %d from %x illegal\n", __FUNCTION__, irq, (unsigned)dev_id);
+           return;
+         case 11: irq=10;
          default:
-                 }
-       }
+         }
        
-       if (irq<Q40_IRQ_TIMER){
-         if (irq==11) irq=10;
-         if (irq_tab[irq].dev_id != dev_id)
-           printk("%s: Removing probably wrong IRQ %d from %s\n",
-                  __FUNCTION__, irq, irq_tab[irq].devname);
-         
-         irq_tab[irq].handler = q40_defhand;
-         irq_tab[irq].flags   = IRQ_FLG_STD;
-         irq_tab[irq].dev_id  = NULL;
-         /* irq_tab[irq].devname = NULL; */
-       } else { /* == Q40_IRQ_TIMER */
-         sys_free_irq(4,dev_id);
-         sys_free_irq(6,dev_id);
-       }
+       if (irq<Q40_IRQ_TIMER)
+         {
+           if (irq_tab[irq].dev_id != dev_id)
+             printk("%s: Removing probably wrong IRQ %d from %s\n",
+                    __FUNCTION__, irq, irq_tab[irq].devname);
+           
+           irq_tab[irq].handler = q40_defhand;
+           irq_tab[irq].flags   = IRQ_FLG_STD;
+           irq_tab[irq].dev_id  = NULL;
+           /* irq_tab[irq].devname = NULL; */
+           /* do not reset state !! */
+         }
+       else
+         { /* == Q40_IRQ_TIMER */
+           sys_free_irq(4,dev_id);
+           sys_free_irq(6,dev_id);
+         }
 }
 
 #if 1
@@ -224,11 +229,16 @@ static struct IRQ_TABLE eirqs[]={
 
   {0,0}};
 
-/* complaiun only this many times about spurious ints : */
+/* complain only this many times about spurious ints : */
 static int ccleirq=60;    /* ISA dev IRQ's*/
 static int cclirq=60;     /* internal */
 
-/* FIX: add IRQ_INPROGRESS,mask,unmask,probing.... */
+/* FIX: add shared ints,mask,unmask,probing.... */
+
+/* this is an awfull hack.. */
+#define IRQ_INPROGRESS 1
+static int disabled=0;
+/*static unsigned short saved_mask;*/
 
 void q40_irq2_handler (int vec, void *devname, struct pt_regs *fp)
 {
@@ -238,11 +248,6 @@ void q40_irq2_handler (int vec, void *devname, struct pt_regs *fp)
        unsigned mer;
        int irq,i;
 
-       /*
-        *  more than 1 bit might be set, must handle atmost 1 int source,
-        *  - handle only those with explicitly set handler
-        */
-
        if ((mir&IRQ_SER_MASK) || (mir&IRQ_EXT_MASK)) 
          {
            
@@ -257,9 +262,37 @@ void q40_irq2_handler (int vec, void *devname, struct pt_regs *fp)
                    irq=eirqs[i].irq;
                    irq_tab[irq].count++;
                    if (irq_tab[irq].handler == q40_defhand )
-                     continue; /* ignore uninited INTs :-( */
-                   
+                     {
+                       printk("handler for IRQ %d not defined\n",irq);
+                       continue; /* ignore uninited INTs :-( */
+                     }
+
+                   if ( irq_tab[irq].state & IRQ_INPROGRESS )
+                     {
+                       /*printk("IRQ_INPROGRESS detected for irq %d, disabling - %s disabled\n",irq,disabled ? "already" : "not yet"); */
+
+                       /*saved_mask = fp->sr;*/
+                       fp->sr = (fp->sr & (~0x700))+0x200;
+                       disabled=1;
+                       return;
+                     }
+                   irq_tab[irq].state |= IRQ_INPROGRESS;
                    irq_tab[irq].handler(irq,irq_tab[irq].dev_id,fp);
+
+                   /* naively enable everything, if that fails than    */
+                   /* this function will be reentered immediately thus */
+                   /* getting another chance to disable the IRQ        */
+
+                   irq_tab[irq].state &= ~IRQ_INPROGRESS;
+                   if ( disabled ) 
+                     {
+                       /*printk("reenabling irq %d\n",irq); */
+                       fp->sr = (fp->sr & (~0x700)); /*saved_mask; */
+                       disabled=0;
+                     }
+                   else if ( fp->sr &0x200 )
+                     printk("exiting irq handler: fp->sr &0x200 !!\n");
+
                    return;
                  }
              }
@@ -279,7 +312,17 @@ void q40_irq2_handler (int vec, void *devname, struct pt_regs *fp)
                    if (irq_tab[irq].handler == q40_defhand )
                      continue; /* ignore uninited INTs :-( */
                    
+                   /* the INPROGRESS stuff should be completely useless*/
+                   /* for internal ints, nevertheless test it..*/
+                   if ( irq_tab[irq].state & IRQ_INPROGRESS )
+                     {
+                       /*disable_irq(irq);
+                         return;*/
+                       printk("rentering handler for IRQ %d !!\n",irq);
+                     }
                    irq_tab[irq].handler(irq,irq_tab[irq].dev_id,fp);
+                   irq_tab[irq].state &= ~IRQ_INPROGRESS;
+                   /*enable_irq(irq);*/ /* better not try luck !*/
                    return;
                  }
              }
@@ -327,19 +370,59 @@ static void sys_default_handler(int lev, void *dev_id, struct pt_regs *regs)
    sys_default_handler,sys_default_handler,sys_default_handler,sys_default_handler
  };
 
+int irq_disabled=0;
 void q40_enable_irq (unsigned int irq)
 {
+  /* enable ISA iqs */
+  if ( irq>=0 && irq<=15 ) /* the moderately bad case */
+    master_outb(1,EXT_ENABLE_REG);
+#if 0
+  unsigned long flags;
+  int i;
+
+  if (irq>=10 && irq <= 15)
+    {
+      if ( !(--q40_ablecount[irq]))
+       for (i=10,irq_disabled=0; i<=15; i++)
+         {
+           irq_disabled |= (q40_ablecount[irq] !=0);
+         }
+      if ( !irq_disabled )
+       {
+         save_flags(flags);
+         restore_flags(flags & (~0x700));
+       }
+    }
+#endif
 }
 
 
 void q40_disable_irq (unsigned int irq)
 {
+  /* disable ISA iqs : only do something if the driver has been
+  * verified to be Q40 "compatible" - right now only IDE
+  * Any driver should not attempt to sleep accross disable_irq !!
+  */
+
+  if ( irq>=10 && irq<=15 ) /* the moderately bad case */
+    master_outb(0,EXT_ENABLE_REG);
+#if 0
+  unsigned long flags;
+
+  if (irq>=10 && irq <= 15)
+    {
+      save_flags(flags);
+      restore_flags(flags | 0x200 );
+      irq_disabled=1;
+      q40_ablecount[irq]++;
+    }
+#endif
 }
 
 unsigned long q40_probe_irq_on (void)
 {
-  printk("sorry, irq probing not yet implemented - reconfigure the driver to avoid this\n");
-  return 0;
+  printk("irq probing not working - reconfigure the driver to avoid this\n");
+  return -1;
 }
 int q40_probe_irq_off (unsigned long irqs)
 {
index 0116527dc1f1f2110cdf2af2a37552e5eb2c50f9..9ce38e92150a3759fb96704c6f8657d3d3ee702c 100644 (file)
@@ -4068,8 +4068,7 @@ static struct param_table {
        { "no_unexpected_interrupts", 0, &print_unex, 0, 0 },
        { "L40SX", 0, &print_unex, 0, 0 } };
 
-#define FLOPPY_SETUP
-void __init floppy_setup(char *str)
+static int __init floppy_setup(char *str)
 {
        int i;
        int param;
@@ -4091,7 +4090,7 @@ void __init floppy_setup(char *str)
                                        DPRINT("%s=%d\n", str, param);
                                        *config_params[i].var = param;
                                }
-                               return;
+                               return 1;
                        }
                }
        }
@@ -4105,6 +4104,7 @@ void __init floppy_setup(char *str)
        } else
                DPRINT("botched floppy option\n");
        DPRINT("Read linux/drivers/block/README.fd\n");
+       return 1;
 }
 
 static int have_no_fdc= -EIO;
@@ -4463,6 +4463,9 @@ MODULE_SUPPORTED_DEVICE("fd");
 #endif
 
 #else
+
+__setup ("floppy=", floppy_setup);
+
 /* eject the boot floppy (if we need the drive for a different root floppy) */
 /* This should only be called at boot time when we're sure that there's no
  * resource contention. */
index e3bbf306edc05817b9b025868cd02cc3c621557b..e9eb6da3aa4d07b0e4794d0bea95dfe24c9e08db 100644 (file)
@@ -380,7 +380,7 @@ register_busmouse(struct busmouse *ops)
        if (busmouse_data[msedev])
                return -EBUSY;
 
-       mse = kmalloc(GFP_KERNEL, sizeof(*mse));
+       mse = kmalloc(sizeof(*mse), GFP_KERNEL);
        if (!mse)
                return -ENOMEM;
 
@@ -465,6 +465,7 @@ bus_mouse_init(void))
        return 0;
 }
 
+EXPORT_SYMBOL(busmouse_add_movementbuttons);
 EXPORT_SYMBOL(busmouse_add_movement);
 EXPORT_SYMBOL(busmouse_add_buttons);
 EXPORT_SYMBOL(register_busmouse);
index ea9d7438f3b7b2989346bc377410561285137f68..a4b966aac5b41c61709a08d9706df02e01d26b43 100644 (file)
@@ -240,32 +240,15 @@ int q40kbd_getkeycode(unsigned int scancode)
 
 
 
-int q40kbd_pretranslate(unsigned char scancode, char raw_mode)
-{
-       if (scancode == 0xff) {
-               /* in scancode mode 1, my ESC key generates 0xff */
-               /* the calculator keys on a FOCUS 9000 generate 0xff */
-#ifndef KBD_IS_FOCUS_9000
-#ifdef KBD_REPORT_ERR
-               if (!raw_mode)
-                 printk(KERN_DEBUG "Keyboard error\n");
-#endif
-#endif
-               prev_scancode = 0;
-               return 0;
-       }
 
-       if (scancode == 0xe0 || scancode == 0xe1) {
+int q40kbd_translate(unsigned char scancode, unsigned char *keycode,
+                   char raw_mode)
+{
+       if (scancode == 0xe0 || scancode == 0xe1) {
                prev_scancode = scancode;
                return 0;
        }
-       return 1;
-}
 
-int q40kbd_translate(unsigned char scancode, unsigned char *keycode,
-                   char raw_mode)
-{
-  /*printk("translate ...\n");*/
        if (prev_scancode) {
          /*
           * usually it will be 0xe0, but a Pause key generates
@@ -376,7 +359,7 @@ static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                if (qcode == 0xe0)
                  {
                    qprev=0xe0;
-                   handle_scancode(qprev);
+                   handle_scancode(qprev , 1);
                    goto exit;
                  }
                
@@ -394,7 +377,7 @@ static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                if (scancode==0xff)  /* SySrq */
                  scancode=SYSRQ_KEY;
 
-               handle_scancode(scancode | (keyup ? 0200 : 0));
+               handle_scancode(scancode, ! keyup );
                keyup=0;
                mark_bh(KEYBOARD_BH);
 
index 620a2aa6e3365b7f3ce3c627a7c3f6da9fba0977..1b7f07bc46f182a3fd58f024cd408bd19d018d3d 100644 (file)
@@ -47,7 +47,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/skbuff.h>
index 9b4c47d436716d07d7d9d1ecacaf1461848d8155..d5562fb3801e8a38b22b604d7d4043beecbbdc19 100644 (file)
@@ -34,7 +34,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/skbuff.h>
index ff7629cb0f71f9631c378d8f6cc7b13724f811b0..9af06268abff0ed69731b66340844a665be19387 100644 (file)
@@ -34,7 +34,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/skbuff.h>
index eb8c5714918ee08d650c55ef5394eac743a41237..73fd8d24728c05f650b6d523ed557f7322b26330 100644 (file)
@@ -38,7 +38,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/skbuff.h>
index 7ee924993b011b9b7e18b2c79f7ac7406e84b0a2..ec58f43c000890362809d86937adb470ed9b03f3 100644 (file)
@@ -31,7 +31,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/version.h>
 #include "isdn_divert.h"
index 7454aa0958be583234f589d455898d6e7c545db4..6650d47f4a12506560ea4f18ac3bbfbd8057133e 100644 (file)
@@ -29,7 +29,6 @@
 
 
 
-#include <linux/config.h>
 #define __NO_VERSION__
 #include <linux/module.h>
 #include <linux/version.h>
index 7a2b5cf08a8a0e965e58ab728f9ac24fbbe96554..336187837b559310e6cfd9770b79fdc2b8378578 100644 (file)
@@ -29,7 +29,6 @@
 
 
 
-#include <linux/config.h>
 #include <linux/ioctl.h>
 #include <linux/types.h>
 
index 88f408cd148f2e717ef83e6a51bde21f81333323..444732e7b6fa11a72c72fe3771bc709e77413be9 100644 (file)
@@ -186,6 +186,7 @@ typedef struct {
 #ifdef __KERNEL__
 
 /* Kernel includes */
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/tqueue.h>
index 412eb46ba9d12f2746ef2aad39498dbb7e0f1877..c10b014cdf2661dfc39d769fbc0fc9f5b798f70b 100644 (file)
@@ -70,6 +70,7 @@
  *
  */
 
+#include <linux/config.h>
 #define __NO_VERSION__
 #include "eicon.h"
 #include "eicon_idi.h"
index 9a1da1751303f97767e12d66517ec8292689c236..ca989cf9d83ec050d0ea91ce1ae6ab26fee04773 100644 (file)
@@ -54,6 +54,7 @@
 #ifndef IDI_H
 #define IDI_H
 
+#include <linux/config.h>
 
 #define ASSIGN  0x01
 #define REMOVE  0xff
index 79ce41eed87c5b5e7867421b32b8358bf5b62d4f..058afa229c0aa9c275ea31e06f08921a757de4a6 100644 (file)
@@ -36,6 +36,7 @@
  */
 
 
+#include <linux/config.h>
 #include "eicon.h"
 
 void
index 924d5620f686743b520a72997304a61838da0b26..ba2dd0f852c1cd2da3e55ea5e67511b56d0c30be 100644 (file)
@@ -50,6 +50,7 @@
  *
  */
 
+#include <linux/config.h>
 #include "eicon.h"
 #include "eicon_isa.h"
 
index a5611394c3aaf2be31313ebae5bb723f9f7d695d..6bb4c9a30904e53044e288798861e7aa89cf52ec 100644 (file)
@@ -64,6 +64,7 @@
  *
  */
 
+#include <linux/config.h>
 #include <linux/pci.h>
 
 #include "eicon.h"
index e97c8e9bf01e07aca1c17c7f744df25bf2dd47f5..adf6b73b20127753c6620ece6fefc221ebfcc210 100644 (file)
@@ -28,6 +28,7 @@
 
 #define __NO_VERSION__
 
+#include <linux/config.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
index 0e014ebc06e1f757bab17e5bb58fa80935216e7d..0defb74b59dd1b749321e496600611cfc1bac1e7 100644 (file)
@@ -27,6 +27,7 @@
  */
 #define __NO_VERSION__
 
+#include <linux/config.h>
 #include "hisax.h"
 #include "isac.h"
 #include "ipac.h"
index 6284a4cf38caf9d3e4b3575c47d1d7338f1694c0..6caf0341fe717174b8d5f70dbe17b877e23f89a9 100644 (file)
  *
  */
 
+#include <linux/config.h>
 #define __NO_VERSION__
 #include "hisax.h"
 #include "../avmb1/capicmd.h"  /* this should be moved in a common place */
index a1016fd4b40f5e228c17bc871dccea6c399d2a0a..e4b35e50290098e98a01132d150c070225861e75 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/config.h>
 #include <linux/serial.h>
 #include <linux/serial_reg.h>
 
index ea27f28b230ff62d1c0a920ada589d1a4cb520dd..199bf2b609c89ec89a4d9fc90fa68688422d086d 100644 (file)
@@ -23,6 +23,7 @@
  * Initial revision
  *
  */
+#include <linux/config.h>
 #define __NO_VERSION__
 #include "hisax.h"
 #include "isac.h"
index 2d972f3fe6259084ab7fc04947619f747d2ec80a..837c957bed8024bf0c1b6685aaa20ec74f5a1954 100644 (file)
@@ -67,6 +67,7 @@
  *
  */
 
+#include <linux/config.h>
 #define __NO_VERSION__
 #include "hisax.h"
 #include "hfc_pci.h"
index 68813448084a12ec74c71cc571cb979a07029b8c..9ed3106727cb7b961014a6455f577bb1e6688e12 100644 (file)
 const char *l1_revision = "$Revision: 2.34 $";
 
 #define __NO_VERSION__
-#include <linux/config.h>
 #include "hisax.h"
 #include "isdnl1.h"
 
index a5d251b713820637bc0b719a9febd0424bb7c17b..a81bf07605e2d799668c426d220d4d14cb9c7683 100644 (file)
@@ -17,7 +17,6 @@
  */
 
 #define __NO_VERSION__
-#include <linux/config.h>
 #include "hisax.h"
 #include "isac.h"
 #include "isar.h"
index 92012c8e5c7b44ce1c4cb03a85b21416f6671b49..e5cc0ea30be552fed8e594948a1899410b0797f4 100644 (file)
@@ -64,7 +64,6 @@
 #include <linux/malloc.h>
 #include <linux/tty.h>
 #include <linux/errno.h>
-#include <linux/sched.h>       /* to get the struct task_struct */
 #include <linux/string.h>      /* used in new tty drivers */
 #include <linux/signal.h>      /* used in new tty drivers */
 
index 4fe9568ca9e207c1e3092c25b6037b03e5c070c1..62e723eafbed13927aa01ce374dc10606a05112b 100644 (file)
@@ -86,6 +86,7 @@
  *
  */
 
+#include <linux/config.h>
 
 #define DLE 0x10
 #define ETX 0x03
index fc17b5b830ac5ea70428ed4f899a224c2dda13b1..cc7c14fc6a6d4642531060d7e1fc5be91a1ef6bd 100644 (file)
@@ -33,7 +33,6 @@
 #undef ISDN_TTY_FAX_CMD_DEBUG
 
 #define __NO_VERSION__
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/isdn.h>
 #include "isdn_common.h"
index 348b2e790452d1895fa527d6b0c627ce90e364ff..6699709e40ffe4c5fec0b13c353f6debc689c875 100644 (file)
@@ -499,7 +499,7 @@ static int lance_open (struct device *dev)
        last_dev = dev;
 
        /* Install the Interrupt handler */
-       if (request_irq(IRQ_AMIGA_PORTS, lance_interrupt, 0,
+       if (request_irq(IRQ_AMIGA_PORTS, lance_interrupt, SA_SHIRQ,
                        "a2065 Ethernet", dev))
                return -EAGAIN;
 
index 28ac93605072804bbf08b9dde0e51e2e254493ff..fd8f1e577d3d2801bd9264701c80c1dcd9533439 100644 (file)
@@ -294,7 +294,8 @@ static int __init apne_probe1(struct device *dev, int ioaddr)
     dev->base_addr = ioaddr;
 
     /* Install the Interrupt handler */
-    if (request_irq(IRQ_AMIGA_PORTS, apne_interrupt, 0, "apne Ethernet", dev))
+    if (request_irq(IRQ_AMIGA_PORTS, apne_interrupt, SA_SHIRQ,
+                   "apne Ethernet", dev))
         return -EAGAIN;
 
 
index e08455cf83f12201e46428ee1dcff9f5cc19508d..7b396c6933c6bffd44dfa8f707ba58073bc57901 100644 (file)
@@ -293,7 +293,7 @@ static int ariadne_open(struct device *dev)
     dev->interrupt = 0;
     dev->start = 1;
 
-    if (request_irq(IRQ_AMIGA_PORTS, ariadne_interrupt, 0,
+    if (request_irq(IRQ_AMIGA_PORTS, ariadne_interrupt, SA_SHIRQ,
                     "Ariadne Ethernet", dev))
        return(-EAGAIN);
 
index 83ed4359b8667a6f6c03bd4d80f447db8ebd05ac..9dcffecc0516dac2a7399bd36599b28c382ce30a 100644 (file)
@@ -180,8 +180,8 @@ static int __init ariadne2_init(struct device *dev, unsigned int key,
     dev->irq = IRQ_AMIGA_PORTS;
 
     /* Install the Interrupt handler */
-    if (request_irq(IRQ_AMIGA_PORTS, ei_interrupt, 0, "AriadNE2 Ethernet",
-                   dev))
+    if (request_irq(IRQ_AMIGA_PORTS, ei_interrupt, SA_SHIRQ,
+                   "AriadNE2 Ethernet", dev))
        return -EAGAIN;
 
     /* Allocate dev->priv and fill in 8390 specific dev fields. */
index 5ced788bbacbd3a4ddbfa4c5d0b031b1c0e8cc71..79649cfbc533e84df8c3776dcdff65d06a1b1ee6 100644 (file)
@@ -282,7 +282,8 @@ static int hydra_open(struct device *dev)
        dev->interrupt = 0;
        dev->start = 1;
     
-       if(request_irq(IRQ_AMIGA_PORTS, hydra_interrupt, 0, "Hydra Ethernet", dev))
+       if(request_irq(IRQ_AMIGA_PORTS, hydra_interrupt, SA_SHIRQ,
+                      "Hydra Ethernet", dev))
                return(-EAGAIN);
 
        MOD_INC_USE_COUNT;
index 351585bc8d08f852ae4592ef74e273212146951c..1a0da9bca44fe210668af81534f964cf80b384c7 100644 (file)
@@ -346,7 +346,7 @@ __initfunc(int parport_mfc3_init(void))
 
                                        if (p->irq != PARPORT_IRQ_NONE)
                                                if (use_cnt++ == 0)
-                                                       if (request_irq(IRQ_AMIGA_PORTS, mfc3_interrupt, 0, p->name, &pp_mfc3_ops))
+                                                       if (request_irq(IRQ_AMIGA_PORTS, mfc3_interrupt, SA_SHIRQ, p->name, &pp_mfc3_ops))
                                                                use_cnt--;
 
                                        if (parport_probe_hook)
index 0aa5aa426b34186bd7d9192a96ea414e415c0bef..a350c45266f042c5c22fe0f641d5c0666fb63338 100644 (file)
@@ -1,3 +1,11 @@
 #
 # Plug and Play configuration
 #
+mainmenu_option next_comment
+comment 'Plug and Play configuration'
+
+tristate 'Plug and Play support' CONFIG_PNP
+
+dep_tristate 'ISA Plug and Play support' CONFIG_ISAPNP $CONFIG_PNP
+
+endmenu
index a801f19925c441ceb7eef34ba67e0680de11dd29..f12b5686d1d53c8524044c53f69e2fc8f2c372a5 100644 (file)
@@ -18,4 +18,12 @@ LX_OBJS  :=
 MI_OBJS  :=
 MIX_OBJS :=
 
+ifeq ($(CONFIG_ISAPNP),y)
+  LX_OBJS += isapnp.o
+else
+  ifeq ($(CONFIG_ISAPNP),m)
+    MX_OBJS += isapnp.o
+  endif
+endif
+
 include $(TOPDIR)/Rules.make
diff --git a/drivers/pnp/isapnp.c b/drivers/pnp/isapnp.c
new file mode 100644 (file)
index 0000000..c8b5cef
--- /dev/null
@@ -0,0 +1,2159 @@
+/*
+ *  ISA Plug & Play support
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *
+ *
+ *   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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/proc_fs.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/irq.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/isapnp.h>
+
+#ifdef CONFIG_PROC_FS
+#include "isapnp_proc.c"
+#endif
+
+#if 0
+#define ISAPNP_REGION_OK
+#endif
+#if 0
+#define ISAPNP_DEBUG
+#endif
+
+struct resource *pidxr_res = NULL;
+struct resource *pnpwrp_res = NULL;
+struct resource *isapnp_rdp_res = NULL;
+
+int isapnp_disable = 0;                        /* Disable ISA PnP */
+int isapnp_rdp = 0;                    /* Read Data Port */
+int isapnp_reset = 0;                  /* reset all PnP cards (deactivate) */
+int isapnp_skip_pci_scan = 0;          /* skip PCI resource scanning */
+int isapnp_verbose = 1;                        /* verbose mode */
+int isapnp_reserve_irq[16] = { [0 ... 15] = -1 };      /* reserve (don't use) some IRQ */
+int isapnp_reserve_dma[8] = { [0 ... 7] = -1 };                /* reserve (don't use) some DMA */
+int isapnp_reserve_io[16] = { [0 ... 15] = -1 };       /* reserve (don't use) some I/O region */
+int isapnp_reserve_mem[16] = { [0 ... 15] = -1 };      /* reserve (don't use) some memory region */
+
+MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_DESCRIPTION("Generic ISA Plug & Play support");
+MODULE_PARM(isapnp_disable, "i");
+MODULE_PARM_DESC(isapnp_disable, "ISA Plug & Play disable");
+MODULE_PARM(isapnp_rdp, "i");
+MODULE_PARM_DESC(isapnp_rdp, "ISA Plug & Play read data port");
+MODULE_PARM(isapnp_reset, "i");
+MODULE_PARM_DESC(isapnp_reset, "ISA Plug & Play reset all cards");
+MODULE_PARM(isapnp_skip_pci_scan, "i");
+MODULE_PARM_DESC(isapnp_skip_pci_scan, "ISA Plug & Play skip PCI resource scanning");
+MODULE_PARM(isapnp_verbose, "i");
+MODULE_PARM_DESC(isapnp_verbose, "ISA Plug & Play verbose mode");
+MODULE_PARM(isapnp_reserve_irq, "1-16i");
+MODULE_PARM_DESC(isapnp_reserve_irq, "ISA Plug & Play - reserve IRQ line(s)");
+MODULE_PARM(isapnp_reserve_dma, "1-8i");
+MODULE_PARM_DESC(isapnp_reserve_dma, "ISA Plug & Play - reserve DMA channel(s)");
+MODULE_PARM(isapnp_reserve_io, "1-16i");
+MODULE_PARM_DESC(isapnp_reserve_io, "ISA Plug & Play - reserve I/O region(s) - port,size");
+MODULE_PARM(isapnp_reserve_mem, "1-16i");
+MODULE_PARM_DESC(isapnp_reserve_mem, "ISA Plug & Play - reserve memory region(s) - address,size");
+
+#define _PIDXR         0x279
+#define _PNPWRP                0xa79
+
+/* short tags */
+#define _STAG_PNPVERNO         0x01
+#define _STAG_LOGDEVID         0x02
+#define _STAG_COMPATDEVID      0x03
+#define _STAG_IRQ              0x04
+#define _STAG_DMA              0x05
+#define _STAG_STARTDEP         0x06
+#define _STAG_ENDDEP           0x07
+#define _STAG_IOPORT           0x08
+#define _STAG_FIXEDIO          0x09
+#define _STAG_VENDOR           0x0e
+#define _STAG_END              0x0f
+/* long tags */
+#define _LTAG_MEMRANGE         0x81
+#define _LTAG_ANSISTR          0x82
+#define _LTAG_UNICODESTR       0x83
+#define _LTAG_VENDOR           0x84
+#define _LTAG_MEM32RANGE       0x85
+#define _LTAG_FIXEDMEM32RANGE  0x86
+
+struct pci_bus *isapnp_cards = NULL;   /* ISA PnP cards */
+struct pci_dev *isapnp_devices = NULL; /* ISA PnP devices */
+static struct pci_dev *isapnp_last_device = NULL;
+static unsigned char isapnp_checksum_value;
+static DECLARE_MUTEX(isapnp_cfg_mutex);
+static int isapnp_detected = 0;
+
+/* some prototypes */
+
+static int isapnp_config_prepare(struct pci_dev *dev);
+static int isapnp_config_activate(struct pci_dev *dev);
+static int isapnp_config_deactivate(struct pci_dev *dev);
+
+static int isapnp_debug = 0;
+
+static inline void write_data(unsigned char x)
+{
+// if (isapnp_debug) printk("<D:%02x>",x);
+       outb(x, _PNPWRP);
+}
+
+static inline void write_address(unsigned char x)
+{
+// if (isapnp_debug) printk("<A:%02x>",x);
+       outb(x, _PIDXR);
+       udelay(10);
+}
+
+static inline unsigned char read_data(void)
+{
+       unsigned char val = inb(isapnp_rdp);
+// if (isapnp_debug) printk("<R:%02x>",val);
+       return val;
+}
+
+unsigned char isapnp_read_byte(unsigned char idx)
+{
+       write_address(idx);
+       return read_data();
+}
+
+unsigned short isapnp_read_word(unsigned char idx)
+{
+       unsigned short val;
+
+       val = isapnp_read_byte(idx);
+       val = (val << 8) + isapnp_read_byte(idx+1);
+       return val;
+}
+
+unsigned int isapnp_read_dword(unsigned char idx)
+{
+       unsigned int val;
+
+       val = isapnp_read_byte(idx);
+       val = (val << 8) + isapnp_read_byte(idx+1);
+       val = (val << 8) + isapnp_read_byte(idx+2);
+       val = (val << 8) + isapnp_read_byte(idx+3);
+       return val;
+}
+
+void isapnp_write_byte(unsigned char idx, unsigned char val)
+{
+       write_address(idx);
+       write_data(val);
+}
+
+void isapnp_write_word(unsigned char idx, unsigned short val)
+{
+       isapnp_write_byte(idx, val >> 8);
+       isapnp_write_byte(idx+1, val);
+}
+
+void isapnp_write_dword(unsigned char idx, unsigned int val)
+{
+       isapnp_write_byte(idx, val >> 24);
+       isapnp_write_byte(idx+1, val >> 16);
+       isapnp_write_byte(idx+2, val >> 8);
+       isapnp_write_byte(idx+3, val);
+}
+
+static void *isapnp_alloc(long size)
+{
+       void *result;
+
+       result = kmalloc(size, GFP_KERNEL);
+       if (!result)
+               return NULL;
+       memset(result, 0, size);
+       return result;
+}
+
+static void isapnp_key(void)
+{
+       unsigned char code = 0x6a, msb;
+       int i;
+
+       mdelay(1);
+       write_address(0x00);
+       write_address(0x00);
+
+       write_address(code);
+
+       for (i = 1; i < 32; i++) {
+               msb = ((code & 0x01) ^ ((code & 0x02) >> 1)) << 7;
+               code = (code >> 1) | msb;
+               write_address(code);
+       }
+}
+
+/* place all pnp cards in wait-for-key state */
+static void isapnp_wait(void)
+{
+       isapnp_write_byte(0x02, 0x02);
+}
+
+void isapnp_wake(unsigned char csn)
+{
+       isapnp_write_byte(0x03, csn);
+}
+
+void isapnp_device(unsigned char logdev)
+{
+       isapnp_write_byte(0x07, logdev);
+}
+
+void isapnp_activate(unsigned char logdev)
+{
+       isapnp_device(logdev);
+       isapnp_write_byte(ISAPNP_CFG_ACTIVATE, 1);
+       udelay(250);
+}
+
+void isapnp_deactivate(unsigned char logdev)
+{
+       isapnp_device(logdev);
+       isapnp_write_byte(ISAPNP_CFG_ACTIVATE, 0);
+}
+
+static void __init isapnp_peek(unsigned char *data, int bytes)
+{
+       int i, j;
+       unsigned char d;
+
+       for (i = 1; i <= bytes; i++) {
+               for (j = 0; j < 10; j++) {
+                       d = isapnp_read_byte(0x05);
+                       if (d & 1)
+                               break;
+                       udelay(10);
+               }
+               if (!(d & 1)) {
+                       *data++ = 0xff;
+                       continue;
+               }
+               d = isapnp_read_byte(0x04);     /* PRESDI */
+               isapnp_checksum_value += d;
+               if (data != NULL)
+                       *data++ = d;
+       }
+}
+
+#define RDP_STEP       32      /* minimum is 4 */
+
+static int isapnp_next_rdp(void)
+{
+       int rdp = isapnp_rdp;
+       while (rdp <= 0x3ff) {
+               if (!check_region(rdp, 1)) {
+                       isapnp_rdp = rdp;
+                       return 0;
+               }
+               rdp += RDP_STEP;
+       }
+       return -1;
+}
+
+/* Set read port address */
+static inline void isapnp_set_rdp(void)
+{
+       isapnp_write_byte(0x00, isapnp_rdp >> 2);
+       udelay(100);
+}
+
+
+static int __init isapnp_isolate_rdp_select(void)
+{
+       isapnp_wait();
+       isapnp_key();
+
+       isapnp_write_byte(0x02, 0x04);  /* Control: reset CSN */
+       mdelay(2);
+
+       isapnp_wait();
+       isapnp_key();
+       isapnp_wake(0x00);
+
+       if (isapnp_next_rdp() < 0) {
+               isapnp_wait();
+               return -1;
+       }
+
+       isapnp_set_rdp();
+       udelay(1000);
+       write_address(0x01);
+       udelay(1000);
+       return 0;
+}
+
+/*
+ *  Isolate (assign uniqued CSN) to all ISA PnP devices.
+ */
+
+static int __init isapnp_isolate(void)
+{
+       unsigned char checksum = 0x6a;
+       unsigned char chksum = 0x00;
+       unsigned char bit = 0x00;
+       int data;
+       int csn = 0;
+       int i;
+       int iteration = 1;
+
+       isapnp_rdp = 0x213;
+       if (isapnp_isolate_rdp_select() < 0)
+               return -1;
+
+       while (1) {
+               for (i = 1; i <= 64; i++) {
+                       data = read_data() << 8;
+                       udelay(250);
+                       data = data | read_data();
+                       udelay(250);
+                       if (data == 0x55aa)
+                               bit = 0x01;
+                       checksum = ((((checksum ^ (checksum >> 1)) & 0x01) ^ bit) << 7) | (checksum >> 1);
+                       bit = 0x00;
+               }
+               for (i = 65; i <= 72; i++) {
+                       data = read_data() << 8;
+                       udelay(250);
+                       data = data | read_data();
+                       udelay(250);
+                       if (data == 0x55aa)
+                               chksum |= (1 << (i - 65));
+               }
+               if (checksum != 0x00 && checksum == chksum) {
+                       csn++;
+
+                       isapnp_write_byte(0x06, csn);
+                       udelay(250);
+                       iteration++;
+                       isapnp_wake(0x00);
+                       write_address(0x01);
+                       goto __next;
+               }
+               if (iteration == 1) {
+                       isapnp_rdp += RDP_STEP;
+isapnp_debug = 0;
+                       if (isapnp_isolate_rdp_select() < 0)
+                               return -1;
+               } else if (iteration > 1) {
+                       break;
+               }
+             __next:
+               checksum = 0x6a;
+               chksum = 0x00;
+               bit = 0x00;
+       }
+       isapnp_wait();
+       return csn;
+}
+
+/*
+ *  Read one tag from stream.
+ */
+
+static int __init isapnp_read_tag(unsigned char *type, unsigned short *size)
+{
+       unsigned char tag, tmp[2];
+
+       isapnp_peek(&tag, 1);
+       if (tag == 0)                           /* invalid tag */
+               return -1;
+       if (tag & 0x80) {       /* large item */
+               *type = tag;
+               isapnp_peek(tmp, 2);
+               *size = (tmp[1] << 8) | tmp[0];
+       } else {
+               *type = (tag >> 3) & 0x0f;
+               *size = tag & 0x07;
+       }
+#if 0
+       printk("tag = 0x%x, type = 0x%x, size = %i\n", tag, *type, *size);
+#endif
+       if (type == 0)                          /* wrong type */
+               return -1;
+       if (*type == 0xff && *size == 0xffff)   /* probably invalid data */
+               return -1;
+       return 0;
+}
+
+/*
+ *  Skip specified number of bytes from stream.
+ */
+static void __init isapnp_skip_bytes(int count)
+{
+       isapnp_peek(NULL, count);
+}
+
+/*
+ *  Parse logical device tag.
+ */
+
+static struct pci_dev * __init isapnp_parse_device(struct pci_bus *card, int size, int number)
+{
+       unsigned char tmp[6];
+       struct pci_dev *dev;
+
+       isapnp_peek(tmp, size);
+       dev = isapnp_alloc(sizeof(struct pci_dev));
+       if (!dev)
+               return NULL;
+       dev->devfn = number;
+       dev->vendor = (tmp[1] << 8) | tmp[0];
+       dev->device = (tmp[3] << 8) | tmp[2];
+       dev->regs = tmp[4];
+       dev->bus = card;
+       if (size > 5)
+               dev->regs |= tmp[5] << 8;
+       dev->prepare = isapnp_config_prepare;
+       dev->activate = isapnp_config_activate;
+       dev->deactivate = isapnp_config_deactivate;
+       return dev;
+}
+
+/*
+ *  Build new resources structure
+ */
+
+static struct isapnp_resources * __init isapnp_build_resources(struct pci_dev *dev, int dependent)
+{
+       struct isapnp_resources *res, *ptr, *ptra;
+       
+       res = isapnp_alloc(sizeof(struct isapnp_resources));
+       if (!res)
+               return NULL;
+       res->dev = dev;
+       ptr = (struct isapnp_resources *)dev->sysdata;
+       while (ptr && ptr->next)
+               ptr = ptr->next;
+       if (ptr && ptr->dependent && dependent) { /* add to another list */
+               ptra = ptr->alt;
+               while (ptra && ptra->alt)
+                       ptra = ptra->alt;
+               if (!ptra)
+                       ptr->alt = res;
+               else
+                       ptra->alt = res;
+       } else {
+               if (!ptr)
+                       dev->sysdata = res;
+               else
+                       ptr->next = res;
+       }
+       if (dependent) {
+               res->priority = dependent & 0xff;
+               if (res->priority > ISAPNP_RES_PRIORITY_FUNCTIONAL)
+                       res->priority = ISAPNP_RES_PRIORITY_INVALID;
+               res->dependent = 1;
+       } else {
+               res->priority = ISAPNP_RES_PRIORITY_PREFERRED;
+               res->dependent = 0;
+       }
+       return res;
+}
+
+/*
+ *  Add IRQ resource to resources list.
+ */
+
+static void __init isapnp_add_irq_resource(struct pci_dev *dev,
+                                              struct isapnp_resources **res,
+                                               int dependent, int size)
+{
+       unsigned char tmp[3];
+       struct isapnp_irq *irq, *ptr;
+
+       isapnp_peek(tmp, size);
+       irq = isapnp_alloc(sizeof(struct isapnp_irq));
+       if (!irq)
+               return;
+       if (*res == NULL) {
+               *res = isapnp_build_resources(dev, dependent);
+               if (*res == NULL) {
+                       kfree(irq);
+                       return;
+               }
+       }
+       irq->map = (tmp[1] << 8) | tmp[0];
+       if (size > 2)
+               irq->flags = tmp[2];
+       else
+               irq->flags = DEVICE_IRQ_FLAG_HIGHEDGE;
+       irq->res = *res;
+       ptr = (*res)->irq;
+       while (ptr && ptr->next)
+               ptr = ptr->next;
+       if (ptr)
+               ptr->next = irq;
+       else
+               (*res)->irq = irq;
+}
+
+/*
+ *  Add DMA resource to resources list.
+ */
+
+static void __init isapnp_add_dma_resource(struct pci_dev *dev,
+                                              struct isapnp_resources **res,
+                                              int dependent, int size)
+{
+       unsigned char tmp[2];
+       struct isapnp_dma *dma, *ptr;
+
+       isapnp_peek(tmp, size);
+       dma = isapnp_alloc(sizeof(struct isapnp_dma));
+       if (!dma)
+               return;
+       if (*res == NULL) {
+               *res = isapnp_build_resources(dev, dependent);
+               if (*res == NULL) {
+                       kfree(dma);
+                       return;
+               }
+       }
+       dma->map = tmp[0];
+       dma->type = tmp[1] & 3;
+       dma->flags = (tmp[1] >> 2) & 7;
+       dma->speed = (tmp[1] >> 6) & 3;
+       dma->res = *res;
+       ptr = (*res)->dma;
+       while (ptr && ptr->next)
+               ptr = ptr->next;
+       if (ptr)
+               ptr->next = dma;
+       else
+               (*res)->dma = dma;
+}
+
+/*
+ *  Add port resource to resources list.
+ */
+
+static void __init isapnp_add_port_resource(struct pci_dev *dev,
+                                               struct isapnp_resources **res,
+                                               int dependent, int size)
+{
+       unsigned char tmp[7];
+       struct isapnp_port *port, *ptr;
+
+       isapnp_peek(tmp, size);
+       port = isapnp_alloc(sizeof(struct isapnp_port));
+       if (!port)
+               return;
+       if (*res == NULL) {
+               *res = isapnp_build_resources(dev, dependent);
+               if (*res == NULL) {
+                       kfree(port);
+                       return;
+               }
+       }
+       port->min = (tmp[2] << 8) | tmp[1];
+       port->max = (tmp[4] << 8) | tmp[3];
+       port->align = tmp[5];
+       port->size = tmp[6];
+       port->flags = tmp[0] ? ISAPNP_PORT_FLAG_16BITADDR : 0;
+       port->res = *res;
+       ptr = (*res)->port;
+       while (ptr && ptr->next)
+               ptr = ptr->next;
+       if (ptr)
+               ptr->next = port;
+       else
+               (*res)->port = port;
+}
+
+/*
+ *  Add fixed port resource to resources list.
+ */
+
+static void __init isapnp_add_fixed_port_resource(struct pci_dev *dev,
+                                                     struct isapnp_resources **res,
+                                                     int dependent, int size)
+{
+       unsigned char tmp[3];
+       struct isapnp_port *port, *ptr;
+
+       isapnp_peek(tmp, size);
+       port = isapnp_alloc(sizeof(struct isapnp_port));
+       if (!port)
+               return;
+       if (*res == NULL) {
+               *res = isapnp_build_resources(dev, dependent);
+               if (*res == NULL) {
+                       kfree(port);
+                       return;
+               }
+       }
+       port->min = port->max = (tmp[1] << 8) | tmp[0];
+       port->size = tmp[2];
+       port->align = 0;
+       port->flags = ISAPNP_PORT_FLAG_FIXED;
+       port->res = *res;
+       ptr = (*res)->port;
+       while (ptr && ptr->next)
+               ptr = ptr->next;
+       if (ptr)
+               ptr->next = port;
+       else
+               (*res)->port = port;
+}
+
+/*
+ *  Add memory resource to resources list.
+ */
+
+static void __init isapnp_add_mem_resource(struct pci_dev *dev,
+                                              struct isapnp_resources **res,
+                                              int dependent, int size)
+{
+       unsigned char tmp[9];
+       struct isapnp_mem *mem, *ptr;
+
+       isapnp_peek(tmp, size);
+       mem = isapnp_alloc(sizeof(struct isapnp_mem));
+       if (!mem)
+               return;
+       if (*res == NULL) {
+               *res = isapnp_build_resources(dev, dependent);
+               if (*res == NULL) {
+                       kfree(mem);
+                       return;
+               }
+       }
+       mem->min = ((tmp[2] << 8) | tmp[1]) << 8;
+       mem->max = ((tmp[4] << 8) | tmp[3]) << 8;
+       mem->align = (tmp[6] << 8) | tmp[5];
+       mem->size = ((tmp[8] << 8) | tmp[7]) << 8;
+       mem->flags = tmp[0] & 7;
+       mem->flags |= (tmp[0] >> 2) & 0x18;
+       mem->type = (tmp[0] >> 3) & 3;
+       mem->res = *res;
+       ptr = (*res)->mem;
+       while (ptr && ptr->next)
+               ptr = ptr->next;
+       if (ptr)
+               ptr->next = mem;
+       else
+               (*res)->mem = mem;
+}
+
+/*
+ *  Add 32-bit memory resource to resources list.
+ */
+
+static void __init isapnp_add_mem32_resource(struct pci_dev *dev,
+                                                struct isapnp_resources **res,
+                                                int dependent, int size)
+{
+       unsigned char tmp[17];
+       struct isapnp_mem32 *mem32, *ptr;
+
+       isapnp_peek(tmp, size);
+       mem32 = isapnp_alloc(sizeof(struct isapnp_mem32));
+       if (!mem32)
+               return;
+       if (*res == NULL) {
+               *res = isapnp_build_resources(dev, dependent);
+               if (*res == NULL) {
+                       kfree(mem32);
+                       return;
+               }
+       }
+       memcpy(mem32->data, tmp, 17);
+       mem32->res = *res;
+       ptr = (*res)->mem32;
+       while (ptr && ptr->next)
+               ptr = ptr->next;
+       if (ptr)
+               ptr->next = mem32;
+       else
+               (*res)->mem32 = mem32;
+}
+
+/*
+ *  Add 32-bit fixed memory resource to resources list.
+ */
+
+static void __init isapnp_add_fixed_mem32_resource(struct pci_dev *dev,
+                                                      struct isapnp_resources **res,
+                                                      int dependent, int size)
+{
+       unsigned char tmp[17];
+       struct isapnp_mem32 *mem32, *ptr;
+
+       isapnp_peek(tmp, size);
+       mem32 = isapnp_alloc(sizeof(struct isapnp_mem32));
+       if (!mem32)
+               return;
+       if (*res == NULL) {
+               *res = isapnp_build_resources(dev, dependent);
+               if (*res == NULL) {
+                       kfree(mem32);
+                       return;
+               }
+       }
+       memcpy(mem32->data, tmp, 17);
+       mem32->res = *res;
+       ptr = (*res)->mem32;
+       while (ptr && ptr->next)
+               ptr = ptr->next;
+       if (ptr)
+               ptr->next = mem32;
+       else
+               (*res)->mem32 = mem32;
+}
+
+/*
+ *  Parse resource map for logical device.
+ */
+
+static int __init isapnp_create_device(struct pci_bus *card,
+                                          unsigned short size)
+{
+       int number = 0, skip = 0, dependent = 0, compat = 0;
+       unsigned char type, tmp[17];
+       struct pci_dev *dev, *prev_dev;
+       struct isapnp_resources *res = NULL;
+       
+       if ((dev = isapnp_parse_device(card, size, number++)) == NULL)
+               return 1;
+       card->devices = dev;
+       if (isapnp_last_device) {
+               isapnp_last_device->next = dev;
+               isapnp_last_device = dev;
+       } else {
+               isapnp_devices = isapnp_last_device = dev;
+       }
+       while (1) {
+               if (isapnp_read_tag(&type, &size)<0)
+                       return 1;
+               if (skip && type != _STAG_LOGDEVID && type != _STAG_END)
+                       goto __skip;
+               switch (type) {
+               case _STAG_LOGDEVID:
+                       if (size >= 5 && size <= 6) {
+                               prev_dev = dev;
+                               isapnp_config_prepare(dev);
+                               if ((dev = isapnp_parse_device(card, size, number++)) == NULL)
+                                       return 1;
+                               prev_dev->sibling = dev;
+                               isapnp_last_device->next = dev;
+                               isapnp_last_device = dev;
+                               size = 0;
+                               skip = 0;
+                       } else {
+                               skip = 1;
+                       }
+                       res = NULL;
+                       dependent = 0;
+                       compat = 0;
+                       break;
+               case _STAG_COMPATDEVID:
+                       if (size == 4 && compat < DEVICE_COUNT_COMPATIBLE) {
+                               isapnp_peek(tmp, 4);
+                               dev->vendor_compatible[compat] = (tmp[1] << 8) | tmp[0];
+                               dev->device_compatible[compat] = (tmp[3] << 8) | tmp[2];
+                               compat++;
+                               size = 0;
+                       }
+                       break;
+               case _STAG_IRQ:
+                       if (size < 2 || size > 3)
+                               goto __skip;
+                       isapnp_add_irq_resource(dev, &res, dependent, size);
+                       size = 0;
+                       break;
+               case _STAG_DMA:
+                       if (size != 2)
+                               goto __skip;
+                       isapnp_add_dma_resource(dev, &res, dependent, size);
+                       size = 0;
+                       break;
+               case _STAG_STARTDEP:
+                       if (size > 1)
+                               goto __skip;
+                       res = NULL;
+                       dependent = 0x100 | ISAPNP_RES_PRIORITY_ACCEPTABLE;
+                       if (size > 0) {
+                               isapnp_peek(tmp, size);
+                               dependent = 0x100 | tmp[0];
+                               size = 0;
+                       }
+                       break;
+               case _STAG_ENDDEP:
+                       if (size != 0)
+                               goto __skip;
+                       res = NULL;
+                       dependent = 0;
+                       break;
+               case _STAG_IOPORT:
+                       if (size != 7)
+                               goto __skip;
+                       isapnp_add_port_resource(dev, &res, dependent, size);
+                       size = 0;
+                       break;
+               case _STAG_FIXEDIO:
+                       if (size != 3)
+                               goto __skip;
+                       isapnp_add_fixed_port_resource(dev, &res, dependent, size);
+                       size = 0;
+                       break;
+               case _STAG_VENDOR:
+                       break;
+               case _LTAG_MEMRANGE:
+                       if (size != 9)
+                               goto __skip;
+                       isapnp_add_mem_resource(dev, &res, dependent, size);
+                       size = 0;
+                       break;
+               case _LTAG_ANSISTR:
+                       if (dev->name[0] == '\0') {
+                               unsigned short size1 = size > 47 ? 47 : size;
+                               isapnp_peek(dev->name, size1);
+                               dev->name[size1] = '\0';
+                               size -= size1;
+                       }
+                       break;
+               case _LTAG_UNICODESTR:
+                       /* silently ignore */
+                       /* who use unicode for hardware identification? */
+                       break;
+               case _LTAG_VENDOR:
+                       break;
+               case _LTAG_MEM32RANGE:
+                       if (size != 17)
+                               goto __skip;
+                       isapnp_add_mem32_resource(dev, &res, dependent, size);
+                       size = 0;
+                       break;
+               case _LTAG_FIXEDMEM32RANGE:
+                       if (size != 17)
+                               goto __skip;
+                       isapnp_add_fixed_mem32_resource(dev, &res, dependent, size);
+                       size = 0;
+                       break;
+               case _STAG_END:
+                       if (size > 0)
+                               isapnp_skip_bytes(size);
+                       return 1;
+               default:
+                       printk("isapnp: unexpected or unknown tag type 0x%x for logical device %i (device %i), ignored\n", type, dev->devfn, card->number);
+               }
+             __skip:
+               if (size > 0)
+                       isapnp_skip_bytes(size);
+       }
+       isapnp_config_prepare(dev);
+       return 0;
+}
+
+/*
+ *  Parse resource map for ISA PnP card.
+ */
+static void __init isapnp_parse_resource_map(struct pci_bus *card)
+{
+       unsigned char type, tmp[17];
+       unsigned short size;
+       
+       while (1) {
+               if (isapnp_read_tag(&type, &size)<0)
+                       return;
+               switch (type) {
+               case _STAG_PNPVERNO:
+                       if (size != 2)
+                               goto __skip;
+                       isapnp_peek(tmp, 2);
+                       card->pnpver = tmp[0];
+                       card->productver = tmp[1];
+                       size = 0;
+                       break;
+               case _STAG_LOGDEVID:
+                       if (size >= 5 && size <= 6) {
+                               if (isapnp_create_device(card, size)==1)
+                                       return;
+                               size = 0;
+                       }
+                       break;
+               case _STAG_VENDOR:
+                       break;
+               case _LTAG_ANSISTR:
+                       if (card->name[0] == '\0') {
+                               unsigned short size1 = size > 47 ? 47 : size;
+                               isapnp_peek(card->name, size1);
+                               card->name[size1] = '\0';
+                               size -= size1;
+                       }
+                       break;
+               case _LTAG_UNICODESTR:
+                       /* silently ignore */
+                       /* who use unicode for hardware identification? */
+                       break;
+               case _LTAG_VENDOR:
+                       break;
+               case _STAG_END:
+                       if (size > 0)
+                               isapnp_skip_bytes(size);
+                       return;
+               default:
+                       printk("isapnp: unexpected or unknown tag type 0x%x for device %i, ignored\n", type, card->number);
+               }
+             __skip:
+               if (size > 0)
+                       isapnp_skip_bytes(size);
+       }
+}
+
+/*
+ *  Compute ISA PnP checksum for first eight bytes.
+ */
+
+static unsigned char __init isapnp_checksum(unsigned char *data)
+{
+       int i, j;
+       unsigned char checksum = 0x6a, bit, b;
+       
+       for (i = 0; i < 8; i++) {
+               b = data[i];
+               for (j = 0; j < 8; j++) {
+                       bit = 0;
+                       if (b & (1 << j))
+                               bit = 1;
+                       checksum = ((((checksum ^ (checksum >> 1)) & 0x01) ^ bit) << 7) | (checksum >> 1);
+               }
+       }
+       return checksum;
+}
+
+/*
+ *  Build device list for all present ISA PnP devices.
+ */
+
+static int __init isapnp_build_device_list(void)
+{
+       int csn;
+       unsigned char header[9], checksum;
+       struct pci_bus *card, *prev = NULL;
+
+       isapnp_wait();
+       isapnp_key();
+       for (csn = 1; csn <= 10; csn++) {
+               isapnp_wake(csn);
+               isapnp_peek(header, 9);
+               checksum = isapnp_checksum(header);
+#if 0
+               printk("vendor: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+                       header[0], header[1], header[2], header[3],
+                       header[4], header[5], header[6], header[7], header[8]);
+               printk("checksum = 0x%x\n", checksum);
+#endif
+               if (checksum == 0x00 || checksum != header[8])  /* not valid CSN */
+                       continue;
+               if ((card = isapnp_alloc(sizeof(struct pci_bus))) == NULL)
+                       continue;
+               card->number = csn;
+               card->vendor = (header[1] << 8) | header[0];
+               card->device = (header[3] << 8) | header[2];
+               card->serial = (header[7] << 24) | (header[6] << 16) | (header[5] << 8) | header[4];
+               isapnp_checksum_value = 0x00;
+               isapnp_parse_resource_map(card);
+               if (isapnp_checksum_value != 0x00)
+                       printk("isapnp: checksum for device %i is not valid (0x%x)\n", csn, isapnp_checksum_value);
+               card->checksum = isapnp_checksum_value;
+               if (!isapnp_cards)
+                       isapnp_cards = card;
+               else
+                       prev->next = card;
+               prev = card;
+       }
+       return 0;
+}
+
+/*
+ *  Basic configuration routines.
+ */
+
+int isapnp_present(void)
+{
+       if (isapnp_devices)
+               return 1;
+       return 0;
+}
+
+int isapnp_cfg_begin(int csn, int logdev)
+{
+       if (csn < 1 || csn > 10 || logdev > 10)
+               return -EINVAL;
+       MOD_INC_USE_COUNT;
+       down(&isapnp_cfg_mutex);
+       isapnp_wait();
+       isapnp_key();
+       isapnp_wake(csn);
+#if 1  /* to avoid malfunction when isapnptools is used */
+       isapnp_set_rdp();
+       udelay(1000);   /* delay 1000us */
+       write_address(0x01);
+       udelay(1000);   /* delay 1000us */
+#endif
+       if (logdev >= 0)
+               isapnp_device(logdev);
+       return 0;
+}
+
+int isapnp_cfg_end(void)
+{
+       isapnp_wait();
+       up(&isapnp_cfg_mutex);
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+/*
+ *  Resource manager.
+ */
+
+static struct isapnp_port *isapnp_find_port(struct pci_dev *dev, int index)
+{
+       struct isapnp_resources *res;
+       struct isapnp_port *port;
+       
+       if (!dev || index < 0 || index > 7)
+               return NULL;
+       for (res = (struct isapnp_resources *)dev->sysdata; res; res = res->next) {
+               for (port = res->port; port; port = port->next) {
+                       if (!index)
+                               return port;
+                       index--;
+               }
+       }
+       return NULL;
+}
+
+struct isapnp_irq *isapnp_find_irq(struct pci_dev *dev, int index)
+{
+       struct isapnp_resources *res, *resa;
+       struct isapnp_irq *irq;
+       int index1, index2, index3;
+       
+       if (!dev || index < 0 || index > 7)
+               return NULL;
+       for (res = (struct isapnp_resources *)dev->sysdata; res; res = res->next) {
+               index3 = 0;
+               for (resa = res; resa; resa = resa->alt) {
+                       index1 = index;
+                       index2 = 0;
+                       for (irq = resa->irq; irq; irq = irq->next) {
+                               if (!index1)
+                                       return irq;
+                               index1--;
+                               index2++;
+                       }
+                       if (index3 < index2)
+                               index3 = index2;
+               }
+               index -= index3;
+       }
+       return NULL;
+}
+
+struct isapnp_dma *isapnp_find_dma(struct pci_dev *dev, int index)
+{
+       struct isapnp_resources *res;
+       struct isapnp_dma *dma;
+       
+       if (!dev || index < 0 || index > 7)
+               return NULL;
+       for (res = (struct isapnp_resources *)dev->sysdata; res; res = res->next) {
+               for (dma = res->dma; dma; dma = dma->next) {
+                       if (!index)
+                               return dma;
+                       index--;
+               }
+       }
+       return NULL;
+}
+
+struct isapnp_mem *isapnp_find_mem(struct pci_dev *dev, int index)
+{
+       struct isapnp_resources *res;
+       struct isapnp_mem *mem;
+       
+       if (!dev || index < 0 || index > 7)
+               return NULL;
+       for (res = (struct isapnp_resources *)dev->sysdata; res; res = res->next) {
+               for (mem = res->mem; mem; mem = mem->next) {
+                       if (!index)
+                               return mem;
+                       index--;
+               }
+       }
+       return NULL;
+}
+
+struct isapnp_mem32 *isapnp_find_mem32(struct pci_dev *dev, int index)
+{
+       struct isapnp_resources *res;
+       struct isapnp_mem32 *mem32;
+       
+       if (!dev || index < 0 || index > 7)
+               return NULL;
+       for (res = (struct isapnp_resources *)dev->sysdata; res; res = res->next) {
+               for (mem32 = res->mem32; mem32; mem32 = mem32->next) {
+                       if (!index)
+                               return mem32;
+                       index--;
+               }
+       }
+       return NULL;
+}
+
+/*
+ *  Device manager.
+ */
+
+struct pci_bus *isapnp_find_card(unsigned short vendor,
+                                unsigned short device,
+                                struct pci_bus *from)
+{
+       struct pci_bus *card;
+
+       if (from == NULL) {
+               from = isapnp_cards;
+       } else {
+               from = from->next;
+       }
+       for (card = from; card; card = card->next) {
+               if (card->vendor == vendor && card->device == device)
+                       return card;
+       }
+       return NULL;
+}
+
+struct pci_dev *isapnp_find_dev(struct pci_bus *card,
+                               unsigned short vendor,
+                               unsigned short function,
+                               struct pci_dev *from)
+{
+       struct pci_dev *dev;
+       int idx;
+       
+       if (card == NULL) {     /* look for a logical device from all cards */
+               if (from == NULL) {
+                       from = isapnp_devices;
+               } else {
+                       from = from->next;
+               }
+               for (dev = from; dev; dev = dev->next) {
+                       if (dev->vendor == vendor && dev->device == function)
+                               return dev;
+                       for (idx = 0; idx < DEVICE_COUNT_COMPATIBLE; idx++)
+                               if (dev->vendor_compatible[idx] == vendor &&
+                                   dev->device_compatible[idx] == function)
+                                       return dev;
+               }
+       } else {
+               if (from == NULL) {
+                       from = card->devices;
+               } else {
+                       from = from->next;
+               }
+               if (from->bus != card)  /* something is wrong */
+                       return NULL;
+               for (dev = from; dev; dev = dev->sibling) {
+                       if (dev->vendor == vendor && dev->device == function)
+                               return dev;
+                       for (idx = 0; idx < DEVICE_COUNT_COMPATIBLE; idx++)
+                               if (dev->vendor_compatible[idx] == vendor &&
+                                   dev->device_compatible[idx] == function)
+                                       return dev;
+               }               
+       }
+       return NULL;
+}
+
+static int isapnp_config_prepare(struct pci_dev *dev)
+{
+       struct isapnp_resources *res, *resa;
+       struct isapnp_port *port;
+       struct isapnp_irq *irq;
+       struct isapnp_dma *dma;
+       struct isapnp_mem *mem;
+       int port_count, port_count1;
+       int irq_count, irq_count1;
+       int dma_count, dma_count1;
+       int mem_count, mem_count1;
+       int idx;
+
+       if (dev == NULL)
+               return -EINVAL;
+       if (dev->active || dev->ro)
+               return -EBUSY;
+       dev->irq = dev->irq2 = DEVICE_IRQ_NOTSET;
+       dev->irq_flags = dev->irq2_flags = 0;
+       for (idx = 0; idx < DEVICE_COUNT_DMA; idx++) {
+               dev->dma[idx] = DEVICE_DMA_NOTSET;
+               dev->dma_type[idx] = DEVICE_DMA_TYPE_8AND16BIT;
+               dev->dma_flags[idx] = 0;
+               dev->dma_speed[idx] = DEVICE_DMA_SPEED_COMPATIBLE;
+       }
+       for (idx = 0; idx < DEVICE_COUNT_RESOURCE; idx++) {
+               dev->resource[idx].name = NULL;
+               dev->resource[idx].start = DEVICE_IO_NOTSET;
+               dev->resource[idx].end = 0;
+               dev->resource[idx].fixed = 0;
+               dev->resource[idx].bits = 12;
+               dev->resource[idx].hw_flags = 0;
+               dev->resource[idx].type = DEVICE_IO_TYPE_8AND16BIT;
+       }
+       port_count = irq_count = dma_count = mem_count = 0;
+       for (res = (struct isapnp_resources *)dev->sysdata; res; res = res->next) {
+               port_count1 = irq_count1 = dma_count1 = mem_count1 = 0;
+               for (resa = res; resa; resa = resa->alt) {
+                       for (port = resa->port, idx = 0; port; port = port->next, idx++) {
+                               if (dev->resource[port_count + idx].start == DEVICE_IO_NOTSET) {
+                                       dev->resource[port_count + idx].start = DEVICE_IO_AUTO;
+                                       dev->resource[port_count + idx].end = port->size;
+                                       dev->resource[port_count + idx].bits = port->flags & ISAPNP_PORT_FLAG_16BITADDR ? 16 : 12;
+                                       dev->resource[port_count + idx].fixed = port->flags & ISAPNP_PORT_FLAG_FIXED ? 1 : 0;
+                               }
+                       }
+                       if (port_count1 < idx)
+                               port_count1 = idx;
+                       for (irq = resa->irq, idx = 0; irq; irq = irq->next, idx++) {
+                               if (irq_count + idx == 0) {
+                                       if (dev->irq == DEVICE_IRQ_NOTSET) {
+                                               dev->irq = DEVICE_IRQ_AUTO;
+                                               dev->irq_flags = irq->flags;
+                                       }
+                               } else if (irq_count + idx == 1) {
+                                       if (dev->irq2 == DEVICE_IRQ_NOTSET) {
+                                               dev->irq2 = DEVICE_IRQ_AUTO;
+                                               dev->irq2_flags = irq->flags;
+                                       }
+                               }
+                               
+                       }
+                       if (irq_count1 < idx)
+                               irq_count1 = idx;
+                       for (dma = resa->dma, idx = 0; dma; dma = dma->next, idx++)
+                               if (dev->dma[idx] == DEVICE_DMA_NOTSET) {
+                                       dev->dma[idx] = DEVICE_DMA_AUTO;
+                                       dev->dma_type[idx] = dma->type;
+                                       dev->dma_flags[idx] = dma->flags;
+                                       dev->dma_speed[idx] = dma->speed;
+                               }
+                       if (dma_count1 < idx)
+                               dma_count1 = idx;
+                       for (mem = resa->mem, idx = 0; mem; mem = mem->next, idx++)
+                               if (dev->resource[mem_count + idx + 8].start == DEVICE_IO_AUTO) {
+                                       dev->resource[mem_count + idx].start = DEVICE_IO_AUTO;
+                                       dev->resource[mem_count + idx].end = mem->size;
+                                       dev->resource[mem_count + idx].bits = 24;
+                                       dev->resource[mem_count + idx].fixed = 0;
+                                       dev->resource[mem_count + idx].hw_flags = mem->flags;
+                                       dev->resource[mem_count + idx].type = mem->type;
+                               }
+                       if (mem_count1 < idx)
+                               mem_count1 = idx;
+               }
+               port_count += port_count1;
+               irq_count += irq_count1;
+               dma_count += dma_count1;
+               mem_count += mem_count1;
+       }
+       return 0;
+}
+
+struct isapnp_cfgtmp {
+       struct isapnp_port *port[8];
+       struct isapnp_irq *irq[2];
+       struct isapnp_dma *dma[2];
+       struct isapnp_mem *mem[4];
+       struct pci_dev *request;
+       struct pci_dev result;
+};
+
+static int isapnp_alternative_switch(struct isapnp_cfgtmp *cfg,
+                                    struct isapnp_resources *from,
+                                    struct isapnp_resources *to)
+{
+       int tmp, tmp1;
+       struct isapnp_port *port;
+       struct isapnp_irq *irq;
+       struct isapnp_dma *dma;
+       struct isapnp_mem *mem;
+
+       if (!cfg)
+               return -EINVAL;
+       /* process port settings */
+       for (tmp = 0; tmp < 8; tmp++) {
+               if (cfg->request->resource[tmp].start != DEVICE_IO_AUTO)
+                       continue;               /* don't touch */
+               port = cfg->port[tmp];
+               if (!port) {
+                       cfg->port[tmp] = port = isapnp_find_port(cfg->request, tmp);
+                       if (!port)
+                               return -EINVAL;
+               }
+               if (from && port->res == from) {
+                       while (port->res != to) {
+                               if (!port->res->alt)
+                                       return -EINVAL;
+                               port = port->res->alt->port;
+                               for (tmp1 = tmp; tmp1 > 0 && port; tmp1--)
+                                       port = port->next;
+                               cfg->port[tmp] = port;
+                               cfg->result.resource[tmp].start = DEVICE_IO_AUTO;
+                               if (!port)
+                                       return -ENOENT;
+                       }
+               }
+       }
+       /* process irq settings */
+       for (tmp = 0; tmp < 2; tmp++) {
+               if (tmp == 0) {
+                       if (cfg->request->irq != DEVICE_IRQ_AUTO)
+                               continue;               /* don't touch */
+               } else {
+                       if (cfg->request->irq2 != DEVICE_IRQ_AUTO)
+                               continue;               /* don't touch */
+               }
+               irq = cfg->irq[tmp];
+               if (!irq) {
+                       cfg->irq[tmp] = irq = isapnp_find_irq(cfg->request, tmp);
+                       if (!irq)
+                               return -EINVAL;
+               }
+               if (from && irq->res == from) {
+                       while (irq->res != to) {
+                               if (!irq->res->alt)
+                                       return -EINVAL;
+                               irq = irq->res->alt->irq;
+                               for (tmp1 = tmp; tmp1 > 0 && irq; tmp1--)
+                                       irq = irq->next;
+                               cfg->irq[tmp] = irq;
+                               if (tmp == 0) {
+                                       cfg->result.irq = DEVICE_IRQ_AUTO;
+                               } else {
+                                       cfg->result.irq2 = DEVICE_IRQ_AUTO;
+                               }
+                               if (!irq)
+                                       return -ENOENT;
+                       }
+               }
+       }
+       /* process dma settings */
+       for (tmp = 0; tmp < 2; tmp++) {
+               if (cfg->request->dma[tmp] != DEVICE_DMA_AUTO)
+                       continue;               /* don't touch */
+               dma = cfg->dma[tmp];
+               if (!dma) {
+                       cfg->dma[tmp] = dma = isapnp_find_dma(cfg->request, tmp);
+                       if (!dma)
+                               return -EINVAL;
+               }
+               if (from && dma->res == from) {
+                       while (dma->res != to) {
+                               if (!dma->res->alt)
+                                       return -EINVAL;
+                               dma = dma->res->alt->dma;
+                               for (tmp1 = tmp; tmp1 > 0 && dma; tmp1--)
+                                       dma = dma->next;
+                               cfg->dma[tmp] = dma;
+                               cfg->result.dma[tmp] = DEVICE_DMA_AUTO;
+                               if (!dma)
+                                       return -ENOENT;
+                       }
+               }
+       }
+       /* process memory settings */
+       for (tmp = 0; tmp < 4; tmp++) {
+               if (cfg->request->resource[tmp + 8].start != DEVICE_IO_AUTO)
+                       continue;               /* don't touch */
+               mem = cfg->mem[tmp];
+               if (!mem) {
+                       cfg->mem[tmp] = mem = isapnp_find_mem(cfg->request, tmp);
+                       if (!mem)
+                               return -EINVAL;
+               }
+               if (from && mem->res == from) {
+                       while (mem->res != to) {
+                               if (!mem->res->alt)
+                                       return -EINVAL;
+                               mem = mem->res->alt->mem;
+                               for (tmp1 = tmp; tmp1 > 0 && mem; tmp1--)
+                                       mem = mem->next;
+                               cfg->mem[tmp] = mem;
+                               cfg->result.resource[tmp + 8].start = DEVICE_IO_AUTO;
+                               if (!mem)
+                                       return -ENOENT;
+                       }
+               }
+       }
+       return 0;
+}
+
+static int isapnp_check_port(struct isapnp_cfgtmp *cfg, int port, int size, int idx)
+{
+       int i, tmp, rport, rsize;
+       struct isapnp_port *xport;
+       struct pci_dev *dev;
+
+       if (check_region(port, size))
+               return 1;
+       for (i = 0; i < 8; i++) {
+               rport = isapnp_reserve_io[i << 1];
+               rsize = isapnp_reserve_io[(i << 1) + 1];
+               if (port >= rport && port < rport + rsize)
+                       return 1;
+               if (port + size > rport && port + size < (rport + rsize) - 1)
+                       return 1;
+       }
+       for (dev = isapnp_devices; dev; dev = dev->next) {
+               if (dev->active) {
+                       for (tmp = 0; tmp < 8; tmp++) {
+                               if (dev->resource[tmp].start != DEVICE_IO_NOTSET) {
+                                       rport = dev->resource[tmp].start;
+                                       rsize = (dev->resource[tmp].end - rport) + 1;
+                                       if (port >= rport && port < rport + rsize)
+                                               return 1;
+                                       if (port + size > rport && port + size < (rport + rsize) - 1)
+                                               return 1;
+                               }
+                       }
+               }
+       }
+       for (i = 0; i < 8; i++) {
+               if (i == idx)
+                       continue;
+               tmp = cfg->request->resource[i].start;
+               if (tmp == DEVICE_IO_NOTSET)
+                       continue;
+               if (tmp == DEVICE_IO_AUTO) {            /* auto */
+                       xport = cfg->port[i];
+                       if (!xport)
+                               return 1;
+                       tmp = cfg->result.resource[i].start;
+                       if (tmp == DEVICE_IO_AUTO)
+                               continue;
+                       if (tmp + xport->size >= port && tmp <= port + xport->size)
+                               return 1;
+                       continue;
+               }
+               if (port == tmp)
+                       return 1;
+               xport = isapnp_find_port(cfg->request, i);
+               if (!xport)
+                       return 1;
+               if (tmp + xport->size >= port && tmp <= port + xport->size)
+                       return 1;
+       }
+       return 0;
+}
+
+static int isapnp_valid_port(struct isapnp_cfgtmp *cfg, int idx)
+{
+       int err;
+       unsigned long *value;
+       struct isapnp_port *port;
+
+       if (!cfg || idx < 0 || idx > 7)
+               return -EINVAL;
+       if (cfg->result.resource[idx].start != DEVICE_IO_AUTO) /* don't touch */
+               return 0;
+      __again:
+       port = cfg->port[idx];
+       if (!port)
+               return -EINVAL;
+       value = &cfg->result.resource[idx].start;
+       if (*value == DEVICE_IO_AUTO) {
+               if (!isapnp_check_port(cfg, *value = port->min, port->size, idx))
+                       return 0;
+       }
+       do {
+               *value += port->align;
+               if (*value > port->max || !port->align) {
+                       if (port->res && port->res->alt) {
+                               if ((err = isapnp_alternative_switch(cfg, port->res, port->res->alt))<0)
+                                       return err;
+                               goto __again;
+                       }
+                       return -ENOENT;
+               }
+       } while (isapnp_check_port(cfg, *value, port->size, idx));
+       return 0;
+}
+
+static void isapnp_test_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+static int isapnp_check_interrupt(struct isapnp_cfgtmp *cfg, int irq, int idx)
+{
+       int i;
+       struct pci_dev *dev;
+
+       if (irq < 0 || irq > 15)
+               return 1;
+       for (i = 0; i < 16; i++) {
+               if (isapnp_reserve_irq[i] == irq)
+                       return 1;
+       }
+       for (dev = isapnp_devices; dev; dev = dev->next) {
+               if (dev->active) {
+                       if (dev->irq == irq || dev->irq2 == irq)
+                               return 1;
+               }
+       }
+       if (request_irq(irq, isapnp_test_handler, SA_INTERRUPT, "isapnp", NULL))
+               return 1;
+       free_irq(irq, NULL);
+       if (idx != 0) {
+               if (cfg->result.irq != DEVICE_IRQ_AUTO &&
+                   cfg->result.irq != DEVICE_IRQ_NOTSET)
+                       if (cfg->result.irq == irq)
+                               return 1;
+       }
+       if (idx != 1) {
+               if (cfg->result.irq2 != DEVICE_IRQ_AUTO &&
+                   cfg->result.irq2 != DEVICE_IRQ_NOTSET)
+                       if (cfg->result.irq2 == irq)
+                               return 1;
+       }
+       return 0;
+}
+
+static int isapnp_valid_irq(struct isapnp_cfgtmp *cfg, int idx)
+{
+       /* IRQ priority: table is good for i386 */
+       static unsigned short xtab[16] = {
+               5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
+       };
+       int err, i;
+       unsigned int *value;
+       struct isapnp_irq *irq;
+
+       if (!cfg || idx < 0 || idx > 1)
+               return -EINVAL;
+       if (idx == 0) {
+               if (cfg->result.irq != DEVICE_IRQ_AUTO) /* don't touch */
+                       return 0;
+       } else {
+               if (cfg->result.irq2 != DEVICE_IRQ_AUTO) /* don't touch */
+                       return 0;
+       }
+      __again:
+       irq = cfg->irq[idx];
+       if (!irq)
+               return -EINVAL;
+       if (idx == 0) {
+               value = &cfg->result.irq;
+       } else {
+               value = &cfg->result.irq2;
+       }
+       if (*value == DEVICE_IRQ_AUTO) {
+               for (i = 0; i < 16 && !(irq->map & (1<<xtab[i])); i++);
+               if (i >= 16)
+                       return -ENOENT;
+               if (!isapnp_check_interrupt(cfg, *value = xtab[i], idx))
+                       return 0;
+       }
+       do {
+               for (i = 0; i < 16 && xtab[i] != *value; i++);
+               for (i++; i < 16 && !(irq->map & (1<<xtab[i])); i++);
+               if (i >= 16) {
+                       if (irq->res && irq->res->alt) {
+                               if ((err = isapnp_alternative_switch(cfg, irq->res, irq->res->alt))<0)
+                                       return err;
+                               goto __again;
+                       }
+                       return -ENOENT;
+               } else {
+                       *value = xtab[i];
+               }
+       } while (isapnp_check_interrupt(cfg, *value, idx));
+       return 0;
+}
+
+static int isapnp_check_dma(struct isapnp_cfgtmp *cfg, int dma, int idx)
+{
+       int i;
+       struct pci_dev *dev;
+
+       if (dma < 0 || dma == 4 || dma > 7)
+               return 1;
+       for (i = 0; i < 8; i++) {
+               if (isapnp_reserve_dma[i] == dma)
+                       return 1;
+       }
+       for (dev = isapnp_devices; dev; dev = dev->next) {
+               if (dev->active) {
+                       if (dev->dma[0] == dma || dev->dma[1] == dma)
+                               return 1;
+               }
+       }
+       if (request_dma(dma, "isapnp"))
+               return 1;
+       free_dma(dma);
+       for (i = 0; i < 2; i++) {
+               if (i == idx)
+                       continue;
+               if (cfg->result.dma[i] == DEVICE_DMA_NOTSET ||
+                   cfg->result.dma[i] == DEVICE_DMA_AUTO)
+                       continue;
+               if (cfg->result.dma[i] == dma)
+                       return 1;
+       }
+       return 0;
+}
+
+static int isapnp_valid_dma(struct isapnp_cfgtmp *cfg, int idx)
+{
+       int err, i;
+       unsigned char *value;
+       struct isapnp_dma *dma;
+
+       if (!cfg || idx < 0 || idx > 1)
+               return -EINVAL;
+       if (cfg->result.dma[idx] != DEVICE_DMA_AUTO)    /* don't touch */
+               return 0;
+      __again:
+       dma = cfg->dma[idx];
+       if (!dma)
+               return -EINVAL;
+       value = &cfg->result.dma[idx];
+       if (*value == DEVICE_DMA_AUTO) {
+               for (i = 0; i < 8 && !(dma->map & (1<<i)); i++);
+               if (i >= 8)
+                       return -ENOENT;
+               if (!isapnp_check_dma(cfg, *value = i, idx))
+                       return 0;
+       }
+       do {
+               for (i = *value + 1; i < 8 && !(dma->map & (1<<i)); i++);
+               if (i >= 8) {
+                       if (dma->res && dma->res->alt) {
+                               if ((err = isapnp_alternative_switch(cfg, dma->res, dma->res->alt))<0)
+                                       return err;
+                               goto __again;
+                       }
+                       return -ENOENT;
+               } else {
+                       *value = i;
+               }
+       } while (isapnp_check_dma(cfg, *value, idx));
+       return 0;
+}
+
+static int isapnp_check_mem(struct isapnp_cfgtmp *cfg, unsigned int addr, unsigned int size, int idx)
+{
+       int i, tmp;
+       unsigned int raddr, rsize;
+       struct pci_dev *dev;
+       struct isapnp_mem *xmem;
+
+       for (i = 0; i < 8; i++) {
+               raddr = (unsigned int)isapnp_reserve_mem[i << 1];
+               rsize = (unsigned int)isapnp_reserve_mem[(i << 1) + 1];
+               if (addr >= raddr && addr < raddr + rsize)
+                       return 1;
+               if (addr + size > raddr && addr + size < (raddr + rsize) - 1)
+                       return 1;
+               if (__check_region(&iomem_resource, addr, size))
+                       return 1;
+       }
+       for (dev = isapnp_devices; dev; dev = dev->next) {
+               if (dev->active) {
+                       for (tmp = 0; tmp < 4; tmp++) {
+                               if (dev->resource[tmp].start != DEVICE_IO_NOTSET) {
+                                       raddr = dev->resource[tmp + 8].start;
+                                       rsize = (dev->resource[tmp + 8].end - raddr) + 1;
+                                       if (addr >= raddr && addr < raddr + rsize)
+                                               return 1;
+                                       if (addr + size > raddr && addr + size < (raddr + rsize) - 1)
+                                               return 1;
+                               }
+                       }
+               }
+       }
+       for (i = 0; i < 4; i++) {
+               if (i == idx)
+                       continue;
+               tmp = cfg->request->resource[i + 8].start;
+               if (tmp == DEVICE_IO_NOTSET)
+                       continue;
+               if (tmp == DEVICE_IO_AUTO) {            /* auto */
+                       xmem = cfg->mem[i];
+                       if (!xmem)
+                               return 1;
+                       tmp = cfg->result.resource[i + 8].start;
+                       if (tmp == DEVICE_IO_AUTO)
+                               continue;
+                       if (tmp + xmem->size >= addr && tmp <= addr + xmem->size)
+                               return 1;
+                       continue;
+               }
+               if (addr == tmp)
+                       return 1;
+               xmem = isapnp_find_mem(cfg->request, i);
+               if (!xmem)
+                       return 1;
+               if (tmp + xmem->size >= addr && tmp <= addr + xmem->size)
+                       return 1;
+       }
+       return 0;
+}
+
+static int isapnp_valid_mem(struct isapnp_cfgtmp *cfg, int idx)
+{
+       int err;
+       unsigned long *value;
+       struct isapnp_mem *mem;
+
+       if (!cfg || idx < 0 || idx > 3)
+               return -EINVAL;
+       if (cfg->result.resource[idx + 8].start != DEVICE_IO_AUTO) /* don't touch */
+               return 0;
+      __again:
+       mem = cfg->mem[idx];
+       if (!mem)
+               return -EINVAL;
+       value = &cfg->result.resource[idx].start;
+       if (*value == DEVICE_IO_AUTO) {
+               *value = mem->min;
+               if (!isapnp_check_mem(cfg, *value, mem->size, idx))
+                       return 0;
+       }
+       do {
+               *value += mem->align;
+               if (*value >= 8 || !mem->align) {
+                       if (mem->res && mem->res->alt) {
+                               if ((err = isapnp_alternative_switch(cfg, mem->res, mem->res->alt))<0)
+                                       return err;
+                               goto __again;
+                       }
+                       return -ENOENT;
+               }
+       } while (isapnp_check_mem(cfg, *value, mem->size, idx));
+       return 0;
+}
+
+static int isapnp_check_valid(struct isapnp_cfgtmp *cfg)
+{
+       int tmp;
+       
+       for (tmp = 0; tmp < 8; tmp++)
+               if (cfg->result.resource[tmp].start == DEVICE_IO_AUTO)
+                       return -EAGAIN;
+       if (cfg->result.irq == DEVICE_IRQ_AUTO)
+               return -EAGAIN;
+       if (cfg->result.irq2 == DEVICE_IRQ_AUTO)
+               return -EAGAIN;
+       for (tmp = 0; tmp < 2; tmp++)
+               if (cfg->result.dma[tmp] == DEVICE_DMA_AUTO)
+                       return -EAGAIN;
+       for (tmp = 0; tmp < 4; tmp++)
+               if (cfg->result.resource[tmp + 1].start == DEVICE_IO_AUTO)
+                       return -EAGAIN;
+       return 0;
+}
+
+static int isapnp_config_activate(struct pci_dev *dev)
+{
+       struct isapnp_cfgtmp cfg;
+       int tmp, fauto, err;
+       
+       if (!dev)
+               return -EINVAL;
+       if (dev->active)
+               return -EBUSY;
+       memset(&cfg, 0, sizeof(cfg));
+       cfg.request = dev;
+       memcpy(&cfg.result, dev, sizeof(struct pci_dev));
+       /* check if all values are set, otherwise try auto-configuration */
+       for (tmp = fauto = 0; !fauto && tmp < 8; tmp++) {
+               if (dev->resource[tmp].start == DEVICE_IO_AUTO)
+                       fauto++;
+       }
+       if (dev->irq == DEVICE_IRQ_AUTO)
+               fauto++;
+       if (dev->irq2 == DEVICE_IRQ_AUTO)
+               fauto++;
+       for (tmp = 0; !fauto && tmp < 2; tmp++) {
+               if (dev->dma[tmp] == DEVICE_DMA_AUTO)
+                       fauto++;
+       }
+       for (tmp = 0; !fauto && tmp < 4; tmp++) {
+               if (dev->resource[tmp + 8].start == DEVICE_IO_AUTO)
+                       fauto++;
+       }
+       if (!fauto)
+               goto __skip_auto;
+       /* set variables to initial values */
+       if ((err = isapnp_alternative_switch(&cfg, NULL, NULL))<0)
+               return err;
+       /* find first valid configuration */
+       fauto = 0;
+       do {
+               for (tmp = 0; tmp < 8 && cfg.result.resource[tmp].start != DEVICE_IO_NOTSET; tmp++)
+                       if ((err = isapnp_valid_port(&cfg, tmp))<0)
+                               return err;
+               if (cfg.result.irq != DEVICE_IRQ_NOTSET)
+                       if ((err = isapnp_valid_irq(&cfg, 0))<0)
+                               return err;
+               if (cfg.result.irq2 != DEVICE_IRQ_NOTSET)
+                       if ((err = isapnp_valid_irq(&cfg, 1))<0)
+                               return err;
+               for (tmp = 0; tmp < 2 && tmp < cfg.result.dma[tmp] != DEVICE_DMA_NOTSET; tmp++)
+                       if ((err = isapnp_valid_dma(&cfg, tmp))<0)
+                               return err;
+               for (tmp = 0; tmp < 4 && tmp < cfg.result.resource[tmp + 8].start != DEVICE_IO_NOTSET; tmp++)
+                       if ((err = isapnp_valid_mem(&cfg, tmp))<0)
+                               return err;
+       } while (isapnp_check_valid(&cfg)<0 && fauto++ < 20);
+       if (fauto >= 20)
+               return -EAGAIN;
+      __skip_auto:
+       /* we have valid configuration, try configure hardware */
+       isapnp_cfg_begin(dev->bus->number, dev->devfn);
+       dev->active = 1;
+       dev->irq = cfg.result.irq;
+       dev->irq2 = cfg.result.irq2;
+       dev->dma[0] = cfg.result.dma[0];
+       dev->dma[1] = cfg.result.dma[1];
+       for (tmp = 0; tmp < 12; tmp++) {
+               dev->resource[tmp].start = cfg.result.resource[tmp].start;
+               if (cfg.result.resource[tmp].start != DEVICE_IO_NOTSET &&
+                   cfg.result.resource[tmp].end != DEVICE_IO_AUTO)
+                       dev->resource[tmp].end += cfg.result.resource[tmp].start;
+       }       
+       for (tmp = 0; tmp < 8 && dev->resource[tmp].start != DEVICE_IO_NOTSET; tmp++)
+               isapnp_write_word(ISAPNP_CFG_PORT+(tmp<<1), dev->resource[tmp].start);
+       if (dev->irq != DEVICE_IRQ_NOTSET) {
+               if (dev->irq == 2)
+                       dev->irq = 9;
+               isapnp_write_byte(ISAPNP_CFG_IRQ+(0<<1), dev->irq);
+       }
+       if (dev->irq2 != DEVICE_IRQ_NOTSET) {
+               if (dev->irq2 == 2)
+                       dev->irq2 = 9;
+               isapnp_write_byte(ISAPNP_CFG_IRQ+(1<<1), dev->irq2);
+       }
+       for (tmp = 0; tmp < 2 && dev->dma[tmp] != DEVICE_DMA_NOTSET; tmp++)
+               isapnp_write_byte(ISAPNP_CFG_DMA+tmp, dev->dma[tmp]);
+       for (tmp = 0; tmp < 4 && dev->resource[tmp].start != DEVICE_IO_NOTSET; tmp++)
+               isapnp_write_word(ISAPNP_CFG_MEM+(tmp<<2), (dev->resource[tmp + 8].start >> 8) & 0xffff);
+       isapnp_activate(dev->devfn);
+       isapnp_cfg_end();
+       return 0;
+}
+
+static int isapnp_config_deactivate(struct pci_dev *dev)
+{
+       if (!dev || !dev->active)
+               return -EINVAL;
+       isapnp_cfg_begin(dev->bus->number, dev->devfn);
+       isapnp_deactivate(dev->devfn);
+       dev->activate = 0;
+       isapnp_cfg_end();
+       return 0;
+}
+
+/*
+ *  Inititialization.
+ */
+
+#ifdef MODULE
+
+static void isapnp_free_port(struct isapnp_port *port)
+{
+       struct isapnp_port *next;
+
+       while (port) {
+               next = port->next;
+               kfree(port);
+               port = next;
+       }
+}
+
+static void isapnp_free_irq(struct isapnp_irq *irq)
+{
+       struct isapnp_irq *next;
+
+       while (irq) {
+               next = irq->next;
+               kfree(irq);
+               irq = next;
+       }
+}
+
+static void isapnp_free_dma(struct isapnp_dma *dma)
+{
+       struct isapnp_dma *next;
+
+       while (dma) {
+               next = dma->next;
+               kfree(dma);
+               dma = next;
+       }
+}
+
+static void isapnp_free_mem(struct isapnp_mem *mem)
+{
+       struct isapnp_mem *next;
+
+       while (mem) {
+               next = mem->next;
+               kfree(mem);
+               mem = next;
+       }
+}
+
+static void isapnp_free_mem32(struct isapnp_mem32 *mem32)
+{
+       struct isapnp_mem32 *next;
+
+       while (mem32) {
+               next = mem32->next;
+               kfree(mem32);
+               mem32 = next;
+       }
+}
+
+static void isapnp_free_resources(struct isapnp_resources *resources, int alt)
+{
+       struct isapnp_resources *next;
+
+       while (resources) {
+               next = alt ? resources->alt : resources->next;
+               isapnp_free_port(resources->port);
+               isapnp_free_irq(resources->irq);
+               isapnp_free_dma(resources->dma);
+               isapnp_free_mem(resources->mem);
+               isapnp_free_mem32(resources->mem32);
+               if (!alt && resources->alt)
+                       isapnp_free_resources(resources->alt, 1);
+               kfree(resources);
+               resources = next;
+       }
+}
+
+static void isapnp_free_device(struct pci_dev *dev)
+{
+       struct pci_dev *next;
+
+       while (dev) {
+               next = dev->next;
+               isapnp_free_resources((struct isapnp_resources *)dev->sysdata, 0);
+               kfree(dev);
+               dev = next;
+       }
+}
+
+#endif /* MODULE */
+
+static void isapnp_free_all_resources(void)
+{
+#ifdef MODULE
+       struct pci_bus *card, *cardnext;
+#endif
+
+#ifdef ISAPNP_REGION_OK
+       release_resource(pidxr_res);
+#endif
+       release_resource(pnpwrp_res);
+       if (isapnp_rdp >= 0x203 && isapnp_rdp <= 0x3ff)
+               release_resource(isapnp_rdp_res);
+#ifdef MODULE
+       for (card = isapnp_cards; card; card = cardnext) {
+               cardnext = card->next;
+               isapnp_free_device(card->devices);
+               kfree(card);
+       }
+#ifdef CONFIG_PROC_FS
+       isapnp_proc_done();
+#endif
+#endif
+}
+
+static int __init isapnp_do_reserve_irq(int irq)
+{
+       int i;
+       
+       if (irq < 0 || irq > 15)
+               return -EINVAL;
+       for (i = 0; i < 16; i++) {
+               if (isapnp_reserve_irq[i] == irq)
+                       return 0;
+       }
+       for (i = 0; i < 16; i++) {
+               if (isapnp_reserve_irq[i] < 0) {
+                       isapnp_reserve_irq[i] = irq;
+#ifdef ISAPNP_DEBUG
+                       printk("IRQ %i is reserved now.\n", irq);
+#endif
+                       return 0;
+               }
+       }
+       return -ENOMEM;
+}
+
+#ifdef CONFIG_PCI
+
+static void __init isapnp_pci_init(void)
+{
+       int devfn;
+       struct pci_dev *dev;
+       
+       for (devfn = 0; devfn < 255; devfn++) {
+               dev = pci_find_slot(0, devfn);
+               if (dev != NULL)
+                       break;
+       }
+       if (dev == NULL)
+               return;
+       while (dev) {
+#ifdef ISAPNP_DEBUG
+               printk("PCI: reserved IRQ: %i\n", dev->irq);
+#endif
+               if (dev->irq > 0)
+                       isapnp_do_reserve_irq(dev->irq);
+               dev = dev->next;
+       }
+}
+
+#endif /* CONFIG_PCI */
+
+EXPORT_SYMBOL(isapnp_present);
+EXPORT_SYMBOL(isapnp_cfg_begin);
+EXPORT_SYMBOL(isapnp_cfg_end);
+EXPORT_SYMBOL(isapnp_read_byte);
+EXPORT_SYMBOL(isapnp_read_word);
+EXPORT_SYMBOL(isapnp_read_dword);
+EXPORT_SYMBOL(isapnp_write_byte);
+EXPORT_SYMBOL(isapnp_write_word);
+EXPORT_SYMBOL(isapnp_write_dword);
+EXPORT_SYMBOL(isapnp_wake);
+EXPORT_SYMBOL(isapnp_device);
+EXPORT_SYMBOL(isapnp_activate);
+EXPORT_SYMBOL(isapnp_deactivate);
+EXPORT_SYMBOL(isapnp_find_card);
+EXPORT_SYMBOL(isapnp_find_dev);
+
+int __init isapnp_init(void)
+{
+       int cards;
+       struct pci_bus *card;
+       struct pci_dev *dev;
+
+       if (isapnp_disable) {
+               isapnp_detected = 0;
+               printk("isapnp: ISA Plug & Play support disabled\n");
+               return 0;
+       }
+#ifdef ISAPNP_REGION_OK
+       pidxr_res=request_region(_PIDXR, 1, "isapnp index");
+       if(!pidxr_res) {
+               printk("isapnp: Index Register 0x%x already used\n", _PIDXR);
+               return -EBUSY;
+       }
+#endif
+       pnpwrp_res=request_region(_PNPWRP, 1, "isapnp write");
+       if(!pnpwrp_res) {
+               printk("isapnp: Write Data Register 0x%x already used\n", _PNPWRP);
+               return -EBUSY;
+       }
+       if (isapnp_rdp >= 0x203 && isapnp_rdp <= 0x3ff) {
+               isapnp_rdp_res=request_region(isapnp_rdp, 1, "isapnp read");
+               if(!isapnp_rdp_res) {
+                       printk("isapnp: Read Data Register 0x%x already used\n", isapnp_rdp);
+                       return -EBUSY;
+               }
+       }
+       isapnp_detected = 1;
+       if (isapnp_rdp < 0x203 || isapnp_rdp > 0x3ff) {
+               cards = isapnp_isolate();
+               if (cards < 0 || 
+                   (isapnp_rdp < 0x203 || isapnp_rdp > 0x3ff)) {
+                       isapnp_free_all_resources();
+                       isapnp_detected = 0;
+                       printk("isapnp: No Plug & Play device found\n");
+                       return 0;
+               }
+               isapnp_rdp_res=request_region(isapnp_rdp, 1, "isapnp read");
+       }
+       isapnp_build_device_list();
+       cards = 0;
+       for (card = isapnp_cards; card; card = card->next)
+               cards++;
+       if (isapnp_verbose) {
+               for (card = isapnp_cards; card; card = card->next) {
+                       printk( "isapnp: Card '%s'\n", card->name[0]?card->name:"Unknown");
+                       if (isapnp_verbose < 2)
+                               continue;
+                       for (dev = card->devices; dev; dev = dev->next)
+                               printk("isapnp:   Device '%s'\n", dev->name[0]?card->name:"Unknown");
+               }
+       }
+       if (cards) {
+               printk("isapnp: %i Plug & Play card%s detected total\n", cards, cards>1?"s":"");
+       } else {
+               printk("isapnp: No Plug & Play card found\n");
+       }
+#ifdef CONFIG_PCI
+       if (!isapnp_skip_pci_scan)
+               isapnp_pci_init();
+#endif
+#ifdef CONFIG_PROC_FS
+       isapnp_proc_init();
+#endif
+       return 0;
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+       return isapnp_init();
+}
+
+void cleanup_module(void)
+{
+       if (isapnp_detected)
+               isapnp_free_all_resources();
+}
+
+#endif
diff --git a/drivers/pnp/isapnp_proc.c b/drivers/pnp/isapnp_proc.c
new file mode 100644 (file)
index 0000000..9c6f0be
--- /dev/null
@@ -0,0 +1,945 @@
+/*
+ *  ISA Plug & Play support
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *
+ *
+ *   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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+static void *isapnp_alloc(long size);
+struct pci_bus *isapnp_cards;
+struct pci_dev *isapnp_devices;
+
+struct isapnp_info_buffer {
+       char *buffer;           /* pointer to begin of buffer */
+       char *curr;             /* current position in buffer */
+       unsigned long size;     /* current size */
+       unsigned long len;      /* total length of buffer */
+       int stop;               /* stop flag */
+       int error;              /* error code */
+};
+
+typedef struct isapnp_info_buffer isapnp_info_buffer_t;
+
+static struct proc_dir_entry *isapnp_proc_entry = NULL;
+
+static void isapnp_info_read(isapnp_info_buffer_t *buffer);
+static void isapnp_info_write(isapnp_info_buffer_t *buffer);
+
+int isapnp_printf(isapnp_info_buffer_t * buffer, char *fmt,...)
+{
+       va_list args;
+       int res;
+       char sbuffer[512];
+
+       if (buffer->stop || buffer->error)
+               return 0;
+       va_start(args, fmt);
+       res = vsprintf(sbuffer, fmt, args);
+       va_end(args);
+       if (buffer->size + res >= buffer->len) {
+               buffer->stop = 1;
+               return 0;
+       }
+       strcpy(buffer->curr, sbuffer);
+       buffer->curr += res;
+       buffer->size += res;
+       return res;
+}
+
+static loff_t isapnp_info_entry_lseek(struct file *file, loff_t offset, int orig)
+{
+       switch (orig) {
+       case 0: /* SEEK_SET */
+               file->f_pos = offset;
+               return file->f_pos;
+       case 1: /* SEEK_CUR */
+               file->f_pos += offset;
+               return file->f_pos;
+       case 2: /* SEEK_END */
+       default:
+               return -EINVAL;
+       }
+       return -ENXIO;
+}
+
+static ssize_t isapnp_info_entry_read(struct file *file, char *buffer,
+                                     size_t count, loff_t * offset)
+{
+       isapnp_info_buffer_t *buf;
+       long size = 0, size1;
+       int mode;
+
+       mode = file->f_flags & O_ACCMODE;
+       if (mode != O_RDONLY)
+               return -EINVAL;
+       buf = (isapnp_info_buffer_t *) file->private_data;
+       if (!buf)
+               return -EIO;
+       if (file->f_pos >= buf->size)
+               return 0;
+       size = buf->size < count ? buf->size : count;
+       size1 = buf->size - file->f_pos;
+       if (size1 < size)
+               size = size1;
+       if (copy_to_user(buffer, buf->buffer + file->f_pos, size))
+               return -EFAULT;
+       file->f_pos += size;
+       return size;
+}
+
+static ssize_t isapnp_info_entry_write(struct file *file, const char *buffer,
+                                      size_t count, loff_t * offset)
+{
+       isapnp_info_buffer_t *buf;
+       long size = 0, size1;
+       int mode;
+
+       mode = file->f_flags & O_ACCMODE;
+       if (mode != O_WRONLY)
+               return -EINVAL;
+       buf = (isapnp_info_buffer_t *) file->private_data;
+       if (!buf)
+               return -EIO;
+       if (file->f_pos < 0)
+               return -EINVAL;
+       if (file->f_pos >= buf->len)
+               return -ENOMEM;
+       size = buf->len < count ? buf->len : count;
+       size1 = buf->len - file->f_pos;
+       if (size1 < size)
+               size = size1;
+       if (copy_from_user(buf->buffer + file->f_pos, buffer, size))
+               return -EFAULT;
+       if (buf->size < file->f_pos + size)
+               buf->size = file->f_pos + size;
+       file->f_pos += size;
+       return size;
+}
+
+static int isapnp_info_entry_open(struct inode *inode, struct file *file)
+{
+       isapnp_info_buffer_t *buffer;
+       int mode;
+
+       mode = file->f_flags & O_ACCMODE;
+       if (mode != O_RDONLY && mode != O_WRONLY)
+               return -EINVAL;
+       buffer = (isapnp_info_buffer_t *)
+                               isapnp_alloc(sizeof(isapnp_info_buffer_t));
+       if (!buffer)
+               return -ENOMEM;
+       buffer->len = 4 * PAGE_SIZE;
+       buffer->buffer = vmalloc(buffer->len);
+       if (!buffer->buffer) {
+               kfree(buffer);
+               return -ENOMEM;
+       }
+       buffer->curr = buffer->buffer;
+       file->private_data = buffer;
+       MOD_INC_USE_COUNT;
+       if (mode == O_RDONLY)
+               isapnp_info_read(buffer);
+       return 0;
+}
+
+static int isapnp_info_entry_release(struct inode *inode, struct file *file)
+{
+       isapnp_info_buffer_t *buffer;
+       int mode;
+
+       if ((buffer = (isapnp_info_buffer_t *) file->private_data) == NULL)
+               return -EINVAL;
+       mode = file->f_flags & O_ACCMODE;
+       if (mode == O_WRONLY)
+               isapnp_info_write(buffer);
+       vfree(buffer->buffer);
+       kfree(buffer);
+       MOD_DEC_USE_COUNT;
+       return 0;
+}
+
+static unsigned int isapnp_info_entry_poll(struct file *file, poll_table * wait)
+{
+       if (!file->private_data)
+               return 0;
+       return POLLIN | POLLRDNORM;
+}
+
+static int isapnp_info_entry_ioctl(struct inode *inode, struct file *file,
+                                  unsigned int cmd, unsigned long arg)
+{
+       return -EINVAL;
+}
+
+static int isapnp_info_entry_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       return -ENXIO;
+}
+
+static struct file_operations isapnp_info_entry_operations =
+{
+       isapnp_info_entry_lseek,        /* lseek */
+       isapnp_info_entry_read,         /* read */
+       isapnp_info_entry_write,        /* write */
+       NULL,                           /* readdir */
+       isapnp_info_entry_poll,         /* poll */
+       isapnp_info_entry_ioctl,        /* ioctl - default */
+       isapnp_info_entry_mmap,         /* mmap */
+       isapnp_info_entry_open,         /* open */
+       NULL,                           /* flush */
+       isapnp_info_entry_release,      /* release */
+       NULL,                           /* can't fsync */
+       NULL,                           /* fasync */
+       NULL,                           /* check_media_change */
+       NULL,                           /* revalidate */
+       NULL,                           /* lock */
+};
+
+static struct inode_operations isapnp_info_entry_inode_operations =
+{
+       &isapnp_info_entry_operations,  /* default sound info directory file-ops */
+       NULL,                   /* create */
+       NULL,                   /* lookup */
+       NULL,                   /* link */
+       NULL,                   /* unlink */
+       NULL,                   /* symlink */
+       NULL,                   /* mkdir */
+       NULL,                   /* rmdir */
+       NULL,                   /* mknod */
+       NULL,                   /* rename */
+       NULL,                   /* readlink */
+       NULL,                   /* follow_link */
+       NULL,                   /* readpage */
+       NULL,                   /* writepage */
+       NULL,                   /* bmap */
+       NULL,                   /* truncate */
+       NULL                    /* permission */
+};
+
+__initfunc(static int isapnp_proc_init(void))
+{
+       struct proc_dir_entry *p;
+
+       isapnp_proc_entry = NULL;
+       p = create_proc_entry("isapnp", S_IFREG | S_IRUGO | S_IWUSR, &proc_root);
+       if (!p)
+               return -ENOMEM;
+       p->ops = &isapnp_info_entry_inode_operations;
+       isapnp_proc_entry = p;
+       return 0;
+}
+
+#ifdef MODULE
+static int isapnp_proc_done(void)
+{
+       if (isapnp_proc_entry)
+               proc_unregister(&proc_root, isapnp_proc_entry->low_ino);
+       return 0;
+}
+#endif /* MODULE */
+
+/*
+ *
+ */
+
+static void isapnp_print_devid(isapnp_info_buffer_t *buffer, unsigned short vendor, unsigned short device)
+{
+       char tmp[8];
+       
+       sprintf(tmp, "%c%c%c%x%x%x%x",
+                       'A' + ((vendor >> 2) & 0x3f) - 1,
+                       'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
+                       'A' + ((vendor >> 8) & 0x1f) - 1,
+                       (device >> 4) & 0x0f,
+                       device & 0x0f,
+                       (device >> 12) & 0x0f,
+                       (device >> 8) & 0x0f);
+       isapnp_printf(buffer, tmp);
+}
+
+static void isapnp_print_compatible(isapnp_info_buffer_t *buffer, struct pci_dev *dev)
+{
+       int idx;
+
+       for (idx = 0; idx < DEVICE_COUNT_COMPATIBLE; idx++) {
+               if (dev->vendor_compatible[idx] == 0)
+                       continue;
+               isapnp_printf(buffer, "    Compatible device ");
+               isapnp_print_devid(buffer,
+                                  dev->vendor_compatible[idx],
+                                  dev->device_compatible[idx]);
+               isapnp_printf(buffer, "\n");
+       }
+}
+
+static void isapnp_print_port(isapnp_info_buffer_t *buffer, char *space, struct isapnp_port *port)
+{
+       isapnp_printf(buffer, "%sPort 0x%x-0x%x, align 0x%x, size 0x%x, %i-bit address decoding\n",
+                       space, port->min, port->max, port->align ? (port->align-1) : 0, port->size,
+                       port->flags & ISAPNP_PORT_FLAG_16BITADDR ? 16 : 10);
+}
+
+static void isapnp_print_irq(isapnp_info_buffer_t *buffer, char *space, struct isapnp_irq *irq)
+{
+       int first = 1, i;
+
+       isapnp_printf(buffer, "%sIRQ ", space);
+       for (i = 0; i < 16; i++)
+               if (irq->map & (1<<i)) {
+                       if (!first) {
+                               isapnp_printf(buffer, ",");
+                       } else {
+                               first = 0;
+                       }
+                       if (i == 2 || i == 9)
+                               isapnp_printf(buffer, "2/9");
+                       else
+                               isapnp_printf(buffer, "%i", i);
+               }
+       if (!irq->map)
+               isapnp_printf(buffer, "<none>");
+       if (irq->flags & DEVICE_IRQ_FLAG_HIGHEDGE)
+               isapnp_printf(buffer, " High-Edge");
+       if (irq->flags & DEVICE_IRQ_FLAG_LOWEDGE)
+               isapnp_printf(buffer, " Low-Edge");
+       if (irq->flags & DEVICE_IRQ_FLAG_HIGHLEVEL)
+               isapnp_printf(buffer, " High-Level");
+       if (irq->flags & DEVICE_IRQ_FLAG_LOWLEVEL)
+               isapnp_printf(buffer, " Low-Level");
+       isapnp_printf(buffer, "\n");
+}
+
+static void isapnp_print_dma(isapnp_info_buffer_t *buffer, char *space, struct isapnp_dma *dma)
+{
+       int first = 1, i;
+       char *s;
+
+       isapnp_printf(buffer, "%sDMA ", space);
+       for (i = 0; i < 8; i++)
+               if (dma->map & (1<<i)) {
+                       if (!first) {
+                               isapnp_printf(buffer, ",");
+                       } else {
+                               first = 0;
+                       }
+                       isapnp_printf(buffer, "%i", i);
+               }
+       if (!dma->map)
+               isapnp_printf(buffer, "<none>");
+       switch (dma->type) {
+       case DEVICE_DMA_TYPE_8BIT:
+               s = "8-bit";
+               break;
+       case DEVICE_DMA_TYPE_8AND16BIT:
+               s = "8-bit&16-bit";
+               break;
+       default:
+               s = "16-bit";
+       }
+       isapnp_printf(buffer, " %s", s);
+       if (dma->flags & DEVICE_DMA_FLAG_MASTER)
+               isapnp_printf(buffer, " master");
+       if (dma->flags & DEVICE_DMA_FLAG_BYTE)
+               isapnp_printf(buffer, " byte-count");
+       if (dma->flags & DEVICE_DMA_FLAG_WORD)
+               isapnp_printf(buffer, " word-count");
+       switch (dma->speed) {
+       case DEVICE_DMA_SPEED_TYPEA:
+               s = "type-A";
+               break;
+       case DEVICE_DMA_SPEED_TYPEB:
+               s = "type-B";
+               break;
+       case DEVICE_DMA_SPEED_TYPEF:
+               s = "type-F";
+               break;
+       default:
+               s = "compatible";
+               break;
+       }
+       isapnp_printf(buffer, " %s\n", s);
+}
+
+static void isapnp_print_mem(isapnp_info_buffer_t *buffer, char *space, struct isapnp_mem *mem)
+{
+       char *s;
+
+       isapnp_printf(buffer, "%sMemory 0x%x-0x%x, align 0x%x, size 0x%x",
+                       space, mem->min, mem->max, mem->align, mem->size);
+       if (mem->flags & DEVICE_IO_FLAG_WRITEABLE)
+               isapnp_printf(buffer, ", writeable");
+       if (mem->flags & DEVICE_IO_FLAG_CACHEABLE)
+               isapnp_printf(buffer, ", cacheable");
+       if (mem->flags & DEVICE_IO_FLAG_RANGELENGTH)
+               isapnp_printf(buffer, ", range-length");
+       if (mem->flags & DEVICE_IO_FLAG_SHADOWABLE)
+               isapnp_printf(buffer, ", shadowable");
+       if (mem->flags & DEVICE_IO_FLAG_EXPANSIONROM)
+               isapnp_printf(buffer, ", expansion ROM");
+       switch (mem->type) {
+       case DEVICE_IO_TYPE_8BIT:
+               s = "8-bit";
+               break;
+       case DEVICE_IO_TYPE_8AND16BIT:
+               s = "8-bit&16-bit";
+               break;
+       default:
+               s = "16-bit";
+       }
+       isapnp_printf(buffer, ", %s\n", s);
+}
+
+static void isapnp_print_mem32(isapnp_info_buffer_t *buffer, char *space, struct isapnp_mem32 *mem32)
+{
+       int first = 1, i;
+
+       isapnp_printf(buffer, "%s32-bit memory ", space);
+       for (i = 0; i < 17; i++) {
+               if (first) {
+                       first = 0;
+               } else {
+                       isapnp_printf(buffer, ":");
+               }
+               isapnp_printf(buffer, "%02x", mem32->data[i]);
+       }
+}
+
+static void isapnp_print_resources(isapnp_info_buffer_t *buffer, char *space, struct isapnp_resources *res)
+{
+       char *s;
+       struct isapnp_port *port;
+       struct isapnp_irq *irq;
+       struct isapnp_dma *dma;
+       struct isapnp_mem *mem;
+       struct isapnp_mem32 *mem32;
+
+       switch (res->priority) {
+       case ISAPNP_RES_PRIORITY_PREFERRED:
+               s = "preferred";
+               break;
+       case ISAPNP_RES_PRIORITY_ACCEPTABLE:
+               s = "acceptable";
+               break;
+       case ISAPNP_RES_PRIORITY_FUNCTIONAL:
+               s = "functional";
+               break;
+       default:
+               s = "invalid";
+       }
+       isapnp_printf(buffer, "%sPriority %s\n", space, s);
+       for (port = res->port; port; port = port->next)
+               isapnp_print_port(buffer, space, port);
+       for (irq = res->irq; irq; irq = irq->next)
+               isapnp_print_irq(buffer, space, irq);
+       for (dma = res->dma; dma; dma = dma->next)
+               isapnp_print_dma(buffer, space, dma);
+       for (mem = res->mem; mem; mem = mem->next)
+               isapnp_print_mem(buffer, space, mem);
+       for (mem32 = res->mem32; mem32; mem32 = mem32->next)
+               isapnp_print_mem32(buffer, space, mem32);
+}
+
+static void isapnp_print_configuration(isapnp_info_buffer_t *buffer, struct pci_dev *dev)
+{
+       int i, tmp, next;
+       char *space = "    ";
+
+       isapnp_cfg_begin(dev->bus->number, dev->devfn);
+       isapnp_printf(buffer, "%sDevice is %sactive\n",
+                       space, isapnp_read_byte(ISAPNP_CFG_ACTIVATE)?"":"not ");
+       for (i = next = 0; i < 8; i++) {
+               tmp = isapnp_read_word(ISAPNP_CFG_PORT + (i << 1));
+               if (!tmp)
+                       continue;
+               if (!next) {
+                       isapnp_printf(buffer, "%sActive port ", space);
+                       next = 1;
+               }
+               isapnp_printf(buffer, "%s0x%x", i > 0 ? "," : "", tmp);
+       }
+       if (next)
+               isapnp_printf(buffer, "\n");
+       for (i = next = 0; i < 2; i++) {
+               tmp = isapnp_read_word(ISAPNP_CFG_IRQ + (i << 1));
+               if (!(tmp >> 8))
+                       continue;
+               if (!next) {
+                       isapnp_printf(buffer, "%sActive IRQ ", space);
+                       next = 1;
+               }
+               isapnp_printf(buffer, "%s%i", i > 0 ? "," : "", tmp >> 8);
+               if (tmp & 0xff)
+                       isapnp_printf(buffer, " [0x%x]", tmp & 0xff);
+       }
+       if (next)
+               isapnp_printf(buffer, "\n");
+       for (i = next = 0; i < 2; i++) {
+               tmp = isapnp_read_byte(ISAPNP_CFG_DMA + i);
+               if (tmp == 4)
+                       continue;
+               if (!next) {
+                       isapnp_printf(buffer, "%sActive DMA ", space);
+                       next = 1;
+               }
+               isapnp_printf(buffer, "%s%i", i > 0 ? "," : "", tmp);
+       }
+       if (next)
+               isapnp_printf(buffer, "\n");
+       for (i = next = 0; i < 4; i++) {
+               tmp = isapnp_read_dword(ISAPNP_CFG_MEM + (i << 3));
+               if (!tmp)
+                       continue;
+               if (!next) {
+                       isapnp_printf(buffer, "%sActive memory ", space);
+                       next = 1;
+               }
+               isapnp_printf(buffer, "%s0x%x", i > 0 ? "," : "", tmp);
+       }
+       if (next)
+               isapnp_printf(buffer, "\n");
+       isapnp_cfg_end();
+}
+
+static void isapnp_print_device(isapnp_info_buffer_t *buffer, struct pci_dev *dev)
+{
+       int block, block1;
+       char *space = "    ";
+       struct isapnp_resources *res, *resa;
+
+       if (!dev)
+               return;
+       isapnp_printf(buffer, "  Logical device %i '", dev->devfn);
+       isapnp_print_devid(buffer, dev->vendor, dev->device);
+       isapnp_printf(buffer, ":%s'", dev->name[0]?dev->name:"Unknown");
+       isapnp_printf(buffer, "\n");
+#if 0
+       isapnp_cfg_begin(dev->bus->number, dev->devfn);
+       for (block = 0; block < 128; block++)
+               if ((block % 16) == 15)
+                       isapnp_printf(buffer, "%02x\n", isapnp_read_byte(block));
+               else
+                       isapnp_printf(buffer, "%02x:", isapnp_read_byte(block));
+       isapnp_cfg_end();
+#endif
+       if (dev->regs)
+               isapnp_printf(buffer, "%sSupported registers 0x%x\n", space, dev->regs);
+       isapnp_print_compatible(buffer, dev);
+       isapnp_print_configuration(buffer, dev);
+       for (res = (struct isapnp_resources *)dev->sysdata, block = 0; res; res = res->next, block++) {
+               isapnp_printf(buffer, "%sResources %i\n", space, block);
+               isapnp_print_resources(buffer, "      ", res);
+               for (resa = res->alt, block1 = 1; resa; resa = resa->alt, block1++) {
+                       isapnp_printf(buffer, "%s  Alternate resources %i:%i\n", space, block, block1);
+                       isapnp_print_resources(buffer, "        ", resa);
+               }
+       }
+}
+
+/*
+ *  Main read routine
+ */
+static void isapnp_info_read(isapnp_info_buffer_t *buffer)
+{
+       struct pci_bus *card;
+       struct pci_dev *dev;
+       
+       for (card = isapnp_cards; card; card = card->next) {
+               isapnp_printf(buffer, "Card %i '", card->number);
+               isapnp_print_devid(buffer, card->vendor, card->device);
+               isapnp_printf(buffer, ":%s'", card->name[0]?card->name:"Unknown");
+               if (card->pnpver)
+                       isapnp_printf(buffer, " PnP version %x.%x", card->pnpver >> 4, card->pnpver & 0x0f);
+               if (card->productver)
+                       isapnp_printf(buffer, " Product version %x.%x", card->productver >> 4, card->productver & 0x0f);
+               isapnp_printf(buffer,"\n");
+               for (dev = card->devices; dev; dev = dev->sibling)
+                       isapnp_print_device(buffer, dev);
+       }
+}
+
+/*
+ *
+ */
+
+static struct pci_bus *isapnp_info_card;
+static struct pci_dev *isapnp_info_device;
+
+static char *isapnp_get_str(char *dest, char *src, int len)
+{
+       int c;
+
+       while (*src == ' ' || *src == '\t')
+               src++;
+       if (*src == '"' || *src == '\'') {
+               c = *src++;
+               while (--len > 0 && *src && *src != c) {
+                       *dest++ = *src++;
+               }
+               if (*src == c)
+                       src++;
+       } else {
+               while (--len > 0 && *src && *src != ' ' && *src != '\t') {
+                       *dest++ = *src++;
+               }
+       }
+       *dest = 0;
+       while (*src == ' ' || *src == '\t')
+               src++;
+       return src;
+}
+
+static unsigned char isapnp_get_hex(unsigned char c)
+{
+       if (c >= '0' || c <= '9')
+               return c - '0';
+       if (c >= 'a' || c <= 'f')
+               return (c - 'a') + 10;
+       if (c >= 'A' || c <= 'F')
+               return (c - 'A') + 10;
+       return 0;
+}
+
+static unsigned int isapnp_parse_id(const char *id)
+{
+       if (strlen(id) != 7) {
+               printk("isapnp: wrong PnP ID\n");
+               return 0;
+       }
+       return (ISAPNP_VENDOR(id[0], id[1], id[2])<<16) |
+                       (isapnp_get_hex(id[3])<<4) |
+                       (isapnp_get_hex(id[4])<<0) |
+                       (isapnp_get_hex(id[5])<<12) |
+                       (isapnp_get_hex(id[6])<<8);
+}
+
+static int isapnp_set_card(char *line)
+{
+       int idx, idx1;
+       unsigned int id;
+       char index[16], value[32];
+
+       isapnp_info_card = NULL;
+       line = isapnp_get_str(index, line, sizeof(index));
+       isapnp_get_str(value, line, sizeof(value));
+       idx = idx1 = simple_strtoul(index, NULL, 0);
+       id = isapnp_parse_id(value);
+       isapnp_info_card = isapnp_find_card(id >> 16, id & 0xffff, NULL);
+       while (isapnp_info_card && idx1-- > 0)
+               isapnp_info_card = isapnp_find_card(id >> 16, id & 0xffff, isapnp_info_card);
+       if (isapnp_info_card == NULL) {
+               printk("isapnp: card '%s' order %i not found\n", value, idx);
+               return 1;
+       }
+       if (isapnp_cfg_begin(isapnp_info_card->number, -1)<0) {
+               printk("isapnp: configuration start sequence for device '%s' failed\n", value);
+               isapnp_info_card = NULL;
+               return 1;
+       }
+       return 0;
+}
+
+static int isapnp_select_csn(char *line)
+{
+       int csn;
+       char index[16], value[32];
+
+       isapnp_info_device = NULL;
+       isapnp_get_str(index, line, sizeof(index));
+       csn = simple_strtoul(index, NULL, 0);
+       for (isapnp_info_card = isapnp_cards; isapnp_info_card; isapnp_info_card = isapnp_info_card->next)
+               if (isapnp_info_card->number == csn)
+                       break;
+       if (isapnp_info_card == NULL) {
+               printk("isapnp: cannot find CSN %i\n", csn);
+               return 1;
+       }
+       if (isapnp_cfg_begin(isapnp_info_card->number, -1)<0) {
+               printk("isapnp: configuration start sequence for device '%s' failed\n", value);
+               isapnp_info_card = NULL;
+               return 1;
+       }
+       return 0;
+}
+
+static int isapnp_set_device(char *line)
+{
+       int idx, idx1;
+       unsigned int id;
+       char index[16], value[32];
+
+       line = isapnp_get_str(index, line, sizeof(index));
+       isapnp_get_str(value, line, sizeof(value));
+       idx = idx1 = simple_strtoul(index, NULL, 0);
+       id = isapnp_parse_id(value);
+       isapnp_info_device = isapnp_find_dev(isapnp_info_card, id >> 16, id & 0xffff, NULL);
+       while (isapnp_info_device && idx-- > 0)
+               isapnp_info_device = isapnp_find_dev(isapnp_info_card, id >> 16, id & 0xffff, isapnp_info_device);
+       if (isapnp_info_device == NULL) {
+               printk("isapnp: device '%s' order %i not found\n", value, idx);
+               return 1;
+       }
+       isapnp_device(isapnp_info_device->devfn);
+       return 0;
+}
+
+static int isapnp_autoconfigure(void)
+{
+       if (isapnp_info_device == NULL) {
+               printk("isapnp: device is not set\n");
+               return 0;
+       }
+       if (isapnp_info_device->active)
+               isapnp_info_device->deactivate(isapnp_info_device);
+       if (isapnp_info_device->prepare(isapnp_info_device) < 0) {
+               printk("isapnp: cannot prepare device for the activation");
+               return 0;
+       }
+       if (isapnp_info_device->activate(isapnp_info_device) < 0) {
+               printk("isapnp: cannot activate device");
+               return 0;
+       }
+       return 0;
+}
+
+static int isapnp_set_port(char *line)
+{
+       int idx, port;
+       char index[16], value[32];
+
+       line = isapnp_get_str(index, line, sizeof(index));
+       isapnp_get_str(value, line, sizeof(value));
+       idx = simple_strtoul(index, NULL, 0);
+       port = simple_strtoul(value, NULL, 0);
+       if (idx < 0 || idx > 7) {
+               printk("isapnp: wrong port index %i\n", idx);
+               return 1;
+       }
+       if (port < 0 || port > 0xffff) {
+               printk("isapnp: wrong port value 0x%x\n", port);
+               return 1;
+       }
+       isapnp_write_word(ISAPNP_CFG_PORT + (idx << 1), port);
+       if (isapnp_info_device->resource[idx].start == DEVICE_IO_NOTSET)
+               return 0;
+       if (isapnp_info_device->resource[idx].start == DEVICE_IO_AUTO) {
+               isapnp_info_device->resource[idx].start = port;
+               isapnp_info_device->resource[idx].end += port - 1;
+       } else {
+               isapnp_info_device->resource[idx].end -= isapnp_info_device->resource[idx].start;
+               isapnp_info_device->resource[idx].start = port;
+               isapnp_info_device->resource[idx].end += port;
+       }
+       return 0;
+}
+static int isapnp_set_irq(char *line)
+{
+       int idx, irq;
+       char index[16], value[32];
+
+       line = isapnp_get_str(index, line, sizeof(index));
+       isapnp_get_str(value, line, sizeof(value));
+       idx = simple_strtoul(index, NULL, 0);
+       irq = simple_strtoul(value, NULL, 0);
+       if (idx < 0 || idx > 1) {
+               printk("isapnp: wrong IRQ index %i\n", idx);
+               return 1;
+       }
+       if (irq == 2)
+               irq = 9;
+       if (irq < 0 || irq > 15) {
+               printk("isapnp: wrong IRQ value %i\n", irq);
+               return 1;
+       }
+       isapnp_write_byte(ISAPNP_CFG_IRQ + (idx << 1), irq);
+       if (idx == 0) {
+                if (isapnp_info_device->irq == DEVICE_IRQ_NOTSET)
+                       return 0;
+                isapnp_info_device->irq = irq;
+       } else {
+                if (isapnp_info_device->irq2 == DEVICE_IRQ_NOTSET)
+                       return 0;
+                isapnp_info_device->irq2 = irq;        
+       }
+       return 0;
+}
+static int isapnp_set_dma(char *line)
+{
+       int idx, dma;
+       char index[16], value[32];
+
+       line = isapnp_get_str(index, line, sizeof(index));
+       isapnp_get_str(value, line, sizeof(value));
+       idx = simple_strtoul(index, NULL, 0);
+       dma = simple_strtoul(value, NULL, 0);
+       if (idx < 0 || idx > 1) {
+               printk("isapnp: wrong DMA index %i\n", idx);
+               return 1;
+       }
+       if (dma < 0 || dma > 7) {
+               printk("isapnp: wrong DMA value %i\n", dma);
+               return 1;
+       }
+       isapnp_write_byte(ISAPNP_CFG_DMA + idx, dma);
+       if (isapnp_info_device->dma[idx] == DEVICE_DMA_NOTSET)
+               return 0;
+       isapnp_info_device->dma[idx] = dma;
+       return 0;
+}
+static int isapnp_set_mem(char *line)
+{
+       int idx;
+       unsigned int mem;
+       char index[16], value[32];
+
+       line = isapnp_get_str(index, line, sizeof(index));
+       isapnp_get_str(value, line, sizeof(value));
+       idx = simple_strtoul(index, NULL, 0);
+       mem = simple_strtoul(value, NULL, 0);
+       if (idx < 0 || idx > 3) {
+               printk("isapnp: wrong memory index %i\n", idx);
+               return 1;
+       }
+       mem >>= 8;
+       isapnp_write_word(ISAPNP_CFG_MEM + (idx<<2), mem & 0xffff);
+       if (isapnp_info_device->resource[idx + 8].start == DEVICE_IO_NOTSET)
+               return 0;
+       if (isapnp_info_device->resource[idx + 8].start == DEVICE_IO_AUTO) {
+               isapnp_info_device->resource[idx + 8].start = mem & ~0x00ffff00;
+               isapnp_info_device->resource[idx + 8].end += (mem & ~0x00ffff00) - 1;
+       } else {
+               isapnp_info_device->resource[idx + 8].end -= isapnp_info_device->resource[idx + 8].start;
+               isapnp_info_device->resource[idx + 8].start = mem & ~0x00ffff00;
+               isapnp_info_device->resource[idx + 8].end += mem & ~0x00ffff00;
+       }
+       return 0;
+}
+static int isapnp_poke(char *line, int what)
+{
+       int reg;
+       unsigned int val;
+       char index[16], value[32];
+
+       line = isapnp_get_str(index, line, sizeof(index));
+       isapnp_get_str(value, line, sizeof(value));
+       reg = simple_strtoul(index, NULL, 0);
+       val = simple_strtoul(value, NULL, 0);
+       if (reg < 0 || reg > 127) {
+               printk("isapnp: wrong register %i\n", reg);
+               return 1;
+       }
+       switch (what) {
+       case 1:
+               isapnp_write_word(reg, val);
+               break;
+       case 2:
+               isapnp_write_dword(reg, val);
+               break;
+       default:
+               isapnp_write_byte(reg, val);
+               break;
+       }
+       return 0;
+}
+static int isapnp_decode_line(char *line)
+{
+       char cmd[32];
+
+       line = isapnp_get_str(cmd, line, sizeof(cmd));
+       if (!strcmp(cmd, "card"))
+               return isapnp_set_card(line);
+       if (!strcmp(cmd, "csn"))
+               return isapnp_select_csn(line);
+       if (!isapnp_info_card) {
+               printk("isapnp: card is not selected\n");
+               return 1;
+       }
+       if (!strncmp(cmd, "dev", 3))
+               return isapnp_set_device(line);
+       if (!isapnp_info_device) {
+               printk("isapnp: device is not selected\n");
+               return 1;
+       }
+       if (!strncmp(cmd, "auto", 4))
+               return isapnp_autoconfigure();
+       if (!strncmp(cmd, "act", 3)) {
+               isapnp_activate(isapnp_info_device->devfn);
+               isapnp_info_device->active = 1;
+               return 0;
+       }
+       if (!strncmp(cmd, "deact", 5)) {
+               isapnp_deactivate(isapnp_info_device->devfn);
+               isapnp_info_device->active = 0;
+               return 0;
+       }
+       if (!strcmp(cmd, "port"))
+               return isapnp_set_port(line);
+       if (!strcmp(cmd, "irq"))
+               return isapnp_set_irq(line);
+       if (!strcmp(cmd, "dma"))
+               return isapnp_set_dma(line);
+       if (!strncmp(cmd, "mem", 3))
+               return isapnp_set_mem(line);
+       if (!strcmp(cmd, "poke"))
+               return isapnp_poke(line, 0);
+       if (!strcmp(cmd, "pokew"))
+               return isapnp_poke(line, 1);
+       if (!strcmp(cmd, "poked"))
+               return isapnp_poke(line, 2);
+       printk("isapnp: wrong command '%s'\n", cmd);
+       return 1;
+}
+
+/*
+ *  Main write routine
+ */
+
+static void isapnp_info_write(isapnp_info_buffer_t *buffer)
+{
+       int c, idx, idx1 = 0;
+       char line[128];
+
+       if (buffer->size <= 0)
+               return;
+       isapnp_info_card = NULL;
+       isapnp_info_device = NULL;
+       for (idx = 0; idx < buffer->size; idx++) {
+               c = buffer->buffer[idx];
+               if (c == '\n') {
+                       line[idx1] = '\0';
+                       if (line[0] != '#') {
+                               if (isapnp_decode_line(line))
+                                       goto __end;
+                       }
+                       idx1 = 0;
+                       continue;
+               }
+               if (idx1 >= sizeof(line)-1) {
+                       printk("isapnp: line too long, aborting\n");
+                       return;
+               }
+               line[idx1++] = c;
+       }
+      __end:
+       if (isapnp_info_card)
+               isapnp_cfg_end();
+}
index f35145d21825f84db81eff218355ed825718a753..a0a009071c6902081fe44bb5f683bfd2d4c26acd 100644 (file)
@@ -1074,7 +1074,7 @@ NCR53c7x0_init (struct Scsi_Host *host) {
 
     NCR53c7x0_driver_init (host);
 
-    if (request_irq(host->irq, NCR53c7x0_intr, 0, "53c7xx", host))
+    if (request_irq(host->irq, NCR53c7x0_intr, SA_SHIRQ, "53c7xx", host))
     {
        printk("scsi%d : IRQ%d not free, detaching\n",
                host->host_no, host->irq);
index 4223226a7b4dae3ec0e0b86f06c900906d484cb6..ecfbb8778862c05cd94b0c0c57b4818813bf0ca5 100644 (file)
@@ -39,8 +39,6 @@
 #include <asm/amigaints.h>
 #include <asm/amigahw.h>
 
-#include <asm/pgtable.h>
-
 #ifdef USE_BOTTOM_HALF
 #include <linux/tqueue.h>
 #include <linux/interrupt.h>
index d7150954872bdcbde7f840efa8ba327d387372c7..755d48bb9eba420cb56a401f33790b3102a5a45d 100644 (file)
 #include "hosts.h"
 #include "constants.h"
 
-#define SHUTDOWN_SIGS  (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM))
+#ifdef MODULE
+       #define SHUTDOWN_SIGS   (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM))
+#else
+       #define SHUTDOWN_SIGS   (0UL)
+#endif
 
 #ifdef DEBUG
     #define SENSE_TIMEOUT SCSI_TIMEOUT
diff --git a/drivers/sound/lowlevel/awe_compat-fbsd.h b/drivers/sound/lowlevel/awe_compat-fbsd.h
deleted file mode 100644 (file)
index 8ebe5ca..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * sound/awe_compat.h
- *
- * Compat defines for the AWE32/SB32/AWE64 wave table synth driver.
- *   version 0.4.3; Nov. 1, 1998
- *
- * Copyright (C) 1996-1998 Takashi Iwai
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef AWE_COMPAT_H_DEF
-#define AWE_COMPAT_H_DEF
-
-/*================================================================
- * version check
- *================================================================*/
-
-/* FreeBSD version check */
-#include <i386/isa/sound/awe_config.h>
-
-#define AWE_OBSOLETE_VOXWARE
-#if __FreeBSD__ >= 2
-#  include <osreldate.h>
-#  if __FreeBSD_version >= 300000
-#    undef AWE_OBSOLETE_VOXWARE
-#  endif
-#endif
-#ifdef __linux__
-#  include <linux/config.h>
-#endif
-
-
-/*================================================================
- * INCLUDE OTHER HEADER FILES
- *================================================================*/
-
-/* reading configuration of sound driver */
-
-#include <i386/isa/sound/sound_config.h>
-#ifdef AWE_OBSOLETE_VOXWARE
-
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AWE32)
-#define CONFIG_AWE32_SYNTH
-#endif
-
-#else /* AWE_OBSOLETE_VOXWARE */
-
-#ifdef HAS_LOWLEVEL_H
-#include "lowlevel.h"
-#endif
-
-#if defined(CONFIGURE_SOUNDCARD) && defined(CONFIG_AWE32)
-#  define CONFIG_AWE32_SYNTH
-#endif
-
-#endif /* AWE_OBSOLETE_VOXWARE */
-
-
-/*================================================================
- * include AWE header files
- *================================================================*/
-
-#if defined(CONFIG_AWE32_SYNTH) || defined(CONFIG_AWE32_SYNTH_MODULE)
-
-#include <i386/isa/sound/awe_hw.h>
-#include <i386/isa/sound/awe_version.h>
-#include <i386/isa/sound/awe_voice.h>
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-/* include finetune table */
-#ifdef AWE_OBSOLETE_VOXWARE
-#  define SEQUENCER_C
-#endif
-#include <i386/isa/sound/tuning.h>
-#include <machine/ultrasound.h>
-#endif /* AWE_HAS_GUS_COMPATIBILITY */
-
-
-/*----------------------------------------------------------------
- * compatibility macros for AWE32 driver
- *----------------------------------------------------------------*/
-
-/* redefine following macros */
-#undef IOCTL_IN
-#undef IOCTL_OUT
-#undef OUTW
-#undef COPY_FROM_USER
-#undef COPY_TO_USER
-#undef GET_BYTE_FROM_USER
-#undef GET_SHORT_FROM_USER
-#undef IOCTL_TO_USER
-  
-/* inline is not checked yet.. maybe it'll work */
-#define INLINE /*inline*/
-
-#define KERN_WARNING /**/
-
-/*----------------------------------------------------------------
- * memory management for freebsd
- *----------------------------------------------------------------*/
-
-/* i/o requests; nothing */
-#define awe_check_port()       0       /* always false */
-#define awe_request_region()   /* nothing */
-#define awe_release_region()   /* nothing */
-
-#define AWE_DYNAMIC_BUFFER
-
-#define my_malloc_init(ptr)    /* nothing */
-#define my_malloc_memptr()     0
-#define my_malloc(size)                malloc(size, M_TEMP, M_WAITOK)
-#define my_free(ptr)           if (ptr) {free(ptr, M_TEMP);}
-
-#define INIT_TABLE(buffer,index,nums,type) {buffer=NULL; index=0;}
-
-/*----------------------------------------------------------------
- * i/o interfaces for freebsd
- *----------------------------------------------------------------*/
-
-/* according to linux rule; the arguments are swapped */
-#define OUTW(data,addr)                outw(addr, data)
-
-#define COPY_FROM_USER(target,source,offs,count) \
-       uiomove(((caddr_t)(target)),(count),((struct uio *)(source)))
-#define COPY_TO_USER(target,source,offs,count) \
-       uiomove(((caddr_t)(source)),(count),((struct uio *)(target)))
-#define GET_BYTE_FROM_USER(target,addr,offs) \
-       uiomove(((char*)&(target)), 1, ((struct uio *)(addr)))
-#define GET_SHORT_FROM_USER(target,addr,offs) \
-       uiomove(((char*)&(target)), 2, ((struct uio *)(addr)))
-#define IOCTL_TO_USER(target,offs,source,count) \
-       memcpy(&((target)[offs]), (source), (count))
-#define IO_WRITE_CHECK(cmd)    (cmd & IOC_IN)
-#define IOCTL_IN(arg)          (*(int*)(arg))
-#define IOCTL_OUT(arg,val)     (*(int*)(arg) = (val))
-#define BZERO(target,len)      bzero((caddr_t)target, len)
-#define MEMCPY(dst,src,len)    bcopy((caddr_t)src, (caddr_t)dst, len)
-
-#ifndef AWE_OBSOLETE_VOXWARE
-#  define printk printf
-#  define RET_ERROR(err)               -err
-#endif
-
-
-/* old style device tables (not modulized) */
-#define sound_alloc_synthdev() \
-       (num_synths >= MAX_SYNTH_DEV ? -1 : num_synths++)
-#define sound_alloc_mixerdev() \
-       (num_mixers >= MAX_MIXER_DEV ? -1 : num_mixers++)
-#define sound_alloc_mididev() \
-       (num_midis >= MAX_MIXER_DEV ? -1 : num_midis++)
-#define sound_unload_synthdev(dev)     /**/
-#define sound_unload_mixerdev(dev)     /**/
-#define sound_unload_mididev(dev)      /**/
-
-
-#endif /* CONFIG_AWE32_SYNTH */
-
-#endif /* AWE_COMPAT_H_DEF */
diff --git a/drivers/sound/lowlevel/awe_compat-linux.h b/drivers/sound/lowlevel/awe_compat-linux.h
deleted file mode 100644 (file)
index 6ab482a..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * sound/awe_compat.h
- *
- * Compat defines for the AWE32/SB32/AWE64 wave table synth driver.
- *   version 0.4.3; Oct. 1, 1998
- *
- * Copyright (C) 1996-1998 Takashi Iwai
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef AWE_COMPAT_H_DEF
-#define AWE_COMPAT_H_DEF
-
-/*================================================================
- * version check
- *================================================================*/
-
-#include "awe_config.h"
-
-#define ASC_LINUX_VERSION(V,P,S)    (((V) * 65536) + ((P) * 256) + (S))
-
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif
-
-/* linux version check */
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
-#define AWE_OBSOLETE_VOXWARE
-#endif
-
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
-#define AWE_NEW_KERNEL_INTERFACE
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,80)
-#define AWE_MODULE_SUPPORT
-#endif
-#endif
-
-#ifdef AWE_OBSOLETE_VOXWARE
-#include "soundvers.h"
-#else
-#include "../soundvers.h"
-#endif
-
-#if defined(SOUND_INTERNAL_VERSION) && SOUND_INTERNAL_VERSION >= 0x30803
-/* OSS/Free-3.8 */
-#define AWE_NO_PATCHMGR
-#define AWE_OSS38
-#define HAS_LOWLEVEL_H
-#endif
-
-/*================================================================
- * INCLUDE OTHER HEADER FILES
- *================================================================*/
-
-/* set up module */
-
-#if defined(AWE_MODULE_SUPPORT) && defined(MODULE)
-#include <linux/config.h>
-#include <linux/string.h>
-#include <linux/module.h>
-#include "../soundmodule.h"
-#endif
-
-
-/* reading configuration of sound driver */
-
-#ifdef AWE_OBSOLETE_VOXWARE
-
-#include "sound_config.h"
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AWE32)
-#define CONFIG_AWE32_SYNTH
-#endif
-
-#else /* AWE_OBSOLETE_VOXWARE */
-
-#ifdef HAS_LOWLEVEL_H
-#include "lowlevel.h"
-#endif
-
-#include "../sound_config.h"
-
-#endif /* AWE_OBSOLETE_VOXWARE */
-
-
-/*================================================================
- * include AWE header files
- *================================================================*/
-
-#if defined(CONFIG_AWE32_SYNTH) || defined(CONFIG_AWE32_SYNTH_MODULE)
-
-#include "awe_hw.h"
-#include "awe_version.h"
-#include <linux/awe_voice.h>
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-/* include finetune table */
-#ifdef AWE_OBSOLETE_VOXWARE
-#  include "tuning.h"
-#else
-#  include "../tuning.h"
-#endif
-#include <linux/ultrasound.h>
-#endif /* AWE_HAS_GUS_COMPATIBILITY */
-
-
-/*----------------------------------------------------------------
- * compatibility macros for AWE32 driver
- *----------------------------------------------------------------*/
-
-/* redefine following macros */
-#undef IOCTL_IN
-#undef IOCTL_OUT
-#undef OUTW
-#undef COPY_FROM_USER
-#undef COPY_TO_USER
-#undef GET_BYTE_FROM_USER
-#undef GET_SHORT_FROM_USER
-#undef IOCTL_TO_USER
-  
-/* use inline prefix */
-#define INLINE inline
-
-/*----------------------------------------------------------------
- * memory management for linux
- *----------------------------------------------------------------*/
-
-#ifdef AWE_OBSOLETE_VOXWARE
-/* old type linux system */
-
-/* i/o requests; nothing */
-#define awe_check_port()       0       /* always false */
-#define awe_request_region()   /* nothing */
-#define awe_release_region()   /* nothing */
-
-static int _mem_start;  /* memory pointer for permanent buffers */
-
-#define my_malloc_init(memptr) _mem_start = (memptr)
-#define my_malloc_memptr()     _mem_start
-#define my_free(ptr)   /* do nothing */
-
-/* allocate buffer only once */
-#define INIT_TABLE(buffer,index,nums,type) {\
-PERMANENT_MALLOC(buffer, char*, size, _mem_start); index = (nums);\
-}
-
-#else
-
-#define AWE_DYNAMIC_BUFFER
-
-#define my_malloc_init(ptr)    /* nothing */
-#define my_malloc_memptr()     0
-#define my_malloc(size)                vmalloc(size)
-#define my_free(ptr)           if (ptr) {vfree(ptr);}
-
-/* do not allocate buffer at beginning */
-#define INIT_TABLE(buffer,index,nums,type) {buffer=NULL; index=0;}
-
-/* old type macro */
-#define RET_ERROR(err)         -err
-
-#endif
-
-/*----------------------------------------------------------------
- * i/o interfaces for linux
- *----------------------------------------------------------------*/
-
-#define OUTW(data,addr)                outw(data, addr)
-
-#ifdef AWE_NEW_KERNEL_INTERFACE
-#define COPY_FROM_USER(target,source,offs,count) \
-       copy_from_user(target, (source)+(offs), count)
-#define GET_BYTE_FROM_USER(target,addr,offs) \
-       get_user(target, (unsigned char*)&((addr)[offs]))
-#define GET_SHORT_FROM_USER(target,addr,offs) \
-       get_user(target, (unsigned short*)&((addr)[offs]))
-#ifdef AWE_OSS38
-#define IOCTL_TO_USER(target,offs,source,count) \
-       memcpy(target, (source)+(offs), count)
-#define IO_WRITE_CHECK(cmd)    (_SIOC_DIR(cmd) & _IOC_WRITE)
-#else
-#define IOCTL_TO_USER(target,offs,source,count) \
-       copy_to_user(target, (source)+(offs), count)
-#define IO_WRITE_CHECK(cmd)    (_IOC_DIR(cmd) & _IOC_WRITE)
-#endif /* AWE_OSS38 */
-#define COPY_TO_USER   IOCTL_TO_USER
-#define IOCTL_IN(arg)  (*(int*)(arg))
-#define IOCTL_OUT(arg,val) (*(int*)(arg) = (val))
-
-#else /* old type i/o */
-#define COPY_FROM_USER(target,source,offs,count) \
-       memcpy_fromfs(target, (source)+(offs), (count))
-#define GET_BYTE_FROM_USER(target,addr,offs) \
-       *((char  *)&(target)) = get_fs_byte((addr)+(offs))
-#define GET_SHORT_FROM_USER(target,addr,offs) \
-       *((short *)&(target)) = get_fs_word((addr)+(offs))
-#ifdef AWE_OSS38
-#define IOCTL_TO_USER(target,offs,source,count) \
-       memcpy(target, (source)+(offs), count)
-#define COPY_TO_USER(target,offs,source,count)  \
-       memcpy_tofs(target, (source)+(offs), (count))
-#define IOCTL_IN(arg)  (*(int*)(arg))
-#define IOCTL_OUT(arg,val) (*(int*)(arg) = (val))
-#define IO_WRITE_CHECK(cmd)    (_SIOC_DIR(cmd) & _IOC_WRITE)
-#else /* AWE_OSS38 */
-#define IOCTL_TO_USER(target,offs,source,count) \
-       memcpy_tofs(target, (source)+(offs), (count))
-#define COPY_TO_USER   IOCTL_TO_USER
-#define IOCTL_IN(arg)          get_fs_long((long *)(arg))
-#define IOCTL_OUT(arg,ret)     snd_ioctl_return((int *)arg, ret)
-#define IO_WRITE_CHECK(cmd)    (cmd & IOC_IN)
-#endif /* AWE_OSS38 */
-
-#endif /* AWE_NEW_KERNEL_INTERFACE */
-
-#define BZERO(target,len)      memset(target, 0, len)
-#define MEMCPY(dst,src,len)    memcpy(dst, src, len)
-
-/* old style device tables (not modulized) */
-#ifndef AWE_MODULE_SUPPORT
-
-#define sound_alloc_synthdev() \
-       (num_synths >= MAX_SYNTH_DEV ? -1 : num_synths++)
-#define sound_alloc_mixerdev() \
-       (num_mixers >= MAX_MIXER_DEV ? -1 : num_mixers++)
-#define sound_alloc_mididev() \
-       (num_midis >= MAX_MIXER_DEV ? -1 : num_midis++)
-#define sound_unload_synthdev(dev)     /**/
-#define sound_unload_mixerdev(dev)     /**/
-#define sound_unload_mididev(dev)      /**/
-
-#endif /* AWE_MODULE_SUPPORT */
-
-#endif /* CONFIG_AWE32_SYNTH */
-
-#endif /* AWE_COMPAT_H_DEF */
index 6039a8b2102e33d0f856a115ec767321c0773c13..704ec051f503c880134ac4e7186baa229a4c8a84 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/module.h>
 
 #include "usb.h"
+#define AUDIO_DEBUG 1
 
 static int usb_audio_probe(struct usb_device *dev);
 static void usb_audio_disconnect(struct usb_device *dev);
@@ -35,23 +36,23 @@ static int usb_audio_irq(int state, void *buffer, int len, void *dev_id)
 
 static int usb_audio_probe(struct usb_device *dev)
 {
-       struct usb_interface_descriptor *interface;
+       struct usb_interface_descriptor *intf_desc;
        struct usb_endpoint_descriptor *endpoint;
        struct usb_audio *aud;
+       int bEndpointAddress = 0;
        int i;
        int na=0;
        
-       interface = &dev->config[0].altsetting[0].interface[0];
 
        for (i=0; i<dev->config[0].bNumInterfaces; i++) {
-               endpoint = &interface->endpoint[i];
+               intf_desc = &dev->config->interface[i].altsetting[0];
 
-               if(interface->bInterfaceClass != 1) 
+               if(intf_desc->bInterfaceClass != 1) 
                        continue;
 
                printk(KERN_INFO "USB audio device detected.\n");
        
-               switch(interface->bInterfaceSubClass) {
+               switch(intf_desc->bInterfaceSubClass) {
                        case 0x01:
                                printk(KERN_INFO "audio: Control device.\n");
                                break;
@@ -74,8 +75,6 @@ static int usb_audio_probe(struct usb_device *dev)
                aud->dev = dev;
                dev->private = aud;
 
-               endpoint = &interface->endpoint[0];
-
 //             if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
 //                     printk (KERN_INFO " Failed usb_set_configuration: Audio\n");
 //                     break;
@@ -83,11 +82,11 @@ static int usb_audio_probe(struct usb_device *dev)
 //             usb_set_protocol(dev, 0);
 //             usb_set_idle(dev, 0, 0);
         
-               usb_request_irq(dev,
-                        usb_rcvctrlpipe(dev, endpoint->bEndpointAddress),
-                        usb_audio_irq,
-                        endpoint->bInterval,
-                        aud);
+//             usb_request_irq(dev,
+//                        usb_rcvctrlpipe(dev, bEndpointAddress),
+//                        usb_audio_irq,
+//                        endpoint->bInterval,
+//                        aud);
 
                list_add(&aud->list, &usb_audio_list);
                
@@ -123,10 +122,16 @@ int usb_audio_init(void)
  
 void usb_audio_interface(struct usb_interface_descriptor *interface, u8 *data)
 {
+#ifdef AUDIO_DEBUG
+       printk(KERN_DEBUG "usb_audio_interface.\n");
+#endif
 }
 
 void usb_audio_endpoint(struct usb_endpoint_descriptor *interface, u8 *data)
 {
+#ifdef AUDIO_DEBUG
+       printk(KERN_DEBUG "usb_audio_interface.\n");
+#endif
 }
 
 #ifdef MODULE
index 64116d483d22715afc6c8731a62d78733ab2bc58..072d769014b9236572a25ff97f7495d9cfceada4 100644 (file)
@@ -199,7 +199,7 @@ static void usb_hub_configure(struct usb_hub *hub)
 
 static int hub_probe(struct usb_device *dev)
 {
-       struct usb_interface_descriptor *interface;
+       struct usb_interface_descriptor *intf_desc;
        struct usb_endpoint_descriptor *endpoint;
        struct usb_hub *hub;
        unsigned long flags;
@@ -212,20 +212,20 @@ static int hub_probe(struct usb_device *dev)
        if (dev->config[0].bNumInterfaces != 1)
                return -1;
 
-       interface = &dev->config[0].altsetting[0].interface[0];
+       intf_desc = &dev->config[0].interface[0].altsetting[0];
 
        /* Is it a hub? */
-       if (interface->bInterfaceClass != 9)
+       if (intf_desc->bInterfaceClass != 9)
                return -1;
-       if ((interface->bInterfaceSubClass != 0) &&
-           (interface->bInterfaceSubClass != 1))
+       if ((intf_desc->bInterfaceSubClass != 0) &&
+           (intf_desc->bInterfaceSubClass != 1))
                return -1;
 
        /* Multiple endpoints? What kind of mutant ninja-hub is this? */
-       if (interface->bNumEndpoints != 1)
+       if (intf_desc->bNumEndpoints != 1)
                return -1;
 
-       endpoint = &interface->endpoint[0];
+       endpoint = &intf_desc->endpoint[0];
 
        /* Output endpoint? Curiousier and curiousier.. */
        if (!(endpoint->bEndpointAddress & USB_DIR_IN))
index 44ab909862656c8b3fb1a467dd180e4aa1cfef24..60d454048282a594b41c92720e23c9b3b55f235f 100644 (file)
@@ -256,7 +256,7 @@ static struct miscdevice usb_mouse = {
 
 static int mouse_probe(struct usb_device *dev)
 {
-       struct usb_interface_descriptor *interface;
+       struct usb_interface_descriptor *intf_desc;
        struct usb_endpoint_descriptor *endpoint;
        struct mouse_state *mouse = &static_mouse_state;
 
@@ -269,19 +269,19 @@ static int mouse_probe(struct usb_device *dev)
                return -1;
 
        /* Is it a mouse interface? */
-       interface = &dev->config[0].altsetting[0].interface[0];
-       if (interface->bInterfaceClass != 3)
+       intf_desc = &dev->config[0].interface[0].altsetting[0];
+       if (intf_desc->bInterfaceClass != 3)
                return -1;
-       if (interface->bInterfaceSubClass != 1)
+       if (intf_desc->bInterfaceSubClass != 1)
                return -1;
-       if (interface->bInterfaceProtocol != 2)
+       if (intf_desc->bInterfaceProtocol != 2)
                return -1;
 
        /* Multiple endpoints? What kind of mutant ninja-mouse is this? */
-       if (interface->bNumEndpoints != 1)
+       if (intf_desc->bNumEndpoints != 1)
                return -1;
 
-       endpoint = &interface->endpoint[0];
+       endpoint = &intf_desc->endpoint[0];
 
        /* Output endpoint? Curiousier and curiousier.. */
        if (!(endpoint->bEndpointAddress & 0x80))
index 20cb728ba8a6e4e2b3ca33152816c2dbd2ca92fa..565fb3923b7d61f97f1d8bb791f8db0489e2af25 100644 (file)
@@ -213,7 +213,7 @@ static int usb_dump_config (const struct usb_config_descriptor *config,
                                const int active, char *buf, int *len)
 {
        int i, j;
-       struct usb_alternate_setting *as;
+       struct usb_interface *intf;
 
        if (!config) {          /* getting these some in 2.3.7; none in 2.3.6 */
                *len += sprintf (buf + *len, "(null Cfg. desc.)\n");
@@ -223,13 +223,13 @@ static int usb_dump_config (const struct usb_config_descriptor *config,
        if (usb_dump_config_descriptor (config, active, buf, len) < 0)
                return -1;
 
-       for (i = 0; i < config->num_altsetting; i++) {
-               as = config->altsetting + i;
-               if ((as) == NULL)
+       for (i = 0; i < config->bNumInterfaces; i++) {
+               intf = config->interface + i;
+               if ((intf) == NULL)
                        break;
 
-               for (j = 0; j < config->bNumInterfaces; j++)
-                       if (usb_dump_interface (as->interface + j, buf, len) < 0)
+               for (j = 0; j < intf->num_altsetting; j++)
+                       if (usb_dump_interface (intf->altsetting + j, buf, len) < 0)
                                return -1;
        }
 
index 56441efb7cf1bf3e4b872392954b305f876a0256..6e53155506da364ddd67cc2f223ac1dfdb18c9d4 100644 (file)
@@ -63,7 +63,10 @@ static LIST_HEAD(uhci_list);
 #define UHCI_DEBUG
 
 /*
- * Map status to standard result codes
+ * Map status to standard result codes.
+ *
+ * <status> is ((td->status >> 16) & 0xff) [a.k.a. uhci_status_bits(td->status)]
+ * <dir_out> is True for output TDs and False for input TDs.
  */
 static int uhci_map_status(int status, int dir_out)
 {
@@ -109,20 +112,19 @@ static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned
        /* locate the first failing td, if any */
 
        do {
-               status = (tmp->status >> 16) & 0xff;
+               status = uhci_status_bits(tmp->status);
                if (status) {
                        /* must reset the toggle on first error */
                        if (uhci_debug) {
                                printk(KERN_DEBUG "Set toggle from %x rval %ld\n",
                                        (unsigned int)tmp, rval ? *rval : 0);
                        }
-                       usb_settoggle(dev->usb, usb_pipeendpoint(tmp->info),
-                               usb_pipeout(tmp->info) ^ 1,
-                               (tmp->info >> 19) & 1);
+                       usb_settoggle(dev->usb, uhci_endpoint(tmp->info),
+                               uhci_packetout(tmp->info), uhci_toggle(tmp->info));
                        break;
                } else {
                    if (rval)
-                       *rval += (tmp->status & 0x3ff) + 1;
+                       *rval += uhci_actual_length(tmp->status);
                }
                if ((tmp->link & UHCI_PTR_TERM) ||
                    (tmp->link & UHCI_PTR_QH))
@@ -154,8 +156,8 @@ static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned
 
        if (status & 0x40) {
                /* endpoint has stalled - mark it halted */
-               usb_endpoint_halt(dev->usb, usb_pipeendpoint(tmp->info),
-                               usb_pipeout(tmp->info) ^ 1);
+               usb_endpoint_halt(dev->usb, uhci_endpoint(tmp->info),
+                               uhci_packetout(tmp->info));
                return USB_ST_STALL;
        }
 
@@ -164,7 +166,7 @@ static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned
                if (!rval)
                        return USB_ST_DATAUNDERRUN;
        }
-       return uhci_map_status(status, usb_pipeout(tmp->info) ^ 1);
+       return uhci_map_status(status, uhci_packetout(tmp->info));
 }
 
 /*
@@ -434,7 +436,7 @@ static void *uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb
        td->link = UHCI_PTR_TERM;               /* Terminate */
        td->status = status;                    /* In */
        td->info = destination | ((usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe)) - 1) << 21) |
-               (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << 19);
+               (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << TD_TOKEN_TOGGLE);
        td->buffer = virt_to_bus(dev->data);
        td->qh = qh;
        td->dev = dev;
@@ -507,14 +509,14 @@ static int uhci_compress_isochronous(struct usb_device *usb_dev, void *_isodesc)
        for (i = 0; i < isodesc->num; i++) {
                struct uhci_td *td = &isodesc->td[i];
                char *cdata = uhci_ptr_to_virt(td->buffer);
-               int n = (td->status + 1) & 0x7FF;
+               int n = uhci_actual_length(td->status);
 
                if ((cdata != data) && (n))
                        memmove(data, cdata, n);
 
 #ifdef UHCI_DEBUG
                /* Debugging */
-               if ((td->status >> 16) & 0xFF)
+               if (uhci_status_bits(td->status))
                        printk(KERN_DEBUG "error: %d %X\n", i,
                                (td->status >> 16));
 #endif
@@ -790,8 +792,8 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devre
        if (!td)
                return -ENOMEM;
 
-       /* The "pipe" thing contains the destination in bits 8--18, 0x2D is SETUP */
-       destination = (pipe & PIPE_DEVEP_MASK) | 0x2D;
+       /* The "pipe" thing contains the destination in bits 8--18. */
+       destination = (pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
 
        /* 3 errors */
        status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_SPD | (3 << 27);
@@ -805,11 +807,11 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devre
 
        /*
         * If direction is "send", change the frame from SETUP (0x2D)
-        * to OUT (0xE1). Else change it from SETUP to IN (0x69)
+        * to OUT (0xE1). Else change it from SETUP to IN (0x69).
         */
-       destination ^= (0x2D ^ 0x69);                   /* SETUP -> IN */
+       destination ^= (USB_PID_SETUP ^ USB_PID_IN);            /* SETUP -> IN */
        if (usb_pipeout(pipe))
-               destination ^= (0xE1 ^ 0x69);           /* IN -> OUT */
+               destination ^= (USB_PID_OUT ^ USB_PID_IN);      /* IN -> OUT */
 
        prevtd = td;
        td = uhci_td_alloc(dev);
@@ -829,7 +831,7 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devre
                        pktsze = maxsze;
 
                /* Alternate Data0/1 (start with Data1) */
-               destination ^= 1 << 19;
+               destination ^= 1 << TD_TOKEN_TOGGLE;
        
                td->status = status;                                    /* Status */
                td->info = destination | ((pktsze - 1) << 21);          /* pktsze bytes of data */
@@ -849,8 +851,8 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devre
        /*
         * Build the final TD for control status 
         */
-       destination ^= (0xE1 ^ 0x69);                   /* OUT -> IN */
-       destination |= 1 << 19;                         /* End in Data1 */
+       destination ^= (USB_PID_OUT ^ USB_PID_IN);      /* OUT -> IN */
+       destination |= 1 << TD_TOKEN_TOGGLE;            /* End in Data1 */
 
        td->status = status | TD_CTRL_IOC;                      /* no limit on errors on final packet */
        td->info = destination | (UHCI_NULL_DATA_SIZE << 21);   /* 0 bytes of data */
@@ -966,10 +968,10 @@ static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da
        int maxsze = usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe));
 
        if (usb_endpoint_halted(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) &&
-           usb_clear_halt(usb_dev, usb_pipeendpoint(pipe) | (pipe & 0x80)))
+           usb_clear_halt(usb_dev, usb_pipeendpoint(pipe) | (pipe & USB_DIR_IN)))
                return USB_ST_STALL;
 
-       /* The "pipe" thing contains the destination in bits 8--18 */
+       /* The "pipe" thing contains the destination in bits 8--18. */
        destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid (pipe);
 
        /* 3 errors */
@@ -993,7 +995,7 @@ static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da
                td->status = status;                                    /* Status */
                td->info = destination | ((pktsze-1) << 21) |
                        (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe),
-                               usb_pipeout(pipe)) << 19); /* pktsze bytes of data */
+                               usb_pipeout(pipe)) << TD_TOKEN_TOGGLE); /* pktsze bytes of data */
                td->buffer = virt_to_bus(data);
                td->backptr = &prevtd->link;
 
@@ -1053,7 +1055,7 @@ static void * uhci_request_bulk(struct usb_device *usb_dev, unsigned int pipe, u
        unsigned long destination, status;
        int maxsze = usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe));
 
-       /* The "pipe" thing contains the destination in bits 8--18, 0x69 is IN */
+       /* The "pipe" thing contains the destination in bits 8--18. */
        destination = (pipe & PIPE_DEVEP_MASK) | usb_packetid(pipe);
 
        /* Infinite errors is 0 */
@@ -1071,7 +1073,7 @@ static void * uhci_request_bulk(struct usb_device *usb_dev, unsigned int pipe, u
 
                td->status = status;                                    /* Status */
                td->info = destination | ((pktsze-1) << 21) |
-                       (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << 19); /* pktsze bytes of data */
+                       (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << TD_TOKEN_TOGGLE); /* pktsze bytes of data */
                td->buffer = virt_to_bus(data);
                td->backptr = &prevtd->link;
                td->qh = bulk_qh;
@@ -1338,7 +1340,7 @@ static void uhci_interrupt_notify(struct uhci *uhci)
                list_del(&td->irq_list);
                INIT_LIST_HEAD(&td->irq_list);
 
-               if (td->completed(uhci_map_status(status, usb_pipeout(td->info) ^ 1),
+               if (td->completed(uhci_map_status(uhci_status_bits(status), uhci_packetout(td->info)),
                    bus_to_virt(td->buffer), -1, td->dev_id)) {
                        list_add(&td->irq_list, &uhci->interrupt_list);
 
@@ -1346,10 +1348,10 @@ static void uhci_interrupt_notify(struct uhci *uhci)
                        if (!(td->status & TD_CTRL_IOS)) {
                                struct usb_device *usb_dev = td->dev->usb;
 
-                               usb_dotoggle(usb_dev, usb_pipeendpoint(td->info), usb_pipeout(td->info) ^ 1);
-                               td->info &= ~(1 << 19); /* clear data toggle */
-                               td->info |= usb_gettoggle(usb_dev, usb_pipeendpoint(td->info),
-                                       usb_pipeout(td->info) ^ 1) << 19; /* toggle between data0 and data1 */
+                               usb_dotoggle(usb_dev, uhci_endpoint(td->info), uhci_packetout(td->info));
+                               td->info &= ~(1 << TD_TOKEN_TOGGLE); /* clear data toggle */
+                               td->info |= usb_gettoggle(usb_dev, uhci_endpoint(td->info),
+                                       uhci_packetout(td->info)) << TD_TOKEN_TOGGLE; /* toggle between data0 and data1 */
                                td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
                                /* The HC removes it, so re-add it */
                                uhci_insert_td_in_qh(td->qh, td);
@@ -1359,7 +1361,7 @@ static void uhci_interrupt_notify(struct uhci *uhci)
 
                        /* marked for removal */
                        td->flags &= ~UHCI_TD_REMOVE;
-                       usb_dotoggle(usb_dev, usb_pipeendpoint(td->info), usb_pipeout(td->info) ^ 1);
+                       usb_dotoggle(usb_dev, uhci_endpoint(td->info), uhci_packetout(td->info));
                        uhci_remove_qh(td->qh->skel, td->qh);
                        uhci_qh_free(td->qh);
                        uhci_td_free(td);
@@ -1436,7 +1438,7 @@ static void uhci_init_ticktd(struct uhci *uhci)
        /* Don't clobber the frame */
        td->link = uhci->fl->frame[0];
        td->status = TD_CTRL_IOC;
-       td->info = (15 << 21) | 0x7f69;         /* (ignored) input packet, 16 bytes, device 127 */
+       td->info = (15 << 21) | (0x7f << 8) | USB_PID_IN;       /* (ignored) input packet, 16 bytes, device 127 */
        td->buffer = 0;
        td->qh = NULL;
 
index 51457fb5663ca70055e1ef32ef01b55d0e16c34d..1432b6909fe6c15debc8769b33eaf807dfb858db 100644 (file)
@@ -91,6 +91,13 @@ struct uhci_framelist {
 #define TD_CTRL_NAK            (1 << 19)       /* NAK Received */
 #define TD_CTRL_CRCTIME                (1 << 18)       /* CTC/Time Out Error */
 #define TD_CTRL_BITSTUFF       (1 << 17)       /* Bit Stuff Error */
+#define TD_CTRL_ACTLEN_MASK    0x7ff           /* actual length, encoded as n - 1 */
+
+#define TD_CTRL_ANY_ERROR      (TD_CTRL_STALLED | TD_CTRL_DBUFERR | \
+                                TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF)
+
+#define uhci_status_bits(ctrl_sts)     ((ctrl_sts >> 16) & 0xff)
+#define uhci_actual_length(ctrl_sts)   ((ctrl_sts + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */
 
 #define uhci_ptr_to_virt(x)    bus_to_virt(x & ~UHCI_PTR_BITS)
 
index e656cc6c4c8e34a3ffac8f0bb135ee1b7c0b9e87..36010f24c6a17f2c2bf89f55318768192dc598db 100644 (file)
@@ -13,28 +13,28 @@ static void usb_show_endpoint(struct usb_endpoint_descriptor *endpoint)
        usb_show_endpoint_descriptor(endpoint);
 }
 
-static void usb_show_interface(struct usb_interface_descriptor *interface)
+static void usb_show_interface(struct usb_interface_descriptor *altsetting)
 {
        int i;
 
-       usb_show_interface_descriptor(interface);
-       for (i = 0 ; i < interface->bNumEndpoints; i++)
-               usb_show_endpoint(interface->endpoint + i);
+       usb_show_interface_descriptor(altsetting);
+       for (i = 0 ; i < altsetting->bNumEndpoints; i++)
+               usb_show_endpoint(altsetting->endpoint + i);
 }
 
 static void usb_show_config(struct usb_config_descriptor *config)
 {
   int i, j;
-  struct usb_alternate_setting *as;
+  struct usb_interface *intf;
 
   usb_show_config_descriptor(config);
-  for (i = 0; i < config->num_altsetting; i++) {
-    as = config->altsetting + i;
-    if ((as) == NULL)
+  for (i = 0; i < config->bNumInterfaces; i++) {
+    intf = config->interface + i;
+    if ((intf) == NULL)
       break;
-    printk("\n  Alternate Setting: %d\n", i);
-    for (j = 0 ; j < config->bNumInterfaces; j++)
-      usb_show_interface(as->interface + j);
+    printk("\n  Interface: %d\n", i);
+    for (j = 0 ; j < intf->num_altsetting; j++)
+      usb_show_interface(intf->altsetting + j);
   }
 }
 
@@ -99,7 +99,7 @@ void usb_show_config_descriptor(struct usb_config_descriptor * desc)
 
 void usb_show_interface_descriptor(struct usb_interface_descriptor * desc)
 {
-       printk("  Interface:\n");
+       printk("  Alternate Setting: %2d\n", desc->bAlternateSetting);
        printk("    bLength             = %4d%s\n", desc->bLength,
                desc->bLength == USB_DT_INTERFACE_SIZE ? "" : " (!!!)");
        printk("    bDescriptorType     =   %02x\n", desc->bDescriptorType);
@@ -113,10 +113,13 @@ void usb_show_interface_descriptor(struct usb_interface_descriptor * desc)
 
 void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor * desc)
 {
+       char *bLengthCommentString = (USB_DT_AUCLSTEP_SIZE == desc->bLength) ?
+                 " (!Audio)" : " (!!!)";
+
        char *EndpointType[4] = { "Control", "Isochronous", "Bulk", "Interrupt" };
        printk("    Endpoint:\n");
        printk("      bLength             = %4d%s\n", desc->bLength,
-               desc->bLength == USB_DT_ENDPOINT_SIZE ? "" : " (!!!)");
+               desc->bLength == USB_DT_ENDPOINT_SIZE ? "" : bLengthCommentString);
        printk("      bDescriptorType     =   %02x\n", desc->bDescriptorType);
        printk("      bEndpointAddress    =   %02x (%s)\n", desc->bEndpointAddress,
                (desc->bEndpointAddress & 0x80) ? "in" : "out");
@@ -124,6 +127,10 @@ void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor * desc)
                EndpointType[3 & desc->bmAttributes]);
        printk("      wMaxPacketSize      = %04x\n", desc->wMaxPacketSize);
        printk("      bInterval           =   %02x\n", desc->bInterval);
+       if (USB_DT_AUCLSTEP_SIZE == desc->bLength) {
+               printk("      bRefresh            = %04x\n", desc->bRefresh);
+               printk("      bSynchAddress       =   %02x\n", desc->bSynchAddress);
+       }
 }
 
 void usb_show_hub_descriptor(struct usb_hub_descriptor * desc)
index a2359d0415425d74d19952714412e2229ff2e8ac..982afa36d96bbb9e36c7572b4557e12a1fe09841 100644 (file)
@@ -329,7 +329,7 @@ static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descri
        return parsed;// + ptr[parsed];
 }
 
-static int usb_parse_interface(struct usb_device *dev, struct usb_interface_descriptor *interface, unsigned char *ptr, int len)
+static int usb_parse_altsetting(struct usb_device *dev, struct usb_interface_descriptor *altsetting, unsigned char *ptr, int len)
 {
        int i;
        int parsed = usb_expect_descriptor(ptr, len, USB_DT_INTERFACE, USB_DT_INTERFACE_SIZE);
@@ -338,35 +338,35 @@ static int usb_parse_interface(struct usb_device *dev, struct usb_interface_desc
        if (parsed < 0)
                return parsed;
 
-       memcpy(interface, ptr + parsed, *ptr);
+       memcpy(altsetting, ptr + parsed, *ptr);
        len -= ptr[parsed];
        parsed += ptr[parsed];
 
        while((i=usb_check_descriptor(ptr+parsed, len, 0x24)) >= 0) {
-               usb_audio_interface(interface, ptr+parsed+i);
+               usb_audio_interface(altsetting, ptr+parsed+i);
                len -= ptr[parsed+i];
                parsed += ptr[parsed+i];
        }
        
-       if (interface->bNumEndpoints > USB_MAXENDPOINTS) {
+       if (altsetting->bNumEndpoints > USB_MAXENDPOINTS) {
                printk(KERN_WARNING "usb: too many endpoints.\n");
                return -1;
        }
 
-       interface->endpoint = (struct usb_endpoint_descriptor *)
-               kmalloc(interface->bNumEndpoints * sizeof(struct usb_endpoint_descriptor), GFP_KERNEL);
-       if (!interface->endpoint) {
+       altsetting->endpoint = (struct usb_endpoint_descriptor *)
+               kmalloc(altsetting->bNumEndpoints * sizeof(struct usb_endpoint_descriptor), GFP_KERNEL);
+       if (!altsetting->endpoint) {
                printk(KERN_WARNING "usb: out of memory.\n");
                return -1;      
        }
-       memset(interface->endpoint, 0, interface->bNumEndpoints*sizeof(struct usb_endpoint_descriptor));
+       memset(altsetting->endpoint, 0, altsetting->bNumEndpoints*sizeof(struct usb_endpoint_descriptor));
        
-       for (i = 0; i < interface->bNumEndpoints; i++) {
+       for (i = 0; i < altsetting->bNumEndpoints; i++) {
 //             if(((USB_DT_HID << 8) | 9) == *(unsigned short*)(ptr + parsed)) {
 //                     parsed += 9;    /* skip over the HID descriptor for now */
 //                     len -= 9;
 //             }
-               retval = usb_parse_endpoint(dev, interface->endpoint + i, ptr + parsed, len);
+               retval = usb_parse_endpoint(dev, altsetting->endpoint + i, ptr + parsed, len);
                if (retval < 0)
                        return retval;
                parsed += retval;
@@ -377,10 +377,13 @@ static int usb_parse_interface(struct usb_device *dev, struct usb_interface_desc
 
 static int usb_parse_config(struct usb_device *dev, struct usb_config_descriptor *config, unsigned char *ptr, int len)
 {
-       int i, j;
+       int i;
        int retval;
-       struct usb_alternate_setting *as;
+       struct usb_interface *intf;
+       struct usb_interface_descriptor as;     /* This is needing for copying. */
        int parsed = usb_expect_descriptor(ptr, len, USB_DT_CONFIG, 9);
+       unsigned short bNumInterfaces;
+       unsigned short bIntfaceNum = 0, bAltSetting = 0;
 
        if (parsed < 0)
                return parsed;
@@ -389,65 +392,65 @@ static int usb_parse_config(struct usb_device *dev, struct usb_config_descriptor
        len -= *ptr;
        parsed += *ptr;
        le16_to_cpus(&config->wTotalLength);
+       bNumInterfaces = config->bNumInterfaces;
 
-       if (config->bNumInterfaces > USB_MAXINTERFACES) {
+       if (bNumInterfaces > USB_MAXINTERFACES) {
                printk(KERN_WARNING "usb: too many interfaces.\n");
                return -1;
-
        }
 
-       config->altsetting = (struct usb_alternate_setting *)
-               kmalloc(USB_MAXALTSETTING * sizeof(struct usb_alternate_setting), GFP_KERNEL);
-       if (!config->altsetting) {
+       config->interface = (struct usb_interface *)
+               kmalloc(bNumInterfaces * sizeof(struct usb_interface), GFP_KERNEL);
+       if (!config->interface) {
                printk(KERN_WARNING "usb: out of memory.\n");
                return -1;
        }
-       config->act_altsetting = 0;
-       config->num_altsetting = 1;
-
-       config->altsetting->interface = (struct usb_interface_descriptor *)
-               kmalloc(config->bNumInterfaces * sizeof(struct usb_interface_descriptor), GFP_KERNEL);
-       if (!config->altsetting->interface) {
-               printk(KERN_WARNING "usb: out of memory.\n");
-               return -1;      
+       memset(config->interface, 
+                  0, (bNumInterfaces) * sizeof(struct usb_interface));
+
+       for (i = 0; i < bNumInterfaces; i++) {
+               intf = (config->interface) +i;
+               /* We have at least one interface */
+               intf->num_altsetting = 1;
+               intf->altsetting = (struct usb_interface_descriptor*)
+                       kmalloc((USB_MAXALTSETTING +1) * sizeof(struct usb_interface_descriptor), GFP_KERNEL);
+               if (!config->interface[i].altsetting) {
+                       printk(KERN_WARNING "usb: out of memory.\n");
+                       return -1;      
+               }
+               memset(intf->altsetting, 
+                          0, (USB_MAXALTSETTING+1) * sizeof(struct usb_interface_descriptor));
        }
-       memset(config->altsetting->interface, 
-              0, config->bNumInterfaces*sizeof(struct usb_interface_descriptor));
-       
-       for (i = 0; i < config->bNumInterfaces; i++) {
-               retval = usb_parse_interface(dev, config->altsetting->interface + i, ptr + parsed, len);
+               
+       /* Ok, we now have allocated the necessary structures, now decide
+     * where to put the parsed interface descriptors - sort by
+        * bAltSetting and bInterfaceNumber.
+        */
+       while (len > 0) {
+               retval = usb_parse_altsetting(dev, &as, ptr + parsed, len);
                if (retval < 0)
                        return parsed; // HACK
-//                     return retval;
+       //              return retval;
                parsed += retval;
                len -= retval;
-       }
-
-       printk("parsed = %d len = %d\n", parsed, len);
-
-       // now parse for additional alternate settings
-       for (j = 1; j < USB_MAXALTSETTING; j++) {
-               retval = usb_expect_descriptor(ptr + parsed, len, USB_DT_INTERFACE, 9);
-               if (retval) 
-                       break;
-               config->num_altsetting++;
-               as = config->altsetting + j;
-               as->interface = (struct usb_interface_descriptor *)
-                       kmalloc(config->bNumInterfaces * sizeof(struct usb_interface_descriptor), GFP_KERNEL);
-               if (!as->interface) {
-                       printk(KERN_WARNING "usb: out of memory.\n");
+               bIntfaceNum = as.bInterfaceNumber;
+               if (bIntfaceNum > config->bNumInterfaces) {
+                       printk(KERN_WARNING "usb: bInterfaceNumber %2u exceeding config->bNumINterfaces.\n", bIntfaceNum);
+                       return -1;
+               }
+               bAltSetting = as.bAlternateSetting;
+               if (bAltSetting > USB_MAXALTSETTING) {
+                       printk(KERN_WARNING "usb: illegal bAlternateSetting %2u.\n", bAltSetting);
                        return -1;
                }
-               memset(as->interface, 0, config->bNumInterfaces * sizeof(struct usb_interface_descriptor));
-               for (i = 0; i < config->bNumInterfaces; i++) {
-                       retval = usb_parse_interface(dev, as->interface + i, 
-                                        ptr + parsed, len);
-                       if (retval < 0)
-                               return parsed;
-                       parsed += retval;
-                       len -= retval;
+               if (bAltSetting > config->interface[bIntfaceNum].num_altsetting) {
+                       config->interface[bIntfaceNum].num_altsetting = bAltSetting +1;
                }
+               memcpy( &(config->interface[bIntfaceNum].altsetting[bAltSetting]),
+                               &as, sizeof(struct usb_interface_descriptor));
        }
+
+       printk("parsed = %d len = %d\n", parsed, len);
        return parsed;
 }
 
@@ -484,29 +487,29 @@ void usb_destroy_configuration(struct usb_device *dev)
 {
        int c, a, i;
        struct usb_config_descriptor *cf;
-       struct usb_alternate_setting *as;
-       struct usb_interface_descriptor *ifp;
+       struct usb_interface *intf;
+       struct usb_interface_descriptor *as;
        
        if (!dev->config)
                return;
 
        for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
                cf = &dev->config[c];
-               if (!cf->altsetting)
+               if (!cf->interface)
                        break;
-               for (a = 0; a < cf->num_altsetting; a++) {
-                       as = &cf->altsetting[a];
-                       if (as->interface == NULL)
+               for (a = 0; a < cf->bNumInterfaces; a++) {
+                       intf = &cf->interface[a];
+                       if (intf->altsetting == NULL)
                                break;
-                       for(i=0;i<cf->bNumInterfaces;i++) {
-                               ifp = &as->interface[i];
-                               if(ifp->endpoint==NULL)
+                       for(i=0; i <= USB_MAXALTSETTING ;i++) {
+                               as = &intf->altsetting[i];
+                               if(as->endpoint==NULL)
                                       break;
-                               kfree(ifp->endpoint);
+                               kfree(as->endpoint);
                        }
-                       kfree(as->interface);
+                       kfree(intf->altsetting);
                }
-               kfree(cf->altsetting);
+               kfree(cf->interface);
        }
        kfree(dev->config);
 
@@ -700,22 +703,24 @@ int usb_set_idle(struct usb_device *dev,  int duration, int report_id)
 
 static void usb_set_maxpacket(struct usb_device *dev)
 {
-       int i;
-       int act_as = dev->actconfig->act_altsetting;
-       struct usb_alternate_setting *as = dev->actconfig->altsetting + act_as;
+       int i, j;
+       struct usb_interface *intf;
 
        for (i=0; i<dev->actconfig->bNumInterfaces; i++) {
-               struct usb_interface_descriptor *ip = &as->interface[i];
-               struct usb_endpoint_descriptor *ep = ip->endpoint;
-               int e;
-
-               for (e=0; e<ip->bNumEndpoints; e++) {
-                       if (usb_endpoint_out(ep[e].bEndpointAddress))
-                               dev->epmaxpacketout[ep[e].bEndpointAddress & 0x0f] =
-                                       ep[e].wMaxPacketSize;
-                       else
-                               dev->epmaxpacketin [ep[e].bEndpointAddress & 0x0f] =
-                                       ep[e].wMaxPacketSize;
+               intf = (dev->actconfig->interface) +i;
+               for (j = 0; j < intf->num_altsetting; j++) {
+                       struct usb_interface_descriptor *as = intf->altsetting +j;
+                       struct usb_endpoint_descriptor *ep = as->endpoint;
+                       int e;
+
+                       for (e=0; e<as->bNumEndpoints; e++) {
+                               if (usb_endpoint_out(ep[e].bEndpointAddress))
+                                       dev->epmaxpacketout[ep[e].bEndpointAddress & 0x0f] =
+                                               ep[e].wMaxPacketSize;
+                               else
+                                       dev->epmaxpacketin[ep[e].bEndpointAddress & 0x0f] =
+                                               ep[e].wMaxPacketSize;
+                       }
                }
        }
 }
@@ -781,7 +786,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
                return -1;
 
        dev->ifnum = interface;
-       dev->actconfig->act_altsetting = alternate;
+       dev->actconfig->interface[interface].act_altsetting = alternate;
        usb_set_maxpacket(dev);
        return 0;
 }
index b73d73f25a5c128570f21a2609488b88e3b92705..871f003f77ab8c01bc6ebcb6c93b8842233c1882 100644 (file)
@@ -61,6 +61,7 @@ typedef struct {
 #define USB_DT_CONFIG_SIZE             9
 #define USB_DT_INTERFACE_SIZE          9
 #define USB_DT_ENDPOINT_SIZE           7
+#define USB_DT_AUCLSTEP_SIZE           9       /* Audio Classes are special */
 #define USB_DT_HUB_NONVAR_SIZE         7
 
 /*
@@ -167,7 +168,7 @@ struct usb_devmap {
  */
 
 #define USB_MAXCONFIG          8
-#define USB_MAXALTSETTING       5
+#define USB_MAXALTSETTING   6   
 #define USB_MAXINTERFACES      32
 #define USB_MAXENDPOINTS       32
 
@@ -196,6 +197,8 @@ struct usb_endpoint_descriptor {
        __u8  bmAttributes;
        __u16 wMaxPacketSize;
        __u8  bInterval;
+       __u8  bRefresh;
+       __u8  bSynchAddress;
        void  *audio;
 };
 
@@ -215,9 +218,10 @@ struct usb_interface_descriptor {
        void  *audio;
 };
 
-/* hack for alternate settings */
-struct usb_alternate_setting {
-        struct usb_interface_descriptor *interface;
+struct usb_interface {
+        struct usb_interface_descriptor *altsetting;
+        int act_altsetting;                /* active alternate setting */
+        int num_altsetting;                /* number of alternate settings */
 };
 
 /* Configuration descriptor information.. */
@@ -230,9 +234,7 @@ struct usb_config_descriptor {
        __u8  iConfiguration;
        __u8  bmAttributes;
        __u8  MaxPower;
-        int act_altsetting;                /* active alternate setting */
-        int num_altsetting;                /* number of alternate settings */
-       struct usb_alternate_setting *altsetting;
+       struct usb_interface *interface;
 };
 
 /* String descriptor */
@@ -398,7 +400,7 @@ extern int usb_compress_isochronous (struct usb_device *usb_dev, void *_isodesc)
  * unsigned int. The encoding is:
  *
  *  - max size:                bits 0-1        (00 = 8, 01 = 16, 10 = 32, 11 = 64)
- *  - direction:       bit 7           (0 = Host-to-Device, 1 = Device-to-Host)
+ *  - direction:       bit 7           (0 = Host-to-Device [Out], 1 = Device-to-Host [In])
  *  - device:          bits 8-14
  *  - endpoint:                bits 15-18
  *  - Data0/1:         bit 19
@@ -414,7 +416,7 @@ extern int usb_compress_isochronous (struct usb_device *usb_dev, void *_isodesc)
 #define usb_maxpacket(dev, pipe, out)  (out \
                                ? (dev)->epmaxpacketout[usb_pipeendpoint(pipe)] \
                                : (dev)->epmaxpacketin [usb_pipeendpoint(pipe)] )
-#define usb_packetid(pipe)     (((pipe) & 0x80) ? 0x69 : 0xE1)
+#define usb_packetid(pipe)     (((pipe) & USB_DIR_IN) ? USB_PID_IN : USB_PID_OUT)
 
 #define usb_pipeout(pipe)      ((((pipe) >> 7) & 1) ^ 1)
 #define usb_pipein(pipe)       (((pipe) >> 7) & 1)
@@ -454,13 +456,13 @@ static inline unsigned int __default_pipe(struct usb_device *dev)
 
 /* Create various pipes... */
 #define usb_sndctrlpipe(dev,endpoint)  ((2 << 30) | __create_pipe(dev,endpoint))
-#define usb_rcvctrlpipe(dev,endpoint)  ((2 << 30) | __create_pipe(dev,endpoint) | 0x80)
+#define usb_rcvctrlpipe(dev,endpoint)  ((2 << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
 #define usb_sndisocpipe(dev,endpoint)  ((0 << 30) | __create_pipe(dev,endpoint))
-#define usb_rcvisocpipe(dev,endpoint)  ((0 << 30) | __create_pipe(dev,endpoint) | 0x80)
+#define usb_rcvisocpipe(dev,endpoint)  ((0 << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
 #define usb_sndbulkpipe(dev,endpoint)  ((3 << 30) | __create_pipe(dev,endpoint))
-#define usb_rcvbulkpipe(dev,endpoint)  ((3 << 30) | __create_pipe(dev,endpoint) | 0x80)
+#define usb_rcvbulkpipe(dev,endpoint)  ((3 << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
 #define usb_snddefctrl(dev)            ((2 << 30) | __default_pipe(dev))
-#define usb_rcvdefctrl(dev)            ((2 << 30) | __default_pipe(dev) | 0x80)
+#define usb_rcvdefctrl(dev)            ((2 << 30) | __default_pipe(dev) | USB_DIR_IN)
 
 /*
  * Send and receive control messages..
index 9930eb89fcf39578a449ba98dfdf606b6f949e08..9c19c4c30147dd1e10746b940464ba8a019d7a95 100644 (file)
@@ -33,6 +33,7 @@
 
 #define CLGEN_VERSION "1.9.3"
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
index 7956b25c97434bf7f121a3677a1d6a23086ebf9f..9ca7f6313dd39cba643ed8190788bb5a2851e6a9 100644 (file)
@@ -447,7 +447,7 @@ static int __init offb_init_driver(struct device_node *dp)
 #endif /* CONFIG_FB_PLATINUM */
 #ifdef CONFIG_FB_CLGEN
     if ((!strncmp(dp->name, "MacPicasso",10) ||
-        (!strncmp(dp->name, "54m30",10)) {
+        (!strncmp(dp->name, "54m30",5)) {
        clgen_of_init(dp);
        return 1;
     }
index 6308bf8408608ac56fa67e46892ebfef5523e5f6..09ead177c0cd2848da942ef5325894da54f131fe 100644 (file)
@@ -325,9 +325,9 @@ static int tgafb_encode_fix(struct fb_fix_screeninfo *fix, const void *fb_par,
        fix->visual = FB_VISUAL_TRUECOLOR;
 
     fix->line_length = par->xres * (par->bits_per_pixel >> 3);
-    fix->smem_start = (char *)__pa(fb_info.tga_fb_base + dense_mem(fb_info.tga_fb_base));
+    fix->smem_start = ioremap(fb_info.tga_fb_base);
     fix->smem_len = fix->line_length * par->yres;
-    fix->mmio_start = (char *)__pa(fb_info.tga_regs_base);
+    fix->mmio_start = ioremap(fb_info.tga_regs_base);
     fix->mmio_len = 0x1000;            /* Is this sufficient? */
     fix->xpanstep = fix->ypanstep = fix->ywrapstep = 0;
     fix->accel = FB_ACCEL_DEC_TGA;
@@ -934,7 +934,7 @@ static int tgafb_blank(int blank, struct fb_info_gen *info)
 static void tgafb_set_disp(const void *fb_par, struct display *disp,
        struct fb_info_gen *info)
 {
-    disp->screen_base = (char *)fb_info.tga_fb_base + dense_mem(fb_info.tga_fb_base);
+    disp->screen_base = ioremap(fb_info.tga_fb_base);
     switch (fb_info.tga_type) {
 #ifdef FBCON_HAS_CFB8
        case 0: /* 8-plane */
index a92fde108ecadc9ee4a690e2d55a8732d330d8d4..044673301ec22d612b66c39e3f6a9b0bf7e4d4ce 100644 (file)
@@ -17,6 +17,7 @@
 #ifndef __linux_video_vga_h__
 #define __linux_video_vga_h__
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <asm/io.h>
 #ifndef CONFIG_AMIGA
index dc82db05b0de4f76f0c2fd0b1ec540b34d824bff..9b0e6a9dea63fb7e7586655203200a7714b4e027 100644 (file)
@@ -277,6 +277,7 @@ static const char __init *vgacon_startup(void)
                        vga_video_font_height = 8;
                }
        }
+
        vga_vram_base = VGA_MAP_MEM(vga_vram_base);
        vga_vram_end = VGA_MAP_MEM(vga_vram_end);
 
index ec30732e9b6520eab4ca15d60b6d64bc45a79bb2..5f0c6557b16336af2949cef03ca2d0eb5dd36a9b 100644 (file)
@@ -7,6 +7,9 @@ if [ "$CONFIG_PARTITION_ADVANCED" = "n" ]; then
   if [ "$ARCH" = "alpha" ]; then
     define_bool CONFIG_OSF_PARTITION y
   fi
+  if [ "$CONFIG_AMIGA" = "y" ]; then
+    define_bool CONFIG_AMIGA_PARTITION y
+  fi
   if [ "$CONFIG_ARM" = "y" ]; then
     if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
       define_bool CONFIG_ACORN_PARTITION y
@@ -17,6 +20,9 @@ if [ "$CONFIG_PARTITION_ADVANCED" = "n" ]; then
       define_bool CONFIG_ACORN_PARTITION_RISCIX y
     fi
   fi
+  if [ "$CONFIG_ATARI" = "y" ]; then
+    define_bool CONFIG_ATARI_PARTITION y
+  fi
   bool 'SMD disklabel (Sun partition tables) support' CONFIG_SMD_DISKLABEL
   if [ "$ARCH" = "sparc" -o "$CONFIG_SMD_DISKLABEL" = "y" ]; then
     define_bool CONFIG_SUN_PARTITION y
index 229e514d6feee09dbb6de4f685419b0a2e6b66ad..aa86053155083f86e8dd8ba163164505196bc6c9 100644 (file)
 #include "check.h"
 #include "amiga.h"
 
-static int current_minor;
-
 static __inline__ u32
 checksum_block(u32 *m, int size)
 {
        u32 sum = 0;
 
        while (size--)
-               sum += htonl(*m++);
+               sum += be32_to_cpu(*m++);
        return sum;
 }
 
@@ -48,6 +46,9 @@ amiga_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int
        old_blocksize = get_ptable_blocksize(dev);
        blocksize = get_hardsect_size(dev);
 
+       if (blocksize < 512)
+               blocksize = 512;
+
        set_blocksize(dev,blocksize);
        res = 0;
 
@@ -57,15 +58,15 @@ amiga_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int
                               kdevname(dev),blk);
                        goto rdb_done;
                }
-               if (*(u32 *)bh->b_data == htonl(IDNAME_RIGIDDISK)) {
+               if (*(u32 *)bh->b_data == cpu_to_be32(IDNAME_RIGIDDISK)) {
                        rdb = (struct RigidDiskBlock *)bh->b_data;
-                       if (checksum_block((u32 *)bh->b_data,htonl(rdb->rdb_SummedLongs) & 0x7F)) {
+                       if (checksum_block((u32 *)bh->b_data,be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F)) {
                                /* Try again with 0xdc..0xdf zeroed, Windows might have
                                 * trashed it.
                                 */
                                *(u32 *)(&bh->b_data[0xdc]) = 0;
                                if (checksum_block((u32 *)bh->b_data,
-                                               htonl(rdb->rdb_SummedLongs) & 0x7F)) {
+                                               be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F)) {
                                        brelse(bh);
                                        printk("Dev %s: RDB in block %d has bad checksum\n",
                                               kdevname(dev),blk);
@@ -75,7 +76,7 @@ amiga_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int
                                        "ignored in checksum calculation\n",blk);
                        }
                        printk(" RDSK");
-                       blk = htonl(rdb->rdb_PartitionList);
+                       blk = be32_to_cpu(rdb->rdb_PartitionList);
                        brelse(bh);
                        for (part = 1; blk > 0 && part <= 16; part++) {
                                if (!(bh = bread(dev,blk,blocksize))) {
@@ -84,29 +85,30 @@ amiga_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector, int
                                        goto rdb_done;
                                }
                                pb  = (struct PartitionBlock *)bh->b_data;
-                               blk = htonl(pb->pb_Next);
-                               if (pb->pb_ID == htonl(IDNAME_PARTITION) && checksum_block(
-                                   (u32 *)pb,htonl(pb->pb_SummedLongs) & 0x7F) == 0 ) {
+                               blk = be32_to_cpu(pb->pb_Next);
+                               if (pb->pb_ID == cpu_to_be32(IDNAME_PARTITION) && checksum_block(
+                                   (u32 *)pb,be32_to_cpu(pb->pb_SummedLongs) & 0x7F) == 0 ) {
 
                                        /* Tell Kernel about it */
 
-                                       if (!(nr_sects = (htonl(pb->pb_Environment[10]) + 1 -
-                                                         htonl(pb->pb_Environment[9])) *
-                                                        htonl(pb->pb_Environment[3]) *
-                                                        htonl(pb->pb_Environment[5]))) {
+                                       if (!(nr_sects = (be32_to_cpu(pb->pb_Environment[10]) + 1 -
+                                                         be32_to_cpu(pb->pb_Environment[9])) *
+                                                        be32_to_cpu(pb->pb_Environment[3]) *
+                                                        be32_to_cpu(pb->pb_Environment[5]))) {
                                                brelse(bh);
                                                continue;
-                                       }
-                                       start_sect = htonl(pb->pb_Environment[9]) *
-                                                    htonl(pb->pb_Environment[3]) *
-                                                    htonl(pb->pb_Environment[5]);
-                                       add_gd_partition(hd,current_minor,start_sect,nr_sects);
-                                       current_minor++;
+                                       }
+                                       start_sect = be32_to_cpu(pb->pb_Environment[9]) *
+                                                    be32_to_cpu(pb->pb_Environment[3]) *
+                                                    be32_to_cpu(pb->pb_Environment[5]);
+                                       add_gd_partition(hd,first_part_minor,start_sect,nr_sects);
+                                       first_part_minor++;
                                        res = 1;
                                }
                                brelse(bh);
                        }
                        printk("\n");
+                       break;
                }
                else
                        brelse(bh);
@@ -116,4 +118,3 @@ rdb_done:
        set_blocksize(dev,old_blocksize);
        return res;
 }
-
index 5656ce953c2cec198f00c2451638ee41bcd515e7..04e76b1d1f93c26831b32d9133711b5e9443a460 100644 (file)
@@ -13,7 +13,7 @@
  * EGCS (of varying versions) does a good job of using insxl and extxl.
  */
 
-#if __GNUC__ > 2 || __GNUC_MINOR__ >= 91
+#if 0 && (__GNUC__ > 2 || __GNUC_MINOR__ >= 91)
 #define __kernel_insbl(val, shift) \
   (((unsigned long)(val) & 0xfful) << ((shift) * 8))
 #define __kernel_inswl(val, shift) \
@@ -29,7 +29,7 @@
      __kir; })
 #endif
 
-#if __GNUC__ > 2 || __GNUC_MINOR__ >= 92
+#if 0 && (__GNUC__ > 2 || __GNUC_MINOR__ >= 92)
 #define __kernel_extbl(val, shift)  (((val) >> (((shift) & 7) * 8)) & 0xfful)
 #define __kernel_extwl(val, shift)  (((val) >> (((shift) & 7) * 8)) & 0xfffful)
 #else
index 3346346f9cb6bf99fed6ec2902c6825a79baf077..d105281cb0483f7cc15b5a835a91377395287cb3 100644 (file)
@@ -426,12 +426,12 @@ static inline void * apecs_xl_bus_to_virt(unsigned long address)
         * detect null "pointers" (the NCR driver is much simpler if
         * NULL pointers are preserved).
         */
-        if (address < APECS_XL_DMA_WIN1_BASE)
-                return 0;
-        else if (address < (APECS_XL_DMA_WIN1_BASE + APECS_XL_DMA_WIN1_SIZE))
-                address -= APECS_XL_DMA_WIN1_BASE;
+       if (address < APECS_XL_DMA_WIN1_BASE)
+               return 0;
+       else if (address < (APECS_XL_DMA_WIN1_BASE + APECS_XL_DMA_WIN1_SIZE))
+               address -= APECS_XL_DMA_WIN1_BASE;
        else /* should be more checking here, maybe? */
-                address -= APECS_XL_DMA_WIN2_BASE;
+               address -= APECS_XL_DMA_WIN2_BASE;
        return phys_to_virt(address);
 }
 
@@ -501,6 +501,15 @@ __EXTERN_INLINE unsigned long apecs_readb(unsigned long addr)
 {
        unsigned long result, msb;
 
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "apecs: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += APECS_DENSE_MEM;
+       }
+#endif
+
+       addr -= APECS_DENSE_MEM;
        if (addr >= (1UL << 24)) {
                msb = addr & 0xf8000000;
                addr -= msb;
@@ -514,6 +523,15 @@ __EXTERN_INLINE unsigned long apecs_readw(unsigned long addr)
 {
        unsigned long result, msb;
 
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "apecs: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += APECS_DENSE_MEM;
+       }
+#endif
+
+       addr -= APECS_DENSE_MEM;
        if (addr >= (1UL << 24)) {
                msb = addr & 0xf8000000;
                addr -= msb;
@@ -525,18 +543,43 @@ __EXTERN_INLINE unsigned long apecs_readw(unsigned long addr)
 
 __EXTERN_INLINE unsigned long apecs_readl(unsigned long addr)
 {
-       return *(vuip) (addr + APECS_DENSE_MEM);
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "apecs: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += APECS_DENSE_MEM;
+       }
+#endif
+
+       return *(vuip)addr;
 }
 
 __EXTERN_INLINE unsigned long apecs_readq(unsigned long addr)
 {
-       return *(vulp) (addr + APECS_DENSE_MEM);
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "apecs: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += APECS_DENSE_MEM;
+       }
+#endif
+
+       return *(vulp)addr;
 }
 
 __EXTERN_INLINE void apecs_writeb(unsigned char b, unsigned long addr)
 {
        unsigned long msb;
 
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "apecs: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += APECS_DENSE_MEM;
+       }
+#endif
+
+       addr -= APECS_DENSE_MEM;
        if (addr >= (1UL << 24)) {
                msb = addr & 0xf8000000;
                addr -= msb;
@@ -549,6 +592,15 @@ __EXTERN_INLINE void apecs_writew(unsigned short b, unsigned long addr)
 {
        unsigned long msb;
 
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "apecs: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += APECS_DENSE_MEM;
+       }
+#endif
+
+       addr -= APECS_DENSE_MEM;
        if (addr >= (1UL << 24)) {
                msb = addr & 0xf8000000;
                addr -= msb;
@@ -559,19 +611,38 @@ __EXTERN_INLINE void apecs_writew(unsigned short b, unsigned long addr)
 
 __EXTERN_INLINE void apecs_writel(unsigned int b, unsigned long addr)
 {
-       *(vuip) (addr + APECS_DENSE_MEM) = b;
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "apecs: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += APECS_DENSE_MEM;
+       }
+#endif
+
+       *(vuip)addr = b;
 }
 
 __EXTERN_INLINE void apecs_writeq(unsigned long b, unsigned long addr)
 {
-       *(vulp) (addr + APECS_DENSE_MEM) = b;
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "apecs: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += APECS_DENSE_MEM;
+       }
+#endif
+
+       *(vulp)addr = b;
 }
 
-/* Find the DENSE memory area for a given bus address.  */
+__EXTERN_INLINE unsigned long apecs_ioremap(unsigned long addr)
+{
+       return APECS_DENSE_MEM + addr;
+}
 
-__EXTERN_INLINE unsigned long apecs_dense_mem(unsigned long addr)
+__EXTERN_INLINE int apecs_is_ioaddr(unsigned long addr)
 {
-       return APECS_DENSE_MEM;
+       return addr >= IDENT_ADDR + 0x100000000UL;
 }
 
 #undef vip
@@ -602,7 +673,8 @@ __EXTERN_INLINE unsigned long apecs_dense_mem(unsigned long addr)
 #define __writew       apecs_writew
 #define __writel       apecs_writel
 #define __writeq       apecs_writeq
-#define dense_mem      apecs_dense_mem
+#define __ioremap      apecs_ioremap
+#define __is_ioaddr    apecs_is_ioaddr
 
 #define inb(port) \
 (__builtin_constant_p((port))?__inb(port):_inb(port))
@@ -610,10 +682,12 @@ __EXTERN_INLINE unsigned long apecs_dense_mem(unsigned long addr)
 #define outb(x, port) \
 (__builtin_constant_p((port))?__outb((x),(port)):_outb((x),(port)))
 
-#define readl(a)       __readl((unsigned long)(a))
-#define readq(a)       __readq((unsigned long)(a))
-#define writel(v,a)    __writel((v),(unsigned long)(a))
-#define writeq(v,a)    __writeq((v),(unsigned long)(a))
+#if !__DEBUG_IOREMAP
+#define __raw_readl(a)         __readl((unsigned long)(a))
+#define __raw_readq(a)         __readq((unsigned long)(a))
+#define __raw_writel(v,a)      __writel((v),(unsigned long)(a))
+#define __raw_writeq(v,a)      __writeq((v),(unsigned long)(a))
+#endif
 
 #endif /* __WANT_IO_DEF */
 
index c4d4658a23bb297fc7abf754b399e9d74b672be1..cd4cceadb837342f1b4216ef253335d826d30bfd 100644 (file)
 
 /* CIA ADDRESS BIT DEFINITIONS
  *
- *  3 3 3 3|3 3 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
- *  9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |1| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |0|0|0|
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
- *  |                                                                        \_/ \_/
- *  |                                                                         |   |
- *  +-- IO space, not cached.                                   Byte Enable --+   |
- *                                                              Transfer Length --+
- *
- *
+ *  3333 3333 3322 2222 2222 1111 1111 11 
+ *  9876 5432 1098 7654 3210 9876 5432 1098 7654 3210
+ *  ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
+ *  1                                             000
+ *  ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
+ *  |                                             |\|
+ *  |                               Byte Enable --+ |
+ *  |                             Transfer Length --+
+ *  +-- IO space, not cached
  *
  *   Byte      Transfer
  *   Enable    Length    Transfer  Byte    Address
@@ -404,6 +402,15 @@ __EXTERN_INLINE unsigned long cia_srm_base(unsigned long addr)
 {
        unsigned long mask, base;
 
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "cia: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += CIA_DENSE_MEM;
+       }
+#endif
+
+       addr -= CIA_DENSE_MEM;
        if (addr >= alpha_mv.sm_base_r1
            && addr <= alpha_mv.sm_base_r1 + CIA_MEM_R1_MASK) {
                mask = CIA_MEM_R1_MASK;
@@ -422,7 +429,8 @@ __EXTERN_INLINE unsigned long cia_srm_base(unsigned long addr)
        else
        {
 #if 0
-               printk("cia: address 0x%lx not covered by HAE\n", addr);
+               printk(KERN_CRIT "cia: address 0x%lx not covered by HAE\n",
+                      addr);
 #endif
                return 0;
        }
@@ -456,8 +464,9 @@ __EXTERN_INLINE unsigned long cia_srm_readw(unsigned long addr)
 
 __EXTERN_INLINE void cia_srm_writeb(unsigned char b, unsigned long addr)
 {
-       unsigned long work = cia_srm_base(addr), w;
-       if (work) {
+       unsigned long work, w;
+
+       if ((work = cia_srm_base(addr)) != 0) {
                work += 0x00;   /* add transfer length */
                w = __kernel_insbl(b, addr & 3);
                *(vuip) work = w;
@@ -466,8 +475,10 @@ __EXTERN_INLINE void cia_srm_writeb(unsigned char b, unsigned long addr)
 
 __EXTERN_INLINE void cia_srm_writew(unsigned short b, unsigned long addr)
 {
-       unsigned long work = cia_srm_base(addr), w;
-       if (work) {
+       unsigned long work, w;
+
+       addr -= CIA_DENSE_MEM;
+       if ((work = cia_srm_base(addr)) != 0) {
                work += 0x08;   /* add transfer length */
                w = __kernel_inswl(b, addr & 3);
                *(vuip) work = w;
@@ -478,6 +489,15 @@ __EXTERN_INLINE unsigned long cia_readb(unsigned long addr)
 {
        unsigned long result, msb;
 
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "cia: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+       }
+#endif
+
+       /* Note that CIA_DENSE_MEM has no bits not masked in these 
+          operations, so we don't have to subtract it back out.  */
        msb = addr & 0xE0000000;
        addr &= CIA_MEM_R1_MASK;
        set_hae(msb);
@@ -490,6 +510,15 @@ __EXTERN_INLINE unsigned long cia_readw(unsigned long addr)
 {
        unsigned long result, msb;
 
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "cia: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+       }
+#endif
+
+       /* Note that CIA_DENSE_MEM has no bits not masked in these 
+          operations, so we don't have to subtract it back out.  */
        msb = addr & 0xE0000000;
        addr &= CIA_MEM_R1_MASK;
        set_hae(msb);
@@ -500,8 +529,17 @@ __EXTERN_INLINE unsigned long cia_readw(unsigned long addr)
 
 __EXTERN_INLINE void cia_writeb(unsigned char b, unsigned long addr)
 {
-        unsigned long msb, w; 
+       unsigned long msb, w; 
 
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "cia: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+       }
+#endif
+
+       /* Note that CIA_DENSE_MEM has no bits not masked in these 
+          operations, so we don't have to subtract it back out.  */
        msb = addr & 0xE0000000;
        addr &= CIA_MEM_R1_MASK;
        set_hae(msb);
@@ -512,8 +550,17 @@ __EXTERN_INLINE void cia_writeb(unsigned char b, unsigned long addr)
 
 __EXTERN_INLINE void cia_writew(unsigned short b, unsigned long addr)
 {
-        unsigned long msb, w; 
+       unsigned long msb, w; 
+
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "cia: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+       }
+#endif
 
+       /* Note that CIA_DENSE_MEM has no bits not masked in these 
+          operations, so we don't have to subtract it back out.  */
        msb = addr & 0xE0000000;
        addr &= CIA_MEM_R1_MASK;
        set_hae(msb);
@@ -524,29 +571,60 @@ __EXTERN_INLINE void cia_writew(unsigned short b, unsigned long addr)
 
 __EXTERN_INLINE unsigned long cia_readl(unsigned long addr)
 {
-       return *(vuip) (addr + CIA_DENSE_MEM);
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "cia: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+       }
+#endif
+
+       return *(vuip)addr;
 }
 
 __EXTERN_INLINE unsigned long cia_readq(unsigned long addr)
 {
-       return *(vulp) (addr + CIA_DENSE_MEM);
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "cia: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+       }
+#endif
+
+       return *(vulp)addr;
 }
 
 __EXTERN_INLINE void cia_writel(unsigned int b, unsigned long addr)
 {
-       *(vuip) (addr + CIA_DENSE_MEM) = b;
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "cia: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+       }
+#endif
+
+       *(vuip)addr = b;
 }
 
 __EXTERN_INLINE void cia_writeq(unsigned long b, unsigned long addr)
 {
-       *(vulp) (addr + CIA_DENSE_MEM) = b;
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "cia: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+       }
+#endif
+
+       *(vulp)addr = b;
 }
 
-/* Find the DENSE memory area for a given bus address.  */
+__EXTERN_INLINE unsigned long cia_ioremap(unsigned long addr)
+{
+       return CIA_DENSE_MEM + addr;
+}
 
-__EXTERN_INLINE unsigned long cia_dense_mem(unsigned long addr)
+__EXTERN_INLINE int cia_is_ioaddr(unsigned long addr)
 {
-       return CIA_DENSE_MEM;
+       return addr >= IDENT_ADDR + 0x8000000000UL;
 }
 
 #undef vip
@@ -580,7 +658,8 @@ __EXTERN_INLINE unsigned long cia_dense_mem(unsigned long addr)
 #define __readq                cia_readq
 #define __writel       cia_writel
 #define __writeq       cia_writeq
-#define dense_mem      cia_dense_mem
+#define __ioremap      cia_ioremap
+#define __is_ioaddr    cia_is_ioaddr
 
 #define inb(port) \
 (__builtin_constant_p((port))?__inb(port):_inb(port))
@@ -595,10 +674,12 @@ __EXTERN_INLINE unsigned long cia_dense_mem(unsigned long addr)
 #define inl(port)      __inl(port)
 #define outl(x,port)   __outl((x),(port))
 
-#define readl(a)       __readl((unsigned long)(a))
-#define readq(a)       __readq((unsigned long)(a))
-#define writel(v,a)    __writel((v),(unsigned long)(a))
-#define writeq(v,a)    __writeq((v),(unsigned long)(a))
+#if !__DEBUG_IOREMAP
+#define __raw_readl(a)         __readl((unsigned long)(a))
+#define __raw_readq(a)         __readq((unsigned long)(a))
+#define __raw_writel(v,a)      __writel((v),(unsigned long)(a))
+#define __raw_writeq(v,a)      __writeq((v),(unsigned long)(a))
+#endif
 
 #endif /* __WANT_IO_DEF */
 
index 63f25892459d7047462b2c1ffa26d3c560f5939c..aaa272db6c5e4e9c42f2f6aef66b94a6703c5911 100644 (file)
@@ -305,6 +305,15 @@ __EXTERN_INLINE unsigned long lca_readb(unsigned long addr)
 {
        unsigned long result, msb;
 
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "lca: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += LCA_DENSE_MEM;
+       }
+#endif
+
+       addr -= LCA_DENSE_MEM;
        if (addr >= (1UL << 24)) {
                msb = addr & 0xf8000000;
                addr -= msb;
@@ -318,6 +327,15 @@ __EXTERN_INLINE unsigned long lca_readw(unsigned long addr)
 {
        unsigned long result, msb;
 
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "lca: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += LCA_DENSE_MEM;
+       }
+#endif
+
+       addr -= LCA_DENSE_MEM;
        if (addr >= (1UL << 24)) {
                msb = addr & 0xf8000000;
                addr -= msb;
@@ -329,12 +347,28 @@ __EXTERN_INLINE unsigned long lca_readw(unsigned long addr)
 
 __EXTERN_INLINE unsigned long lca_readl(unsigned long addr)
 {
-       return *(vuip) (addr + LCA_DENSE_MEM);
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "lca: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += LCA_DENSE_MEM;
+       }
+#endif
+
+       return *(vuip)addr;
 }
 
 __EXTERN_INLINE unsigned long lca_readq(unsigned long addr)
 {
-       return *(vulp) (addr + LCA_DENSE_MEM);
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "lca: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += LCA_DENSE_MEM;
+       }
+#endif
+
+       return *(vulp)addr;
 }
 
 __EXTERN_INLINE void lca_writeb(unsigned char b, unsigned long addr)
@@ -342,6 +376,15 @@ __EXTERN_INLINE void lca_writeb(unsigned char b, unsigned long addr)
        unsigned long msb;
        unsigned long w;
 
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "lca: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += LCA_DENSE_MEM;
+       }
+#endif
+
+       addr -= LCA_DENSE_MEM;
        if (addr >= (1UL << 24)) {
                msb = addr & 0xf8000000;
                addr -= msb;
@@ -356,6 +399,15 @@ __EXTERN_INLINE void lca_writew(unsigned short b, unsigned long addr)
        unsigned long msb;
        unsigned long w;
 
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "lca: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += LCA_DENSE_MEM;
+       }
+#endif
+
+       addr -= LCA_DENSE_MEM;
        if (addr >= (1UL << 24)) {
                msb = addr & 0xf8000000;
                addr -= msb;
@@ -367,19 +419,38 @@ __EXTERN_INLINE void lca_writew(unsigned short b, unsigned long addr)
 
 __EXTERN_INLINE void lca_writel(unsigned int b, unsigned long addr)
 {
-       *(vuip) (addr + LCA_DENSE_MEM) = b;
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "lca: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += LCA_DENSE_MEM;
+       }
+#endif
+
+       *(vuip)addr = b;
 }
 
 __EXTERN_INLINE void lca_writeq(unsigned long b, unsigned long addr)
 {
-       *(vulp) (addr + LCA_DENSE_MEM) = b;
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "lca: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += LCA_DENSE_MEM;
+       }
+#endif
+
+       *(vulp)addr = b;
 }
 
-/* Find the DENSE memory area for a given bus address.  */
+__EXTERN_INLINE unsigned long lca_ioremap(unsigned long addr)
+{
+       return LCA_DENSE_MEM + addr;
+}
 
-__EXTERN_INLINE unsigned long lca_dense_mem(unsigned long addr)
+__EXTERN_INLINE int lca_is_ioaddr(unsigned long addr)
 {
-       return LCA_DENSE_MEM;
+       return addr >= IDENT_ADDR + 0x100000000UL;
 }
 
 #undef vip
@@ -404,7 +475,8 @@ __EXTERN_INLINE unsigned long lca_dense_mem(unsigned long addr)
 #define __readq                lca_readq
 #define __writel       lca_writel
 #define __writeq       lca_writeq
-#define dense_mem      lca_dense_mem
+#define __ioremap      lca_ioremap
+#define __is_ioaddr    lca_is_ioaddr
 
 #define inb(port) \
 (__builtin_constant_p((port))?__inb(port):_inb(port))
@@ -412,10 +484,12 @@ __EXTERN_INLINE unsigned long lca_dense_mem(unsigned long addr)
 #define outb(x, port) \
 (__builtin_constant_p((port))?__outb((x),(port)):_outb((x),(port)))
 
-#define readl(a)       __readl((unsigned long)(a))
-#define readq(a)       __readq((unsigned long)(a))
-#define writel(v,a)    __writel((v),(unsigned long)(a))
-#define writeq(v,a)    __writeq((v),(unsigned long)(a))
+#if !__DEBUG_IOREMAP
+#define __raw_readl(a)         __readl((unsigned long)(a))
+#define __raw_readq(a)         __readq((unsigned long)(a))
+#define __raw_writel(v,a)      __writel((v),(unsigned long)(a))
+#define __raw_writeq(v,a)      __writeq((v),(unsigned long)(a))
+#endif
 
 #endif /* __WANT_IO_DEF */
 
index 84eab12d8230f5a751d023bc8d58dfc997db3e82..9afaf0cc77ccf97b4ca27fa7b8928fa91905b56c 100644 (file)
 
 /* MCPCIA ADDRESS BIT DEFINITIONS
  *
- *  3 3 3 3|3 3 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
- *  9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |1| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |0|0|0|
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
- *  |                                                                        \_/ \_/
- *  |                                                                         |   |
- *  +-- IO space, not cached.                                   Byte Enable --+   |
- *                                                              Transfer Length --+
- *
- *
+ *  3333 3333 3322 2222 2222 1111 1111 11
+ *  9876 5432 1098 7654 3210 9876 5432 1098 7654 3210
+ *  ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
+ *  1                                             000
+ *  ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
+ *  |                                             |\|
+ *  |                               Byte Enable --+ |
+ *  |                             Transfer Length --+
+ *  +-- IO space, not cached
  *
  *   Byte      Transfer
  *   Enable    Length    Transfer  Byte    Address
  * Data structure for handling MCPCIA machine checks:
  */
 struct el_MCPCIA_uncorrected_frame_mcheck {
-        struct el_common header;
-        struct el_common_EV5_uncorrectable_mcheck procdata;
+       struct el_common header;
+       struct el_common_EV5_uncorrectable_mcheck procdata;
 };
 
 
@@ -215,41 +213,6 @@ __EXTERN_INLINE void * mcpcia_bus_to_virt(unsigned long address)
 #define vuip   volatile unsigned int *
 #define vulp   volatile unsigned long *
 
-#if 0 /* BWIO */
-__EXTERN_INLINE unsigned int mcpcia_bw_inb(unsigned long addr)
-{
-       return __kernel_ldbu(*(vucp)(addr+MCPCIA_BW_IO));
-}
-
-__EXTERN_INLINE void mcpcia_bw_outb(unsigned char b, unsigned long addr)
-{
-       __kernel_stb(b, *(vucp)(addr+MCPCIA_BW_IO));
-       mb();
-}
-
-__EXTERN_INLINE unsigned int mcpcia_bw_inw(unsigned long addr)
-{
-       return __kernel_ldwu(*(vusp)(addr+MCPCIA_BW_IO));
-}
-
-__EXTERN_INLINE void mcpcia_bw_outw(unsigned short b, unsigned long addr)
-{
-       __kernel_stw(b, *(vusp)(addr+MCPCIA_BW_IO));
-       mb();
-}
-
-__EXTERN_INLINE unsigned int mcpcia_bw_inl(unsigned long addr)
-{
-       return *(vuip)(addr+MCPCIA_BW_IO);
-}
-
-__EXTERN_INLINE void mcpcia_bw_outl(unsigned int b, unsigned long addr)
-{
-       *(vuip)(addr+MCPCIA_BW_IO) = b;
-       mb();
-}
-#endif
-
 __EXTERN_INLINE unsigned int mcpcia_inb(unsigned long in_addr)
 {
        unsigned long addr = in_addr & 0xffffffffUL;
@@ -307,8 +270,8 @@ __EXTERN_INLINE void mcpcia_outl(unsigned int b, unsigned long in_addr)
 /*
  * Memory functions.  64-bit and 32-bit accesses are done through
  * dense memory space, everything else through sparse space.
- * 
- * For reading and writing 8 and 16 bit quantities we need to 
+ *
+ * For reading and writing 8 and 16 bit quantities we need to
  * go through one of the three sparse address mapping regions
  * and use the HAE_MEM CSR to provide some bits of the address.
  * The following few routines use only sparse address region 1
@@ -317,10 +280,10 @@ __EXTERN_INLINE void mcpcia_outl(unsigned int b, unsigned long in_addr)
  * See p 6-17 of the specification but it looks something like this:
  *
  * 21164 Address:
- * 
+ *
  *          3         2         1
  * 9876543210987654321098765432109876543210
- * 1ZZZZ0.PCI.QW.Address............BBLL                 
+ * 1ZZZZ0.PCI.QW.Address............BBLL
  *
  * ZZ = SBZ
  * BB = Byte offset
@@ -333,56 +296,34 @@ __EXTERN_INLINE void mcpcia_outl(unsigned int b, unsigned long in_addr)
  * HHH....PCI.QW.Address........ 00
  *
  * HHH = 31:29 HAE_MEM CSR
- * 
+ *
  */
 
-#if 0 /* BWIO */
-__EXTERN_INLINE unsigned long mcpcia_bw_readb(unsigned long addr)
-{
-       return __kernel_ldbu(*(vucp)(addr+MCPCIA_BW_MEM));
-}
-
-__EXTERN_INLINE unsigned long mcpcia_bw_readw(unsigned long addr)
-{
-       return __kernel_ldbw(*(vusp)(addr+MCPCIA_BW_MEM));
-}
-
-__EXTERN_INLINE unsigned long mcpcia_bw_readl(unsigned long addr)
-{
-       return *(vuip)(addr + MCPCIA_BW_MEM);
-}
-
-__EXTERN_INLINE unsigned long mcpcia_bw_readq(unsigned long addr)
+__EXTERN_INLINE unsigned long mcpcia_ioremap(unsigned long in_addr)
 {
-       return *(vulp)(addr + MCPCIA_BW_MEM);
-}
-
-__EXTERN_INLINE void mcpcia_bw_writeb(unsigned char b, unsigned long addr)
-{
-       __kernel_stb(b, *(vucp)(addr+MCPCIA_BW_MEM));
-}
-
-__EXTERN_INLINE void mcpcia_bw_writew(unsigned short b, unsigned long addr)
-{
-       __kernel_stw(b, *(vusp)(addr+MCPCIA_BW_MEM));
-}
-
-__EXTERN_INLINE void mcpcia_bw_writel(unsigned int b, unsigned long addr)
-{
-       *(vuip)(addr+MCPCIA_BW_MEM) = b;
+       unsigned long addr = in_addr & 0xffffffffUL;
+       unsigned long hose = (in_addr >> 32) & 3;
+       return addr + MCPCIA_DENSE(hose);
 }
 
-__EXTERN_INLINE void mcpcia_bw_writeq(unsigned long b, unsigned long addr)
+__EXTERN_INLINE int mcpcia_is_ioaddr(unsigned long addr)
 {
-       *(vulp)(addr+MCPCIA_BW_MEM) = b;
+       return addr >= IDENT_ADDR + 0x8000000000UL;
 }
-#endif
 
 __EXTERN_INLINE unsigned long mcpcia_srm_base(unsigned long addr)
 {
        unsigned long mask, base;
        unsigned long hose = (addr >> 32) & 3;
 
+#if __DEBUG_IOREMAP
+       if (addr <= 0x1000000000) {
+               printk(KERN_CRIT "mcpcia: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+       }
+#endif
+
+       addr &= 0xfffffffful;
        if (addr >= alpha_mv.sm_base_r1
            && addr <= alpha_mv.sm_base_r1 + MCPCIA_MEM_MASK) {
                mask = MCPCIA_MEM_MASK;
@@ -407,7 +348,7 @@ __EXTERN_INLINE unsigned long mcpcia_srm_readb(unsigned long addr)
                return 0xff;
        work += 0x00;   /* add transfer length */
 
-       result = *(vip) work;
+       result = *(vip)work;
        return __kernel_extbl(result, addr & 3);
 }
 
@@ -425,28 +366,39 @@ __EXTERN_INLINE unsigned long mcpcia_srm_readw(unsigned long addr)
 
 __EXTERN_INLINE void mcpcia_srm_writeb(unsigned char b, unsigned long addr)
 {
-       unsigned long work = mcpcia_srm_base(addr);
+       unsigned long w, work = mcpcia_srm_base(addr);
        if (work) {
                work += 0x00;   /* add transfer length */
-               *(vuip) work = b * 0x01010101;
+               w = __kernel_insbl(b, addr & 3);
+               *(vuip)work = w;
        }
 }
 
 __EXTERN_INLINE void mcpcia_srm_writew(unsigned short b, unsigned long addr)
 {
-       unsigned long work = mcpcia_srm_base(addr);
+       unsigned long w, work = mcpcia_srm_base(addr);
        if (work) {
                work += 0x08;   /* add transfer length */
-               *(vuip) work = b * 0x00010001;
+               w = __kernel_inswl(b, addr & 3);
+               *(vuip)work = w;
        }
 }
 
 __EXTERN_INLINE unsigned long mcpcia_readb(unsigned long in_addr)
 {
+       /* Note that MCPCIA_DENSE(hose) has no bits not masked here, and
+          that the hose calculation is still correct.  */
        unsigned long addr = in_addr & 0xffffffffUL;
        unsigned long hose = (in_addr >> 32) & 3;
        unsigned long result, msb, work, temp;
 
+#if __DEBUG_IOREMAP
+       if (in_addr <= 0x1000000000) {
+               printk(KERN_CRIT "mcpcia: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+       }
+#endif
+
        msb = addr & ~MCPCIA_MEM_MASK;
        temp = addr & MCPCIA_MEM_MASK;
        set_hae(msb);
@@ -458,12 +410,21 @@ __EXTERN_INLINE unsigned long mcpcia_readb(unsigned long in_addr)
 
 __EXTERN_INLINE unsigned long mcpcia_readw(unsigned long in_addr)
 {
+       /* Note that MCPCIA_DENSE(hose) has no bits not masked here, and
+          that the hose calculation is still correct.  */
        unsigned long addr = in_addr & 0xffffffffUL;
        unsigned long hose = (in_addr >> 32) & 3;
        unsigned long result, msb, work, temp;
 
+#if __DEBUG_IOREMAP
+       if (in_addr <= 0x1000000000) {
+               printk(KERN_CRIT "mcpcia: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+       }
+#endif
+
        msb = addr & ~MCPCIA_MEM_MASK;
-       temp = addr & MCPCIA_MEM_MASK ;
+       temp = addr & MCPCIA_MEM_MASK;
        set_hae(msb);
 
        work = ((temp << 5) + MCPCIA_SPARSE(hose) + 0x08);
@@ -473,63 +434,100 @@ __EXTERN_INLINE unsigned long mcpcia_readw(unsigned long in_addr)
 
 __EXTERN_INLINE void mcpcia_writeb(unsigned char b, unsigned long in_addr)
 {
+       /* Note that MCPCIA_DENSE(hose) has no bits not masked here, and
+          that the hose calculation is still correct.  */
        unsigned long addr = in_addr & 0xffffffffUL;
        unsigned long hose = (in_addr >> 32) & 3;
-        unsigned long msb; 
+       unsigned long msb, w;
+
+#if __DEBUG_IOREMAP
+       if (in_addr <= 0x1000000000) {
+               printk(KERN_CRIT "mcpcia: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+       }
+#endif
 
        msb = addr & ~MCPCIA_MEM_MASK;
        addr &= MCPCIA_MEM_MASK;
        set_hae(msb);
 
-       *(vuip) ((addr << 5) + MCPCIA_SPARSE(hose) + 0x00) = b * 0x01010101;
+       w = __kernel_insbl(b, in_addr & 3);
+       *(vuip) ((addr << 5) + MCPCIA_SPARSE(hose) + 0x00) = w;
 }
 
 __EXTERN_INLINE void mcpcia_writew(unsigned short b, unsigned long in_addr)
 {
+       /* Note that MCPCIA_DENSE(hose) has no bits not masked here, and
+          that the hose calculation is still correct.  */
        unsigned long addr = in_addr & 0xffffffffUL;
        unsigned long hose = (in_addr >> 32) & 3;
-        unsigned long msb ; 
+       unsigned long msb, w;
+
+#if __DEBUG_IOREMAP
+       if (in_addr <= 0x1000000000) {
+               printk(KERN_CRIT "mcpcia: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+       }
+#endif
 
-       msb = addr & ~MCPCIA_MEM_MASK ;
-       addr &= MCPCIA_MEM_MASK ;
+       msb = addr & ~MCPCIA_MEM_MASK;
+       addr &= MCPCIA_MEM_MASK;
        set_hae(msb);
 
-       *(vuip) ((addr << 5) + MCPCIA_SPARSE(hose) + 0x08) = b * 0x00010001;
+       w = __kernel_inswl(b, in_addr & 3);
+       *(vuip) ((addr << 5) + MCPCIA_SPARSE(hose) + 0x08) = w;
 }
 
-__EXTERN_INLINE unsigned long mcpcia_readl(unsigned long in_addr)
+__EXTERN_INLINE unsigned long mcpcia_readl(unsigned long addr)
 {
-       unsigned long addr = in_addr & 0xffffffffUL;
-       unsigned long hose = (in_addr >> 32) & 3;
-       return *(vuip) (addr + MCPCIA_DENSE(hose));
-}
+#if __DEBUG_IOREMAP
+       if (addr <= 0x1000000000) {
+               printk(KERN_CRIT "mcpcia: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr = mcpcia_ioremap(addr);
+       }
+#endif
 
-__EXTERN_INLINE unsigned long mcpcia_readq(unsigned long in_addr)
-{
-       unsigned long addr = in_addr & 0xffffffffUL;
-       unsigned long hose = (in_addr >> 32) & 3;
-       return *(vulp) (addr + MCPCIA_DENSE(hose));
+       return *(vuip)addr;
 }
 
-__EXTERN_INLINE void mcpcia_writel(unsigned int b, unsigned long in_addr)
+__EXTERN_INLINE unsigned long mcpcia_readq(unsigned long addr)
 {
-       unsigned long addr = in_addr & 0xffffffffUL;
-       unsigned long hose = (in_addr >> 32) & 3;
-       *(vuip) (addr + MCPCIA_DENSE(hose)) = b;
+#if __DEBUG_IOREMAP
+       if (addr <= 0x1000000000) {
+               printk(KERN_CRIT "mcpcia: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr = mcpcia_ioremap(addr);
+       }
+#endif
+
+       return *(vulp)addr;
 }
 
-__EXTERN_INLINE void mcpcia_writeq(unsigned long b, unsigned long in_addr)
+__EXTERN_INLINE void mcpcia_writel(unsigned int b, unsigned long addr)
 {
-       unsigned long addr = in_addr & 0xffffffffUL;
-       unsigned long hose = (in_addr >> 32) & 3;
-       *(vulp) (addr + MCPCIA_DENSE(hose)) = b;
-}
+#if __DEBUG_IOREMAP
+       if (addr <= 0x1000000000) {
+               printk(KERN_CRIT "mcpcia: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr = mcpcia_ioremap(addr);
+       }
+#endif
 
-/* Find the DENSE memory area for a given bus address.  */
+       *(vuip)addr = b;
+}
 
-__EXTERN_INLINE unsigned long mcpcia_dense_mem(unsigned long addr)
+__EXTERN_INLINE void mcpcia_writeq(unsigned long b, unsigned long addr)
 {
-       return MCPCIA_DENSE((addr >> 32) & 3);
+#if __DEBUG_IOREMAP
+       if (addr <= 0x1000000000) {
+               printk(KERN_CRIT "mcpcia: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr = mcpcia_ioremap(addr);
+       }
+#endif
+
+       *(vulp)addr = b;
 }
 
 #undef vucp
@@ -543,69 +541,42 @@ __EXTERN_INLINE unsigned long mcpcia_dense_mem(unsigned long addr)
 #define virt_to_bus    mcpcia_virt_to_bus
 #define bus_to_virt    mcpcia_bus_to_virt
 
-#if 0 /* BWIO */
-# define __inb         mcpcia_bw_inb
-# define __inw         mcpcia_bw_inw
-# define __inl         mcpcia_bw_inl
-# define __outb                mcpcia_bw_outb
-# define __outw                mcpcia_bw_outw
-# define __outl                mcpcia_bw_outl
-# define __readb       mcpcia_bw_readb
-# define __readw       mcpcia_bw_readw
-# define __writeb      mcpcia_bw_writeb
-# define __writew      mcpcia_bw_writew
-# define __readl       mcpcia_bw_readl
-# define __readq       mcpcia_bw_readq
-# define __writel      mcpcia_bw_writel
-# define __writeq      mcpcia_bw_writeq
-#else
-# define __inb         mcpcia_inb
-# define __inw         mcpcia_inw
-# define __inl         mcpcia_inl
-# define __outb                mcpcia_outb
-# define __outw                mcpcia_outw
-# define __outl                mcpcia_outl
-# ifdef CONFIG_ALPHA_SRM_SETUP
-#  define __readb      mcpcia_srm_readb
-#  define __readw      mcpcia_srm_readw
-#  define __writeb     mcpcia_srm_writeb
-#  define __writew     mcpcia_srm_writew
-# else
-#  define __readb      mcpcia_readb
-#  define __readw      mcpcia_readw
-#  define __writeb     mcpcia_writeb
-#  define __writew     mcpcia_writew
-# endif
-# define __readl       mcpcia_readl
-# define __readq       mcpcia_readq
-# define __writel      mcpcia_writel
-# define __writeq      mcpcia_writeq
-#endif /* BWIO */
-
-#define dense_mem      mcpcia_dense_mem
-
-#if 0 /* BWIO */
-# define inb(port) __inb((port))
-# define inw(port) __inw((port))
-# define inl(port) __inl((port))
-# define outb(x, port) __outb((x),(port))
-# define outw(x, port) __outw((x),(port))
-# define outl(x, port) __outl((x),(port))
-# define readb(addr) __readb((addr))
-# define readw(addr) __readw((addr))
-# define writeb(b, addr) __writeb((b),(addr))
-# define writew(b, addr) __writew((b),(addr))
+#define __inb          mcpcia_inb
+#define __inw          mcpcia_inw
+#define __inl          mcpcia_inl
+#define __outb         mcpcia_outb
+#define __outw         mcpcia_outw
+#define __outl         mcpcia_outl
+#ifdef CONFIG_ALPHA_SRM_SETUP
+# define __readb       mcpcia_srm_readb
+# define __readw       mcpcia_srm_readw
+# define __writeb      mcpcia_srm_writeb
+# define __writew      mcpcia_srm_writew
 #else
+# define __readb       mcpcia_readb
+# define __readw       mcpcia_readw
+# define __writeb      mcpcia_writeb
+# define __writew      mcpcia_writew
+#endif
+#define __readl                mcpcia_readl
+#define __readq                mcpcia_readq
+#define __writel       mcpcia_writel
+#define __writeq       mcpcia_writeq
+
+#define __ioremap      mcpcia_ioremap
+#define __is_ioaddr    mcpcia_is_ioaddr
+
 # define inb(port) \
   (__builtin_constant_p((port))?__inb(port):_inb(port))
 # define outb(x, port) \
   (__builtin_constant_p((port))?__outb((x),(port)):_outb((x),(port)))
-#endif /* BWIO */
 
-#define readl(a)       __readl((unsigned long)(a))
-#define readq(a)       __readq((unsigned long)(a))
-#define writel(v,a)    __writel((v),(unsigned long)(a))
-#define writeq(v,a)    __writeq((v),(unsigned long)(a))
+#if !__DEBUG_IOREMAP
+#define __raw_readl(a)         __readl((unsigned long)(a))
+#define __raw_readq(a)         __readq((unsigned long)(a))
+#define __raw_writel(v,a)      __writel((v),(unsigned long)(a))
+#define __raw_writeq(v,a)      __writeq((v),(unsigned long)(a))
+#endif
 
 #endif /* __WANT_IO_DEF */
 
index 8caf50622bc2bd7092d9948a8b2b972379e0fb39..75e42e8a2a22121b2f8a283afa102f423e4f6946 100644 (file)
  */
 
 /* Polaris memory regions */
-#define                POLARIS_SPARSE_MEM_BASE         (IDENT_ADDR + 0xf800000000)
-#define                POLARIS_DENSE_MEM_BASE          (IDENT_ADDR + 0xf900000000)
-#define        POLARIS_SPARSE_IO_BASE          (IDENT_ADDR + 0xf980000000)
-#define                POLARIS_SPARSE_CONFIG_BASE      (IDENT_ADDR + 0xf9c0000000)
-#define                POLARIS_IACK_BASE               (IDENT_ADDR + 0xf9f8000000)
-#define                POLARIS_DENSE_IO_BASE           (IDENT_ADDR + 0xf9fc000000)
-#define                POLARIS_DENSE_CONFIG_BASE       (IDENT_ADDR + 0xf9fe000000)
+#define POLARIS_SPARSE_MEM_BASE                (IDENT_ADDR + 0xf800000000)
+#define POLARIS_DENSE_MEM_BASE         (IDENT_ADDR + 0xf900000000)
+#define POLARIS_SPARSE_IO_BASE         (IDENT_ADDR + 0xf980000000)
+#define POLARIS_SPARSE_CONFIG_BASE     (IDENT_ADDR + 0xf9c0000000)
+#define POLARIS_IACK_BASE              (IDENT_ADDR + 0xf9f8000000)
+#define POLARIS_DENSE_IO_BASE          (IDENT_ADDR + 0xf9fc000000)
+#define POLARIS_DENSE_CONFIG_BASE      (IDENT_ADDR + 0xf9fe000000)
 
-#define                POLARIS_IACK_SC                 POLARIS_IACK_BASE
+#define POLARIS_IACK_SC                        POLARIS_IACK_BASE
 
 /* The Polaris command/status registers live in PCI Config space for
  * bus 0/device 0.  As such, they may be bytes, words, or doublewords.
  */
-#define                POLARIS_W_VENID         (POLARIS_DENSE_CONFIG_BASE)
-#define                POLARIS_W_DEVID         (POLARIS_DENSE_CONFIG_BASE+2)
-#define                POLARIS_W_CMD           (POLARIS_DENSE_CONFIG_BASE+4)
-#define                POLARIS_W_STATUS        (POLARIS_DENSE_CONFIG_BASE+6)
+#define POLARIS_W_VENID                (POLARIS_DENSE_CONFIG_BASE)
+#define POLARIS_W_DEVID                (POLARIS_DENSE_CONFIG_BASE+2)
+#define POLARIS_W_CMD          (POLARIS_DENSE_CONFIG_BASE+4)
+#define POLARIS_W_STATUS       (POLARIS_DENSE_CONFIG_BASE+6)
 
 /* No HAE address.  Polaris has no concept of an HAE, since it
  * supports transfers of all sizes in dense space.
@@ -62,7 +62,7 @@ struct el_POLARIS_sysdata_mcheck {
     u_long     psc_pcictl2;
 };
 
- #ifdef __KERNEL__
+#ifdef __KERNEL__
 
 #ifndef __EXTERN_INLINE
 #define __EXTERN_INLINE extern inline
@@ -96,7 +96,7 @@ __EXTERN_INLINE void * polaris_bus_to_virt(unsigned long address)
 
 __EXTERN_INLINE unsigned int polaris_inb(unsigned long addr)
 {
-        return __kernel_ldbu(*(vucp)(addr + POLARIS_DENSE_IO_BASE));
+       return __kernel_ldbu(*(vucp)(addr + POLARIS_DENSE_IO_BASE));
 }
 
 __EXTERN_INLINE void polaris_outb(unsigned char b, unsigned long addr)
@@ -107,7 +107,7 @@ __EXTERN_INLINE void polaris_outb(unsigned char b, unsigned long addr)
 
 __EXTERN_INLINE unsigned int polaris_inw(unsigned long addr)
 {
-        return __kernel_ldwu(*(vusp)(addr + POLARIS_DENSE_IO_BASE));
+       return __kernel_ldwu(*(vusp)(addr + POLARIS_DENSE_IO_BASE));
 }
 
 __EXTERN_INLINE void polaris_outw(unsigned short b, unsigned long addr)
@@ -118,13 +118,13 @@ __EXTERN_INLINE void polaris_outw(unsigned short b, unsigned long addr)
 
 __EXTERN_INLINE unsigned int polaris_inl(unsigned long addr)
 {
-        return *(vuip)(addr + POLARIS_DENSE_IO_BASE);
+       return *(vuip)(addr + POLARIS_DENSE_IO_BASE);
 }
 
 __EXTERN_INLINE void polaris_outl(unsigned int b, unsigned long addr)
 {
-        *(vuip)(addr + POLARIS_DENSE_IO_BASE) = b;
-        mb();
+       *(vuip)(addr + POLARIS_DENSE_IO_BASE) = b;
+       mb();
 }
 
 /*
@@ -136,53 +136,116 @@ __EXTERN_INLINE void polaris_outl(unsigned int b, unsigned long addr)
 
 __EXTERN_INLINE unsigned long polaris_readb(unsigned long addr)
 {
-        return __kernel_ldbu(*(vucp)(addr + POLARIS_DENSE_MEM_BASE));
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "polaris: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += POLARIS_DENSE_MEM_BASE;
+       }
+#endif
+
+       return __kernel_ldbu(*(vucp)addr);
 }
 
 __EXTERN_INLINE unsigned long polaris_readw(unsigned long addr)
 {
-        return __kernel_ldwu(*(vusp)(addr + POLARIS_DENSE_MEM_BASE));
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "polaris: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += POLARIS_DENSE_MEM_BASE;
+       }
+#endif
+
+       return __kernel_ldwu(*(vusp)addr);
 }
 
 __EXTERN_INLINE unsigned long polaris_readl(unsigned long addr)
 {
-        return *(vuip)(addr + POLARIS_DENSE_MEM_BASE);
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "polaris: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += POLARIS_DENSE_MEM_BASE;
+       }
+#endif
+
+       return *(vuip)addr;
 }
 
 __EXTERN_INLINE unsigned long polaris_readq(unsigned long addr)
 {
-        return *(vulp)(addr + POLARIS_DENSE_MEM_BASE);
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "polaris: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += POLARIS_DENSE_MEM_BASE;
+       }
+#endif
+
+       return *(vulp)addr;
 }
 
 __EXTERN_INLINE void polaris_writeb(unsigned char b, unsigned long addr)
 {
-        __kernel_stb(b, *(vucp)(addr + POLARIS_DENSE_MEM_BASE));
-        mb();
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "polaris: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += POLARIS_DENSE_MEM_BASE;
+       }
+#endif
+
+       __kernel_stb(b, *(vucp)addr);
 }
 
 __EXTERN_INLINE void polaris_writew(unsigned short b, unsigned long addr)
 {
-        __kernel_stw(b, *(vusp)(addr + POLARIS_DENSE_MEM_BASE));
-        mb();
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "polaris: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += POLARIS_DENSE_MEM_BASE;
+       }
+#endif
+
+       __kernel_stw(b, *(vusp)addr);
 }
 
 __EXTERN_INLINE void polaris_writel(unsigned int b, unsigned long addr)
 {
-        *(vuip)(addr + POLARIS_DENSE_MEM_BASE) = b;
-        mb();
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "polaris: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += POLARIS_DENSE_MEM_BASE;
+       }
+#endif
+
+       *(vuip)addr = b;
 }
 
 __EXTERN_INLINE void polaris_writeq(unsigned long b, unsigned long addr)
 {
-        *(vulp)(addr + POLARIS_DENSE_MEM_BASE) = b;
-        mb();
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "polaris: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += POLARIS_DENSE_MEM_BASE;
+       }
+#endif
+
+       *(vulp)addr = b;
 }
 
-/* Find the DENSE memory area for a given bus address.  */
+__EXTERN_INLINE unsigned long polaris_ioremap(unsigned long addr)
+{
+       return POLARIS_DENSE_MEM_BASE + addr;
+}
 
-__EXTERN_INLINE unsigned long polaris_dense_mem(unsigned long addr)
+__EXTERN_INLINE int polaris_is_ioaddr(unsigned long addr)
 {
-        return POLARIS_DENSE_MEM_BASE;
+       return addr >= IDENT_ADDR + 0x8000000000UL;
 }
 
 #undef vucp
@@ -209,7 +272,8 @@ __EXTERN_INLINE unsigned long polaris_dense_mem(unsigned long addr)
 #define __readq         polaris_readq
 #define __writel        polaris_writel
 #define __writeq        polaris_writeq
-#define dense_mem       polaris_dense_mem
+#define __ioremap       polaris_ioremap
+#define __is_ioaddr    polaris_is_ioaddr
 
 #define inb(port) __inb((port))
 #define inw(port) __inw((port))
@@ -219,15 +283,16 @@ __EXTERN_INLINE unsigned long polaris_dense_mem(unsigned long addr)
 #define outw(v, port) __outw((v),(port))
 #define outl(v, port) __outl((v),(port))
 
-#define readb(a)        __readb((unsigned long)(a))
-#define readw(a)        __readw((unsigned long)(a))
-#define readl(a)        __readl((unsigned long)(a))
-#define readq(a)        __readq((unsigned long)(a))
-
-#define writeb(v,a)     __writeb((v),(unsigned long)(a))
-#define writew(v,a)     __writew((v),(unsigned long)(a))
-#define writel(v,a)     __writel((v),(unsigned long)(a))
-#define writeq(v,a)     __writeq((v),(unsigned long)(a))
+#if !__DEBUG_IOREMAP
+#define __raw_readb(a)         __readb((unsigned long)(a))
+#define __raw_readw(a)         __readw((unsigned long)(a))
+#define __raw_readl(a)         __readl((unsigned long)(a))
+#define __raw_readq(a)         __readq((unsigned long)(a))
+#define __raw_writeb(v,a)      __writeb((v),(unsigned long)(a))
+#define __raw_writeb(v,a)      __writew((v),(unsigned long)(a))
+#define __raw_writel(v,a)      __writel((v),(unsigned long)(a))
+#define __raw_writeq(v,a)      __writeq((v),(unsigned long)(a))
+#endif
 
 #endif /* __WANT_IO_DEF */
 
index 7ca0d151456900b592188b322a3c46d7fdf76b03..3ae7cbe1782291517575d49eef0acb2a12caddf7 100644 (file)
 **------------------------------------------------------------------------*/
 
 
-/* CIA ADDRESS BIT DEFINITIONS
- *
- *  3 3 3 3|3 3 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
- *  9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |1| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |0|0|0|
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
- *  |                                                                        \_/ \_/
- *  |                                                                         |   |
- *  +-- IO space, not cached.                                   Byte Enable --+   |
- *                                                              Transfer Length --+
- *
+/* PYXIS ADDRESS BIT DEFINITIONS
  *
+ *  3333 3333 3322 2222 2222 1111 1111 11
+ *  9876 5432 1098 7654 3210 9876 5432 1098 7654 3210
+ *  ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
+ *  1                                             000
+ *  ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
+ *  |                                            |\|
+ *  |                               Byte Enable --+ |
+ *  |                             Transfer Length --+
+ *  +-- IO space, not cached
  *
  *   Byte      Transfer
  *   Enable    Length    Transfer  Byte    Address
  * Data structure for handling PYXIS machine checks:
  */
 struct el_PYXIS_sysdata_mcheck {
-    u_long      coma_gcr;                       
-    u_long      coma_edsr;                      
-    u_long      coma_ter;                       
-    u_long      coma_elar;                      
-    u_long      coma_ehar;                      
-    u_long      coma_ldlr;                      
-    u_long      coma_ldhr;                      
-    u_long      coma_base0;                     
-    u_long      coma_base1;                     
-    u_long      coma_base2;                     
-    u_long      coma_cnfg0;                     
-    u_long      coma_cnfg1;                     
-    u_long      coma_cnfg2;                     
-    u_long      epic_dcsr;                      
-    u_long      epic_pear;                      
-    u_long      epic_sear;                      
-    u_long      epic_tbr1;                      
-    u_long      epic_tbr2;                      
-    u_long      epic_pbr1;                      
-    u_long      epic_pbr2;                      
-    u_long      epic_pmr1;                      
-    u_long      epic_pmr2;                      
-    u_long      epic_harx1;                     
-    u_long      epic_harx2;                     
-    u_long      epic_pmlt;                      
-    u_long      epic_tag0;                      
-    u_long      epic_tag1;                      
-    u_long      epic_tag2;                      
-    u_long      epic_tag3;                      
-    u_long      epic_tag4;                      
-    u_long      epic_tag5;                      
-    u_long      epic_tag6;                      
-    u_long      epic_tag7;                      
-    u_long      epic_data0;                     
-    u_long      epic_data1;                     
-    u_long      epic_data2;                     
-    u_long      epic_data3;                     
-    u_long      epic_data4;                     
-    u_long      epic_data5;                     
-    u_long      epic_data6;                     
-    u_long      epic_data7;                     
+    u_long      coma_gcr;
+    u_long      coma_edsr;
+    u_long      coma_ter;
+    u_long      coma_elar;
+    u_long      coma_ehar;
+    u_long      coma_ldlr;
+    u_long      coma_ldhr;
+    u_long      coma_base0;
+    u_long      coma_base1;
+    u_long      coma_base2;
+    u_long      coma_cnfg0;
+    u_long      coma_cnfg1;
+    u_long      coma_cnfg2;
+    u_long      epic_dcsr;
+    u_long      epic_pear;
+    u_long      epic_sear;
+    u_long      epic_tbr1;
+    u_long      epic_tbr2;
+    u_long      epic_pbr1;
+    u_long      epic_pbr2;
+    u_long      epic_pmr1;
+    u_long      epic_pmr2;
+    u_long      epic_harx1;
+    u_long      epic_harx2;
+    u_long      epic_pmlt;
+    u_long      epic_tag0;
+    u_long      epic_tag1;
+    u_long      epic_tag2;
+    u_long      epic_tag3;
+    u_long      epic_tag4;
+    u_long      epic_tag5;
+    u_long      epic_tag6;
+    u_long      epic_tag7;
+    u_long      epic_data0;
+    u_long      epic_data1;
+    u_long      epic_data2;
+    u_long      epic_data3;
+    u_long      epic_data4;
+    u_long      epic_data5;
+    u_long      epic_data6;
+    u_long      epic_data7;
 };
 
 
@@ -373,8 +371,8 @@ __EXTERN_INLINE void pyxis_outl(unsigned int b, unsigned long addr)
 /*
  * Memory functions.  64-bit and 32-bit accesses are done through
  * dense memory space, everything else through sparse space.
- * 
- * For reading and writing 8 and 16 bit quantities we need to 
+ *
+ * For reading and writing 8 and 16 bit quantities we need to
  * go through one of the three sparse address mapping regions
  * and use the HAE_MEM CSR to provide some bits of the address.
  * The following few routines use only sparse address region 1
@@ -383,10 +381,10 @@ __EXTERN_INLINE void pyxis_outl(unsigned int b, unsigned long addr)
  * See p 6-17 of the specification but it looks something like this:
  *
  * 21164 Address:
- * 
- *          3         2         1                                                               
+ *
+ *          3         2         1
  * 9876543210987654321098765432109876543210
- * 1ZZZZ0.PCI.QW.Address............BBLL                 
+ * 1ZZZZ0.PCI.QW.Address............BBLL
  *
  * ZZ = SBZ
  * BB = Byte offset
@@ -394,60 +392,136 @@ __EXTERN_INLINE void pyxis_outl(unsigned int b, unsigned long addr)
  *
  * PCI Address:
  *
- * 3         2         1                                                               
+ * 3         2         1
  * 10987654321098765432109876543210
  * HHH....PCI.QW.Address........ 00
  *
  * HHH = 31:29 HAE_MEM CSR
- * 
+ *
  */
 
 __EXTERN_INLINE unsigned long pyxis_bw_readb(unsigned long addr)
 {
-       return __kernel_ldbu(*(vucp)(addr+PYXIS_BW_MEM));
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "pyxis: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += PYXIS_BW_MEM;
+       }
+#endif
+
+       return __kernel_ldbu(*(vucp)addr);
 }
 
 __EXTERN_INLINE unsigned long pyxis_bw_readw(unsigned long addr)
 {
-       return __kernel_ldwu(*(vusp)(addr+PYXIS_BW_MEM));
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "pyxis: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += PYXIS_BW_MEM;
+       }
+#endif
+
+       return __kernel_ldwu(*(vusp)addr);
 }
 
 __EXTERN_INLINE unsigned long pyxis_bw_readl(unsigned long addr)
 {
-       return *(vuip)(addr+PYXIS_BW_MEM);
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "pyxis: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += PYXIS_BW_MEM;
+       }
+#endif
+
+       return *(vuip)addr;
 }
 
 __EXTERN_INLINE unsigned long pyxis_bw_readq(unsigned long addr)
 {
-       return *(vulp)(addr+PYXIS_BW_MEM);
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "pyxis: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += PYXIS_BW_MEM;
+       }
+#endif
+
+       return *(vulp)addr;
 }
 
 __EXTERN_INLINE void pyxis_bw_writeb(unsigned char b, unsigned long addr)
 {
-       __kernel_stb(b, *(vucp)(addr+PYXIS_BW_MEM));
-       mb();
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "pyxis: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += PYXIS_BW_MEM;
+       }
+#endif
+
+       __kernel_stb(b, *(vucp)addr);
 }
 
 __EXTERN_INLINE void pyxis_bw_writew(unsigned short b, unsigned long addr)
 {
-       __kernel_stw(b, *(vusp)(addr+PYXIS_BW_MEM));
-       mb();
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "pyxis: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += PYXIS_BW_MEM;
+       }
+#endif
+
+       __kernel_stw(b, *(vusp)addr);
 }
 
 __EXTERN_INLINE void pyxis_bw_writel(unsigned int b, unsigned long addr)
 {
-       *(vuip)(addr+PYXIS_BW_MEM) = b;
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "pyxis: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += PYXIS_BW_MEM;
+       }
+#endif
+
+       *(vuip)addr = b;
 }
 
 __EXTERN_INLINE void pyxis_bw_writeq(unsigned long b, unsigned long addr)
 {
-       *(vulp)(addr+PYXIS_BW_MEM) = b;
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "pyxis: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += PYXIS_BW_MEM;
+       }
+#endif
+
+       *(vulp)addr = b;
+}
+
+__EXTERN_INLINE unsigned long pyxis_bw_ioremap(unsigned long addr)
+{
+       return PYXIS_BW_MEM + addr;
 }
 
 __EXTERN_INLINE unsigned long pyxis_srm_base(unsigned long addr)
 {
        unsigned long mask, base;
 
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "pyxis: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += PYXIS_BW_MEM;
+       }
+#endif
+
+       addr -= PYXIS_BW_MEM;
        if (addr >= alpha_mv.sm_base_r1
            && addr <= alpha_mv.sm_base_r1 + PYXIS_MEM_R1_MASK) {
                mask = PYXIS_MEM_R1_MASK;
@@ -500,19 +574,21 @@ __EXTERN_INLINE unsigned long pyxis_srm_readw(unsigned long addr)
 
 __EXTERN_INLINE void pyxis_srm_writeb(unsigned char b, unsigned long addr)
 {
-       unsigned long work = pyxis_srm_base(addr);
+       unsigned long w, work = pyxis_srm_base(addr);
        if (work) {
                work += 0x00;   /* add transfer length */
-               *(vuip) work = b * 0x01010101;
+               w = __kernel_insbl(b, addr & 3);
+               *(vuip)work = w;
        }
 }
 
 __EXTERN_INLINE void pyxis_srm_writew(unsigned short b, unsigned long addr)
 {
-       unsigned long work = pyxis_srm_base(addr);
+       unsigned long w, work = pyxis_srm_base(addr);
        if (work) {
                work += 0x08;   /* add transfer length */
-               *(vuip) work = b * 0x00010001;
+               w = __kernel_inswl(b, addr & 3);
+               *(vuip)work = w;
        }
 }
 
@@ -520,8 +596,17 @@ __EXTERN_INLINE unsigned long pyxis_readb(unsigned long addr)
 {
        unsigned long result, msb, work, temp;
 
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "pyxis: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+       }
+#endif
+
+       /* Note that PYXIS_DENSE_MEM has no bits not masked in these
+          operations, so we don't have to subtract it back out.  */
        msb = addr & 0xE0000000UL;
-       temp = addr & PYXIS_MEM_R1_MASK ;
+       temp = addr & PYXIS_MEM_R1_MASK;
        set_hae(msb);
 
        work = ((temp << 5) + PYXIS_SPARSE_MEM + 0x00);
@@ -533,8 +618,17 @@ __EXTERN_INLINE unsigned long pyxis_readw(unsigned long addr)
 {
        unsigned long result, msb, work, temp;
 
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "pyxis: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+       }
+#endif
+
+       /* Note that PYXIS_DENSE_MEM has no bits not masked in these
+          operations, so we don't have to subtract it back out.  */
        msb = addr & 0xE0000000UL;
-       temp = addr & PYXIS_MEM_R1_MASK ;
+       temp = addr & PYXIS_MEM_R1_MASK;
        set_hae(msb);
 
        work = ((temp << 5) + PYXIS_SPARSE_MEM + 0x08);
@@ -544,51 +638,106 @@ __EXTERN_INLINE unsigned long pyxis_readw(unsigned long addr)
 
 __EXTERN_INLINE void pyxis_writeb(unsigned char b, unsigned long addr)
 {
-        unsigned long msb ; 
+       unsigned long msb, w;
 
-       msb = addr & 0xE0000000 ;
-       addr &= PYXIS_MEM_R1_MASK ;
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "pyxis: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+       }
+#endif
+
+       /* Note that PYXIS_DENSE_MEM has no bits not masked in these
+          operations, so we don't have to subtract it back out.  */
+       msb = addr & 0xE0000000;
+       addr &= PYXIS_MEM_R1_MASK;
        set_hae(msb);
 
-       *(vuip) ((addr << 5) + PYXIS_SPARSE_MEM + 0x00) = b * 0x01010101;
+       w = __kernel_insbl(b, addr & 3);
+       *(vuip) ((addr << 5) + PYXIS_SPARSE_MEM + 0x00) = w;
 }
 
 __EXTERN_INLINE void pyxis_writew(unsigned short b, unsigned long addr)
 {
-        unsigned long msb ; 
+       unsigned long msb, w;
 
-       msb = addr & 0xE0000000 ;
-       addr &= PYXIS_MEM_R1_MASK ;
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "pyxis: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+       }
+#endif
+
+       /* Note that PYXIS_DENSE_MEM has no bits not masked in these
+          operations, so we don't have to subtract it back out.  */
+       msb = addr & 0xE0000000;
+       addr &= PYXIS_MEM_R1_MASK;
        set_hae(msb);
 
-       *(vuip) ((addr << 5) + PYXIS_SPARSE_MEM + 0x08) = b * 0x00010001;
+       w = __kernel_inswl(b, addr & 3);
+       *(vuip) ((addr << 5) + PYXIS_SPARSE_MEM + 0x08) = w;
 }
 
 __EXTERN_INLINE unsigned long pyxis_readl(unsigned long addr)
 {
-       return *(vuip) (addr + PYXIS_DENSE_MEM);
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "pyxis: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += PYXIS_DENSE_MEM;
+       }
+#endif
+
+       return *(vuip)addr;
 }
 
 __EXTERN_INLINE unsigned long pyxis_readq(unsigned long addr)
 {
-       return *(vulp) (addr + PYXIS_DENSE_MEM);
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "pyxis: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += PYXIS_DENSE_MEM;
+       }
+#endif
+
+       return *(vulp)addr;
 }
 
 __EXTERN_INLINE void pyxis_writel(unsigned int b, unsigned long addr)
 {
-       *(vuip) (addr + PYXIS_DENSE_MEM) = b;
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "pyxis: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += PYXIS_DENSE_MEM;
+       }
+#endif
+
+       *(vuip)addr = b;
 }
 
 __EXTERN_INLINE void pyxis_writeq(unsigned long b, unsigned long addr)
 {
-       *(vulp) (addr + PYXIS_DENSE_MEM) = b;
+#if __DEBUG_IOREMAP
+       if (addr <= 0x100000000) {
+               printk(KERN_CRIT "pyxis: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr += PYXIS_DENSE_MEM;
+       }
+#endif
+
+       *(vulp)addr = b;
 }
 
-/* Find the DENSE memory area for a given bus address.  */
+__EXTERN_INLINE unsigned long pyxis_ioremap(unsigned long addr)
+{
+       return PYXIS_DENSE_MEM + addr;
+}
 
-__EXTERN_INLINE unsigned long pyxis_dense_mem(unsigned long addr)
+__EXTERN_INLINE int pyxis_is_ioaddr(unsigned long addr)
 {
-       return PYXIS_DENSE_MEM;
+       return addr >= IDENT_ADDR + 0x8000000000UL;
 }
 
 #undef vucp
@@ -617,6 +766,7 @@ __EXTERN_INLINE unsigned long pyxis_dense_mem(unsigned long addr)
 # define __readq       pyxis_bw_readq
 # define __writel      pyxis_bw_writel
 # define __writeq      pyxis_bw_writeq
+# define __ioremap     pyxis_bw_ioremap
 #else
 # define __inb         pyxis_inb
 # define __inw         pyxis_inw
@@ -639,21 +789,24 @@ __EXTERN_INLINE unsigned long pyxis_dense_mem(unsigned long addr)
 # define __readq       pyxis_readq
 # define __writel      pyxis_writel
 # define __writeq      pyxis_writeq
+# define __ioremap     pyxis_ioremap
 #endif /* BWIO */
 
-#define dense_mem      pyxis_dense_mem
+#define __is_ioaddr    pyxis_is_ioaddr
 
 #if defined(BWIO_ENABLED) && !defined(CONFIG_ALPHA_RUFFIAN)
-# define inb(port) __inb((port))
-# define inw(port) __inw((port))
-# define inl(port) __inl((port))
-# define outb(x, port) __outb((x),(port))
-# define outw(x, port) __outw((x),(port))
-# define outl(x, port) __outl((x),(port))
-# define readb(addr) __readb((addr))
-# define readw(addr) __readw((addr))
-# define writeb(b, addr) __writeb((b),(addr))
-# define writew(b, addr) __writew((b),(addr))
+# define inb(port)             __inb((port))
+# define inw(port)             __inw((port))
+# define inl(port)             __inl((port))
+# define outb(x, port)         __outb((x),(port))
+# define outw(x, port)         __outw((x),(port))
+# define outl(x, port)         __outl((x),(port))
+# if !__DEBUG_IOREMAP
+#  define __raw_readb(addr)    __readb((addr))
+#  define __raw_readw(addr)    __readw((addr))
+#  define __raw_writeb(b, addr)        __writeb((b),(addr))
+#  define __raw_writeb(b, addr)        __writew((b),(addr))
+# endif
 #else
 # define inb(port) \
   (__builtin_constant_p((port))?__inb(port):_inb(port))
@@ -661,10 +814,12 @@ __EXTERN_INLINE unsigned long pyxis_dense_mem(unsigned long addr)
   (__builtin_constant_p((port))?__outb((x),(port)):_outb((x),(port)))
 #endif /* BWIO */
 
-#define readl(a)       __readl((unsigned long)(a))
-#define readq(a)       __readq((unsigned long)(a))
-#define writel(v,a)    __writel((v),(unsigned long)(a))
-#define writeq(v,a)    __writeq((v),(unsigned long)(a))
+#if !__DEBUG_IOREMAP
+#define __raw_readl(a)         __readl((unsigned long)(a))
+#define __raw_readq(a)         __readq((unsigned long)(a))
+#define __raw_writel(v,a)      __writel((v),(unsigned long)(a))
+#define __raw_writeq(v,a)      __writeq((v),(unsigned long)(a))
+#endif
 
 #endif /* __WANT_IO_DEF */
 
index fdb0f82fe4f1379562f0318c77296cc6aae8b179..0767d9d0e3e81ff085fd363ccc7c1585820d12e7 100644 (file)
  3.8fff.ffff
  *
  *  +--------------+ 3 8000 0000
- *  | CPU 0 CSRs   |            
+ *  | CPU 0 CSRs   |
  *  +--------------+ 3 8100 0000
- *  | CPU 1 CSRs   |            
+ *  | CPU 1 CSRs   |
  *  +--------------+ 3 8200 0000
- *  | CPU 2 CSRs   |            
+ *  | CPU 2 CSRs   |
  *  +--------------+ 3 8300 0000
- *  | CPU 3 CSRs   |            
+ *  | CPU 3 CSRs   |
  *  +--------------+ 3 8400 0000
- *  | CPU Reserved |            
+ *  | CPU Reserved |
  *  +--------------+ 3 8700 0000
- *  | Mem Reserved |            
+ *  | Mem Reserved |
  *  +--------------+ 3 8800 0000
- *  | Mem 0 CSRs   |            
+ *  | Mem 0 CSRs   |
  *  +--------------+ 3 8900 0000
- *  | Mem 1 CSRs   |            
+ *  | Mem 1 CSRs   |
  *  +--------------+ 3 8a00 0000
- *  | Mem 2 CSRs   |            
+ *  | Mem 2 CSRs   |
  *  +--------------+ 3 8b00 0000
- *  | Mem 3 CSRs   |            
- *  +--------------+ 3 8c00 0000           
- *  | Mem Reserved |            
- *  +--------------+ 3 8e00 0000           
- *  | PCI Bridge   |            
- *  +--------------+ 3 8f00 0000           
- *  | Expansion IO |            
- *  +--------------+ 3 9000 0000           
- *                                              
+ *  | Mem 3 CSRs   |
+ *  +--------------+ 3 8c00 0000
+ *  | Mem Reserved |
+ *  +--------------+ 3 8e00 0000
+ *  | PCI Bridge   |
+ *  +--------------+ 3 8f00 0000
+ *  | Expansion IO |
+ *  +--------------+ 3 9000 0000
+ *
  *
  */
 #define T2_CPU0_BASE            (IDENT_ADDR + GAMMA_BIAS + 0x380000000L)
@@ -176,7 +176,7 @@ struct el_t2_procdata_mcheck {
        unsigned long   elfmc_bc_tag;   /* Backup Cache Tag Probe Results. */
 };
 
-/* 
+/*
  * Sable processor specific Machine Check Data segment.
  */
 
@@ -184,7 +184,7 @@ struct el_t2_logout_header {
        unsigned int    elfl_size;      /* size in bytes of logout area. */
        int             elfl_sbz1:31;   /* Should be zero. */
        char            elfl_retry:1;   /* Retry flag. */
-        unsigned int   elfl_procoffset; /* Processor-specific offset. */
+       unsigned int    elfl_procoffset; /* Processor-specific offset. */
        unsigned int    elfl_sysoffset;  /* Offset of system-specific. */
        unsigned int    elfl_error_type;        /* PAL error type code. */
        unsigned int    elfl_frame_rev;         /* PAL Frame revision. */
@@ -233,7 +233,7 @@ struct el_t2_data_memory {
  */
 struct el_t2_data_other_cpu {
        short         elco_cpuid;       /* CPU ID */
-       short         elco_res02[3];    
+       short         elco_res02[3];
        unsigned long elco_bcc; /* CSR 0 */
        unsigned long elco_bcce;        /* CSR 1 */
        unsigned long elco_bccea;       /* CSR 2 */
@@ -256,7 +256,7 @@ struct el_t2_data_other_cpu {
  * Sable other CPU error frame - sable pfms section 3.44
  */
 struct el_t2_data_t2{
-        struct el_t2_frame_header elct_hdr;    /* ID$T2-FRAME */
+       struct el_t2_frame_header elct_hdr;     /* ID$T2-FRAME */
        unsigned long elct_iocsr;       /* IO Control and Status Register */
        unsigned long elct_cerr1;       /* Cbus Error Register 1 */
        unsigned long elct_cerr2;       /* Cbus Error Register 2 */
@@ -294,31 +294,31 @@ struct el_t2_data_corrected {
        unsigned long elcpb_bc_tag;
 };
 
-/* 
+/*
  * Sable error log data structure
  * Note there are 4 memory slots on sable (see t2.h)
  */
 struct el_t2_frame_mcheck {
-        struct el_t2_frame_header elfmc_header;        /* ID$P-FRAME_MCHECK */
+       struct el_t2_frame_header elfmc_header; /* ID$P-FRAME_MCHECK */
        struct el_t2_logout_header elfmc_hdr;
        struct el_t2_procdata_mcheck elfmc_procdata;
        struct el_t2_sysdata_mcheck elfmc_sysdata;
        struct el_t2_data_t2 elfmc_t2data;
-       struct el_t2_data_memory elfmc_memdata[4]; 
-        struct el_t2_frame_header elfmc_footer;        /* empty */
+       struct el_t2_data_memory elfmc_memdata[4];
+       struct el_t2_frame_header elfmc_footer; /* empty */
 };
 
 
-/* 
+/*
  * Sable error log data structures on memory errors
  */
 struct el_t2_frame_corrected {
-        struct el_t2_frame_header elfcc_header;        /* ID$P-BC-COR */
+       struct el_t2_frame_header elfcc_header; /* ID$P-BC-COR */
        struct el_t2_logout_header elfcc_hdr;
-       struct el_t2_data_corrected elfcc_procdata; 
+       struct el_t2_data_corrected elfcc_procdata;
 /*     struct el_t2_data_t2 elfcc_t2data;              */
 /*     struct el_t2_data_memory elfcc_memdata[4];      */
-        struct el_t2_frame_header elfcc_footer;        /* empty */
+       struct el_t2_frame_header elfcc_footer; /* empty */
 };
 
 
@@ -398,10 +398,9 @@ __EXTERN_INLINE void t2_outl(unsigned int b, unsigned long addr)
 
 
 /*
- * Memory functions.  64-bit and 32-bit accesses are done through
- * dense memory space, everything else through sparse space.
- * 
- * For reading and writing 8 and 16 bit quantities we need to 
+ * Memory functions.
+ *
+ * For reading and writing 8 and 16 bit quantities we need to
  * go through one of the three sparse address mapping regions
  * and use the HAE_MEM CSR to provide some bits of the address.
  * The following few routines use only sparse address region 1
@@ -410,10 +409,10 @@ __EXTERN_INLINE void t2_outl(unsigned int b, unsigned long addr)
  * See p 6-17 of the specification but it looks something like this:
  *
  * 21164 Address:
- * 
- *          3         2         1                                                               
+ *
+ *          3         2         1
  * 9876543210987654321098765432109876543210
- * 1ZZZZ0.PCI.QW.Address............BBLL                 
+ * 1ZZZZ0.PCI.QW.Address............BBLL
  *
  * ZZ = SBZ
  * BB = Byte offset
@@ -421,12 +420,12 @@ __EXTERN_INLINE void t2_outl(unsigned int b, unsigned long addr)
  *
  * PCI Address:
  *
- * 3         2         1                                                               
+ * 3         2         1
  * 10987654321098765432109876543210
  * HHH....PCI.QW.Address........ 00
  *
  * HHH = 31:29 HAE_MEM CSR
- * 
+ *
  */
 
 __EXTERN_INLINE unsigned long t2_srm_base(unsigned long addr)
@@ -495,19 +494,21 @@ __EXTERN_INLINE unsigned long t2_srm_readq(unsigned long addr)
 
 __EXTERN_INLINE void t2_srm_writeb(unsigned char b, unsigned long addr)
 {
-       unsigned long work = t2_srm_base(addr);
+       unsigned long w, work = t2_srm_base(addr);
        if (work) {
                work += 0x00;   /* add transfer length */
-               *(vuip) work = b * 0x01010101;
+               w = __kernel_insbl(b, addr & 3);
+               *(vuip) work = w;
        }
 }
 
 __EXTERN_INLINE void t2_srm_writew(unsigned short b, unsigned long addr)
 {
-       unsigned long work = t2_srm_base(addr);
+       unsigned long w, work = t2_srm_base(addr);
        if (work) {
                work += 0x08;   /* add transfer length */
-               *(vuip) work = b * 0x00010001;
+               w = __kernel_inswl(b, addr & 3);
+               *(vuip) work = w;
        }
 }
 
@@ -537,11 +538,11 @@ __EXTERN_INLINE unsigned long t2_readb(unsigned long addr)
 {
        unsigned long result, msb;
 
-       msb = addr & 0xE0000000 ;
-       addr &= T2_MEM_R1_MASK ;
+       msb = addr & 0xE0000000;
+       addr &= T2_MEM_R1_MASK;
        set_hae(msb);
 
-       result = *(vip) ((addr << 5) + T2_SPARSE_MEM + 0x00) ;
+       result = *(vip) ((addr << 5) + T2_SPARSE_MEM + 0x00);
        return __kernel_extbl(result, addr & 3);
 }
 
@@ -549,8 +550,8 @@ __EXTERN_INLINE unsigned long t2_readw(unsigned long addr)
 {
        unsigned long result, msb;
 
-       msb = addr & 0xE0000000 ;
-       addr &= T2_MEM_R1_MASK ;
+       msb = addr & 0xE0000000;
+       addr &= T2_MEM_R1_MASK;
        set_hae(msb);
 
        result = *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x08);
@@ -562,8 +563,8 @@ __EXTERN_INLINE unsigned long t2_readl(unsigned long addr)
 {
        unsigned long msb;
 
-       msb = addr & 0xE0000000 ;
-       addr &= T2_MEM_R1_MASK ;
+       msb = addr & 0xE0000000;
+       addr &= T2_MEM_R1_MASK;
        set_hae(msb);
 
        return *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x18);
@@ -573,8 +574,8 @@ __EXTERN_INLINE unsigned long t2_readq(unsigned long addr)
 {
        unsigned long r0, r1, work, msb;
 
-       msb = addr & 0xE0000000 ;
-       addr &= T2_MEM_R1_MASK ;
+       msb = addr & 0xE0000000;
+       addr &= T2_MEM_R1_MASK;
        set_hae(msb);
 
        work = (addr << 5) + T2_SPARSE_MEM + 0x18;
@@ -585,33 +586,35 @@ __EXTERN_INLINE unsigned long t2_readq(unsigned long addr)
 
 __EXTERN_INLINE void t2_writeb(unsigned char b, unsigned long addr)
 {
-        unsigned long msb ; 
+       unsigned long msb, w;
 
-       msb = addr & 0xE0000000 ;
-       addr &= T2_MEM_R1_MASK ;
+       msb = addr & 0xE0000000;
+       addr &= T2_MEM_R1_MASK;
        set_hae(msb);
 
-       *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x00) = b * 0x01010101;
+       w = __kernel_insbl(b, addr & 3);
+       *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x00) = w;
 }
 
 __EXTERN_INLINE void t2_writew(unsigned short b, unsigned long addr)
 {
-        unsigned long msb ; 
+       unsigned long msb, w;
 
-       msb = addr & 0xE0000000 ;
-       addr &= T2_MEM_R1_MASK ;
+       msb = addr & 0xE0000000;
+       addr &= T2_MEM_R1_MASK;
        set_hae(msb);
 
-       *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x08) = b * 0x00010001;
+       w = __kernel_inswl(b, addr & 3);
+       *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x08) = w;
 }
 
 /* On SABLE with T2, we must use SPARSE memory even for 32-bit access. */
 __EXTERN_INLINE void t2_writel(unsigned int b, unsigned long addr)
 {
-        unsigned long msb ; 
+       unsigned long msb;
 
-       msb = addr & 0xE0000000 ;
-       addr &= T2_MEM_R1_MASK ;
+       msb = addr & 0xE0000000;
+       addr &= T2_MEM_R1_MASK;
        set_hae(msb);
 
        *(vuip) ((addr << 5) + T2_SPARSE_MEM + 0x18) = b;
@@ -619,10 +622,10 @@ __EXTERN_INLINE void t2_writel(unsigned int b, unsigned long addr)
 
 __EXTERN_INLINE void t2_writeq(unsigned long b, unsigned long addr)
 {
-        unsigned long msb, work;
+       unsigned long msb, work;
 
-       msb = addr & 0xE0000000 ;
-       addr &= T2_MEM_R1_MASK ;
+       msb = addr & 0xE0000000;
+       addr &= T2_MEM_R1_MASK;
        set_hae(msb);
 
        work = (addr << 5) + T2_SPARSE_MEM + 0x18;
@@ -630,11 +633,14 @@ __EXTERN_INLINE void t2_writeq(unsigned long b, unsigned long addr)
        *(vuip)(work + (4 << 5)) = b >> 32;
 }
 
-/* Find the DENSE memory area for a given bus address.  */
+__EXTERN_INLINE unsigned long t2_ioremap(unsigned long addr)
+{
+       return addr;
+}
 
-__EXTERN_INLINE unsigned long t2_dense_mem(unsigned long addr)
+__EXTERN_INLINE int t2_is_ioaddr(unsigned long addr)
 {
-       return T2_DENSE_MEM;
+       return (long)addr >= 0;
 }
 
 #undef vip
@@ -671,7 +677,8 @@ __EXTERN_INLINE unsigned long t2_dense_mem(unsigned long addr)
 #define __writeq       t2_writeq
 #endif
 
-#define dense_mem      t2_dense_mem
+#define __ioremap      t2_ioremap
+#define __is_ioaddr    t2_is_ioaddr
 
 #define inb(port) \
 (__builtin_constant_p((port))?__inb(port):_inb(port))
index 28a869bb007acddd3d282cf5aa260ee052231cf6..664043b49d693f9cab97bafd373f9a8b31560435 100644 (file)
@@ -158,7 +158,7 @@ union TPchipPERROR {
                unsigned perror_v_rsvd2 : 1;
                unsigned perror_v_cmd : 4;
                unsigned perror_v_syn : 8;
-        } perror_r_bits;
+       } perror_r_bits;
        int perror_q_whole [2];
 };                       
 
@@ -178,7 +178,7 @@ union TPchipWSBA {
                unsigned wsba_v_rsvd1 : 17;
                unsigned wsba_v_addr : 12;
                unsigned wsba_v_rsvd2 : 32;
-        } wsba_r_bits;
+       } wsba_r_bits;
        int wsba_q_whole [2];
 };
 
@@ -272,7 +272,7 @@ union TPchipPERRMASK {
                unsigned perrmask_v_cre : 1;                 
                unsigned perrmask_v_rsvd1 : 20;
                unsigned perrmask_v_rsvd2 : 32;
-        } perrmask_r_bits;
+       } perrmask_r_bits;
        int perrmask_q_whole [2];
 };                       
 
@@ -369,55 +369,118 @@ __EXTERN_INLINE void tsunami_outl(unsigned int b, unsigned long addr)
  * Memory functions.  all accesses are done through linear space.
  */
 
+__EXTERN_INLINE unsigned long tsunami_ioremap(unsigned long addr)
+{
+       return XADDR + TSUNAMI_MEM(XHOSE);
+}
+
+__EXTERN_INLINE int tsunami_is_ioaddr(unsigned long addr)
+{
+       return addr >= IDENT_ADDR+TS_BIAS;
+}
+
 __EXTERN_INLINE unsigned long tsunami_readb(unsigned long addr)
 {
-       return __kernel_ldbu(*(vucp)(XADDR + TSUNAMI_MEM(XHOSE)));
+#if __DEBUG_IOREMAP
+       if (addr <= 0x1000000000) {
+               printk(KERN_CRIT "tsunami: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr = tsunami_ioremap(addr);
+       }
+#endif
+
+       return __kernel_ldbu(*(vucp)addr);
 }
 
 __EXTERN_INLINE unsigned long tsunami_readw(unsigned long addr)
 {
-       return __kernel_ldwu(*(vusp)(XADDR + TSUNAMI_MEM(XHOSE)));
+#if __DEBUG_IOREMAP
+       if (addr <= 0x1000000000) {
+               printk(KERN_CRIT "tsunami: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr = tsunami_ioremap(addr);
+       }
+#endif
+
+       return __kernel_ldwu(*(vusp)addr);
 }
 
 __EXTERN_INLINE unsigned long tsunami_readl(unsigned long addr)
 {
-       return *(vuip)(XADDR + TSUNAMI_MEM(XHOSE));
+#if __DEBUG_IOREMAP
+       if (addr <= 0x1000000000) {
+               printk(KERN_CRIT "tsunami: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr = tsunami_ioremap(addr);
+       }
+#endif
+
+       return *(vuip)addr;
 }
 
 __EXTERN_INLINE unsigned long tsunami_readq(unsigned long addr)
 {
-       return *(vulp)(XADDR + TSUNAMI_MEM(XHOSE));
+#if __DEBUG_IOREMAP
+       if (addr <= 0x1000000000) {
+               printk(KERN_CRIT "tsunami: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr = tsunami_ioremap(addr);
+       }
+#endif
+
+       return *(vulp)addr;
 }
 
 __EXTERN_INLINE void tsunami_writeb(unsigned char b, unsigned long addr)
 {
-       __kernel_stb(b, *(vucp)(XADDR + TSUNAMI_MEM(XHOSE)));
-       mb();
+#if __DEBUG_IOREMAP
+       if (addr <= 0x1000000000) {
+               printk(KERN_CRIT "tsunami: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr = tsunami_ioremap(addr);
+       }
+#endif
+
+       __kernel_stb(b, *(vucp)addr);
 }
 
 __EXTERN_INLINE void tsunami_writew(unsigned short b, unsigned long addr)
 {
-       __kernel_stw(b, *(vusp)(XADDR + TSUNAMI_MEM(XHOSE)));
-       mb();
+#if __DEBUG_IOREMAP
+       if (addr <= 0x1000000000) {
+               printk(KERN_CRIT "tsunami: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr = tsunami_ioremap(addr);
+       }
+#endif
+
+       __kernel_stw(b, *(vusp)addr);
 }
 
 __EXTERN_INLINE void tsunami_writel(unsigned int b, unsigned long addr)
 {
-       *(vuip)(XADDR + TSUNAMI_MEM(XHOSE)) = b;
-       mb();
+#if __DEBUG_IOREMAP
+       if (addr <= 0x1000000000) {
+               printk(KERN_CRIT "tsunami: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr = tsunami_ioremap(addr);
+       }
+#endif
+
+       *(vuip)addr = b;
 }
 
 __EXTERN_INLINE void tsunami_writeq(unsigned long b, unsigned long addr)
 {
-       *(vulp)(XADDR + TSUNAMI_MEM(XHOSE)) = b;
-       mb();
-}
-
-/* Find the DENSE memory area for a given bus address.  */
+#if __DEBUG_IOREMAP
+       if (addr <= 0x1000000000) {
+               printk(KERN_CRIT "tsunami: 0x%lx not ioremapped (%p)\n",
+                      addr, __builtin_return_address(0));
+               addr = tsunami_ioremap(addr);
+       }
+#endif
 
-__EXTERN_INLINE unsigned long tsunami_dense_mem(unsigned long addr)
-{
-       return TSUNAMI_MEM(XHOSE);
+       *(vulp)addr = b;
 }
 
 #undef vucp
@@ -447,7 +510,8 @@ __EXTERN_INLINE unsigned long tsunami_dense_mem(unsigned long addr)
 #define __readq                tsunami_readq
 #define __writel       tsunami_writel
 #define __writeq       tsunami_writeq
-#define dense_mem      tsunami_dense_mem
+#define __ioremap      tsunami_ioremap
+#define __is_ioaddr    tsunami_is_ioaddr
 
 #define inb(port) __inb((port))
 #define inw(port) __inw((port))
@@ -457,15 +521,16 @@ __EXTERN_INLINE unsigned long tsunami_dense_mem(unsigned long addr)
 #define outw(v, port) __outw((v),(port))
 #define outl(v, port) __outl((v),(port))
 
-#define readb(a)       __readb((unsigned long)(a))
-#define readw(a)       __readw((unsigned long)(a))
-#define readl(a)       __readl((unsigned long)(a))
-#define readq(a)       __readq((unsigned long)(a))
-
-#define writeb(v,a)    __writeb((v),(unsigned long)(a))
-#define writew(v,a)    __writew((v),(unsigned long)(a))
-#define writel(v,a)    __writel((v),(unsigned long)(a))
-#define writeq(v,a)    __writeq((v),(unsigned long)(a))
+#if !__DEBUG_IOREMAP
+#define __raw_readb(a)         __readb((unsigned long)(a))
+#define __raw_readw(a)         __readw((unsigned long)(a))
+#define __raw_readl(a)         __readl((unsigned long)(a))
+#define __raw_readq(a)         __readq((unsigned long)(a))
+#define __raw_writeb(v,a)      __writeb((v),(unsigned long)(a))
+#define __raw_writeb(v,a)      __writew((v),(unsigned long)(a))
+#define __raw_writel(v,a)      __writel((v),(unsigned long)(a))
+#define __raw_writeq(v,a)      __writeq((v),(unsigned long)(a))
+#endif
 
 #endif /* __WANT_IO_DEF */
 
index 671e125751e62f853ca9cd89facf947269ddb17c..24cd808892aedcd3953a91da9e5617f16d337100 100644 (file)
@@ -1,7 +1,10 @@
 #ifndef __ALPHA_IO_H
 #define __ALPHA_IO_H
 
+#define __DEBUG_IOREMAP 1
+
 #include <linux/config.h>
+#include <linux/kernel.h>
 #include <asm/system.h>
 
 /* We don't use IO slowdowns on the Alpha, but.. */
@@ -103,6 +106,9 @@ extern void _sethae (unsigned long addr);   /* cached version */
 # define __writel(v,a) alpha_mv.mv_writel((v),(unsigned long)(a))
 # define __writeq(v,a) alpha_mv.mv_writeq((v),(unsigned long)(a))
 
+# define __ioremap(a)  alpha_mv.mv_ioremap(a)
+# define __is_ioaddr(a)        alpha_mv.mv_is_ioaddr(a)
+
 # define inb           __inb
 # define inw           __inw
 # define inl           __inl
@@ -110,16 +116,14 @@ extern void _sethae (unsigned long addr); /* cached version */
 # define outw          __outw
 # define outl          __outl
 
-# define readb         __readb
-# define readw         __readw
-# define readl         __readl
-# define readq         __readq
-# define writeb                __writeb
-# define writew                __writew
-# define writel                __writel
-# define writeq                __writeq
-
-# define dense_mem(a)  alpha_mv.mv_dense_mem(a)
+# define __raw_readb   __readb
+# define __raw_readw   __readw
+# define __raw_readl   __readl
+# define __raw_readq   __readq
+# define __raw_writeb  __writeb
+# define __raw_writeb  __writew
+# define __raw_writel  __writel
+# define __raw_writeq  __writeq
 
 #else
 
@@ -244,21 +248,85 @@ extern void               writel(unsigned int b, unsigned long addr);
 #ifdef __KERNEL__
 
 /*
- * The "address" in IO memory space is not clearly either an integer or a
- * pointer. We will accept both, thus the casts.
+ * On Alpha, we have the whole of I/O space mapped at all times, but
+ * at odd and sometimes discontinuous addresses.  Note that the 
+ * discontinuities are all across busses, so we need not care for that
+ * for any one device.
  *
- * On the alpha, we have the whole physical address space mapped at all
- * times, so "ioremap()" and "iounmap()" do not need to do anything.
+ * Map the I/O space address into the kernel's virtual address space.
  */
 static inline void * ioremap(unsigned long offset, unsigned long size)
 {
-       return (void *) offset;
+       return (void *) __ioremap(offset);
 } 
 
 static inline void iounmap(void *addr)
 {
 }
 
+/* Indirect back to the macros provided.  */
+
+extern unsigned long   ___raw_readb(unsigned long addr);
+extern unsigned long   ___raw_readw(unsigned long addr);
+extern unsigned long   ___raw_readl(unsigned long addr);
+extern unsigned long   ___raw_readq(unsigned long addr);
+extern void            ___raw_writeb(unsigned char b, unsigned long addr);
+extern void            ___raw_writeb(unsigned short b, unsigned long addr);
+extern void            ___raw_writel(unsigned int b, unsigned long addr);
+extern void            ___raw_writeq(unsigned long b, unsigned long addr);
+
+#ifdef __raw_readb
+# define readb(a)      ({ unsigned long r_ = __raw_readb(a); mb(); r_; })
+#endif
+#ifdef __raw_readw
+# define readw(a)      ({ unsigned long r_ = __raw_readw(a); mb(); r_; })
+#endif
+#ifdef __raw_readl
+# define readl(a)      ({ unsigned long r_ = __raw_readl(a); mb(); r_; })
+#endif
+#ifdef __raw_readq
+# define readq(a)      ({ unsigned long r_ = __raw_readq(a); mb(); r_; })
+#endif
+
+#ifdef __raw_writeb
+# define writeb(v,a)   ({ __raw_writeb((v),(a)); mb(); })
+#endif
+#ifdef __raw_writeb
+# define writew(v,a)   ({ __raw_writeb((v),(a)); mb(); })
+#endif
+#ifdef __raw_writel
+# define writel(v,a)   ({ __raw_writel((v),(a)); mb(); })
+#endif
+#ifdef __raw_writeq
+# define writeq(v,a)   ({ __raw_writeq((v),(a)); mb(); })
+#endif
+
+#ifndef __raw_readb
+# define __raw_readb(a)        ___raw_readb((unsigned long)(a))
+#endif
+#ifndef __raw_readw
+# define __raw_readw(a)        ___raw_readw((unsigned long)(a))
+#endif
+#ifndef __raw_readl
+# define __raw_readl(a)        ___raw_readl((unsigned long)(a))
+#endif
+#ifndef __raw_readq
+# define __raw_readq(a)        ___raw_readq((unsigned long)(a))
+#endif
+
+#ifndef __raw_writeb
+# define __raw_writeb(v,a)  ___raw_writeb((v),(unsigned long)(a))
+#endif
+#ifndef __raw_writeb
+# define __raw_writeb(v,a)  ___raw_writeb((v),(unsigned long)(a))
+#endif
+#ifndef __raw_writel
+# define __raw_writel(v,a)  ___raw_writel((v),(unsigned long)(a))
+#endif
+#ifndef __raw_writeq
+# define __raw_writeq(v,a)  ___raw_writeq((v),(unsigned long)(a))
+#endif
+
 #ifndef readb
 # define readb(a)      _readb((unsigned long)(a))
 #endif
@@ -271,6 +339,7 @@ static inline void iounmap(void *addr)
 #ifndef readq
 # define readq(a)      _readq((unsigned long)(a))
 #endif
+
 #ifndef writeb
 # define writeb(v,a)   _writeb((v),(unsigned long)(a))
 #endif
index 874511e94eb68a064b4d6c23a7c2d9d7424a2ba9..826dfc54d4ddc25a64a918902ad5cec8f71ea909 100644 (file)
@@ -292,12 +292,14 @@ __EXTERN_INLINE void jensen_writeq(unsigned long b, unsigned long addr)
        *(vuip) (addr + (4 << 7)) = b >> 32;
 }
 
-/* Find the DENSE memory area for a given bus address.
-   Whee, there is none.  */
+__EXTERN_INLINE unsigned long jensen_ioremap(unsigned long addr)
+{
+       return addr;
+}
 
-__EXTERN_INLINE unsigned long jensen_dense_mem(unsigned long addr)
+__EXTERN_INLINE int jensen_is_ioaddr(unsigned long addr)
 {
-       return 0;
+       return (long)addr >= 0;
 }
 
 #undef vuip
@@ -320,7 +322,8 @@ __EXTERN_INLINE unsigned long jensen_dense_mem(unsigned long addr)
 #define __readq                jensen_readq
 #define __writel       jensen_writel
 #define __writeq       jensen_writeq
-#define dense_mem      jensen_dense_mem
+#define __ioremap      jensen_ioremap
+#define __is_ioaddr    jensen_is_ioaddr
 
 /*
  * The above have so much overhead that it probably doesn't make
index c8a65b4be86b82b3d043c91e371552b68480b34f..4d66386b4aa93631699c2f63205d67db99b4d774 100644 (file)
@@ -56,7 +56,8 @@ struct alpha_machine_vector
        void (*mv_writel)(unsigned int, unsigned long);
        void (*mv_writeq)(unsigned long, unsigned long);
 
-       unsigned long (*mv_dense_mem)(unsigned long);
+       unsigned long (*mv_ioremap)(unsigned long);
+       int (*mv_is_ioaddr)(unsigned long);
 
        int (*hose_read_config_byte)(u8, u8, u8, u8 *value,
                                     struct linux_hose_info *);
index feb0f1e8581cd9c17333b441547f825727a6815d..499363b1f99fa7ca102d8b119d2e0bc3db3fed22 100644 (file)
@@ -1,10 +1,25 @@
 #ifndef __ASM_SMP_H
 #define __ASM_SMP_H
 
+#include <asm/pal.h>
+
+/* HACK: Cabrio WHAMI return value is bogus if more than 8 bits used.. :-( */
+
+static __inline__ unsigned char
+__hard_smp_processor_id(void)
+{
+       register unsigned char __r0 __asm__("$0");
+       __asm__ __volatile__(
+               "call_pal %1 #whami"
+               : "=r"(__r0)
+               :"i" (PAL_whami)
+               : "$1", "$22", "$23", "$24", "$25");
+       return __r0;
+}
+
 #ifdef __SMP__
 
 #include <linux/tasks.h>
-#include <asm/pal.h>
 
 struct cpuinfo_alpha {
        unsigned long loops_per_sec;
@@ -38,20 +53,6 @@ extern int __cpu_logical_map[NR_CPUS];
 
 #endif /* __SMP__ */
 
-/* HACK: Cabrio WHAMI return value is bogus if more than 8 bits used.. :-( */
-
-static __inline__ unsigned char
-__hard_smp_processor_id(void)
-{
-       register unsigned char __r0 __asm__("$0");
-       __asm__ __volatile__(
-               "call_pal %1 #whami"
-               : "=r"(__r0)
-               :"i" (PAL_whami)
-               : "$1", "$22", "$23", "$24", "$25");
-       return __r0;
-}
-
 #define NO_PROC_ID     (-1)
 
 #endif
index 7e66f50d3664017da7e9f4b343e9b61793103030..1bfc05344eded1e45d35f9e83d5b40d08545d36a 100644 (file)
 
 extern inline void scr_writew(u16 val, u16 *addr)
 {
-       if ((long) addr < 0)
-               *addr = val;
-       else
+       if (__is_ioaddr((unsigned long) addr))
                writew(val, (unsigned long) addr);
+       else
+               *addr = val;
 }
 
 extern inline u16 scr_readw(const u16 *addr)
 {
-       if ((long) addr < 0)
-               return *addr;
-       else
+       if (__is_ioaddr((unsigned long) addr))
                return readw((unsigned long) addr);
+       else
+               return *addr;
 }
 
 extern inline void scr_memsetw(u16 *s, u16 c, unsigned int count)
 {
-       if ((long)s < 0)
-               memsetw(s, c, count);
-       else
+       if (__is_ioaddr((unsigned long) s))
                memsetw_io(s, c, count);
+       else
+               memsetw(s, c, count);
 }
 
 extern inline void scr_memcpyw_from(u16 *d, const u16 *s, unsigned int count)
@@ -51,6 +51,6 @@ extern inline void scr_memcpyw_to(u16 *d, const u16 *s, unsigned int count)
 #define vga_readb readb
 #define vga_writeb writeb
 
-#define VGA_MAP_MEM(x) (x)
+#define VGA_MAP_MEM(x) ((unsigned long) ioremap((x), 0))
 
 #endif
index 717ecfa7fed896403881195302db3186cce0f1da..3bcf85065c1910cf0d6e9de496b883e1e920f091 100644 (file)
@@ -11,6 +11,8 @@
 #define FPSTATESIZE (216/sizeof(unsigned char))
 #elif defined(CONFIG_M68040)
 #define FPSTATESIZE (96/sizeof(unsigned char))
+#elif defined(CONFIG_M68KFPU_EMU)
+#define FPSTATESIZE (28/sizeof(unsigned char))
 #elif defined(CONFIG_M68060)
 #define FPSTATESIZE (12/sizeof(unsigned char))
 #else
index 1614ecd0bc0567f86733c53d24b502a49f0f9c72..0a62d30ef96a9f6e913c72aa2d393f5cc5cce604 100644 (file)
@@ -79,13 +79,17 @@ extern int sys_request_irq(unsigned int,
 extern void sys_free_irq(unsigned int, void *);
 
 /*
- * various flags for request_irq()
+ * various flags for request_irq() - the Amiga now uses the standard
+ * mechanism like all other architectures - SA_INTERRUPT and SA_SHIRQ
+ * are your friends.
  */
+#ifndef CONFIG_AMIGA
 #define IRQ_FLG_LOCK   (0x0001)        /* handler is not replaceable   */
 #define IRQ_FLG_REPLACE        (0x0002)        /* replace existing handler     */
 #define IRQ_FLG_FAST   (0x0004)
 #define IRQ_FLG_SLOW   (0x0008)
 #define IRQ_FLG_STD    (0x8000)        /* internally used              */
+#endif
 
 /*
  * This structure is used to chain together the ISRs for a particular
diff --git a/include/asm-m68k/math-emu.h b/include/asm-m68k/math-emu.h
new file mode 100644 (file)
index 0000000..a09dc54
--- /dev/null
@@ -0,0 +1,300 @@
+#ifndef _ASM_M68K_SETUP_H
+#define _ASM_M68K_SETUP_H
+
+#include <asm/setup.h>
+#include <linux/linkage.h>
+
+/* Status Register bits */
+
+/* accrued exception bits */
+#define FPSR_AEXC_INEX 3
+#define FPSR_AEXC_DZ   4
+#define FPSR_AEXC_UNFL 5
+#define FPSR_AEXC_OVFL 6
+#define FPSR_AEXC_IOP  7
+
+/* exception status bits */
+#define FPSR_EXC_INEX1 8
+#define FPSR_EXC_INEX2 9
+#define FPSR_EXC_DZ    10
+#define FPSR_EXC_UNFL  11
+#define FPSR_EXC_OVFL  12
+#define FPSR_EXC_OPERR 13
+#define FPSR_EXC_SNAN  14
+#define FPSR_EXC_BSUN  15
+
+/* quotient byte, assumes big-endian, of course */
+#define FPSR_QUOTIENT(fpsr) (*((signed char *) &(fpsr) + 1))
+
+/* condition code bits */
+#define FPSR_CC_NAN    24
+#define FPSR_CC_INF    25
+#define FPSR_CC_Z      26
+#define FPSR_CC_NEG    27
+
+
+/* Control register bits */
+
+/* rounding mode */
+#define        FPCR_ROUND_RN   0               /* round to nearest/even */
+#define FPCR_ROUND_RZ  1               /* round to zero */
+#define FPCR_ROUND_RM  2               /* minus infinity */
+#define FPCR_ROUND_RP  3               /* plus infinity */
+
+/* rounding precision */
+#define FPCR_PRECISION_X       0       /* long double */
+#define FPCR_PRECISION_S       1       /* double */
+#define FPCR_PRECISION_D       2       /* float */
+
+
+/* Flags to select the debugging output */
+#define PDECODE                0
+#define PEXECUTE       1
+#define PCONV          2
+#define PNORM          3
+#define PREGISTER      4
+#define PINSTR         5
+#define PUNIMPL                6
+#define PMOVEM         7
+
+#define PMDECODE       (1<<PDECODE)
+#define PMEXECUTE      (1<<PEXECUTE)
+#define PMCONV         (1<<PCONV)
+#define PMNORM         (1<<PNORM)
+#define PMREGISTER     (1<<PREGISTER)
+#define PMINSTR                (1<<PINSTR)
+#define PMUNIMPL       (1<<PUNIMPL)
+#define PMMOVEM                (1<<PMOVEM)
+
+#ifndef __ASSEMBLY__
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+union fp_mant64 {
+       unsigned long long m64;
+       unsigned long m32[2];
+};
+
+union fp_mant128 {
+       unsigned long long m64[2];
+       unsigned long m32[4];
+};
+
+/* internal representation of extended fp numbers */
+struct fp_ext {
+       unsigned char lowmant;
+       unsigned char sign;
+       unsigned short exp;
+       union fp_mant64 mant;
+};
+
+/* C representation of FPU registers */
+/* NOTE: if you change this, you have to change the assembler offsets
+   below and the size in <asm/fpu.h>, too */
+struct fp_data {
+       struct fp_ext fpreg[8];
+       unsigned int fpcr;
+       unsigned int fpsr;
+       unsigned int fpiar;
+       unsigned short prec;
+       unsigned short rnd;
+       struct fp_ext temp[2];
+};
+
+#if FPU_EMU_DEBUG
+extern unsigned int fp_debugprint;
+
+#define dprint(bit, fmt, args...) ({                   \
+       if (fp_debugprint & (1 << (bit)))               \
+               printk(fmt, ## args);                   \
+})
+#else
+#define dprint(bit, fmt, args...)
+#endif
+
+#define uprint(str) ({                                 \
+       static int __count = 3;                         \
+                                                       \
+       if (__count > 0) {                              \
+               printk("You just hit an unimplemented " \
+                      "fpu instruction (%s)\n", str);  \
+               printk("Please report this to ....\n"); \
+               __count--;                              \
+       }                                               \
+})
+
+#define FPDATA         ((struct fp_data *)current->thread.fp)
+
+#else  /* __ASSEMBLY__ */
+
+#define FPDATA         %a2
+
+/* offsets from the base register to the floating point data in the task struct */
+#define FPD_FPREG      (TASK_THREAD+THREAD_FPREG+0)
+#define FPD_FPCR       (TASK_THREAD+THREAD_FPREG+96)
+#define FPD_FPSR       (TASK_THREAD+THREAD_FPREG+100)
+#define FPD_FPIAR      (TASK_THREAD+THREAD_FPREG+104)
+#define FPD_PREC       (TASK_THREAD+THREAD_FPREG+108)
+#define FPD_RND                (TASK_THREAD+THREAD_FPREG+110)
+#define FPD_TEMPFP1    (TASK_THREAD+THREAD_FPREG+112)
+#define FPD_TEMPFP2    (TASK_THREAD+THREAD_FPREG+124)
+#define FPD_SIZEOF     (TASK_THREAD+THREAD_FPREG+136)
+
+/* offsets on the stack to access saved registers,
+ * these are only used during instruction decoding
+ * where we always know how deep we're on the stack.
+ */
+#define FPS_DO         (PT_D0)
+#define FPS_D1         (PT_D1)
+#define FPS_D2         (PT_D2)
+#define FPS_A0         (PT_A0)
+#define FPS_A1         (PT_A1)
+#define FPS_A2         (PT_A2)
+#define FPS_SR         (PT_SR)
+#define FPS_PC         (PT_PC)
+#define FPS_EA         (PT_PC+6)
+#define FPS_PC2                (PT_PC+10)
+
+.macro fp_get_fp_reg
+       lea     (FPD_FPREG,FPDATA,%d0.w*4),%a0
+       lea     (%a0,%d0.w*8),%a0
+.endm
+
+/* Macros used to get/put the current program counter.
+ * 020/030 use a different stack frame then 040/060, for the
+ * 040/060 the return pc points already to the next location,
+ * so this only needs to be modified for jump instructions.
+ */
+.macro fp_get_pc dest
+       move.l  (FPS_PC+4,%sp),\dest
+.endm
+
+.macro fp_put_pc src,jump=0
+       move.l  \src,(FPS_PC+4,%sp)
+.endm
+
+.macro fp_get_instr_data       f,s,dest,label
+       getuser \f,%sp@(FPS_PC+4)@(0),\dest,\label,%sp@(FPS_PC+4)
+       addq.l  #\s,%sp@(FPS_PC+4)
+.endm
+
+.macro fp_get_instr_word       dest,label,addr
+       fp_get_instr_data       w,2,\dest,\label,\addr
+.endm
+
+.macro fp_get_instr_long       dest,label,addr
+       fp_get_instr_data       l,4,\dest,\label,\addr
+.endm
+
+/* These macros are used to read from/write to user space
+ * on error we jump to the fixup section, load the fault
+ * address into %a0 and jump to the exit.
+ * (derived from <asm/uaccess.h>)
+ */
+.macro getuser size,src,dest,label,addr
+|      printf  ,"[\size<%08x]",1,\addr
+.Lu1\@:        moves\size      \src,\dest
+
+       .section .fixup,"ax"
+       .even
+.Lu2\@:        move.l  \addr,%a0
+       jra     \label
+       .previous
+
+       .section __ex_table,"a"
+       .align  4
+       .long   .Lu1\@,.Lu2\@
+       .previous
+.endm
+
+.macro putuser size,src,dest,label,addr
+|      printf  ,"[\size>%08x]",1,\addr
+.Lu1\@:        moves\size      \src,\dest
+.Lu2\@:
+
+       .section .fixup,"ax"
+       .even
+.Lu3\@:        move.l  \addr,%a0
+       jra     \label
+       .previous
+
+       .section __ex_table,"a"
+       .align  4
+       .long   .Lu1\@,.Lu3\@
+       .long   .Lu2\@,.Lu3\@
+       .previous
+.endm
+
+
+.macro movestack       nr,arg1,arg2,arg3,arg4,arg5
+       .if     \nr
+       movestack       (\nr-1),\arg2,\arg3,\arg4,\arg5
+       move.l  \arg1,-(%sp)
+       .endif
+.endm
+
+.macro printf  bit=-1,string,nr=0,arg1,arg2,arg3,arg4,arg5
+#ifdef FPU_EMU_DEBUG
+       .data
+.Lpdata\@:
+       .string "\string"
+       .previous
+
+       movem.l %d0/%d1/%a0/%a1,-(%sp)
+       .if     \bit+1
+#if 0
+       moveq   #\bit,%d0
+       andw    #7,%d0
+       btst    %d0,fp_debugprint+((31-\bit)/8)
+#else
+       btst    #\bit,fp_debugprint+((31-\bit)/8)
+#endif
+       jeq     .Lpskip\@
+       .endif
+       movestack       \nr,\arg1,\arg2,\arg3,\arg4,\arg5
+       pea     .Lpdata\@
+       jsr     printk
+       lea     ((\nr+1)*4,%sp),%sp
+.Lpskip\@:
+       movem.l (%sp)+,%d0/%d1/%a0/%a1
+#endif
+.endm
+
+.macro printx  bit,fp
+#ifdef FPU_EMU_DEBUG
+       movem.l %d0/%a0,-(%sp)
+       lea     \fp,%a0
+#if 0
+       moveq   #'+',%d0
+       tst.w   (%a0)
+       jeq     .Lx1\@
+       moveq   #'-',%d0
+.Lx1\@:        printf  \bit," %c",1,%d0
+       move.l  (4,%a0),%d0
+       bclr    #31,%d0
+       jne     .Lx2\@
+       printf  \bit,"0."
+       jra     .Lx3\@
+.Lx2\@:        printf  \bit,"1."
+.Lx3\@:        printf  \bit,"%08x%08x",2,%d0,%a0@(8)
+       move.w  (2,%a0),%d0
+       ext.l   %d0
+       printf  \bit,"E%04x",1,%d0
+#else
+       printf  \bit," %08x%08x%08x",3,%a0@,%a0@(4),%a0@(8)
+#endif
+       movem.l (%sp)+,%d0/%a0
+#endif
+.endm
+
+.macro debug   instr,args
+#ifdef FPU_EMU_DEBUG
+       \instr  \args
+#endif
+.endm
+
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_M68K_SETUP_H */
index d857208fe2911e8f111e6bfda836658bdd5e9ffe..5b6b8c73b92e96b1aee248d706ee53dd9ebd8f2a 100644 (file)
@@ -315,6 +315,16 @@ extern int m68k_is040or060;
 
 #define CPU_TYPE (m68k_cputype)
 
+#ifdef CONFIG_M68KFPU_EMU
+#  ifdef CONFIG_M68KFPU_EMU_ONLY
+#    define FPU_IS_EMU (1)
+#  else
+#    define FPU_IS_EMU (!m68k_fputype)
+#  endif
+#else
+#  define FPU_IS_EMU (0)
+#endif
+
 
     /*
      *  Miscellaneous
index 5c04c73e139975d701a234ac48c2a8257d558d08..fa6ca3b0d39c1b7371e98083fb2023d8dc57916a 100644 (file)
@@ -21,6 +21,7 @@
 #ifndef        _CYCLOMX_H
 #define        _CYCLOMX_H
 
+#include <linux/config.h>
 #include <linux/wanrouter.h>
 #include <asm/spinlock.h>
 
index 28309dc8b1e3307878b5597b96803c87f5cb35cf..b22c43a0b5239d777ea3e86b9234b240c8238f73 100644 (file)
@@ -8,6 +8,19 @@
 #ifndef _LINUX_IOPORT_H
 #define _LINUX_IOPORT_H
 
+#define DEVICE_IO_NOTSET       (~0)
+#define DEVICE_IO_AUTO         ((~0)-1)
+
+#define DEVICE_IO_FLAG_WRITEABLE       (1<<0)
+#define DEVICE_IO_FLAG_CACHEABLE       (1<<1)
+#define DEVICE_IO_FLAG_RANGELENGTH     (1<<2)
+#define DEVICE_IO_FLAG_SHADOWABLE      (1<<4)
+#define DEVICE_IO_FLAG_EXPANSIONROM    (1<<5)
+
+#define DEVICE_IO_TYPE_8BIT            0
+#define DEVICE_IO_TYPE_16BIT           1
+#define DEVICE_IO_TYPE_8AND16BIT       2
+
 /*
  * Resources are tree-like, allowing
  * nesting etc..
@@ -16,6 +29,10 @@ struct resource {
        const char *name;
        unsigned long start, end;
        unsigned long flags;
+       unsigned char bits;             /* decoded bits */
+       unsigned char fixed;            /* fixed range */
+       unsigned short hw_flags;        /* hardware flags */
+       unsigned short type;            /* region type */
        struct resource *parent, *sibling, *child;
 };
 
diff --git a/include/linux/isapnp.h b/include/linux/isapnp.h
new file mode 100644 (file)
index 0000000..9aab523
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ *  ISA Plug & Play support
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *
+ *
+ *   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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef LINUX_ISAPNP_H
+#define LINUX_ISAPNP_H
+
+#include <linux/config.h>
+
+/*
+ *  Configuration registers (TODO: change by specification)
+ */ 
+
+#define ISAPNP_CFG_ACTIVATE            0x30    /* byte */
+#define ISAPNP_CFG_MEM                 0x40    /* 4 * dword */
+#define ISAPNP_CFG_PORT                        0x60    /* 8 * word */
+#define ISAPNP_CFG_IRQ                 0x70    /* 2 * word */
+#define ISAPNP_CFG_DMA                 0x74    /* 2 * byte */
+
+/*
+ *
+ */
+
+#define ISAPNP_VENDOR(a,b,c)   (((((a)-'A'+1)&0x3f)<<2)|\
+                               ((((b)-'A'+1)&0x18)>>3)|((((b)-'A'+1)&7)<<13)|\
+                               ((((c)-'A'+1)&0x1f)<<8))
+#define ISAPNP_DEVICE(x)       ((((x)&0xf000)>>8)|\
+                                (((x)&0x0f00)>>8)|\
+                                (((x)&0x00f0)<<8)|\
+                                (((x)&0x000f)<<8))
+#define ISAPNP_FUNCTION(x)     ISAPNP_DEVICE(x)
+
+/*
+ *
+ */
+
+#ifdef __KERNEL__
+
+#include <linux/pci.h>
+
+#define ISAPNP_PORT_FLAG_16BITADDR     (1<<0)
+#define ISAPNP_PORT_FLAG_FIXED         (1<<1)
+
+struct isapnp_port {
+       unsigned short min;             /* min base number */
+       unsigned short max;             /* max base number */
+       unsigned char align;            /* align boundary */
+       unsigned char size;             /* size of range */
+       unsigned short flags;           /* port flags */
+       struct isapnp_resources *res;   /* parent */
+       struct isapnp_port *next;       /* next port */
+};
+
+struct isapnp_irq {
+       unsigned short map;             /* bitmaks for IRQ lines */
+       unsigned short flags;           /* IRQ flags */
+       struct isapnp_resources *res;   /* parent */
+       struct isapnp_irq *next;        /* next IRQ */
+};
+
+struct isapnp_dma {
+       unsigned char map;              /* bitmask for DMA channels */
+       unsigned char type;             /* DMA type */
+       unsigned char flags;            /* DMA flags */
+       unsigned char speed;            /* DMA speed */
+       struct isapnp_resources *res;   /* parent */
+       struct isapnp_dma *next;        /* next port */
+};
+
+struct isapnp_mem {
+       unsigned int min;               /* min base number */
+       unsigned int max;               /* max base number */
+       unsigned int align;             /* align boundary */
+       unsigned int size;              /* size of range */
+       unsigned short flags;           /* memory flags */
+       unsigned short type;            /* memory type */
+       struct isapnp_resources *res;   /* parent */
+       struct isapnp_mem *next;        /* next memory resource */
+};
+
+struct isapnp_mem32 {
+       /* TODO */
+       unsigned char data[17];
+       struct isapnp_resources *res;   /* parent */
+       struct isapnp_mem32 *next;      /* next 32-bit memory resource */
+};
+
+#define ISAPNP_RES_PRIORITY_PREFERRED  0
+#define ISAPNP_RES_PRIORITY_ACCEPTABLE 1
+#define ISAPNP_RES_PRIORITY_FUNCTIONAL 2
+#define ISAPNP_RES_PRIORITY_INVALID    65535
+
+struct isapnp_resources {
+       unsigned short priority;        /* priority */
+       unsigned short dependent;       /* dependent resources */
+       struct isapnp_port *port;       /* first port */
+       struct isapnp_irq *irq;         /* first IRQ */
+       struct isapnp_dma *dma;         /* first DMA */
+       struct isapnp_mem *mem;         /* first memory resource */
+       struct isapnp_mem32 *mem32;     /* first 32-bit memory */
+       struct pci_dev *dev;            /* parent */
+       struct isapnp_resources *alt;   /* alternative resource (aka dependent resources) */
+       struct isapnp_resources *next;  /* next resource */
+};
+
+#ifdef CONFIG_ISAPNP
+
+/* lowlevel configuration */
+int isapnp_present(void);
+int isapnp_cfg_begin(int csn, int device);
+int isapnp_cfg_end(void);
+unsigned char isapnp_read_byte(unsigned char idx);
+unsigned short isapnp_read_word(unsigned char idx);
+unsigned int isapnp_read_dword(unsigned char idx);
+void isapnp_write_byte(unsigned char idx, unsigned char val);
+void isapnp_write_word(unsigned char idx, unsigned short val);
+void isapnp_write_dword(unsigned char idx, unsigned int val);
+void isapnp_wake(unsigned char csn);
+void isapnp_device(unsigned char device);
+void isapnp_activate(unsigned char device);
+void isapnp_deactivate(unsigned char device);
+/* manager */
+struct pci_bus *isapnp_find_card(unsigned short vendor,
+                                unsigned short device,
+                                struct pci_bus *from);
+struct pci_dev *isapnp_find_dev(struct pci_bus *card,
+                               unsigned short vendor,
+                               unsigned short function,
+                               struct pci_dev *from);
+/* init/main.c */
+int isapnp_init(void);
+
+#else /* !CONFIG_ISAPNP */
+
+/* lowlevel configuration */
+extern inline int isapnp_present(void) { return 0; }
+extern inline int isapnp_cfg_begin(int csn, int device) { return -ENODEV; }
+extern inline int isapnp_cfg_end(void) { return -ENODEV; }
+extern inline unsigned char isapnp_read_byte(unsigned char idx) { return 0xff; }
+extern inline unsigned short isapnp_read_word(unsigned char idx) { return 0xffff; }
+extern inline unsigned int isapnp_read_dword(unsigned char idx) { return 0xffffffff; }
+extern inline void isapnp_write_byte(unsigned char idx, unsigned char val) { ; }
+extern inline void isapnp_write_word(unsigned char idx, unsigned short val) { ; }
+extern inline void isapnp_write_dword(unsigned char idx, unsigned int val) { ; }
+extern void isapnp_wake(unsigned char csn) { ; }
+extern void isapnp_device(unsigned char device) { ; }
+extern void isapnp_activate(unsigned char device) { ; }
+extern void isapnp_deactivate(unsigned char device) { ; }
+/* manager */
+extern struct pci_bus *isapnp_find_card(unsigned short vendor,
+                                       unsigned short device,
+                                       struct pci_bus *from) { return NULL; }
+extern struct pci_dev *isapnp_find_dev(struct pci_bus *card,
+                                      unsigned short vendor,
+                                      unsigned short function,
+                                      struct pci_dev *from) { return NULL; }
+
+#endif /* CONFIG_ISAPNP */
+
+#endif /* __KERNEL__ */
+#endif /* LINUX_ISAPNP_H */
index 853f236f6fef07652b48690b398dfcac88b56385..79190775fa0acda4f42bc7274fe0fe002f784be1 100644 (file)
@@ -393,9 +393,6 @@ typedef struct {
 
 #ifdef __KERNEL__
 
-#ifndef STANDALONE
-#include <linux/config.h>
-#endif
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/major.h>
index a62101d0f7789319ee3adb5f50ee685b5bebc578..9ca7dc7cde3210a0b8031e977bbaeb65aa523b8d 100644 (file)
@@ -3,6 +3,7 @@
 #ifndef _LINUX_ISDN_PPP_H
 #define _LINUX_ISDN_PPP_H
 
+#include <linux/config.h>
 #include <linux/isdn_compat.h>
 
 #define CALLTYPE_INCOMING 0x1
index aeb177ab3956e547f7fde0aa83ebc3d25a30c252..35b66bba836d1ed57b9884a415f6f3cc739f9042 100644 (file)
 #ifndef isdnif_h
 #define isdnif_h
 
+#include <linux/config.h>
 #include <linux/isdn_compat.h>
 
 /*
index e6f96a396f56fffe60dacc78cae64f9fdbebd310..e9111e6bd21baf5ee4c33003ef71768cf2cd5eb6 100644 (file)
 #include <linux/config.h>
 #include <linux/ioport.h>
 
+#define DEVICE_COUNT_COMPATIBLE        4
+#define DEVICE_COUNT_DMA       2
+#define DEVICE_COUNT_RESOURCE  12
+
+#define DEVICE_IRQ_NOTSET      0xffffffff
+#define DEVICE_IRQ_AUTO                0xfffffffe
+#define DEVICE_DMA_NOTSET      0xff
+#define DEVICE_DMA_AUTO                0xfe
+
+#define DEVICE_IRQ_FLAG_HIGHEDGE       (1<<0)
+#define DEVICE_IRQ_FLAG_LOWEDGE                (1<<1)
+#define DEVICE_IRQ_FLAG_HIGHLEVEL      (1<<2)
+#define DEVICE_IRQ_FLAG_LOWLEVEL       (1<<3)
+
+#define DEVICE_DMA_TYPE_8BIT           0
+#define DEVICE_DMA_TYPE_8AND16BIT      1
+#define DEVICE_DMA_TYPE_16BIT          2
+
+#define DEVICE_DMA_FLAG_MASTER         (1<<0)
+#define DEVICE_DMA_FLAG_BYTE           (1<<1)
+#define DEVICE_DMA_FLAG_WORD           (1<<2)
+
+#define DEVICE_DMA_SPEED_COMPATIBLE    0
+#define DEVICE_DMA_SPEED_TYPEA         1
+#define DEVICE_DMA_SPEED_TYPEB         2
+#define DEVICE_DMA_SPEED_TYPEF         3
+
 /*
  * There is one pci_dev structure for each slot-number/function-number
  * combination:
  */
 struct pci_dev {
+       int active;                     /* device is active */
+       int ro;                         /* Read/Only */
+
        struct pci_bus  *bus;           /* bus this device is on */
        struct pci_dev  *sibling;       /* next device on this bus */
        struct pci_dev  *next;          /* chain of all devices */
@@ -1227,6 +1257,12 @@ struct pci_dev {
        unsigned int    hdr_type;       /* PCI header type */
        unsigned int    master : 1;     /* set if device is master capable */
 
+       unsigned short  regs;
+       
+       /* device is compatible with these IDs */
+       unsigned short vendor_compatible[DEVICE_COUNT_COMPATIBLE];
+       unsigned short device_compatible[DEVICE_COUNT_COMPATIBLE];
+
        char            name[48];
 
        /*
@@ -1241,12 +1277,23 @@ struct pci_dev {
         * cannot generate interrupts at all.
         */
        unsigned int    irq;            /* irq generated by this device */
+       unsigned short  irq_flags;      /* irq type */
+       unsigned int    irq2;
+       unsigned short  irq2_flags;     
+       unsigned char   dma[DEVICE_COUNT_DMA];
+       unsigned char   dma_type[DEVICE_COUNT_DMA];
+       unsigned char   dma_flags[DEVICE_COUNT_DMA];
+       unsigned char   dma_speed[DEVICE_COUNT_DMA];
 
        /* Base registers for this device, can be adjusted by
         * pcibios_fixup() as necessary.
         */
-       struct resource resource[6];
+       struct resource resource[DEVICE_COUNT_RESOURCE];
        unsigned long   rom_address;
+
+       int (*prepare)(struct pci_dev *dev);
+       int (*activate)(struct pci_dev *dev);
+       int (*deactivate)(struct pci_dev *dev);
 };
 
 struct pci_bus {
@@ -1264,6 +1311,15 @@ struct pci_bus {
        unsigned char   primary;        /* number of primary bridge */
        unsigned char   secondary;      /* number of secondary bridge */
        unsigned char   subordinate;    /* max number of subordinate buses */
+
+       char            name[48];
+       unsigned short  vendor;
+       unsigned short  device;
+       unsigned int    serial;         /* serial number */
+       unsigned char   pnpver;         /* Plug & Play version */
+       unsigned char   productver;     /* product version */
+       unsigned char   checksum;       /* if zero - checksum passed */
+       unsigned char   pad1;
 };
 
 extern struct pci_bus  pci_root;       /* root bus */
index 065b91c94aff16744d696b3bc984e666a7950505..26bf3ed71a491f022c53112977aa24a039c3d442 100644 (file)
@@ -716,6 +716,7 @@ do {                                                                        \
        add_wait_queue(&wq, &__wait);                                   \
        for (;;) {                                                      \
                current->state = TASK_UNINTERRUPTIBLE;                  \
+               mb();                                                   \
                if (condition)                                          \
                        break;                                          \
                schedule();                                             \
@@ -739,6 +740,7 @@ do {                                                                        \
        add_wait_queue(&wq, &__wait);                                   \
        for (;;) {                                                      \
                current->state = TASK_INTERRUPTIBLE;                    \
+               mb();                                                   \
                if (condition)                                          \
                        break;                                          \
                if (!signal_pending(current)) {                         \
index cf5013ddf366aba90efd3810abf5dde73d555964..4f3df4c74fb3d6fe60847f3e113d2020b6ae1a6e 100644 (file)
 extern void nubus_init(void);
 #endif
 
+#ifdef CONFIG_ISAPNP
+#include <linux/isapnp.h>
+#endif
+
 /*
  * Versions of gcc older than that listed below may actually compile
  * and link okay, but the end product can have subtle run time bugs.
@@ -632,6 +636,9 @@ static void __init do_basic_setup(void)
 #ifdef CONFIG_MAC
        nubus_init();
 #endif
+#ifdef CONFIG_ISAPNP
+       isapnp_init();
+#endif
 
        /* Networking initialization needs a process context */ 
        sock_init();
index ed438f2d96e870bd278df10b6228196297c68eed..09fb686280e94b5de652f16aabe8ed7167dff634 100644 (file)
@@ -118,7 +118,7 @@ __setup("console=", console_setup);
  */
 int do_syslog(int type, char * buf, int len)
 {
-       unsigned long i, j, count, flags;
+       unsigned long i, j, count;
        int do_clear = 0;
        char c;
        int error = -EPERM;
index 6ea7e979152b334ef4be6ec3f8ffb6be8608475d..6178c6abfe3c5d9921ac860316a0d866445a9beb 100644 (file)
@@ -50,10 +50,7 @@ static int try_to_swap_out(struct vm_area_struct* vma, unsigned long address, pt
        if (pte_val(pte) != pte_val(*page_table))
                goto out_failed_unlock;
 
-       /*
-        * Dont be too eager to get aging right if
-        * memory is dangerously low.
-        */
+       /* Don't look at this pte if it's been accessed recently. */
        if (pte_young(pte)) {
                /*
                 * Transfer the "accessed" bit from the page
index f96167bc86ca5dbae43979d9691e57a444de5648..b5abf8660e08a8dff0522fd39a2f07071e0ee0d2 100644 (file)
@@ -178,7 +178,9 @@ EXPORT_SYMBOL(neigh_sysctl_register);
 #endif
 EXPORT_SYMBOL(pneigh_lookup);
 EXPORT_SYMBOL(pneigh_enqueue);
+EXPORT_SYMBOL(neigh_create);
 EXPORT_SYMBOL(neigh_destroy);
+EXPORT_SYMBOL(neigh_lookup);
 EXPORT_SYMBOL(neigh_parms_alloc);
 EXPORT_SYMBOL(neigh_parms_release);
 EXPORT_SYMBOL(neigh_rand_reach_time);