]> git.neil.brown.name Git - history.git/commitdiff
Import 2.3.4pre3 2.3.4pre3
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:25:15 +0000 (15:25 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:25:15 +0000 (15:25 -0500)
171 files changed:
README
arch/i386/defconfig
arch/sparc/defconfig
arch/sparc/kernel/irq.c
arch/sparc/kernel/setup.c
arch/sparc/math-emu/Makefile
arch/sparc/math-emu/fabss.c
arch/sparc/math-emu/fcmpd.c
arch/sparc/math-emu/fcmped.c
arch/sparc/math-emu/fcmpeq.c
arch/sparc/math-emu/fcmpes.c
arch/sparc/math-emu/fcmpq.c
arch/sparc/math-emu/fcmps.c
arch/sparc/math-emu/fdmulq.c
arch/sparc/math-emu/fdtoq.c
arch/sparc/math-emu/fdtos.c
arch/sparc/math-emu/fmovs.c
arch/sparc/math-emu/fnegs.c
arch/sparc/math-emu/fqtod.c
arch/sparc/math-emu/fqtos.c
arch/sparc/math-emu/fsmuld.c
arch/sparc/math-emu/fstod.c
arch/sparc/math-emu/fstoq.c
arch/sparc/math-emu/math.c
arch/sparc/math-emu/sfp-machine.h
arch/sparc/math-emu/sfp-util.h [new file with mode: 0644]
arch/sparc64/defconfig
arch/sparc64/kernel/setup.c
arch/sparc64/math-emu/Makefile
arch/sparc64/math-emu/double.h
arch/sparc64/math-emu/extended.h [new file with mode: 0644]
arch/sparc64/math-emu/fabsq.c
arch/sparc64/math-emu/faddd.c
arch/sparc64/math-emu/faddq.c
arch/sparc64/math-emu/fadds.c
arch/sparc64/math-emu/fcmpeq.c
arch/sparc64/math-emu/fcmpq.c
arch/sparc64/math-emu/fdivd.c
arch/sparc64/math-emu/fdivq.c
arch/sparc64/math-emu/fdivs.c
arch/sparc64/math-emu/fdmulq.c
arch/sparc64/math-emu/fdtoi.c
arch/sparc64/math-emu/fdtoq.c
arch/sparc64/math-emu/fdtos.c
arch/sparc64/math-emu/fdtox.c
arch/sparc64/math-emu/fitoq.c
arch/sparc64/math-emu/fmovq.c
arch/sparc64/math-emu/fmuld.c
arch/sparc64/math-emu/fmulq.c
arch/sparc64/math-emu/fmuls.c
arch/sparc64/math-emu/fnegq.c
arch/sparc64/math-emu/fqtod.c
arch/sparc64/math-emu/fqtoi.c
arch/sparc64/math-emu/fqtos.c
arch/sparc64/math-emu/fqtox.c
arch/sparc64/math-emu/fsmuld.c
arch/sparc64/math-emu/fsqrtd.c
arch/sparc64/math-emu/fsqrtq.c
arch/sparc64/math-emu/fsqrts.c
arch/sparc64/math-emu/fstod.c
arch/sparc64/math-emu/fstoi.c
arch/sparc64/math-emu/fstoq.c
arch/sparc64/math-emu/fstox.c
arch/sparc64/math-emu/fsubd.c
arch/sparc64/math-emu/fsubq.c
arch/sparc64/math-emu/fsubs.c
arch/sparc64/math-emu/fxtoq.c
arch/sparc64/math-emu/math.c
arch/sparc64/math-emu/op-1.h
arch/sparc64/math-emu/op-2.h
arch/sparc64/math-emu/op-4.h
arch/sparc64/math-emu/op-8.h [new file with mode: 0644]
arch/sparc64/math-emu/op-common.h
arch/sparc64/math-emu/quad.h
arch/sparc64/math-emu/sfp-machine.h
arch/sparc64/math-emu/sfp-util.h [new file with mode: 0644]
arch/sparc64/math-emu/single.h
arch/sparc64/math-emu/soft-fp.h
arch/sparc64/math-emu/udivmodti4.c [deleted file]
drivers/block/loop.c
drivers/block/ns87415.c
drivers/char/bttv.c
drivers/char/bttv.h
drivers/net/cosa.c
drivers/net/eexpress.c
drivers/net/irda/Config.in
drivers/net/irda/Makefile
drivers/net/irda/actisys.c
drivers/net/irda/esi.c
drivers/net/irda/girbil.c
drivers/net/irda/irport.c
drivers/net/irda/irtty.c
drivers/net/irda/litelink.c [new file with mode: 0644]
drivers/net/irda/pc87108.c
drivers/net/irda/tekram.c
drivers/net/irda/toshoboe.c [new file with mode: 0644]
drivers/net/irda/uircc.c
drivers/net/irda/w83977af_ir.c
drivers/usb/Config.in
drivers/usb/Makefile
drivers/usb/acm.c
drivers/usb/audio.c
drivers/usb/cpia.c
drivers/usb/hub.c
drivers/usb/inits.h
drivers/usb/keyboard.c
drivers/usb/mouse.c
drivers/usb/ohci-hcd.c
drivers/usb/ohci-hcd.h
drivers/usb/ohci.c
drivers/usb/ohci.h
drivers/usb/uhci-debug.c
drivers/usb/uhci.c
drivers/usb/uhci.h
drivers/usb/usb-core.c [new file with mode: 0644]
drivers/usb/usb.c
drivers/usb/usb.h
include/net/ip_masq.h
include/net/irda/crc.h
include/net/irda/dongle.h
include/net/irda/ircomm_common.h
include/net/irda/irda.h
include/net/irda/irda_device.h
include/net/irda/iriap.h
include/net/irda/irlan_common.h
include/net/irda/irlan_provider.h
include/net/irda/irlap.h
include/net/irda/irlmp.h
include/net/irda/irlpt_common.h
include/net/irda/irport.h
include/net/irda/irttp.h
include/net/irda/irtty.h
include/net/irda/toshoboe.h [new file with mode: 0644]
include/net/irda/w83977af_ir.h
include/net/irda/wrapper.h
net/decnet/Config.in
net/decnet/af_decnet.c
net/decnet/dn_dev.c
net/decnet/dn_nsp_in.c
net/decnet/dn_timer.c
net/irda/af_irda.c
net/irda/crc.c
net/irda/discovery.c
net/irda/ircomm/ircomm_common.c
net/irda/ircomm/irvtd_driver.c
net/irda/irda_device.c
net/irda/iriap.c
net/irda/iriap_event.c
net/irda/irlan/irlan_client.c
net/irda/irlan/irlan_client_event.c
net/irda/irlan/irlan_common.c
net/irda/irlan/irlan_eth.c
net/irda/irlan/irlan_event.c
net/irda/irlan/irlan_filter.c
net/irda/irlan/irlan_provider.c
net/irda/irlan/irlan_provider_event.c
net/irda/irlap_comp.c
net/irda/irlap_event.c
net/irda/irlap_frame.c
net/irda/irlmp.c
net/irda/irlmp_frame.c
net/irda/irlpt/irlpt_cli.c
net/irda/irlpt/irlpt_cli_fsm.c
net/irda/irlpt/irlpt_common.c
net/irda/irlpt/irlpt_srvr.c
net/irda/irmod.c
net/irda/irproc.c
net/irda/irsysctl.c
net/irda/irttp.c
net/irda/qos.c
net/irda/wrapper.c

diff --git a/README b/README
index ff9effabe5b201de5ef658c1c43ac49303b66afa..dd95240e60ed27d25296f92925ee991e9fee6e9a 100644 (file)
--- a/README
+++ b/README
@@ -46,11 +46,11 @@ DOCUMENTATION:
  - There is a lot of documentation available both in electronic form on
    the Internet and in books, both Linux-specific and pertaining to
    general UNIX questions.  I'd recommend looking into the documentation
-   subdirectories on any Linux ftp site for the LDP (Linux Documentation
+   subdirectories on any Linux FTP site for the LDP (Linux Documentation
    Project) books.  This README is not meant to be documentation on the
    system: there are much better sources available.
 
- - There are various readme's in the kernel Documentation/ subdirectory:
+ - There are various README files in the Documentation/ subdirectory:
    these typically contain kernel-specific installation notes for some 
    drivers for example. See ./Documentation/00-INDEX for a list of what
    is contained in each file.  Please read the Changes file, as it
@@ -233,7 +233,7 @@ IF SOMETHING GOES WRONG:
    isn't anyone listed there, then the second best thing is to mail
    them to me (torvalds@transmeta.com), and possibly to any other
    relevant mailing-list or to the newsgroup.  The mailing-lists are
-   useful especially for SCSI and NETworking problems, as I can't test
+   useful especially for SCSI and networking problems, as I can't test
    either of those personally anyway. 
 
  - In all bug-reports, *please* tell what kernel you are talking about,
index 11d77ecc318303b6c872d3d5693fe5a059a56e6b..7960c4dc371509ec719deb3754fe1a25e7bd7de0 100644 (file)
@@ -304,6 +304,7 @@ CONFIG_USB_UHCI=y
 # CONFIG_USB_OHCI_HCD is not set
 CONFIG_USB_MOUSE=y
 CONFIG_USB_KBD=y
+CONFIG_USB_HUB=y
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
index b6a4608e12aaf98d59f855f36518e5808ac6bb35..d3e7ef52a46a4834c8e8c11389fd3c047457fc33 100644 (file)
@@ -128,6 +128,10 @@ CONFIG_IPX=m
 # CONFIG_IPX_INTERN is not set
 # CONFIG_SPX is not set
 CONFIG_ATALK=m
+CONFIG_DECNET=m
+CONFIG_DECNET_SIOCGIFCONF=y
+# CONFIG_DECNET_ROUTER is not set
+CONFIG_DECNET_RAW=y
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_BRIDGE is not set
@@ -272,6 +276,7 @@ CONFIG_BSD_DISKLABEL=y
 # CONFIG_MAC_PARTITION is not set
 CONFIG_SMD_DISKLABEL=y
 CONFIG_SOLARIS_X86_PARTITION=y
+# CONFIG_SGI_DISKLABEL is not set
 # CONFIG_UNIXWARE_DISKLABEL is not set
 CONFIG_AMIGA_PARTITION=y
 CONFIG_NLS=y
index 26f3194bd26661f2f431bdd97d0efcb1edeff475..1ab0ccbce04182a3c077be01ce9a3caf6506b106 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: irq.c,v 1.93 1999/04/21 06:15:45 anton Exp $
+/*  $Id: irq.c,v 1.94 1999/05/28 14:59:20 anton Exp $
  *  arch/sparc/kernel/irq.c:  Interrupt request handling routines. On the
  *                            Sparc the IRQ's are basically 'cast in stone'
  *                            and you are supposed to probe the prom's device
@@ -491,15 +491,13 @@ void handler_irq(int irq, struct pt_regs * regs)
        extern void smp4m_irq_rotate(int cpu);
 #endif
 
+       irq_enter(cpu, irq);
        disable_pil_irq(irq);
-#if 0 /* FIXME: rotating IRQs halts the machine during SCSI probe. -ecd */
 #ifdef __SMP__
        /* Only rotate on lower priority IRQ's (scsi, ethernet, etc.). */
        if(irq < 10)
                smp4m_irq_rotate(cpu);
 #endif
-#endif
-       irq_enter(cpu, irq);
        action = *(irq + irq_action);
        kstat.irqs[cpu][irq]++;
        do {
@@ -508,8 +506,8 @@ void handler_irq(int irq, struct pt_regs * regs)
                action->handler(irq, action->dev_id, regs);
                action = action->next;
        } while (action);
-       irq_exit(cpu, irq);
        enable_pil_irq(irq);
+       irq_exit(cpu, irq);
 }
 
 #ifdef CONFIG_BLK_DEV_FD
index d29c1cb661388b393ec7269903f64f84a3f30a64..51ece9a39da009b9f24b709089d6da74575028c9 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.105 1999/04/13 14:17:08 jj Exp $
+/*  $Id: setup.c,v 1.106 1999/05/28 16:03:18 anton Exp $
  *  linux/arch/sparc/kernel/setup.c
  *
  *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
@@ -456,6 +456,7 @@ __initfunc(void setup_arch(char **cmdline_p,
                                        prom_printf("MrCoffee keyboard\n");
                                } else {
                                        prom_printf("Inconsistent or unknown console\n");
+                                       prom_printf("You cannot mix serial and non serial input/output devices\n");
                                        prom_halt();
                                }
                        }
index d7642b2e9841a1393eb6e1b61aa12d1ef8a06970..b85e48924ec0fe9fb35a87157e0a615c98923b2e 100644 (file)
@@ -14,13 +14,13 @@ O_OBJS   := math.o ashldi3.o fabss.o faddd.o faddq.o fadds.o                \
                fdtos.o fitoq.o fmovs.o fmuld.o fmulq.o fmuls.o         \
                fnegs.o fqtod.o fqtoi.o fqtos.o fsmuld.o fsqrtd.o       \
                fsqrtq.o fsqrts.o fstod.o fstoi.o fstoq.o fsubd.o       \
-               fsubq.o fsubs.o udivmodti4.o
+               fsubq.o fsubs.o
 
 LINKS   := double.h faddd.c faddq.c fadds.c fdivd.c fdivq.c fdivs.c    \
                fdtoi.c fitoq.c fmuld.c fmulq.c fmuls.c fqtoi.c         \
                fsqrtd.c fsqrtq.c fsqrts.c fstoi.c fsubd.c              \
-               fsubq.c fsubs.c op-1.h op-2.h op-4.h op-common.h quad.h \
-               single.h soft-fp.h udivmodti4.c
+               fsubq.c fsubs.c op-1.h op-2.h op-4.h op-8.h             \
+               op-common.h quad.h single.h soft-fp.h
 
 .S.s:
        $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
index 5429cc73365c57fae1c35b28fdaf7cbf2ee4654a..7af16b7f90a6065160e7b83004a460ec1ab2c4c4 100644 (file)
@@ -1,6 +1,12 @@
+/* $Id: fabss.c,v 1.8 1999/05/28 13:41:33 jj Exp $
+ * arch/sparc/math-emu/fabss.c
+ *
+ * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk)
+ *
+ */
+
 int FABSS(unsigned long *rd, unsigned long *rs2)
 {
-       /* Clear the sign bit (high bit of word 0) */
        rd[0] = rs2[0] & 0x7fffffffUL;
        return 0;
 }
index 8adb30d882a893ebc6de01371f6b594e0b411623..05a460eeeaf651236e3a2998ab08dad1a78ef1f8 100644 (file)
@@ -1,18 +1,33 @@
+/* $Id: fcmpd.c,v 1.8 1999/05/28 13:41:36 jj Exp $
+ * arch/sparc/math-emu/fcmpd.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "double.h"
 
 int FCMPD(void *rd, void *rs2, void *rs1)
 {
+       FP_DECL_EX;
        FP_DECL_D(A); FP_DECL_D(B);
        long ret;
-       unsigned long *fsr = rd;
+       unsigned long fsr;
        
-       __FP_UNPACK_D(A, rs1);
-       __FP_UNPACK_D(B, rs2);
-       FP_CMP_D(ret, B, A, 2);
-       if (ret == -1)
-               ret = 2;
-
-       *fsr = (*fsr & ~0xc00) | (ret << 10); 
-       return 0;
+       FP_UNPACK_RAW_DP(A, rs1);
+       FP_UNPACK_RAW_DP(B, rs2);
+       FP_CMP_D(ret, B, A, 3);
+       if (ret == 3 && (FP_ISSIGNAN_D(A) || FP_ISSIGNAN_D(B)))
+               FP_SET_EXCEPTION(FP_EX_INVALID);
+       if (!FP_INHIBIT_RESULTS) {
+               if (ret == -1) ret = 2;
+               fsr = *(long *)rd;
+               fsr &= ~0xc00;
+               fsr |= (ret << 10);
+               *(long *)rd = fsr;
+       }
+       FP_HANDLE_EXCEPTIONS;
 }
index 2033b1dc82e70cca3e4696e076e67840ad04361a..5b634da28e8596cabaa4452ed1c664b00fcbd9d7 100644 (file)
@@ -1,18 +1,33 @@
+/* $Id: fcmped.c,v 1.8 1999/05/28 13:41:38 jj Exp $
+ * arch/sparc/math-emu/fcmped.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "double.h"
 
 int FCMPED(void *rd, void *rs2, void *rs1)
 {
+       FP_DECL_EX;
        FP_DECL_D(A); FP_DECL_D(B);
        long ret;
-       unsigned long *fsr = rd;
+       unsigned long fsr;
        
-       __FP_UNPACK_D(A, rs1);
-       __FP_UNPACK_D(B, rs2);
-       FP_CMP_D(ret, B, A, 2);
-       if (ret == -1)
-               ret = 2;
-
-       *fsr = (*fsr & ~0xc00) | (ret << 10); 
-       return 0;
+       FP_UNPACK_RAW_DP(A, rs1);
+       FP_UNPACK_RAW_DP(B, rs2);
+       FP_CMP_D(ret, B, A, 3);
+       if (ret == 3)
+               FP_SET_EXCEPTION(FP_EX_INVALID);
+       if (!FP_INHIBIT_RESULTS) {
+               if (ret == -1) ret = 2;
+               fsr = *(long *)rd;
+               fsr &= ~0xc00;
+               fsr |= (ret << 10);
+               *(long *)rd = fsr;
+       }
+       FP_HANDLE_EXCEPTIONS;
 }
index de99bf343a4d3a967f5d3dc4dfcc9ddfe86582f6..eb76019abed00b4dd19b76bf11a4eca0ecd90f59 100644 (file)
@@ -1,18 +1,33 @@
+/* $Id: fcmpeq.c,v 1.8 1999/05/28 13:41:42 jj Exp $
+ * arch/sparc/math-emu/fcmpeq.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "quad.h"
 
 int FCMPEQ(void *rd, void *rs2, void *rs1)
 {
+       FP_DECL_EX;
        FP_DECL_Q(A); FP_DECL_Q(B);
        long ret;
        unsigned long fsr;
        
-       __FP_UNPACK_Q(A, rs1);
-       __FP_UNPACK_Q(B, rs2);
+       FP_UNPACK_RAW_QP(A, rs1);
+       FP_UNPACK_RAW_QP(B, rs2);
        FP_CMP_Q(ret, B, A, 3);
-       if (ret == -1) ret = 2;
-       fsr = *(unsigned long *)rd;
-       fsr &= ~0xc00; fsr |= (ret << 10);
-       *(unsigned long *)rd = fsr;
-       return 0;
+       if (ret == 3)
+               FP_SET_EXCEPTION(FP_EX_INVALID);
+       if (!FP_INHIBIT_RESULTS) {
+               if (ret == -1) ret = 2;
+               fsr = *(long *)rd;
+               fsr &= ~0xc00;
+               fsr |= (ret << 10);
+               *(long *)rd = fsr;
+       }
+       FP_HANDLE_EXCEPTIONS;
 }
index a078a1243a58b791cf4482df85c6d6af9c0ea0d3..365937edc2d529044f7b02d8cdc1522d33692600 100644 (file)
@@ -1,18 +1,33 @@
+/* $Id: fcmpes.c,v 1.8 1999/05/28 13:41:45 jj Exp $
+ * arch/sparc/math-emu/fcmpes.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "single.h"
 
 int FCMPES(void *rd, void *rs2, void *rs1)
 {
+       FP_DECL_EX;
        FP_DECL_S(A); FP_DECL_S(B);
        long ret;
-       unsigned long *fsr = rd;
+       unsigned long fsr;
        
-       __FP_UNPACK_S(A, rs1);
-       __FP_UNPACK_S(B, rs2);
-       FP_CMP_S(ret, B, A, 1);
-       if (ret == -1)
-               ret = 2;
-
-       *fsr = (*fsr & ~0xc00) | (ret << 10); 
-       return 0;
+       FP_UNPACK_RAW_SP(A, rs1);
+       FP_UNPACK_RAW_SP(B, rs2);
+       FP_CMP_S(ret, B, A, 3);
+       if (ret == 3)
+               FP_SET_EXCEPTION(FP_EX_INVALID);
+       if (!FP_INHIBIT_RESULTS) {
+               if (ret == -1) ret = 2;
+               fsr = *(long *)rd;
+               fsr &= ~0xc00;
+               fsr |= (ret << 10);
+               *(long *)rd = fsr;
+       }
+       FP_HANDLE_EXCEPTIONS;
 }
index f3d1b1233f68a88e2c71530400464f63c89f5e1d..ffaeb1a1e3c343fb48592e804a90d0af180096c5 100644 (file)
@@ -1,18 +1,33 @@
+/* $Id: fcmpq.c,v 1.8 1999/05/28 13:41:48 jj Exp $
+ * arch/sparc/math-emu/fcmpq.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "quad.h"
 
 int FCMPQ(void *rd, void *rs2, void *rs1)
 {
+       FP_DECL_EX;
        FP_DECL_Q(A); FP_DECL_Q(B);
        long ret;
        unsigned long fsr;
        
-       __FP_UNPACK_Q(A, rs1);
-       __FP_UNPACK_Q(B, rs2);
+       FP_UNPACK_RAW_QP(A, rs1);
+       FP_UNPACK_RAW_QP(B, rs2);
        FP_CMP_Q(ret, B, A, 3);
-       if (ret == -1) ret = 2;
-       fsr = *(unsigned long *)rd;
-       fsr &= ~0xc00; fsr |= (ret << 10);
-       *(unsigned long *)rd = fsr;
-       return 0;
+       if (ret == 3 && (FP_ISSIGNAN_Q(A) || FP_ISSIGNAN_Q(B)))
+               FP_SET_EXCEPTION(FP_EX_INVALID);
+       if (!FP_INHIBIT_RESULTS) {
+               if (ret == -1) ret = 2;
+               fsr = *(long *)rd;
+               fsr &= ~0xc00;
+               fsr |= (ret << 10);
+               *(long *)rd = fsr;
+       }
+       FP_HANDLE_EXCEPTIONS;
 }
index 7e273320f9cb1f06d13fd40dd12726b90f26a937..3be1315d7f49dc90c1494640f6ac7fbaffe11823 100644 (file)
@@ -1,18 +1,33 @@
+/* $Id: fcmps.c,v 1.8 1999/05/28 13:41:51 jj Exp $
+ * arch/sparc/math-emu/fcmps.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "single.h"
 
 int FCMPS(void *rd, void *rs2, void *rs1)
 {
+       FP_DECL_EX;
        FP_DECL_S(A); FP_DECL_S(B);
        long ret;
-       unsigned long *fsr = rd;
+       unsigned long fsr;
        
-       __FP_UNPACK_S(A, rs1);
-       __FP_UNPACK_S(B, rs2);
-       FP_CMP_S(ret, B, A, 1);
-       if (ret == -1)
-               ret = 2;
-
-       *fsr = (*fsr & ~0xc00) | (ret << 10); 
-       return 0;
+       FP_UNPACK_RAW_SP(A, rs1);
+       FP_UNPACK_RAW_SP(B, rs2);
+       FP_CMP_S(ret, B, A, 3);
+       if (ret == 3 && (FP_ISSIGNAN_S(A) || FP_ISSIGNAN_S(B)))
+               FP_SET_EXCEPTION(FP_EX_INVALID);
+       if (!FP_INHIBIT_RESULTS) {
+               if (ret == -1) ret = 2;
+               fsr = *(long *)rd;
+               fsr &= ~0xc00;
+               fsr |= (ret << 10);
+               *(long *)rd = fsr;
+       }
+       FP_HANDLE_EXCEPTIONS;
 }
index dd9c7953c852512d921f07b9a31945694a0c559c..96772d4ef236455354957cf58108f4f721be31c6 100644 (file)
@@ -1,15 +1,26 @@
+/* $Id: fdmulq.c,v 1.9 1999/05/28 13:41:56 jj Exp $
+ * arch/sparc/math-emu/fdmulq.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "quad.h"
 #include "double.h"
 
 int FDMULQ(void *rd, void *rs2, void *rs1)
 {
+       FP_DECL_EX;
        FP_DECL_D(IN); FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R);
 
-       __FP_UNPACK_D(IN, rs1);
+       FP_UNPACK_DP(IN, rs1);
        FP_CONV(Q,D,4,2,A,IN);
-       __FP_UNPACK_D(IN, rs2);
+       FP_UNPACK_DP(IN, rs2);
        FP_CONV(Q,D,4,2,B,IN);
        FP_MUL_Q(R, A, B);
-       return __FP_PACK_Q(rd, R);
+       FP_PACK_QP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index 7b77468217901e200401ea1d6004edea63ded834..701b1ff3f80418a5f493800bc2d43b3e095fe59a 100644 (file)
@@ -1,12 +1,23 @@
+/* $Id: fdtoq.c,v 1.9 1999/05/28 13:42:01 jj Exp $
+ * arch/sparc/math-emu/fdtoq.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "quad.h"
 #include "double.h"
 
 int FDTOQ(void *rd, void *rs2)
 {
+       FP_DECL_EX;
        FP_DECL_D(A); FP_DECL_Q(R);
 
-       __FP_UNPACK_D(A, rs2);
+       FP_UNPACK_DP(A, rs2);
        FP_CONV(Q,D,4,2,R,A);
-       return __FP_PACK_Q(rd, R);
+       FP_PACK_QP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index 612434c406893d7fbb28f5de6df711e80dd6338b..63951befab219a7768a0630c81355abd0c9ceaf4 100644 (file)
@@ -1,12 +1,23 @@
+/* $Id: fdtos.c,v 1.9 1999/05/28 13:42:03 jj Exp $
+ * arch/sparc/math-emu/fdtos.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "double.h"
 #include "single.h"
 
 int FDTOS(void *rd, void *rs2)
 {
+       FP_DECL_EX;
        FP_DECL_D(A); FP_DECL_S(R);
 
-       __FP_UNPACK_D(A, rs2);
+       FP_UNPACK_DP(A, rs2);
        FP_CONV(S,D,1,2,R,A);
-       return __FP_PACK_S(rd, R);
+       FP_PACK_SP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index f113c0bb197a01a74b7c22d225e99b7aa97be912..77087a5246720a195392fc2488a87589c4d298d8 100644 (file)
@@ -1,3 +1,10 @@
+/* $Id: fmovs.c,v 1.7 1999/05/28 13:42:05 jj Exp $
+ * arch/sparc/math-emu/fmovs.c
+ *
+ * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk)
+ *
+ */
+
 int FMOVS(unsigned long *rd, unsigned long *rs2)
 {
        rd[0] = rs2[0];
index 26a90d77889714db5f53c0086aadfb40e3c7caba..da2d36ef5d3359e3b8d60ca2ba98c9d0ee957cff 100644 (file)
@@ -1,3 +1,10 @@
+/* $Id: fnegs.c,v 1.9 1999/05/28 13:42:06 jj Exp $
+ * arch/sparc/math-emu/fnegs.c
+ *
+ * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk)
+ *
+ */
+
 int FNEGS(unsigned long *rd, unsigned long *rs2)
 {
        /* just change the sign bit */
index 62a437e3165d14dc74e836d3c680dd61400f1bd0..c8aa8edf130498a4c8325780bce265656136d675 100644 (file)
@@ -1,12 +1,23 @@
+/* $Id: fqtod.c,v 1.9 1999/05/28 13:42:08 jj Exp $
+ * arch/sparc/math-emu/fqtod.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "quad.h"
 #include "double.h"
 
 int FQTOD(void *rd, void *rs2)
 {
+       FP_DECL_EX;
        FP_DECL_Q(A); FP_DECL_D(R);
 
-       __FP_UNPACK_Q(A, rs2);
+       FP_UNPACK_QP(A, rs2);
        FP_CONV(D,Q,2,4,R,A);
-       return __FP_PACK_D(rd, R);
+       FP_PACK_DP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index 2520affbfd148aa2a2cbb73a7b73673763be9d5d..142dfa9a863e0ad694c3d3855ae647ec22d2b7cd 100644 (file)
@@ -1,12 +1,23 @@
+/* $Id: fqtos.c,v 1.9 1999/05/28 13:42:10 jj Exp $
+ * arch/sparc/math-emu/fqtos.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "quad.h"
 #include "single.h"
 
 int FQTOS(void *rd, void *rs2)
 {
+       FP_DECL_EX;
        FP_DECL_Q(A); FP_DECL_S(R);
 
-       __FP_UNPACK_Q(A, rs2);
+       FP_UNPACK_QP(A, rs2);
        FP_CONV(S,Q,1,4,R,A);
-       return __FP_PACK_S(rd, R);
+       FP_PACK_SP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index b7b992818bc55bb3a53defd77af4f8d00d49c373..2f873e501c6b3f73dc14646a05af8c8d517bca30 100644 (file)
@@ -1,15 +1,26 @@
+/* $Id: fsmuld.c,v 1.9 1999/05/28 13:42:12 jj Exp $
+ * arch/sparc/math-emu/fsmuld.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "double.h"
 #include "single.h"
 
 int FSMULD(void *rd, void *rs2, void *rs1)
 {
+       FP_DECL_EX;
        FP_DECL_S(IN); FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R);
 
-       __FP_UNPACK_S(IN, rs1);
+       FP_UNPACK_SP(IN, rs1);
        FP_CONV(D,S,2,1,A,IN);
-       __FP_UNPACK_S(IN, rs2);
+       FP_UNPACK_SP(IN, rs2);
        FP_CONV(D,S,2,1,B,IN);
        FP_MUL_D(R, A, B);
-       return __FP_PACK_D(rd, R);
+       FP_PACK_DP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index ea73660d82dc921322cc8238ab71fab531143b75..a6206bf20c023275a8ab85615b9a7b675aca75ab 100644 (file)
@@ -1,12 +1,23 @@
+/* $Id: fstod.c,v 1.9 1999/05/28 13:42:14 jj Exp $
+ * arch/sparc/math-emu/fstod.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "double.h"
 #include "single.h"
 
 int FSTOD(void *rd, void *rs2)
 {
+       FP_DECL_EX;
        FP_DECL_S(A); FP_DECL_D(R);
 
-       __FP_UNPACK_S(A, rs2);
+       FP_UNPACK_SP(A, rs2);
        FP_CONV(D,S,2,1,R,A);
-       return __FP_PACK_D(rd, R);
+       FP_PACK_DP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index 7d201310c73a34c1ee30ca9a640d5f85fecc310b..e2257c214a4fb52051d2927e37c1699e7c8b32f7 100644 (file)
@@ -1,12 +1,23 @@
+/* $Id: fstoq.c,v 1.9 1999/05/28 13:42:16 jj Exp $
+ * arch/sparc/math-emu/fstoq.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "quad.h"
 #include "single.h"
 
 int FSTOQ(void *rd, void *rs2)
 {
+       FP_DECL_EX;
        FP_DECL_S(A); FP_DECL_Q(R);
 
-       __FP_UNPACK_S(A, rs2);
+       FP_UNPACK_SP(A, rs2);
        FP_CONV(Q,S,4,1,R,A);
-       return __FP_PACK_Q(rd, R);
+       FP_PACK_QP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index 68ccb932ae834a16c69aadfe622e192e908436a5..15690b21e48a8d5d75f2857ddf897a3b85826fe4 100644 (file)
@@ -1,26 +1,19 @@
-/* 
+/*
  * arch/sparc/math-emu/math.c
  *
  * Copyright (C) 1998 Peter Maydell (pmaydell@chiark.greenend.org.uk)
- * Based on the sparc64 code by Jakub Jelinek.
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
  *
  * This is a good place to start if you're trying to understand the
- * emulation code, because it's pretty simple. What we do is 
+ * emulation code, because it's pretty simple. What we do is
  * essentially analyse the instruction to work out what the operation
  * is and which registers are involved. We then execute the appropriate
  * FXXXX function. [The floating point queue introduces a minor wrinkle;
  * see below...]
  * The fxxxxx.c files each emulate a single insn. They look relatively
  * simple because the complexity is hidden away in an unholy tangle
- * of preprocessor macros. 
- *
- * WARNING : don't look at the macro definitions unless you 
- * absolutely have to! They're extremely ugly, rather complicated
- * and a single line in an fxxxx.c file can expand to the equivalent 
- * of  30 lines or more of C. Of course, any error in those 30 lines 
- * is reported by the compiler as an error in the single line with the
- * macro usage...
- * Question: should we replace them with inline functions?
+ * of preprocessor macros.
  *
  * The first layer of macros is single.h, double.h, quad.h. Generally
  * these files define macros for working with floating point numbers
  * generic macros (in this case _FP_ADD(D,2,R,X,Y) where the number
  * of machine words required to store the given IEEE format is passed
  * as a parameter. [double.h and co check the number of bits in a word
- * and define FP_ADD_D & co appropriately]. 
+ * and define FP_ADD_D & co appropriately].
  * The generic macros are defined in op-common.h. This is where all
  * the grotty stuff like handling NaNs is coded. To handle the possible
  * word sizes macros in op-common.h use macros like _FP_FRAC_SLL_##wc()
- * where wc is the 'number of machine words' parameter (here 2). 
+ * where wc is the 'number of machine words' parameter (here 2).
  * These are defined in the third layer of macros: op-1.h, op-2.h
  * and op-4.h. These handle operations on floating point numbers composed
  * of 1,2 and 4 machine words respectively. [For example, on sparc64
@@ -41,7 +34,7 @@
  * constructs in op-1.h, but on sparc32 they use op-2.h definitions.]
  * soft-fp.h is on the same level as op-common.h, and defines some
  * macros which are independent of both word size and FP format.
- * Finally, sfp-machine.h is the machine dependent part of the 
+ * Finally, sfp-machine.h is the machine dependent part of the
  * code: it defines the word size and what type a word is. It also
  * defines how _FP_MUL_MEAT_t() maps to _FP_MUL_MEAT_n_* : op-n.h
  * provide several possible flavours of multiply algorithm, most
  * so we follow that practice...
  */
 
-/* WISHLIST:
- *
- * + Replace all the macros with inline functions. These should
- * have the same effect but be much easier to work with.
- *
- * + Emulate the IEEE exception flags. We don't currently do this
- * because a) it would require significant alterations to
- * the emulation macros [see the comments about _FP_NEG()
- * in op-common.c and note that we'd need to invent a convention
- * for passing in the flags to FXXXX fns and returning them] and 
- * b) SPARClinux doesn't let users access the flags anyway 
- * [contrast Solaris, which allows you to examine, clear or set
- * the flags, and request that exceptions cause SIGFPE 
- * [which you then set up a signal handler for, obviously...]].
- * Erm, (b) may quite possibly be garbage. %fsr is user-writable
- * so you don't need a syscall. There may or may not be library
- * support.
- *
- * + Emulation of FMULQ, FDIVQ, FSQRTQ, FDMULQ needs to be 
- * written!
- * 
- * + reindent code to conform to Linux kernel standard :->
- *
- * + work out whether all the compile-time warnings are bogus
- *
- * + check that conversion to/from integers works
- * 
- * + check with the SPARC architecture manual to see if we resolve
- * the implementation-dependent bits of the IEEE spec in the
- * same manner as the hardware.
- *
- * + more test cases for the test script always welcome!
- *
- * + illegal opcodes currently cause SIGFPEs. We should arrange
- * to tell the traps.c code to SIGILL instead. Currently,
- * everywhere that we return 0 should cause SIGILL, I think.
- * SIGFPE should only be caused if we set an IEEE exception bit
- * and the relevant trap bit is also set. (this means that 
- * traps.c should do this; also it should handle the case of
- * IEEE exception generated directly by the hardware.)
- * Should illegal_fp_register (which is a flavour of fp exception)
- * cause SIGFPE or  SIGILL?
- *
- * + the test script needs to be extended to handle the quadword
- * and comparison insns.
- *
- * + _FP_DIV_MEAT_2_udiv_64() appears to work but it should be
- * checked by somebody who understands the algorithm :->
- * 
- * + fpsave() saves the FP queue but fpload() doesn't reload it.
+/* TODO:
+ * fpsave() saves the FP queue but fpload() doesn't reload it.
  * Therefore when we context switch or change FPU ownership
  * we have to check to see if the queue had anything in it and
- * emulate it if it did. This is going to be a pain. 
+ * emulate it if it did. This is going to be a pain.
  */
 
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <asm/uaccess.h>
 
+#include "sfp-util.h"
 #include "soft-fp.h"
 
 #define FLOATFUNC(x) extern int x(void *,void *,void *)
 
-/* Current status: we don't properly emulate the difficult quadword
- * insns (MUL, DIV, SQRT).
- * There are also some ops involving the FP registers which we don't
- * emulate: the branch on FP condition flags and the load/store to
- * FP regs or FSR. I'm assuming that these will never generate traps
- * (not unreasonable if there's an FPU at all; comments in the NetBSD
- * kernel source agree on this point). If we wanted to allow
- * purely software-emulation of the FPU with FPU totally disabled
- * or non-existent, we'd have to emulate these as well. We'd also
- * need to alter the fp_disabled trap handler to call the math-emu
- * code appropriately. The structure of do_one_mathemu() is also
- * inappropriate for these ops (as it has no way to alter the pc, 
- * for a start) and it might be better to special-case them in do_mathemu().
- * Oh, and you'd need to alter the traps.c code so it didn't try to
- * fpsave() and fpload(). If there's genuinely no FPU then there's 
- * probably bits of kernel stuff that just won't work anyway...
- */
-
 /* The Vn labels indicate what version of the SPARC architecture gas thinks
- * each insn is. This is from the binutils source :-> 
+ * each insn is. This is from the binutils source :->
  */
 /* quadword instructions */
-FLOATFUNC(FSQRTQ);                                /* v8 NYI */
+FLOATFUNC(FSQRTQ);                                /* v8 */
 FLOATFUNC(FADDQ);                                 /* v8 */
 FLOATFUNC(FSUBQ);                                 /* v8 */
-FLOATFUNC(FMULQ);                                 /* v8 NYI */
-FLOATFUNC(FDIVQ);                                 /* v8 NYI */
-FLOATFUNC(FDMULQ);                                /* v8 NYI */
+FLOATFUNC(FMULQ);                                 /* v8 */
+FLOATFUNC(FDIVQ);                                 /* v8 */
+FLOATFUNC(FDMULQ);                                /* v8 */
 FLOATFUNC(FQTOS);                                 /* v8 */
 FLOATFUNC(FQTOD);                                 /* v8 */
 FLOATFUNC(FITOQ);                                 /* v8 */
@@ -197,7 +125,7 @@ FLOATFUNC(FITOD);                                 /* v6 */
 #define FSR_CEXC_SHIFT 0UL
 #define FSR_CEXC_MASK  (0x1fUL << FSR_CEXC_SHIFT)
 
-static int do_one_mathemu(u32 insn, unsigned long *fsr, unsigned long *fregs);   
+static int do_one_mathemu(u32 insn, unsigned long *fsr, unsigned long *fregs);
 
 /* Unlike the Sparc64 version (which has a struct fpustate), we
  * pass the taskstruct corresponding to the task which currently owns the
@@ -210,65 +138,65 @@ static int do_one_mathemu(u32 insn, unsigned long *fsr, unsigned long *fregs);
  */
 int do_mathemu(struct pt_regs *regs, struct task_struct *fpt)
 {
-   /* regs->pc isn't necessarily the PC at which the offending insn is sitting.
-    * The FPU maintains a queue of FPops which cause traps. 
-    * When it hits an instruction that requires that the trapped op succeeded
-    * (usually because it reads a reg. that the trapped op wrote) then it
-    * causes this exception. We need to emulate all the insns on the queue
-    * and then allow the op to proceed.
-    * This code should also handle the case where the trap was precise,
-    * in which case the queue length is zero and regs->pc points at the 
-    * single FPop to be emulated. (this case is untested, though :->) 
-    * You'll need this case if you want to be able to emulate all FPops
-    * because the FPU either doesn't exist or has been software-disabled.
-    * [The UltraSPARC makes FP a precise trap; this isn't as stupid as it 
-    * might sound because the Ultra does funky things with a superscalar
-    * architecture.]
-    */
-   
-   /* You wouldn't believe how often I typed 'ftp' when I meant 'fpt' :-> */
+       /* regs->pc isn't necessarily the PC at which the offending insn is sitting.
+        * The FPU maintains a queue of FPops which cause traps.
+        * When it hits an instruction that requires that the trapped op succeeded
+        * (usually because it reads a reg. that the trapped op wrote) then it
+        * causes this exception. We need to emulate all the insns on the queue
+        * and then allow the op to proceed.
+        * This code should also handle the case where the trap was precise,
+        * in which case the queue length is zero and regs->pc points at the
+        * single FPop to be emulated. (this case is untested, though :->)
+        * You'll need this case if you want to be able to emulate all FPops
+        * because the FPU either doesn't exist or has been software-disabled.
+        * [The UltraSPARC makes FP a precise trap; this isn't as stupid as it
+        * might sound because the Ultra does funky things with a superscalar
+        * architecture.]
+        */
+
+       /* You wouldn't believe how often I typed 'ftp' when I meant 'fpt' :-> */
 
-   int i;
-   int retcode = 0;                               /* assume all succeed */
-   unsigned long insn;
-   
-#ifdef DEBUG_MATHEMU   
-   printk("In do_mathemu()... pc is %08lx\n", regs->pc);
-   printk("fpqdepth is %ld\n",fpt->tss.fpqdepth);
-   for (i = 0; i < fpt->tss.fpqdepth; i++)
-      printk("%d: %08lx at %08lx\n",i,fpt->tss.fpqueue[i].insn, (unsigned long)fpt->tss.fpqueue[i].insn_addr);
-#endif      
+       int i;
+       int retcode = 0;                               /* assume all succeed */
+       unsigned long insn;
 
-   if (fpt->tss.fpqdepth == 0) {                   /* no queue, guilty insn is at regs->pc */
-#ifdef DEBUG_MATHEMU   
-      printk("precise trap at %08lx\n", regs->pc);
+#ifdef DEBUG_MATHEMU
+       printk("In do_mathemu()... pc is %08lx\n", regs->pc);
+       printk("fpqdepth is %ld\n", fpt->tss.fpqdepth);
+       for (i = 0; i < fpt->tss.fpqdepth; i++)
+               printk("%d: %08lx at %08lx\n", i, fpt->tss.fpqueue[i].insn,
+                      (unsigned long)fpt->tss.fpqueue[i].insn_addr);
 #endif
-      if (!get_user(insn, (u32 *)regs->pc)) {
-         retcode = do_one_mathemu(insn, &fpt->tss.fsr, fpt->tss.float_regs);
-         if (retcode) {
-            /* in this case we need to fix up PC & nPC */
-            regs->pc = regs->npc;
-            regs->npc += 4;
-         }
-      }
-      return retcode;
-   }
 
-   /* Normal case: need to empty the queue... */
-   for (i = 0; i < fpt->tss.fpqdepth; i++)
-   {
-      retcode = do_one_mathemu(fpt->tss.fpqueue[i].insn, &(fpt->tss.fsr), fpt->tss.float_regs);
-      if (!retcode)                               /* insn failed, no point doing any more */
-         break;
-   }
-   /* Now empty the queue and clear the queue_not_empty flag */
-   if(retcode)
-          fpt->tss.fsr &= ~(0x3000 | FSR_CEXC_MASK);
-   else
-          fpt->tss.fsr &= ~0x3000;
-   fpt->tss.fpqdepth = 0;
-   
-   return retcode;
+       if (fpt->tss.fpqdepth == 0) {                   /* no queue, guilty insn is at regs->pc */
+#ifdef DEBUG_MATHEMU
+               printk("precise trap at %08lx\n", regs->pc);
+#endif
+               if (!get_user(insn, (u32 *)regs->pc)) {
+                       retcode = do_one_mathemu(insn, &fpt->tss.fsr, fpt->tss.float_regs);
+                       if (retcode) {
+                               /* in this case we need to fix up PC & nPC */
+                               regs->pc = regs->npc;
+                               regs->npc += 4;
+                       }
+               }
+               return retcode;
+       }
+
+       /* Normal case: need to empty the queue... */
+       for (i = 0; i < fpt->tss.fpqdepth; i++) {
+               retcode = do_one_mathemu(fpt->tss.fpqueue[i].insn, &(fpt->tss.fsr), fpt->tss.float_regs);
+               if (!retcode)                               /* insn failed, no point doing any more */
+                       break;
+       }
+       /* Now empty the queue and clear the queue_not_empty flag */
+       if(retcode)
+               fpt->tss.fsr &= ~(0x3000 | FSR_CEXC_MASK);
+       else
+               fpt->tss.fsr &= ~0x3000;
+       fpt->tss.fpqdepth = 0;
+
+       return retcode;
 }
 
 /* All routines returning an exception to raise should detect
@@ -291,46 +219,36 @@ static int record_exception(unsigned long *pfsr, int eflag)
        if(would_trap != 0) {
                eflag &= ((fsr & FSR_TEM_MASK) >> FSR_TEM_SHIFT);
                if((eflag & (eflag - 1)) != 0) {
-                       if(eflag & EFLAG_INVALID)
-                               eflag = EFLAG_INVALID;
-                       else if(eflag & EFLAG_DIVZERO)
-                               eflag = EFLAG_DIVZERO;
-                       else if(eflag & EFLAG_INEXACT)
-                               eflag = EFLAG_INEXACT;
+                       if(eflag & FP_EX_INVALID)
+                               eflag = FP_EX_INVALID;
+                       else if(eflag & FP_EX_OVERFLOW)
+                               eflag = FP_EX_OVERFLOW;
+                       else if(eflag & FP_EX_UNDERFLOW)
+                               eflag = FP_EX_UNDERFLOW;
+                       else if(eflag & FP_EX_DIVZERO)
+                               eflag = FP_EX_DIVZERO;
+                       else if(eflag & FP_EX_INEXACT)
+                               eflag = FP_EX_INEXACT;
                }
        }
 
-       /* Set CEXC, here are the rules:
+       /* Set CEXC, here is the rule:
         *
-        * 1) In general all FPU ops will set one and only one
+        *    In general all FPU ops will set one and only one
         *    bit in the CEXC field, this is always the case
         *    when the IEEE exception trap is enabled in TEM.
-        *
-        * 2) As a special case, if an overflow or underflow
-        *    is being signalled, AND the trap is not enabled
-        *    in TEM, then the inexact field shall also be set.
         */
        fsr &= ~(FSR_CEXC_MASK);
-       if(would_trap ||
-          (eflag & (EFLAG_OVERFLOW | EFLAG_UNDERFLOW)) == 0) {
-               fsr |= ((long)eflag << FSR_CEXC_SHIFT);
-       } else {
-               fsr |= (((long)eflag << FSR_CEXC_SHIFT) |
-                       (EFLAG_INEXACT << FSR_CEXC_SHIFT));
-       }
+       fsr |= ((long)eflag << FSR_CEXC_SHIFT);
 
-       /* Set the AEXC field, rules are:
+       /* Set the AEXC field, rule is:
         *
-        * 1) If a trap would not be generated, the
+        *    If a trap would not be generated, the
         *    CEXC just generated is OR'd into the
         *    existing value of AEXC.
-        *
-        * 2) When a trap is generated, AEXC is cleared.
         */
        if(would_trap == 0)
                fsr |= ((long)eflag << FSR_AEXC_SHIFT);
-       else
-               fsr &= ~(FSR_AEXC_MASK);
 
        /* If trapping, indicate fault trap type IEEE. */
        if(would_trap != 0)
@@ -343,157 +261,150 @@ static int record_exception(unsigned long *pfsr, int eflag)
 
 static int do_one_mathemu(u32 insn, unsigned long *fsr, unsigned long *fregs)
 {
-   /* Emulate the given insn, updating fsr and fregs appropriately. */
-   int type = 0; 
-   /* 01 is single, 10 is double, 11 is quad, 
-    * 000011 is rs1, 001100 is rs2, 110000 is rd (00 in rd is fcc)
-    * 111100000000 tells which ftt that may happen in 
-    * (this field not used on sparc32 code, as we can't 
-    * extract trap type info for ops on the FP queue) 
-    */
-   int freg, eflag;
-   int (*func)(void *,void *,void *) = NULL;
-   void *rs1 = NULL, *rs2 = NULL, *rd = NULL;   
+       /* Emulate the given insn, updating fsr and fregs appropriately. */
+       int type = 0;
+       /* 01 is single, 10 is double, 11 is quad,
+        * 000011 is rs1, 001100 is rs2, 110000 is rd (00 in rd is fcc)
+        * 111100000000 tells which ftt that may happen in
+        * (this field not used on sparc32 code, as we can't
+        * extract trap type info for ops on the FP queue)
+        */
+       int freg, eflag;
+       int (*func)(void *,void *,void *) = NULL;
+       void *rs1 = NULL, *rs2 = NULL, *rd = NULL;
+
+#ifdef DEBUG_MATHEMU
+       printk("In do_mathemu(), emulating %08lx\n", insn);
+#endif
 
+       if ((insn & 0xc1f80000) == 0x81a00000)  /* FPOP1 */ {
+               switch ((insn >> 5) & 0x1ff) {
+               /* QUAD - ftt == 3 */
+               case 0x001: type = 0x314; func = FMOVS; break;
+               case 0x005: type = 0x314; func = FNEGS; break;
+               case 0x009: type = 0x314; func = FABSS; break;
+               case 0x02b: type = 0x33c; func = FSQRTQ; break;
+               case 0x043: type = 0x33f; func = FADDQ; break;
+               case 0x047: type = 0x33f; func = FSUBQ; break;
+               case 0x04b: type = 0x33f; func = FMULQ; break;
+               case 0x04f: type = 0x33f; func = FDIVQ; break;
+               case 0x06e: type = 0x33a; func = FDMULQ; break;
+               case 0x0c7: type = 0x31c; func = FQTOS; break;
+               case 0x0cb: type = 0x32c; func = FQTOD; break;
+               case 0x0cc: type = 0x334; func = FITOQ; break;
+               case 0x0cd: type = 0x334; func = FSTOQ; break;
+               case 0x0ce: type = 0x338; func = FDTOQ; break;
+               case 0x0d3: type = 0x31c; func = FQTOI; break;
+               /* SUBNORMAL - ftt == 2 */
+               case 0x029: type = 0x214; func = FSQRTS; break;
+               case 0x02a: type = 0x228; func = FSQRTD; break;
+               case 0x041: type = 0x215; func = FADDS; break;
+               case 0x042: type = 0x22a; func = FADDD; break;
+               case 0x045: type = 0x215; func = FSUBS; break;
+               case 0x046: type = 0x22a; func = FSUBD; break;
+               case 0x049: type = 0x215; func = FMULS; break;
+               case 0x04a: type = 0x22a; func = FMULD; break;
+               case 0x04d: type = 0x215; func = FDIVS; break;
+               case 0x04e: type = 0x22a; func = FDIVD; break;
+               case 0x069: type = 0x225; func = FSMULD; break;
+               case 0x0c6: type = 0x218; func = FDTOS; break;
+               case 0x0c9: type = 0x224; func = FSTOD; break;
+               case 0x0d1: type = 0x214; func = FSTOI; break;
+               case 0x0d2: type = 0x218; func = FDTOI; break;
+               default:
+#ifdef DEBUG_MATHEMU
+                       printk("unknown FPop1: %03lx\n",(insn>>5)&0x1ff);
+#endif
+               }
+       } else if ((insn & 0xc1f80000) == 0x81a80000)   /* FPOP2 */ {
+               switch ((insn >> 5) & 0x1ff) {
+               case 0x051: type = 0x305; func = FCMPS; break;
+               case 0x052: type = 0x30a; func = FCMPD; break;
+               case 0x053: type = 0x30f; func = FCMPQ; break;
+               case 0x055: type = 0x305; func = FCMPES; break;
+               case 0x056: type = 0x30a; func = FCMPED; break;
+               case 0x057: type = 0x30f; func = FCMPEQ; break;
+               default:
 #ifdef DEBUG_MATHEMU
-   printk("In do_mathemu(), emulating %08lx\n", insn);
-#endif   
-      
-   if ((insn & 0xc1f80000) == 0x81a00000) /* FPOP1 */ {
-      switch ((insn >> 5) & 0x1ff) {
-         /* QUAD - ftt == 3 */
-         case 0x001: type = 0x314; func = FMOVS; break;
-         case 0x005: type = 0x314; func = FNEGS; break;
-         case 0x009: type = 0x314; func = FABSS; break;
-         case 0x02b: type = 0x33c; func = FSQRTQ; break;
-         case 0x043: type = 0x33f; func = FADDQ; break;
-         case 0x047: type = 0x33f; func = FSUBQ; break;
-         case 0x04b: type = 0x33f; func = FMULQ; break;
-         case 0x04f: type = 0x33f; func = FDIVQ; break;
-         case 0x06e: type = 0x33a; func = FDMULQ; break;
-         case 0x0c7: type = 0x31c; func = FQTOS; break;
-         case 0x0cb: type = 0x32c; func = FQTOD; break;
-         case 0x0cc: type = 0x334; func = FITOQ; break;
-         case 0x0cd: type = 0x334; func = FSTOQ; break;
-         case 0x0ce: type = 0x338; func = FDTOQ; break;
-         case 0x0d3: type = 0x31c; func = FQTOI; break;
-            /* SUBNORMAL - ftt == 2 */
-         case 0x029: type = 0x214; func = FSQRTS; break;
-         case 0x02a: type = 0x228; func = FSQRTD; break;
-         case 0x041: type = 0x215; func = FADDS; break;
-         case 0x042: type = 0x22a; func = FADDD; break;
-         case 0x045: type = 0x215; func = FSUBS; break;
-         case 0x046: type = 0x22a; func = FSUBD; break;
-         case 0x049: type = 0x215; func = FMULS; break;
-         case 0x04a: type = 0x22a; func = FMULD; break;
-         case 0x04d: type = 0x215; func = FDIVS; break;
-         case 0x04e: type = 0x22a; func = FDIVD; break;
-         case 0x069: type = 0x225; func = FSMULD; break;
-         case 0x0c6: type = 0x218; func = FDTOS; break;
-         case 0x0c9: type = 0x224; func = FSTOD; break;
-         case 0x0d1: type = 0x214; func = FSTOI; break;
-         case 0x0d2: type = 0x218; func = FDTOI; break;
-         default: 
-#ifdef DEBUG_MATHEMU         
-               printk("unknown FPop1: %03lx\n",(insn>>5)&0x1ff);
-#endif         
-      }
-   }
-   else if ((insn & 0xc1f80000) == 0x81a80000) /* FPOP2 */ {
-      switch ((insn >> 5) & 0x1ff) {
-         case 0x051: type = 0x305; func = FCMPS; break;
-         case 0x052: type = 0x30a; func = FCMPD; break;
-         case 0x053: type = 0x30f; func = FCMPQ; break;
-         case 0x055: type = 0x305; func = FCMPES; break;
-         case 0x056: type = 0x30a; func = FCMPED; break;
-         case 0x057: type = 0x30f; func = FCMPEQ; break;
-         default: 
-#ifdef DEBUG_MATHEMU         
-               printk("unknown FPop2: %03lx\n",(insn>>5)&0x1ff);
-#endif                 
-      }
-   }
-   
-   if (!type) { /* oops, didn't recognise that FPop */
-      printk("attempt to emulate unrecognised FPop!\n");
-      return 0;
-   }
-   
-   /* Decode the registers to be used */
-   freg = (*fsr >> 14) & 0xf;
+                       printk("unknown FPop2: %03lx\n",(insn>>5)&0x1ff);
+#endif
+               }
+       }
+
+       if (!type) {    /* oops, didn't recognise that FPop */
+               printk("attempt to emulate unrecognised FPop!\n");
+               return 0;
+       }
+
+       /* Decode the registers to be used */
+       freg = (*fsr >> 14) & 0xf;
 
-   *fsr &= ~0x1c000;                              /* clear the traptype bits */
-    
-   freg = ((insn >> 14) & 0x1f);
-   switch (type & 0x3)                            /* is rs1 single, double or quad? */
-   {
-      case 3:
-         if (freg & 3)                            /* quadwords must have bits 4&5 of the */
-         {                                        /* encoded reg. number set to zero. */
-            *fsr |= (6 << 14);                  
-            return 0;                             /* simulate invalid_fp_register exception */
-         }
-         /* fall through */
-      case 2:
-         if (freg & 1)                            /* doublewords must have bit 5 zeroed */
-         {
-            *fsr |= (6 << 14);
-            return 0;
-         }
-   }
-   rs1 = (void *)&fregs[freg];
-   freg = (insn & 0x1f);
-   switch ((type >> 2) & 0x3)
-   {                                              /* same again for rs2 */
-      case 3:
-         if (freg & 3)                            /* quadwords must have bits 4&5 of the */
-         {                                        /* encoded reg. number set to zero. */
-            *fsr |= (6 << 14);                  
-            return 0;                             /* simulate invalid_fp_register exception */
-         }
-         /* fall through */
-      case 2:
-         if (freg & 1)                            /* doublewords must have bit 5 zeroed */
-         {
-            *fsr |= (6 << 14);
-            return 0;
-         }
-   }
-   rs2 = (void *)&fregs[freg];
-   freg = ((insn >> 25) & 0x1f);
-   switch ((type >> 4) & 0x3)                     /* and finally rd. This one's a bit different */
-   {
-      case 0:                                     /* dest is fcc. (this must be FCMPQ or FCMPEQ) */
-         if (freg)                                /* V8 has only one set of condition codes, so */
-         {                                        /* anything but 0 in the rd field is an error */
-            *fsr |= (6 << 14);                    /* (should probably flag as invalid opcode */
-            return 0;                             /* but SIGFPE will do :-> ) */
-         }
-         rd = (void *)(fsr);                      /* FCMPQ and FCMPEQ are special and only  */
-         break;                                   /* set bits they're supposed to :-> */
-      case 3:
-         if (freg & 3)                            /* quadwords must have bits 4&5 of the */
-         {                                        /* encoded reg. number set to zero. */
-            *fsr |= (6 << 14);
-            return 0;                             /* simulate invalid_fp_register exception */
-         }
-         /* fall through */
-      case 2:
-         if (freg & 1)                            /* doublewords must have bit 5 zeroed */
-         {
-            *fsr |= (6 << 14);
-            return 0;
-         }
-         /* fall through */
-      case 1:
-         rd = (void *)&fregs[freg];
-         break;
-   }
-#ifdef DEBUG_MATHEMU   
-   printk("executing insn...\n");
-#endif   
-   eflag = func(rd, rs2, rs1);                   /* do the Right Thing */
-   if(eflag == 0)
-          return 1;                             /* success! */
-   return record_exception(fsr, eflag);
+       *fsr &= ~0x1c000;                               /* clear the traptype bits */
+
+       freg = ((insn >> 14) & 0x1f);
+       switch (type & 0x3) {                           /* is rs1 single, double or quad? */
+       case 3:
+               if (freg & 3) {                         /* quadwords must have bits 4&5 of the */
+                                                       /* encoded reg. number set to zero. */
+                       *fsr |= (6 << 14);
+                       return 0;                       /* simulate invalid_fp_register exception */
+               }
+       /* fall through */
+       case 2:
+               if (freg & 1) {                         /* doublewords must have bit 5 zeroed */
+                       *fsr |= (6 << 14);
+                       return 0;
+               }
+       }
+       rs1 = (void *)&fregs[freg];
+       freg = (insn & 0x1f);
+       switch ((type >> 2) & 0x3) {                    /* same again for rs2 */
+       case 3:
+               if (freg & 3) {                         /* quadwords must have bits 4&5 of the */
+                                                       /* encoded reg. number set to zero. */
+                       *fsr |= (6 << 14);
+                       return 0;                       /* simulate invalid_fp_register exception */
+               }
+       /* fall through */
+       case 2:
+               if (freg & 1) {                         /* doublewords must have bit 5 zeroed */
+                       *fsr |= (6 << 14);
+                       return 0;
+               }
+       }
+       rs2 = (void *)&fregs[freg];
+       freg = ((insn >> 25) & 0x1f);
+       switch ((type >> 4) & 0x3) {                    /* and finally rd. This one's a bit different */
+       case 0:                                         /* dest is fcc. (this must be FCMPQ or FCMPEQ) */
+               if (freg) {                             /* V8 has only one set of condition codes, so */
+                                                       /* anything but 0 in the rd field is an error */
+                       *fsr |= (6 << 14);              /* (should probably flag as invalid opcode */
+                       return 0;                       /* but SIGFPE will do :-> ) */
+               }
+               rd = (void *)(fsr);                     /* FCMPQ and FCMPEQ are special and only  */
+               break;                                  /* set bits they're supposed to :-> */
+       case 3:
+               if (freg & 3) {                         /* quadwords must have bits 4&5 of the */
+                                                       /* encoded reg. number set to zero. */
+                       *fsr |= (6 << 14);
+                       return 0;                       /* simulate invalid_fp_register exception */
+               }
+       /* fall through */
+       case 2:
+               if (freg & 1) {                         /* doublewords must have bit 5 zeroed */
+                       *fsr |= (6 << 14);
+                       return 0;
+               }
+       /* fall through */
+       case 1:
+               rd = (void *)&fregs[freg];
+               break;
+       }
+#ifdef DEBUG_MATHEMU
+       printk("executing insn...\n");
+#endif
+       eflag = func(rd, rs2, rs1);                     /* do the Right Thing */
+       if(eflag == 0)
+               return 1;                               /* success! */
+       return record_exception(fsr, eflag);
 }
index 67a74580cf1a54439b9e42de4091478dcd2a28e3..99448502afa2701a896afa0c54493a2f8fd14bbd 100644 (file)
@@ -1,6 +1,11 @@
-/* Machine-dependent software floating-point definitions.  Sparc version.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+/* Machine-dependent software floating-point definitions.
+   Sparc userland (_Q_*) version.
+   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+                 Jakub Jelinek (jj@ultra.linux.cz),
+                 David S. Miller (davem@redhat.com) and
+                 Peter Maydell (pmaydell@chiark.greenend.org.uk).
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public License as
    You should have received a copy of the GNU Library General Public
    License along with the GNU C Library; see the file COPYING.LIB.  If
    not, write to the Free Software Foundation, Inc.,
-   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
-   Actually, this is a sparc (32bit) version, written based on the
-   i386 and sparc64 versions, by me, 
-   Peter Maydell (pmaydell@chiark.greenend.org.uk).
-   Comments are by and large also mine, although they may be inaccurate.
-
-   In picking out asm fragments I've gone with the lowest common
-   denominator, which also happens to be the hardware I have :->
-   That is, a SPARC without hardware multiply and divide.
- */
-
-
-/* basic word size definitions */
+#ifndef _SFP_MACHINE_H
+#define _SFP_MACHINE_H
+   
 #define _FP_W_TYPE_SIZE                32
 #define _FP_W_TYPE             unsigned long
 #define _FP_WS_TYPE            signed long
 #define _FP_I_TYPE             long
 
-/* You can optionally code some things like addition in asm. For
- * example, i386 defines __FP_FRAC_ADD_2 as asm. If you don't
- * then you get a fragment of C code [if you change an #ifdef 0
- * in op-2.h] or a call to add_ssaaaa (see below).
- * Good places to look for asm fragments to use are gcc and glibc.
- * gcc's longlong.h is useful.
- */
+#define _FP_MUL_MEAT_S(R,X,Y)  _FP_MUL_MEAT_1_wide(S,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_D(R,X,Y)  _FP_MUL_MEAT_2_wide(D,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_Q(R,X,Y)  _FP_MUL_MEAT_4_wide(Q,R,X,Y,umul_ppmm)
 
-/* We need to know how to multiply and divide. If the host word size
- * is >= 2*fracbits you can use FP_MUL_MEAT_n_imm(t,R,X,Y) which
- * codes the multiply with whatever gcc does to 'a * b'.
- * _FP_MUL_MEAT_n_wide(t,R,X,Y,f) is used when you have an asm 
- * function that can multiply two 1W values and get a 2W result. 
- * Otherwise you're stuck with _FP_MUL_MEAT_n_hard(t,R,X,Y) which
- * does bitshifting to avoid overflow.
- * For division there is FP_DIV_MEAT_n_imm(t,R,X,Y,f) for word size
- * >= 2*fracbits, where f is either _FP_DIV_HELP_imm or 
- * _FP_DIV_HELP_ldiv (see op-1.h).
- * _FP_DIV_MEAT_udiv() is if you have asm to do 2W/1W => (1W, 1W).
- * [GCC and glibc have longlong.h which has the asm macro udiv_qrnnd
- * to do this.]
- * In general, 'n' is the number of words required to hold the type,
- * and 't' is either S, D or Q for single/double/quad.
- *           -- PMM
- */
-/* Example: SPARC64:
- * #define _FP_MUL_MEAT_S(R,X,Y)       _FP_MUL_MEAT_1_imm(S,R,X,Y)
- * #define _FP_MUL_MEAT_D(R,X,Y)       _FP_MUL_MEAT_1_wide(D,R,X,Y,umul_ppmm)
- * #define _FP_MUL_MEAT_Q(R,X,Y)       _FP_MUL_MEAT_2_wide(Q,R,X,Y,umul_ppmm)
- *
- * #define _FP_DIV_MEAT_S(R,X,Y)       _FP_DIV_MEAT_1_imm(S,R,X,Y,_FP_DIV_HELP_imm)
- * #define _FP_DIV_MEAT_D(R,X,Y)       _FP_DIV_MEAT_1_udiv(D,R,X,Y)
- * #define _FP_DIV_MEAT_Q(R,X,Y)       _FP_DIV_MEAT_2_udiv_64(Q,R,X,Y)
- *
- * Example: i386:
- * #define _FP_MUL_MEAT_S(R,X,Y)   _FP_MUL_MEAT_1_wide(S,R,X,Y,_i386_mul_32_64)
- * #define _FP_MUL_MEAT_D(R,X,Y)   _FP_MUL_MEAT_2_wide(D,R,X,Y,_i386_mul_32_64)
- *
- * #define _FP_DIV_MEAT_S(R,X,Y)   _FP_DIV_MEAT_1_udiv(S,R,X,Y,_i386_div_64_32)
- * #define _FP_DIV_MEAT_D(R,X,Y)   _FP_DIV_MEAT_2_udiv_64(D,R,X,Y)
- */
-#define _FP_MUL_MEAT_S(R,X,Y)   _FP_MUL_MEAT_1_wide(S,R,X,Y,umul_ppmm)
-#define _FP_MUL_MEAT_D(R,X,Y)   _FP_MUL_MEAT_2_wide(D,R,X,Y,umul_ppmm)
-/* FIXME: This is not implemented, but should be soon */
-#define _FP_MUL_MEAT_Q(R,X,Y)   _FP_FRAC_SET_4(R, _FP_ZEROFRAC_4)
-#define _FP_DIV_MEAT_S(R,X,Y)   _FP_DIV_MEAT_1_udiv(S,R,X,Y)
-#define _FP_DIV_MEAT_D(R,X,Y)   _FP_DIV_MEAT_2_udiv_64(D,R,X,Y)
-/* FIXME: This is not implemented, but should be soon */
-#define _FP_DIV_MEAT_Q(R,X,Y)   _FP_FRAC_SET_4(R, _FP_ZEROFRAC_4)
+#define _FP_DIV_MEAT_S(R,X,Y)  _FP_DIV_MEAT_1_udiv(S,R,X,Y)
+#define _FP_DIV_MEAT_D(R,X,Y)  _FP_DIV_MEAT_2_udiv(D,R,X,Y)
+#define _FP_DIV_MEAT_Q(R,X,Y)  _FP_DIV_MEAT_4_udiv(Q,R,X,Y)
 
-/* These macros define what NaN looks like. They're supposed to expand to 
- * a comma-separated set of 32bit unsigned ints that encode NaN.
- */
-#define _FP_NANFRAC_S          _FP_QNANBIT_S
-#define _FP_NANFRAC_D          _FP_QNANBIT_D, 0
-#define _FP_NANFRAC_Q           _FP_QNANBIT_Q, 0, 0, 0
+#define _FP_NANFRAC_S          ((_FP_QNANBIT_S << 1) - 1)
+#define _FP_NANFRAC_D          ((_FP_QNANBIT_D << 1) - 1), -1
+#define _FP_NANFRAC_Q          ((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1
+#define _FP_NANSIGN_S          0
+#define _FP_NANSIGN_D          0
+#define _FP_NANSIGN_Q          0
 
 #define _FP_KEEPNANFRACP 1
 
-/* This macro appears to be called when both X and Y are NaNs, and 
- * has to choose one and copy it to R. i386 goes for the larger of the
- * two, sparc64 just picks Y. I don't understand this at all so I'll
- * go with sparc64 because it's shorter :->   -- PMM 
+/* If one NaN is signaling and the other is not,
+ * we choose that one, otherwise we choose X.
+ */
+/* For _Qp_* and _Q_*, this should prefer X, for
+ * CPU instruction emulation this should prefer Y.
+ * (see SPAMv9 B.2.2 section).
  */
 #define _FP_CHOOSENAN(fs, wc, R, X, Y)                         \
   do {                                                         \
-    R##_s = Y##_s;                                             \
-    _FP_FRAC_COPY_##wc(R,Y);                                   \
+    if ((_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs)         \
+       && !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs))     \
+      {                                                                \
+       R##_s = X##_s;                                          \
+       _FP_FRAC_COPY_##wc(R,X);                                \
+      }                                                                \
+    else                                                       \
+      {                                                                \
+       R##_s = Y##_s;                                          \
+       _FP_FRAC_COPY_##wc(R,Y);                                \
+      }                                                                \
     R##_c = FP_CLS_NAN;                                                \
   } while (0)
-  
-#define __FP_UNPACK_RAW_1(fs, X, val)                          \
-  do {                                                         \
-    union _FP_UNION_##fs *_flo =                               \
-       (union _FP_UNION_##fs *)val;                            \
-                                                               \
-    X##_f = _flo->bits.frac;                                   \
-    X##_e = _flo->bits.exp;                                    \
-    X##_s = _flo->bits.sign;                                   \
-  } while (0)
-
-#define __FP_UNPACK_RAW_2(fs, X, val)                  \
-  do {                                                 \
-    union _FP_UNION_##fs *_flo =                       \
-       (union _FP_UNION_##fs *)val;                    \
-                                                       \
-    X##_f0 = _flo->bits.frac0;                         \
-    X##_f1 = _flo->bits.frac1;                         \
-    X##_e  = _flo->bits.exp;                           \
-    X##_s  = _flo->bits.sign;                          \
-  } while (0)
 
-#define __FP_UNPACK_RAW_4(fs, X, val)                  \
-  do {                                                 \
-    union _FP_UNION_##fs *_flo =                       \
-       (union _FP_UNION_##fs *)val;                    \
-                                                       \
-    X##_f[0] = _flo->bits.frac0;                       \
-    X##_f[1] = _flo->bits.frac1;                       \
-    X##_f[2] = _flo->bits.frac2;                       \
-    X##_f[3] = _flo->bits.frac3;                       \
-    X##_e  = _flo->bits.exp;                           \
-    X##_s  = _flo->bits.sign;                          \
+/* Some assembly to speed things up. */
+#define __FP_FRAC_ADD_3(r2,r1,r0,x2,x1,x0,y2,y1,y0)                    \
+  __asm__ ("addcc %r7,%8,%2
+           addxcc %r5,%6,%1
+           addx %r3,%4,%0"                                             \
+          : "=r" ((USItype)(r2)),                                      \
+            "=&r" ((USItype)(r1)),                                     \
+            "=&r" ((USItype)(r0))                                      \
+          : "%rJ" ((USItype)(x2)),                                     \
+            "rI" ((USItype)(y2)),                                      \
+            "%rJ" ((USItype)(x1)),                                     \
+            "rI" ((USItype)(y1)),                                      \
+            "%rJ" ((USItype)(x0)),                                     \
+            "rI" ((USItype)(y0))                                       \
+          : "cc")
+
+#define __FP_FRAC_SUB_3(r2,r1,r0,x2,x1,x0,y2,y1,y0)                    \
+  __asm__ ("subcc %r7,%8,%2
+           subxcc %r5,%6,%1
+           subx %r3,%4,%0"                                             \
+          : "=r" ((USItype)(r2)),                                      \
+            "=&r" ((USItype)(r1)),                                     \
+            "=&r" ((USItype)(r0))                                      \
+          : "%rJ" ((USItype)(x2)),                                     \
+            "rI" ((USItype)(y2)),                                      \
+            "%rJ" ((USItype)(x1)),                                     \
+            "rI" ((USItype)(y1)),                                      \
+            "%rJ" ((USItype)(x0)),                                     \
+            "rI" ((USItype)(y0))                                       \
+          : "cc")
+
+#define __FP_FRAC_ADD_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0)           \
+  do {                                                                 \
+    /* We need to fool gcc,  as we need to pass more than 10           \
+       input/outputs.  */                                              \
+    register USItype _t1 __asm__ ("g1"), _t2 __asm__ ("g2");           \
+    __asm__ __volatile__ ("
+           addcc %r8,%9,%1
+           addxcc %r6,%7,%0
+           addxcc %r4,%5,%%g2
+           addx %r2,%3,%%g1"                                           \
+          : "=&r" ((USItype)(r1)),                                     \
+            "=&r" ((USItype)(r0))                                      \
+          : "%rJ" ((USItype)(x3)),                                     \
+            "rI" ((USItype)(y3)),                                      \
+            "%rJ" ((USItype)(x2)),                                     \
+            "rI" ((USItype)(y2)),                                      \
+            "%rJ" ((USItype)(x1)),                                     \
+            "rI" ((USItype)(y1)),                                      \
+            "%rJ" ((USItype)(x0)),                                     \
+            "rI" ((USItype)(y0))                                       \
+          : "cc", "g1", "g2");                                         \
+    __asm__ __volatile__ ("" : "=r" (_t1), "=r" (_t2));                        \
+    r3 = _t1; r2 = _t2;                                                        \
   } while (0)
 
-#define __FP_UNPACK_S(X,val)           \
-  do {                                 \
-    __FP_UNPACK_RAW_1(S,X,val);                \
-    _FP_UNPACK_CANONICAL(S,1,X);       \
+#define __FP_FRAC_SUB_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0)           \
+  do {                                                                 \
+    /* We need to fool gcc,  as we need to pass more than 10           \
+       input/outputs.  */                                              \
+    register USItype _t1 __asm__ ("g1"), _t2 __asm__ ("g2");           \
+    __asm__ __volatile__ ("
+           subcc %r8,%9,%1
+           subxcc %r6,%7,%0
+           subxcc %r4,%5,%%g2
+           subx %r2,%3,%%g1"                                           \
+          : "=&r" ((USItype)(r1)),                                     \
+            "=&r" ((USItype)(r0))                                      \
+          : "%rJ" ((USItype)(x3)),                                     \
+            "rI" ((USItype)(y3)),                                      \
+            "%rJ" ((USItype)(x2)),                                     \
+            "rI" ((USItype)(y2)),                                      \
+            "%rJ" ((USItype)(x1)),                                     \
+            "rI" ((USItype)(y1)),                                      \
+            "%rJ" ((USItype)(x0)),                                     \
+            "rI" ((USItype)(y0))                                       \
+          : "cc", "g1", "g2");                                         \
+    __asm__ __volatile__ ("" : "=r" (_t1), "=r" (_t2));                        \
+    r3 = _t1; r2 = _t2;                                                        \
   } while (0)
 
-#define __FP_UNPACK_D(X,val)           \
-  do {                                 \
-    __FP_UNPACK_RAW_2(D,X,val);                \
-    _FP_UNPACK_CANONICAL(D,2,X);       \
-  } while (0)
-
-#define __FP_UNPACK_Q(X,val)           \
-  do {                                 \
-    __FP_UNPACK_RAW_4(Q,X,val);                \
-    _FP_UNPACK_CANONICAL(Q,4,X);       \
-  } while (0)
-
-#define __FP_PACK_RAW_1(fs, val, X)                            \
-  do {                                                         \
-    union _FP_UNION_##fs *_flo =                               \
-       (union _FP_UNION_##fs *)val;                            \
-                                                               \
-    _flo->bits.frac = X##_f;                                   \
-    _flo->bits.exp  = X##_e;                                   \
-    _flo->bits.sign = X##_s;                                   \
-  } while (0)
-  
-#define __FP_PACK_RAW_2(fs, val, X)                    \
-  do {                                                 \
-    union _FP_UNION_##fs *_flo =                       \
-       (union _FP_UNION_##fs *)val;                    \
-                                                       \
-    _flo->bits.frac0 = X##_f0;                         \
-    _flo->bits.frac1 = X##_f1;                         \
-    _flo->bits.exp   = X##_e;                          \
-    _flo->bits.sign  = X##_s;                          \
-  } while (0)
-
-#define __FP_PACK_RAW_4(fs, val, X)                    \
-  do {                                                 \
-    union _FP_UNION_##fs *_flo =                       \
-       (union _FP_UNION_##fs *)val;                    \
-                                                       \
-    _flo->bits.frac0 = X##_f[0];                       \
-    _flo->bits.frac1 = X##_f[1];                       \
-    _flo->bits.frac2 = X##_f[2];                       \
-    _flo->bits.frac3 = X##_f[3];                       \
-    _flo->bits.exp   = X##_e;                          \
-    _flo->bits.sign  = X##_s;                          \
-  } while (0)
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-
-/* We only actually write to the destination register
- * if exceptions signalled (if any) will not trap.
- */
-#ifdef __SMP__
-#define __FPU_TEM \
-       (((current->tss.fsr)>>23)&0x1f)
-#else
+#define __FP_FRAC_DEC_3(x2,x1,x0,y2,y1,y0) __FP_FRAC_SUB_3(x2,x1,x0,x2,x1,x0,y2,y1,y0)
+
+#define __FP_FRAC_DEC_4(x3,x2,x1,x0,y3,y2,y1,y0) __FP_FRAC_SUB_4(x3,x2,x1,x0,x3,x2,x1,x0,y3,y2,y1,y0)
+
+#define __FP_FRAC_ADDI_4(x3,x2,x1,x0,i)                                        \
+  __asm__ ("addcc %3,%4,%3
+           addxcc %2,%%g0,%2
+           addxcc %1,%%g0,%1
+           addx %0,%%g0,%0"                                            \
+          : "=&r" ((USItype)(x3)),                                     \
+            "=&r" ((USItype)(x2)),                                     \
+            "=&r" ((USItype)(x1)),                                     \
+            "=&r" ((USItype)(x0))                                      \
+          : "rI" ((USItype)(i)),                                       \
+            "0" ((USItype)(x3)),                                       \
+            "1" ((USItype)(x2)),                                       \
+            "2" ((USItype)(x1)),                                       \
+            "3" ((USItype)(x0))                                        \
+          : "cc")
+
+#ifndef __SMP__
 extern struct task_struct *last_task_used_math;
-#define __FPU_TEM \
-       (((last_task_used_math->tss.fsr)>>23)&0x1f)
 #endif
-#define __FPU_TRAP_P(bits) \
-       ((__FPU_TEM & (bits)) != 0)
-
-#define __FP_PACK_S(val,X)                     \
-({  int __exc = _FP_PACK_CANONICAL(S,1,X);     \
-    if(!__exc || !__FPU_TRAP_P(__exc))         \
-        __FP_PACK_RAW_1(S,val,X);              \
-    __exc;                                     \
-})
-
-#define __FP_PACK_D(val,X)                     \
-({  int __exc = _FP_PACK_CANONICAL(D,2,X);     \
-    if(!__exc || !__FPU_TRAP_P(__exc))         \
-        __FP_PACK_RAW_2(D,val,X);              \
-    __exc;                                     \
-})
-
-#define __FP_PACK_Q(val,X)                     \
-({  int __exc = _FP_PACK_CANONICAL(Q,4,X);     \
-    if(!__exc || !__FPU_TRAP_P(__exc))         \
-        __FP_PACK_RAW_4(Q,val,X);              \
-    __exc;                                     \
-})
 
 /* Obtain the current rounding mode. */
+#ifndef FP_ROUNDMODE
 #ifdef __SMP__
 #define FP_ROUNDMODE   ((current->tss.fsr >> 30) & 0x3)
 #else
 #define FP_ROUNDMODE   ((last_task_used_math->tss.fsr >> 30) & 0x3)
 #endif
+#endif
 
-/* the asm fragments go here: all these are taken from glibc-2.0.5's stdlib/longlong.h */
-
-#include <linux/types.h>
-#include <asm/byteorder.h>
-
-/* add_ssaaaa is used in op-2.h and should be equivalent to
- * #define add_ssaaaa(sh,sl,ah,al,bh,bl) (sh = ah+bh+ (( sl = al+bl) < al))
- * add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1,
- * high_addend_2, low_addend_2) adds two UWtype integers, composed by
- * HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and LOW_ADDEND_2
- * respectively.  The result is placed in HIGH_SUM and LOW_SUM.  Overflow
- * (i.e. carry out) is not stored anywhere, and is lost.
- */
-#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
-  __asm__ ("addcc %r4,%5,%1
-        addx %r2,%3,%0"                                                 \
-           : "=r" ((USItype)(sh)),                                      \
-             "=&r" ((USItype)(sl))                                      \
-           : "%rJ" ((USItype)(ah)),                                     \
-             "rI" ((USItype)(bh)),                                      \
-             "%rJ" ((USItype)(al)),                                     \
-             "rI" ((USItype)(bl))                                       \
-           : "cc")
-
-
-/* sub_ddmmss is used in op-2.h and udivmodti4.c and should be equivalent to
- * #define sub_ddmmss(sh, sl, ah, al, bh, bl) (sh = ah-bh - ((sl = al-bl) > al))
- * sub_ddmmss(high_difference, low_difference, high_minuend, low_minuend,
- * high_subtrahend, low_subtrahend) subtracts two two-word UWtype integers,
- * composed by HIGH_MINUEND_1 and LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and
- * LOW_SUBTRAHEND_2 respectively.  The result is placed in HIGH_DIFFERENCE
- * and LOW_DIFFERENCE.  Overflow (i.e. carry out) is not stored anywhere,
- * and is lost.
- */
-
-#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
-  __asm__ ("subcc %r4,%5,%1
-        subx %r2,%3,%0"                                                 \
-           : "=r" ((USItype)(sh)),                                      \
-             "=&r" ((USItype)(sl))                                      \
-           : "rJ" ((USItype)(ah)),                                      \
-             "rI" ((USItype)(bh)),                                      \
-             "rJ" ((USItype)(al)),                                      \
-             "rI" ((USItype)(bl))                                       \
-           : "cc")
-
-
-/* asm fragments for mul and div */     
-/* umul_ppmm(high_prod, low_prod, multipler, multiplicand) multiplies two
- * UWtype integers MULTIPLER and MULTIPLICAND, and generates a two UWtype
- * word product in HIGH_PROD and LOW_PROD.
- * These look ugly because the sun4/4c don't have umul/udiv/smul/sdiv in
- * hardware. 
- */
-#define umul_ppmm(w1, w0, u, v) \
-  __asm__ ("! Inlined umul_ppmm
-        wr      %%g0,%2,%%y     ! SPARC has 0-3 delay insn after a wr
-        sra     %3,31,%%g2      ! Don't move this insn
-        and     %2,%%g2,%%g2    ! Don't move this insn
-        andcc   %%g0,0,%%g1     ! Don't move this insn
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,%3,%%g1
-        mulscc  %%g1,0,%%g1
-        add     %%g1,%%g2,%0
-        rd      %%y,%1"                                                 \
-           : "=r" ((USItype)(w1)),                                      \
-             "=r" ((USItype)(w0))                                       \
-           : "%rI" ((USItype)(u)),                                      \
-             "r" ((USItype)(v))                                         \
-           : "%g1", "%g2", "cc")
-
-/* udiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
- * denominator) divides a UDWtype, composed by the UWtype integers
- * HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and places the quotient
- * in QUOTIENT and the remainder in REMAINDER.  HIGH_NUMERATOR must be less
- * than DENOMINATOR for correct operation.  If, in addition, the most
- * significant bit of DENOMINATOR must be 1, then the pre-processor symbol
- * UDIV_NEEDS_NORMALIZATION is defined to 1.
- */
-
-#define udiv_qrnnd(q, r, n1, n0, d) \
-  __asm__ ("! Inlined udiv_qrnnd
-        mov     32,%%g1
-        subcc   %1,%2,%%g0
-1:      bcs     5f
-         addxcc %0,%0,%0        ! shift n1n0 and a q-bit in lsb
-        sub     %1,%2,%1        ! this kills msb of n
-        addx    %1,%1,%1        ! so this can't give carry
-        subcc   %%g1,1,%%g1
-2:      bne     1b
-         subcc  %1,%2,%%g0
-        bcs     3f
-         addxcc %0,%0,%0        ! shift n1n0 and a q-bit in lsb
-        b       3f
-         sub    %1,%2,%1        ! this kills msb of n
-4:      sub     %1,%2,%1
-5:      addxcc  %1,%1,%1
-        bcc     2b
-         subcc  %%g1,1,%%g1
-! Got carry from n.  Subtract next step to cancel this carry.
-        bne     4b
-         addcc  %0,%0,%0        ! shift n1n0 and a 0-bit in lsb
-        sub     %1,%2,%1
-3:      xnor    %0,0,%0
-        ! End of inline udiv_qrnnd"                                     \
-           : "=&r" ((USItype) (q)),                                     \
-             "=&r" ((USItype) (r))                                      \
-           : "r" ((USItype) (d)),                                       \
-             "1" ((USItype) (n1)),                                      \
-             "0" ((USItype) (n0)) : "%g1", "cc")
-
-#define UDIV_NEEDS_NORMALIZATION 0
+/* Exception flags. */
+#define FP_EX_INVALID          (1 << 4)
+#define FP_EX_OVERFLOW         (1 << 3)
+#define FP_EX_UNDERFLOW                (1 << 2)
+#define FP_EX_DIVZERO          (1 << 1)
+#define FP_EX_INEXACT          (1 << 0)
 
-#define abort()                                                                \
-       return 0
+#define FP_HANDLE_EXCEPTIONS return _fex
 
-#ifdef __BIG_ENDIAN
-#define __BYTE_ORDER __BIG_ENDIAN
+#ifdef __SMP__
+#define FP_INHIBIT_RESULTS ((current->tss.fsr >> 23) & _fex)
 #else
-#define __BYTE_ORDER __LITTLE_ENDIAN
+#define FP_INHIBIT_RESULTS ((last_task_used_math->tss.fsr >> 23) & _fex)
 #endif
 
-/* Exception flags. */
-#define EFLAG_INVALID          (1 << 4)
-#define EFLAG_OVERFLOW         (1 << 3)
-#define EFLAG_UNDERFLOW                (1 << 2)
-#define EFLAG_DIVZERO          (1 << 1)
-#define EFLAG_INEXACT          (1 << 0)
+#endif
diff --git a/arch/sparc/math-emu/sfp-util.h b/arch/sparc/math-emu/sfp-util.h
new file mode 100644 (file)
index 0000000..75ec691
--- /dev/null
@@ -0,0 +1,115 @@
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+#define add_ssaaaa(sh, sl, ah, al, bh, bl)                             \
+  __asm__ ("addcc %r4,%5,%1
+       addx %r2,%3,%0"                                                 \
+          : "=r" ((USItype)(sh)),                                      \
+            "=&r" ((USItype)(sl))                                      \
+          : "%rJ" ((USItype)(ah)),                                     \
+            "rI" ((USItype)(bh)),                                      \
+            "%rJ" ((USItype)(al)),                                     \
+            "rI" ((USItype)(bl))                                       \
+          : "cc")
+#define sub_ddmmss(sh, sl, ah, al, bh, bl)                             \
+  __asm__ ("subcc %r4,%5,%1
+       subx %r2,%3,%0"                                                 \
+          : "=r" ((USItype)(sh)),                                      \
+            "=&r" ((USItype)(sl))                                      \
+          : "rJ" ((USItype)(ah)),                                      \
+            "rI" ((USItype)(bh)),                                      \
+            "rJ" ((USItype)(al)),                                      \
+            "rI" ((USItype)(bl))                                       \
+          : "cc")
+
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("! Inlined umul_ppmm
+       wr      %%g0,%2,%%y     ! SPARC has 0-3 delay insn after a wr
+       sra     %3,31,%%g2      ! Don't move this insn
+       and     %2,%%g2,%%g2    ! Don't move this insn
+       andcc   %%g0,0,%%g1     ! Don't move this insn
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,%3,%%g1
+       mulscc  %%g1,0,%%g1
+       add     %%g1,%%g2,%0
+       rd      %%y,%1"                                                 \
+          : "=r" ((USItype)(w1)),                                      \
+            "=r" ((USItype)(w0))                                       \
+          : "%rI" ((USItype)(u)),                                      \
+            "r" ((USItype)(v))                                         \
+          : "%g1", "%g2", "cc")
+
+/* It's quite necessary to add this much assembler for the sparc.
+   The default udiv_qrnnd (in C) is more than 10 times slower!  */
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  __asm__ ("! Inlined udiv_qrnnd
+       mov     32,%%g1
+       subcc   %1,%2,%%g0
+1:     bcs     5f
+        addxcc %0,%0,%0        ! shift n1n0 and a q-bit in lsb
+       sub     %1,%2,%1        ! this kills msb of n
+       addx    %1,%1,%1        ! so this can't give carry
+       subcc   %%g1,1,%%g1
+2:     bne     1b
+        subcc  %1,%2,%%g0
+       bcs     3f
+        addxcc %0,%0,%0        ! shift n1n0 and a q-bit in lsb
+       b       3f
+        sub    %1,%2,%1        ! this kills msb of n
+4:     sub     %1,%2,%1
+5:     addxcc  %1,%1,%1
+       bcc     2b
+        subcc  %%g1,1,%%g1
+! Got carry from n.  Subtract next step to cancel this carry.
+       bne     4b
+        addcc  %0,%0,%0        ! shift n1n0 and a 0-bit in lsb
+       sub     %1,%2,%1
+3:     xnor    %0,0,%0
+       ! End of inline udiv_qrnnd"                                     \
+          : "=&r" ((USItype)(q)),                                      \
+            "=&r" ((USItype)(r))                                       \
+          : "r" ((USItype)(d)),                                        \
+            "1" ((USItype)(n1)),                                       \
+            "0" ((USItype)(n0)) : "%g1", "cc")
+#define UDIV_NEEDS_NORMALIZATION 0
+
+#define abort()                                                                \
+       return 0
+
+#ifdef __BIG_ENDIAN
+#define __BYTE_ORDER __BIG_ENDIAN
+#else
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#endif
index 020cb551e28764e0ed1e471ba6bc009e57c98d66..11c101a3cabd01d8c9cf8cccd7ab866cd09a5196 100644 (file)
@@ -156,6 +156,10 @@ CONFIG_IPX=m
 # CONFIG_IPX_INTERN is not set
 # CONFIG_SPX is not set
 CONFIG_ATALK=m
+CONFIG_DECNET=m
+CONFIG_DECNET_SIOCGIFCONF=y
+# CONFIG_DECNET_ROUTER is not set
+CONFIG_DECNET_RAW=y
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_BRIDGE is not set
@@ -310,6 +314,7 @@ CONFIG_BSD_DISKLABEL=y
 # CONFIG_MAC_PARTITION is not set
 CONFIG_SMD_DISKLABEL=y
 CONFIG_SOLARIS_X86_PARTITION=y
+# CONFIG_SGI_DISKLABEL is not set
 # CONFIG_UNIXWARE_DISKLABEL is not set
 CONFIG_AMIGA_PARTITION=y
 CONFIG_NLS=y
index caa1d99ef100ddd9a96e9f09f8c7b8ac5a665fad..d5e980ebf15426fc78d3cb3000225da5bbcb08ec 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.43 1999/04/12 08:08:24 davem Exp $
+/*  $Id: setup.c,v 1.44 1999/05/28 02:17:29 davem Exp $
  *  linux/arch/sparc64/kernel/setup.c
  *
  *  Copyright (C) 1995,1996  David S. Miller (davem@caip.rutgers.edu)
@@ -550,7 +550,9 @@ __initfunc(void setup_arch(char **cmdline_p,
                        ic_servaddr = sv;
                        if (gw)
                                ic_gateway = gw;
+#if defined(CONFIG_IP_PNP_BOOTP) || defined(CONFIG_IP_PNP_RARP)
                        ic_proto_enabled = 0;
+#endif
                }
        }
 #endif
index 1f5a194998382adadcb0044844e2b8a5389d30bf..4437032b58acd715ee7b02ec8383bc5175ef48c7 100644 (file)
@@ -11,7 +11,7 @@ O_TARGET := math-emu.o
 O_OBJS   := math.o fabsq.o faddq.o fdivq.o fdmulq.o fitoq.o            \
                fmovq.o fmulq.o fnegq.o fqtoi.o fqtox.o fsubq.o         \
                fxtoq.o fdtoq.o fstoq.o fqtos.o fqtod.o fsqrtq.o        \
-               fcmpq.o fcmpeq.o udivmodti4.o                           \
+               fcmpq.o fcmpeq.o                                        \
                fsqrts.o fsqrtd.o fadds.o faddd.o fsubs.o fsubd.o       \
                fmuls.o fmuld.o fdivs.o fdivd.o fsmuld.o                \
                fstoi.o fdtoi.o fstox.o fdtox.o fstod.o fdtos.o
index 6aff6fdd5ff3cdf3a9915a21e85265fc85bda785..ee581c2da4c0a99349c58da865fea4787a170977 100644 (file)
@@ -1,6 +1,26 @@
-/*
- * Definitions for IEEE Double Precision
- */
+/* Software floating-point emulation.
+   Definitions for IEEE Double Precision
+   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+                 Jakub Jelinek (jj@ultra.linux.cz),
+                 David S. Miller (davem@redhat.com) and
+                 Peter Maydell (pmaydell@chiark.greenend.org.uk).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #if _FP_W_TYPE_SIZE < 32
 #error "Here's a nickel kid.  Go buy yourself a real computer."
@@ -49,7 +69,13 @@ union _FP_UNION_D
 
 #define FP_DECL_D(X)           _FP_DECL(2,X)
 #define FP_UNPACK_RAW_D(X,val) _FP_UNPACK_RAW_2(D,X,val)
+#define FP_UNPACK_RAW_DP(X,val)        _FP_UNPACK_RAW_2_P(D,X,val)
 #define FP_PACK_RAW_D(val,X)   _FP_PACK_RAW_2(D,val,X)
+#define FP_PACK_RAW_DP(val,X)          \
+  do {                                 \
+    if (!FP_INHIBIT_RESULTS)           \
+      _FP_PACK_RAW_2_P(D,val,X);       \
+  } while (0)
 
 #define FP_UNPACK_D(X,val)             \
   do {                                 \
@@ -57,24 +83,42 @@ union _FP_UNION_D
     _FP_UNPACK_CANONICAL(D,2,X);       \
   } while (0)
 
+#define FP_UNPACK_DP(X,val)            \
+  do {                                 \
+    _FP_UNPACK_RAW_2_P(D,X,val);       \
+    _FP_UNPACK_CANONICAL(D,2,X);       \
+  } while (0)
+
 #define FP_PACK_D(val,X)               \
   do {                                 \
     _FP_PACK_CANONICAL(D,2,X);         \
     _FP_PACK_RAW_2(D,val,X);           \
   } while (0)
 
-#define FP_NEG_D(R,X)          _FP_NEG(D,2,R,X)
-#define FP_ADD_D(R,X,Y)                _FP_ADD(D,2,R,X,Y)
-#define FP_SUB_D(R,X,Y)                _FP_SUB(D,2,R,X,Y)
-#define FP_MUL_D(R,X,Y)                _FP_MUL(D,2,R,X,Y)
-#define FP_DIV_D(R,X,Y)                _FP_DIV(D,2,R,X,Y)
-#define FP_SQRT_D(R,X)         _FP_SQRT(D,2,R,X)
+#define FP_PACK_DP(val,X)              \
+  do {                                 \
+    _FP_PACK_CANONICAL(D,2,X);         \
+    if (!FP_INHIBIT_RESULTS)           \
+      _FP_PACK_RAW_2_P(D,val,X);       \
+  } while (0)
+
+#define FP_ISSIGNAN_D(X)               _FP_ISSIGNAN(D,2,X)
+#define FP_NEG_D(R,X)                  _FP_NEG(D,2,R,X)
+#define FP_ADD_D(R,X,Y)                        _FP_ADD(D,2,R,X,Y)
+#define FP_SUB_D(R,X,Y)                        _FP_SUB(D,2,R,X,Y)
+#define FP_MUL_D(R,X,Y)                        _FP_MUL(D,2,R,X,Y)
+#define FP_DIV_D(R,X,Y)                        _FP_DIV(D,2,R,X,Y)
+#define FP_SQRT_D(R,X)                 _FP_SQRT(D,2,R,X)
+#define _FP_SQRT_MEAT_D(R,S,T,X,Q)     _FP_SQRT_MEAT_2(R,S,T,X,Q)
 
 #define FP_CMP_D(r,X,Y,un)     _FP_CMP(D,2,r,X,Y,un)
 #define FP_CMP_EQ_D(r,X,Y)     _FP_CMP_EQ(D,2,r,X,Y)
 
-#define FP_TO_INT_D(r,X,rsz,rsg)  _FP_TO_INT(D,2,r,X,rsz,rsg)
-#define FP_FROM_INT_D(X,r,rs,rt)  _FP_FROM_INT(D,2,X,r,rs,rt)
+#define FP_TO_INT_D(r,X,rsz,rsg)       _FP_TO_INT(D,2,r,X,rsz,rsg)
+#define FP_FROM_INT_D(X,r,rs,rt)       _FP_FROM_INT(D,2,X,r,rs,rt)
+
+#define _FP_FRAC_HIGH_D(X)     _FP_FRAC_HIGH_2(X)
+#define _FP_FRAC_HIGH_RAW_D(X) _FP_FRAC_HIGH_2(X)
 
 #else
 
@@ -96,7 +140,13 @@ union _FP_UNION_D
 
 #define FP_DECL_D(X)           _FP_DECL(1,X)
 #define FP_UNPACK_RAW_D(X,val) _FP_UNPACK_RAW_1(D,X,val)
+#define FP_UNPACK_RAW_DP(X,val)        _FP_UNPACK_RAW_1_P(D,X,val)
 #define FP_PACK_RAW_D(val,X)   _FP_PACK_RAW_1(D,val,X)
+#define FP_PACK_RAW_DP(val,X)          \
+  do {                                 \
+    if (!FP_INHIBIT_RESULTS)           \
+      _FP_PACK_RAW_1_P(D,val,X);       \
+  } while (0)
 
 #define FP_UNPACK_D(X,val)             \
   do {                                 \
@@ -104,18 +154,33 @@ union _FP_UNION_D
     _FP_UNPACK_CANONICAL(D,1,X);       \
   } while (0)
 
+#define FP_UNPACK_DP(X,val)            \
+  do {                                 \
+    _FP_UNPACK_RAW_1_P(D,X,val);       \
+    _FP_UNPACK_CANONICAL(D,1,X);       \
+  } while (0)
+
 #define FP_PACK_D(val,X)               \
   do {                                 \
     _FP_PACK_CANONICAL(D,1,X);         \
     _FP_PACK_RAW_1(D,val,X);           \
   } while (0)
 
-#define FP_NEG_D(R,X)          _FP_NEG(D,1,R,X)
-#define FP_ADD_D(R,X,Y)                _FP_ADD(D,1,R,X,Y)
-#define FP_SUB_D(R,X,Y)                _FP_SUB(D,1,R,X,Y)
-#define FP_MUL_D(R,X,Y)                _FP_MUL(D,1,R,X,Y)
-#define FP_DIV_D(R,X,Y)                _FP_DIV(D,1,R,X,Y)
-#define FP_SQRT_D(R,X)         _FP_SQRT(D,1,R,X)
+#define FP_PACK_DP(val,X)              \
+  do {                                 \
+    _FP_PACK_CANONICAL(D,1,X);         \
+    if (!FP_INHIBIT_RESULTS)           \
+      _FP_PACK_RAW_1_P(D,val,X);       \
+  } while (0)
+
+#define FP_ISSIGNAN_D(X)               _FP_ISSIGNAN(D,1,X)
+#define FP_NEG_D(R,X)                  _FP_NEG(D,1,R,X)
+#define FP_ADD_D(R,X,Y)                        _FP_ADD(D,1,R,X,Y)
+#define FP_SUB_D(R,X,Y)                        _FP_SUB(D,1,R,X,Y)
+#define FP_MUL_D(R,X,Y)                        _FP_MUL(D,1,R,X,Y)
+#define FP_DIV_D(R,X,Y)                        _FP_DIV(D,1,R,X,Y)
+#define FP_SQRT_D(R,X)                 _FP_SQRT(D,1,R,X)
+#define _FP_SQRT_MEAT_D(R,S,T,X,Q)     _FP_SQRT_MEAT_1(R,S,T,X,Q)
 
 /* The implementation of _FP_MUL_D and _FP_DIV_D should be chosen by
    the target machine.  */
@@ -123,7 +188,10 @@ union _FP_UNION_D
 #define FP_CMP_D(r,X,Y,un)     _FP_CMP(D,1,r,X,Y,un)
 #define FP_CMP_EQ_D(r,X,Y)     _FP_CMP_EQ(D,1,r,X,Y)
 
-#define FP_TO_INT_D(r,X,rsz,rsg)  _FP_TO_INT(D,1,r,X,rsz,rsg)
-#define FP_FROM_INT_D(X,r,rs,rt)  _FP_FROM_INT(D,1,X,r,rs,rt)
+#define FP_TO_INT_D(r,X,rsz,rsg)       _FP_TO_INT(D,1,r,X,rsz,rsg)
+#define FP_FROM_INT_D(X,r,rs,rt)       _FP_FROM_INT(D,1,X,r,rs,rt)
+
+#define _FP_FRAC_HIGH_D(X)     _FP_FRAC_HIGH_1(X)
+#define _FP_FRAC_HIGH_RAW_D(X) _FP_FRAC_HIGH_1(X)
 
 #endif /* W_TYPE_SIZE < 64 */
diff --git a/arch/sparc64/math-emu/extended.h b/arch/sparc64/math-emu/extended.h
new file mode 100644 (file)
index 0000000..4a1d7e7
--- /dev/null
@@ -0,0 +1,388 @@
+/* Software floating-point emulation.
+   Definitions for IEEE Extended Precision.
+   Copyright (C) 1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek (jj@ultra.linux.cz).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#if _FP_W_TYPE_SIZE < 32
+#error "Here's a nickel, kid. Go buy yourself a real computer."
+#endif
+
+#if _FP_W_TYPE_SIZE < 64
+#define _FP_FRACTBITS_E         (4*_FP_W_TYPE_SIZE)
+#else
+#define _FP_FRACTBITS_E                (2*_FP_W_TYPE_SIZE)
+#endif
+
+#define _FP_FRACBITS_E         64
+#define _FP_FRACXBITS_E                (_FP_FRACTBITS_E - _FP_FRACBITS_E)
+#define _FP_WFRACBITS_E                (_FP_WORKBITS + _FP_FRACBITS_E)
+#define _FP_WFRACXBITS_E       (_FP_FRACTBITS_E - _FP_WFRACBITS_E)
+#define _FP_EXPBITS_E          15
+#define _FP_EXPBIAS_E          16383
+#define _FP_EXPMAX_E           32767
+
+#define _FP_QNANBIT_E          \
+       ((_FP_W_TYPE)1 << (_FP_FRACBITS_E-2) % _FP_W_TYPE_SIZE)
+#define _FP_IMPLBIT_E          \
+       ((_FP_W_TYPE)1 << (_FP_FRACBITS_E-1) % _FP_W_TYPE_SIZE)
+#define _FP_OVERFLOW_E         \
+       ((_FP_W_TYPE)1 << (_FP_WFRACBITS_E % _FP_W_TYPE_SIZE))
+
+#if _FP_W_TYPE_SIZE < 64
+
+union _FP_UNION_E
+{
+   long double flt;
+   struct 
+   {
+#if __BYTE_ORDER == __BIG_ENDIAN
+      unsigned long pad1 : _FP_W_TYPE_SIZE;
+      unsigned long pad2 : (_FP_W_TYPE_SIZE - 1 - _FP_EXPBITS_E);
+      unsigned long sign : 1;
+      unsigned long exp : _FP_EXPBITS_E;
+      unsigned long frac1 : _FP_W_TYPE_SIZE;
+      unsigned long frac0 : _FP_W_TYPE_SIZE;
+#else
+      unsigned long frac0 : _FP_W_TYPE_SIZE;
+      unsigned long frac1 : _FP_W_TYPE_SIZE;
+      unsigned exp : _FP_EXPBITS_E;
+      unsigned sign : 1;
+#endif /* not bigendian */
+   } bits __attribute__((packed));
+};
+
+
+#define FP_DECL_E(X)           _FP_DECL(4,X)
+
+#define FP_UNPACK_RAW_E(X, val)                                \
+  do {                                                 \
+    union _FP_UNION_E _flo; _flo.flt = (val);          \
+                                                       \
+    X##_f[2] = 0; X##_f[3] = 0;                                \
+    X##_f[0] = _flo.bits.frac0;                                \
+    X##_f[1] = _flo.bits.frac1;                                \
+    X##_e  = _flo.bits.exp;                            \
+    X##_s  = _flo.bits.sign;                           \
+    if (!X##_e && (X##_f[1] || X##_f[0])               \
+        && !(X##_f[1] & _FP_IMPLBIT_E))                        \
+      {                                                        \
+        X##_e++;                                       \
+        FP_SET_EXCEPTION(FP_EX_DENORM);                        \
+      }                                                        \
+  } while (0)
+
+#define FP_UNPACK_RAW_EP(X, val)                       \
+  do {                                                 \
+    union _FP_UNION_E *_flo =                          \
+    (union _FP_UNION_E *)(val);                                \
+                                                       \
+    X##_f[2] = 0; X##_f[3] = 0;                                \
+    X##_f[0] = _flo->bits.frac0;                       \
+    X##_f[1] = _flo->bits.frac1;                       \
+    X##_e  = _flo->bits.exp;                           \
+    X##_s  = _flo->bits.sign;                          \
+    if (!X##_e && (X##_f[1] || X##_f[0])               \
+        && !(X##_f[1] & _FP_IMPLBIT_E))                        \
+      {                                                        \
+        X##_e++;                                       \
+        FP_SET_EXCEPTION(FP_EX_DENORM);                        \
+      }                                                        \
+  } while (0)
+
+#define FP_PACK_RAW_E(val, X)                          \
+  do {                                                 \
+    union _FP_UNION_E _flo;                            \
+                                                       \
+    if (X##_e) X##_f[1] |= _FP_IMPLBIT_E;              \
+    else X##_f[1] &= ~(_FP_IMPLBIT_E);                 \
+    _flo.bits.frac0 = X##_f[0];                                \
+    _flo.bits.frac1 = X##_f[1];                                \
+    _flo.bits.exp   = X##_e;                           \
+    _flo.bits.sign  = X##_s;                           \
+                                                       \
+    (val) = _flo.flt;                                  \
+  } while (0)
+
+#define FP_PACK_RAW_EP(val, X)                         \
+  do {                                                 \
+    if (!FP_INHIBIT_RESULTS)                           \
+      {                                                        \
+       union _FP_UNION_E *_flo =                       \
+         (union _FP_UNION_E *)(val);                   \
+                                                       \
+       if (X##_e) X##_f[1] |= _FP_IMPLBIT_E;           \
+       else X##_f[1] &= ~(_FP_IMPLBIT_E);              \
+       _flo->bits.frac0 = X##_f[0];                    \
+       _flo->bits.frac1 = X##_f[1];                    \
+       _flo->bits.exp   = X##_e;                       \
+       _flo->bits.sign  = X##_s;                       \
+      }                                                        \
+  } while (0)
+
+#define FP_UNPACK_E(X,val)             \
+  do {                                 \
+    FP_UNPACK_RAW_E(X,val);            \
+    _FP_UNPACK_CANONICAL(E,4,X);       \
+  } while (0)
+
+#define FP_UNPACK_EP(X,val)            \
+  do {                                 \
+    FP_UNPACK_RAW_2_P(X,val);          \
+    _FP_UNPACK_CANONICAL(E,4,X);       \
+  } while (0)
+
+#define FP_PACK_E(val,X)               \
+  do {                                 \
+    _FP_PACK_CANONICAL(E,4,X);         \
+    FP_PACK_RAW_E(val,X);              \
+  } while (0)
+
+#define FP_PACK_EP(val,X)              \
+  do {                                 \
+    _FP_PACK_CANONICAL(E,4,X);         \
+    FP_PACK_RAW_EP(val,X);             \
+  } while (0)
+
+#define FP_ISSIGNAN_E(X)       _FP_ISSIGNAN(E,4,X)
+#define FP_NEG_E(R,X)          _FP_NEG(E,4,R,X)
+#define FP_ADD_E(R,X,Y)                _FP_ADD(E,4,R,X,Y)
+#define FP_SUB_E(R,X,Y)                _FP_SUB(E,4,R,X,Y)
+#define FP_MUL_E(R,X,Y)                _FP_MUL(E,4,R,X,Y)
+#define FP_DIV_E(R,X,Y)                _FP_DIV(E,4,R,X,Y)
+#define FP_SQRT_E(R,X)         _FP_SQRT(E,4,R,X)
+
+/*
+ * Square root algorithms:
+ * We have just one right now, maybe Newton approximation
+ * should be added for those machines where division is fast.
+ * This has special _E version because standard _4 square
+ * root would not work (it has to start normally with the
+ * second word and not the first), but as we have to do it
+ * anyway, we optimize it by doing most of the calculations
+ * in two UWtype registers instead of four.
+ */
+#define _FP_SQRT_MEAT_E(R, S, T, X, q)                 \
+  do {                                                 \
+    q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1);                \
+    _FP_FRAC_SRL_4(X, (_FP_WORKBITS));                 \
+    while (q)                                          \
+      {                                                        \
+       T##_f[1] = S##_f[1] + q;                        \
+       if (T##_f[1] <= X##_f[1])                       \
+         {                                             \
+           S##_f[1] = T##_f[1] + q;                    \
+           X##_f[1] -= T##_f[1];                       \
+           R##_f[1] += q;                              \
+         }                                             \
+       _FP_FRAC_SLL_2(X, 1);                           \
+       q >>= 1;                                        \
+      }                                                        \
+    q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1);                \
+    while (q)                                          \
+      {                                                        \
+       T##_f[0] = S##_f[0] + q;                        \
+       T##_f[1] = S##_f[1];                            \
+       if (T##_f[1] < X##_f[1] ||                      \
+           (T##_f[1] == X##_f[1] &&                    \
+            T##_f[0] <= X##_f[0]))                     \
+         {                                             \
+           S##_f[0] = T##_f[0] + q;                    \
+           S##_f[1] += (T##_f[0] > S##_f[0]);          \
+           _FP_FRAC_DEC_2(X, T);                       \
+           R##_f[0] += q;                              \
+         }                                             \
+       _FP_FRAC_SLL_2(X, 1);                           \
+       q >>= 1;                                        \
+      }                                                        \
+    _FP_FRAC_SLL_4(R, (_FP_WORKBITS));                 \
+    if (X##_f[0] | X##_f[1])                           \
+      {                                                        \
+       if (S##_f[1] < X##_f[1] ||                      \
+           (S##_f[1] == X##_f[1] &&                    \
+            S##_f[0] < X##_f[0]))                      \
+         R##_f[0] |= _FP_WORK_ROUND;                   \
+       R##_f[0] |= _FP_WORK_STICKY;                    \
+      }                                                        \
+  } while (0)
+
+#define FP_CMP_E(r,X,Y,un)     _FP_CMP(E,4,r,X,Y,un)
+#define FP_CMP_EQ_E(r,X,Y)     _FP_CMP_EQ(E,4,r,X,Y)
+
+#define FP_TO_INT_E(r,X,rsz,rsg)       _FP_TO_INT(E,4,r,X,rsz,rsg)
+#define FP_FROM_INT_E(X,r,rs,rt)       _FP_FROM_INT(E,4,X,r,rs,rt)
+
+#define _FP_FRAC_HIGH_E(X)     (X##_f[2])
+#define _FP_FRAC_HIGH_RAW_E(X) (X##_f[1])
+
+#else   /* not _FP_W_TYPE_SIZE < 64 */
+union _FP_UNION_E
+{
+  long double flt /* __attribute__((mode(TF))) */ ;
+  struct {
+#if __BYTE_ORDER == __BIG_ENDIAN
+    unsigned long pad : (_FP_W_TYPE_SIZE - 1 - _FP_EXPBITS_E);
+    unsigned sign  : 1;
+    unsigned exp   : _FP_EXPBITS_E;
+    unsigned long frac : _FP_W_TYPE_SIZE;
+#else
+    unsigned long frac : _FP_W_TYPE_SIZE;
+    unsigned exp   : _FP_EXPBITS_E;
+    unsigned sign  : 1;
+#endif
+  } bits;
+};
+
+#define FP_DECL_E(X)           _FP_DECL(2,X)
+
+#define FP_UNPACK_RAW_E(X, val)                                        \
+  do {                                                         \
+    union _FP_UNION_E _flo; _flo.flt = (val);                  \
+                                                               \
+    X##_f0 = _flo.bits.frac;                                   \
+    X##_f1 = 0;                                                        \
+    X##_e = _flo.bits.exp;                                     \
+    X##_s = _flo.bits.sign;                                    \
+    if (!X##_e && X##_f0 && !(X##_f0 & _FP_IMPLBIT_E))         \
+      {                                                                \
+        X##_e++;                                               \
+        FP_SET_EXCEPTION(FP_EX_DENORM);                                \
+      }                                                                \
+  } while (0)
+
+#define FP_UNPACK_RAW_EP(X, val)                               \
+  do {                                                         \
+    union _FP_UNION_E *_flo =                                  \
+      (union _FP_UNION_E *)(val);                              \
+                                                               \
+    X##_f0 = _flo->bits.frac;                                  \
+    X##_f1 = 0;                                                        \
+    X##_e = _flo->bits.exp;                                    \
+    X##_s = _flo->bits.sign;                                   \
+    if (!X##_e && X##_f0 && !(X##_f0 & _FP_IMPLBIT_E))         \
+      {                                                                \
+        X##_e++;                                               \
+        FP_SET_EXCEPTION(FP_EX_DENORM);                                \
+      }                                                                \
+  } while (0)
+
+#define FP_PACK_RAW_E(val, X)                                  \
+  do {                                                         \
+    union _FP_UNION_E _flo;                                    \
+                                                               \
+    if (X##_e) X##_f0 |= _FP_IMPLBIT_E;                                \
+    else X##_f0 &= ~(_FP_IMPLBIT_E);                           \
+    _flo.bits.frac = X##_f0;                                   \
+    _flo.bits.exp  = X##_e;                                    \
+    _flo.bits.sign = X##_s;                                    \
+                                                               \
+    (val) = _flo.flt;                                          \
+  } while (0)
+
+#define FP_PACK_RAW_EP(fs, val, X)                             \
+  do {                                                         \
+    if (!FP_INHIBIT_RESULTS)                                   \
+      {                                                                \
+       union _FP_UNION_E *_flo =                               \
+         (union _FP_UNION_E *)(val);                           \
+                                                               \
+       if (X##_e) X##_f0 |= _FP_IMPLBIT_E;                     \
+       else X##_f0 &= ~(_FP_IMPLBIT_E);                        \
+       _flo->bits.frac = X##_f0;                               \
+       _flo->bits.exp  = X##_e;                                \
+       _flo->bits.sign = X##_s;                                \
+      }                                                                \
+  } while (0)
+
+
+#define FP_UNPACK_E(X,val)             \
+  do {                                 \
+    FP_UNPACK_RAW_E(X,val);            \
+    _FP_UNPACK_CANONICAL(E,2,X);       \
+  } while (0)
+
+#define FP_UNPACK_EP(X,val)            \
+  do {                                 \
+    FP_UNPACK_RAW_EP(X,val);           \
+    _FP_UNPACK_CANONICAL(E,2,X);       \
+  } while (0)
+
+#define FP_PACK_E(val,X)               \
+  do {                                 \
+    _FP_PACK_CANONICAL(E,2,X);         \
+    FP_PACK_RAW_E(val,X);              \
+  } while (0)
+
+#define FP_PACK_EP(val,X)              \
+  do {                                 \
+    _FP_PACK_CANONICAL(E,2,X);         \
+    FP_PACK_RAW_EP(val,X);             \
+  } while (0)
+
+#define FP_ISSIGNAN_E(X)       _FP_ISSIGNAN(E,2,X)
+#define FP_NEG_E(R,X)          _FP_NEG(E,2,R,X)
+#define FP_ADD_E(R,X,Y)                _FP_ADD(E,2,R,X,Y)
+#define FP_SUB_E(R,X,Y)                _FP_SUB(E,2,R,X,Y)
+#define FP_MUL_E(R,X,Y)                _FP_MUL(E,2,R,X,Y)
+#define FP_DIV_E(R,X,Y)                _FP_DIV(E,2,R,X,Y)
+#define FP_SQRT_E(R,X)         _FP_SQRT(E,2,R,X)
+
+/*
+ * Square root algorithms:
+ * We have just one right now, maybe Newton approximation
+ * should be added for those machines where division is fast.
+ * We optimize it by doing most of the calculations
+ * in one UWtype registers instead of two, although we don't
+ * have to.
+ */
+#define _FP_SQRT_MEAT_E(R, S, T, X, q)                 \
+  do {                                                 \
+    q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1);                \
+    _FP_FRAC_SRL_2(X, (_FP_WORKBITS));                 \
+    while (q)                                          \
+      {                                                        \
+        T##_f0 = S##_f0 + q;                           \
+        if (T##_f0 <= X##_f0)                          \
+          {                                            \
+            S##_f0 = T##_f0 + q;                       \
+            X##_f0 -= T##_f0;                          \
+            R##_f0 += q;                               \
+          }                                            \
+        _FP_FRAC_SLL_1(X, 1);                          \
+        q >>= 1;                                       \
+      }                                                        \
+    _FP_FRAC_SLL_2(R, (_FP_WORKBITS));                 \
+    if (X##_f0)                                                \
+      {                                                        \
+       if (S##_f0 < X##_f0)                            \
+         R##_f0 |= _FP_WORK_ROUND;                     \
+       R##_f0 |= _FP_WORK_STICKY;                      \
+      }                                                        \
+  } while (0)
+#define FP_CMP_E(r,X,Y,un)     _FP_CMP(E,2,r,X,Y,un)
+#define FP_CMP_EQ_E(r,X,Y)     _FP_CMP_EQ(E,2,r,X,Y)
+
+#define FP_TO_INT_E(r,X,rsz,rsg)       _FP_TO_INT(E,2,r,X,rsz,rsg)
+#define FP_FROM_INT_E(X,r,rs,rt)       _FP_FROM_INT(E,2,X,r,rs,rt)
+
+#define _FP_FRAC_HIGH_E(X)     (X##_f1)
+#define _FP_FRAC_HIGH_RAW_E(X) (X##_f0)
+
+#endif /* not _FP_W_TYPE_SIZE < 64 */
index 62a7e1839b9424604f710fce96ca6a99b8bb892b..22da43d7125e2e788991c50d53b25c4fe1eba683 100644 (file)
@@ -1,3 +1,10 @@
+/* $Id: fabsq.c,v 1.5 1999/05/28 13:42:27 jj Exp $
+ * arch/sparc64/math-emu/fabsq.c
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@ultra.linux.cz)
+ *
+ */
+
 int FABSQ(unsigned long *rd, unsigned long *rs2)
 {
        rd[0] = rs2[0] & 0x7fffffffffffffffUL;
index 7c755b872453a9d1d60539b35d2c2f18ff4a493e..7ce9de721c386cf508cb8352080d81f5f0bf1568 100644 (file)
@@ -1,12 +1,23 @@
+/* $Id: faddd.c,v 1.4 1999/05/28 13:43:17 jj Exp $
+ * arch/sparc64/math-emu/faddd.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "double.h"
 
 int FADDD(void *rd, void *rs2, void *rs1)
 {
+       FP_DECL_EX;
        FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R);
 
-       __FP_UNPACK_D(A, rs1);
-       __FP_UNPACK_D(B, rs2);
+       FP_UNPACK_DP(A, rs1);
+       FP_UNPACK_DP(B, rs2);
        FP_ADD_D(R, A, B);
-       return __FP_PACK_D(rd, R);
+       FP_PACK_DP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index 052c6c9cd31a4099c47cac177df8bc7287132ea8..c555585af0fc0bd0d7d988fc118e5afbd1d3a797 100644 (file)
@@ -1,12 +1,23 @@
+/* $Id: faddq.c,v 1.4 1999/05/28 13:43:19 jj Exp $
+ * arch/sparc64/math-emu/faddq.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "quad.h"
 
 int FADDQ(void *rd, void *rs2, void *rs1)
 {
+       FP_DECL_EX;
        FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R);
 
-       __FP_UNPACK_Q(A, rs1);
-       __FP_UNPACK_Q(B, rs2);
+       FP_UNPACK_QP(A, rs1);
+       FP_UNPACK_QP(B, rs2);
        FP_ADD_Q(R, A, B);
-       return __FP_PACK_Q(rd, R);
+       FP_PACK_QP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index 35bb2030e5bd75fa6c4eb087ac02440b868e1152..73e865b4a958a5ed94ee1b06c423fa1921e18bdc 100644 (file)
@@ -1,12 +1,23 @@
+/* $Id: fadds.c,v 1.4 1999/05/28 13:43:25 jj Exp $
+ * arch/sparc64/math-emu/fadds.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "single.h"
 
 int FADDS(void *rd, void *rs2, void *rs1)
 {
+       FP_DECL_EX;
        FP_DECL_S(A); FP_DECL_S(B); FP_DECL_S(R);
 
-       __FP_UNPACK_S(A, rs1);
-       __FP_UNPACK_S(B, rs2);
+       FP_UNPACK_SP(A, rs1);
+       FP_UNPACK_SP(B, rs2);
        FP_ADD_S(R, A, B);
-       return __FP_PACK_S(rd, R);
+       FP_PACK_SP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index e99864f55a4f7b537ef0791761c61e3834ea03a6..3e418b9e54c33a3d974a9712bf76841f17febfe4 100644 (file)
@@ -1,25 +1,39 @@
+/* $Id: fcmpeq.c,v 1.5 1999/05/28 13:43:29 jj Exp $
+ * arch/sparc64/math-emu/fcmpeq.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "quad.h"
 
 int FCMPEQ(void *rd, void *rs2, void *rs1)
 {
+       FP_DECL_EX;
        FP_DECL_Q(A); FP_DECL_Q(B);
        long ret;
-       int fccno = ((long)rd) & 3;
+       long fccno = (long)rd;
        unsigned long fsr;
        
-       rd = (void *)(((long)rd)&~3);
-       __FP_UNPACK_Q(A, rs1);
-       __FP_UNPACK_Q(B, rs2);
+       FP_UNPACK_RAW_QP(A, rs1);
+       FP_UNPACK_RAW_QP(B, rs2);
        FP_CMP_Q(ret, B, A, 3);
-       if (ret == -1) ret = 2;
-       fsr = *(unsigned long *)rd;
-       switch (fccno) {
-       case 0: fsr &= ~0xc00; fsr |= (ret << 10); break;
-       case 1: fsr &= ~0x300000000UL; fsr |= (ret << 32); break;
-       case 2: fsr &= ~0xc00000000UL; fsr |= (ret << 34); break;
-       case 3: fsr &= ~0x3000000000UL; fsr |= (ret << 36); break;
+       if (ret == 3)
+               FP_SET_EXCEPTION(FP_EX_INVALID);
+       if (!FP_INHIBIT_RESULTS) {
+               rd = (void *)(((long)rd)&~3);
+               if (ret == -1) ret = 2;
+               fsr = current->tss.xfsr[0];
+               switch (fccno) {
+               case 0: fsr &= ~0xc00; fsr |= (ret << 10); break;
+               case 1: fsr &= ~0x300000000UL; fsr |= (ret << 32); break;
+               case 2: fsr &= ~0xc00000000UL; fsr |= (ret << 34); break;
+               case 3: fsr &= ~0x3000000000UL; fsr |= (ret << 36); break;
+               }
+               current->tss.xfsr[0] = fsr;
        }
-       *(unsigned long *)rd = fsr;
-       return 0;
+       FP_HANDLE_EXCEPTIONS;
 }
index 54ec4492fc24f91b545e13cdc00735823182f04a..b95e62d2079cf472cebff4deacce893eab684003 100644 (file)
@@ -1,25 +1,39 @@
+/* $Id: fcmpq.c,v 1.5 1999/05/28 13:43:33 jj Exp $
+ * arch/sparc64/math-emu/fcmpq.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "quad.h"
 
 int FCMPQ(void *rd, void *rs2, void *rs1)
 {
+       FP_DECL_EX;
        FP_DECL_Q(A); FP_DECL_Q(B);
        long ret;
-       int fccno = ((long)rd) & 3;
+       long fccno = (long)rd;
        unsigned long fsr;
        
-       rd = (void *)(((long)rd)&~3);
-       __FP_UNPACK_Q(A, rs1);
-       __FP_UNPACK_Q(B, rs2);
+       FP_UNPACK_RAW_QP(A, rs1);
+       FP_UNPACK_RAW_QP(B, rs2);
        FP_CMP_Q(ret, B, A, 3);
-       if (ret == -1) ret = 2;
-       fsr = *(unsigned long *)rd;
-       switch (fccno) {
-       case 0: fsr &= ~0xc00; fsr |= (ret << 10); break;
-       case 1: fsr &= ~0x300000000UL; fsr |= (ret << 32); break;
-       case 2: fsr &= ~0xc00000000UL; fsr |= (ret << 34); break;
-       case 3: fsr &= ~0x3000000000UL; fsr |= (ret << 36); break;
+       if (ret == 3 && (FP_ISSIGNAN_Q(A) || FP_ISSIGNAN_Q(B)))
+               FP_SET_EXCEPTION(FP_EX_INVALID);
+       if (!FP_INHIBIT_RESULTS) {
+               rd = (void *)(((long)rd)&~3);
+               if (ret == -1) ret = 2;
+               fsr = current->tss.xfsr[0];
+               switch (fccno) {
+               case 0: fsr &= ~0xc00; fsr |= (ret << 10); break;
+               case 1: fsr &= ~0x300000000UL; fsr |= (ret << 32); break;
+               case 2: fsr &= ~0xc00000000UL; fsr |= (ret << 34); break;
+               case 3: fsr &= ~0x3000000000UL; fsr |= (ret << 36); break;
+               }
+               current->tss.xfsr[0] = fsr;
        }
-       *(unsigned long *)rd = fsr;
-       return 0;
+       FP_HANDLE_EXCEPTIONS;
 }
index a19dbdd78885143cc79a02a147deeddaf8ddd654..c6f4e9810ba9eaabdc74f6675dba64d4b5789067 100644 (file)
@@ -1,19 +1,23 @@
+/* $Id: fdivd.c,v 1.4 1999/05/28 13:43:36 jj Exp $
+ * arch/sparc64/math-emu/fdivd.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "double.h"
 
 int FDIVD(void *rd, void *rs2, void *rs1)
 {
+       FP_DECL_EX;
        FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R);
-       int ret = 0;
 
-       __FP_UNPACK_D(A, rs1);
-       __FP_UNPACK_D(B, rs2);
-       if(B_c == FP_CLS_ZERO &&
-          A_c != FP_CLS_ZERO) {
-               ret |= EFLAG_DIVZERO;
-               if(__FPU_TRAP_P(EFLAG_DIVZERO))
-                       return ret;
-       }
+       FP_UNPACK_DP(A, rs1);
+       FP_UNPACK_DP(B, rs2);
        FP_DIV_D(R, A, B);
-       return (ret | __FP_PACK_D(rd, R));
+       FP_PACK_DP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index 9bc0987f56b348404ead5285d6e9994f0a533a78..f154bcdb82d2e0a0890e51cea261c0a3e949df74 100644 (file)
@@ -1,19 +1,23 @@
+/* $Id: fdivq.c,v 1.4 1999/05/28 13:43:41 jj Exp $
+ * arch/sparc64/math-emu/fdivq.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "quad.h"
 
 int FDIVQ(void *rd, void *rs2, void *rs1)
 {
+       FP_DECL_EX;
        FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R);
-       int ret;
 
-       __FP_UNPACK_Q(A, rs1);
-       __FP_UNPACK_Q(B, rs2);
-       if(B_c == FP_CLS_ZERO &&
-          A_c != FP_CLS_ZERO) {
-               ret |= EFLAG_DIVZERO;
-               if(__FPU_TRAP_P(EFLAG_DIVZERO))
-                       return ret;
-       }
+       FP_UNPACK_QP(A, rs1);
+       FP_UNPACK_QP(B, rs2);
        FP_DIV_Q(R, A, B);
-       return (ret | __FP_PACK_Q(rd, R));
+       FP_PACK_QP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index 41095dc4c2e03f19e491428eae209b9b4e54de77..dd317751f39e8eeee5735498e217c9e95a249d60 100644 (file)
@@ -1,20 +1,24 @@
+/* $Id: fdivs.c,v 1.4 1999/05/28 13:43:45 jj Exp $
+ * arch/sparc64/math-emu/fdivs.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "single.h"
 
 int FDIVS(void *rd, void *rs2, void *rs1)
 {
+       FP_DECL_EX;
        FP_DECL_S(A); FP_DECL_S(B); FP_DECL_S(R);
-       int ret = 0;
 
-       __FP_UNPACK_S(A, rs1);
-       __FP_UNPACK_S(B, rs2);
-       if(B_c == FP_CLS_ZERO &&
-          A_c != FP_CLS_ZERO) {
-               ret |= EFLAG_DIVZERO;
-               if(__FPU_TRAP_P(EFLAG_DIVZERO))
-                       return ret;
-       }
+       FP_UNPACK_SP(A, rs1);
+       FP_UNPACK_SP(B, rs2);
        FP_DIV_S(R, A, B);
-       return (ret | __FP_PACK_S(rd, R));
+       FP_PACK_SP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
 
index 4d4b5916a38ff21f247495eaca0a222573138357..d8b99ecc02b4aa503955ac48eaa9320986b10ece 100644 (file)
@@ -1,15 +1,26 @@
+/* $Id: fdmulq.c,v 1.4 1999/05/28 13:43:48 jj Exp $
+ * arch/sparc64/math-emu/fdmulq.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "quad.h"
 #include "double.h"
 
 int FDMULQ(void *rd, void *rs2, void *rs1)
 {
+       FP_DECL_EX;
        FP_DECL_D(IN); FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R);
 
-       __FP_UNPACK_D(IN, rs1);
+       FP_UNPACK_DP(IN, rs1);
        FP_CONV(Q,D,2,1,A,IN);
-       __FP_UNPACK_D(IN, rs2);
+       FP_UNPACK_DP(IN, rs2);
        FP_CONV(Q,D,2,1,B,IN);
        FP_MUL_Q(R, A, B);
-       return __FP_PACK_Q(rd, R);
+       FP_PACK_QP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index 1b12a6395a283ee9a34dfc9f6f074e6054f58641..8c616c07aaa80a9cbcbb0a41cca210b2884bfd99 100644 (file)
@@ -1,13 +1,25 @@
+/* $Id: fdtoi.c,v 1.3 1999/05/28 13:43:52 jj Exp $
+ * arch/sparc64/math-emu/fdtoi.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#define FP_ROUNDMODE FP_RND_ZERO
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "double.h"
 
-int FDTOI(unsigned *rd, void *rs2)
+int FDTOI(int *rd, void *rs2)
 {
+       FP_DECL_EX;
        FP_DECL_D(A);
-       unsigned r;
+       int r;
 
-       __FP_UNPACK_D(A, rs2);
+       FP_UNPACK_DP(A, rs2);
        FP_TO_INT_D(r, A, 32, 1);
-       *rd = r;
-       return 0;
+       if (!FP_INHIBIT_RESULTS)
+               *rd = r;
+       FP_HANDLE_EXCEPTIONS;
 }
index b37b31198e5142d557481885c03d7ee38cd2a3e8..0607525d615918d90923a00f33078a8bd541e412 100644 (file)
@@ -1,12 +1,23 @@
+/* $Id: fdtoq.c,v 1.4 1999/05/28 13:43:56 jj Exp $
+ * arch/sparc64/math-emu/fdtoq.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "quad.h"
 #include "double.h"
 
 int FDTOQ(void *rd, void *rs2)
 {
+       FP_DECL_EX;
        FP_DECL_D(A); FP_DECL_Q(R);
 
-       __FP_UNPACK_D(A, rs2);
+       FP_UNPACK_DP(A, rs2);
        FP_CONV(Q,D,2,1,R,A);
-       return __FP_PACK_Q(rd, R);
+       FP_PACK_QP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index ae9f382ed6928ebc55e8f3403796410061a8e678..1a86a96c720e229b98c8a0f228ebd06c2179da68 100644 (file)
@@ -1,12 +1,23 @@
+/* $Id: fdtos.c,v 1.4 1999/05/28 13:43:58 jj Exp $
+ * arch/sparc64/math-emu/fdtos.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "double.h"
 #include "single.h"
 
 int FDTOS(void *rd, void *rs2)
 {
+       FP_DECL_EX;
        FP_DECL_D(A); FP_DECL_S(R);
 
-       __FP_UNPACK_D(A, rs2);
+       FP_UNPACK_DP(A, rs2);
        FP_CONV(S,D,1,1,R,A);
-       return __FP_PACK_S(rd, R);
+       FP_PACK_SP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index 062651a478eeae4878ef40af308ec1888ab8b507..465d9962b94ce3fbb37a7558b04a38565eda60b1 100644 (file)
@@ -1,13 +1,25 @@
+/* $Id: fdtox.c,v 1.3 1999/05/28 13:44:02 jj Exp $
+ * arch/sparc64/math-emu/fdtox.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#define FP_ROUNDMODE FP_RND_ZERO
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "double.h"
 
-int FDTOX(unsigned long *rd, void *rs2)
+int FDTOX(long *rd, void *rs2)
 {
+       FP_DECL_EX;
        FP_DECL_D(A);
-       unsigned long r;
+       long r;
 
-       __FP_UNPACK_D(A, rs2);
+       FP_UNPACK_DP(A, rs2);
        FP_TO_INT_D(r, A, 64, 1);
-       *rd = r;
-       return 0;
+       if (!FP_INHIBIT_RESULTS)
+               *rd = r;
+       FP_HANDLE_EXCEPTIONS;
 }
index 68ba2839b303ed8b213542d68ad182add29c826a..3a9af3073c28e93ddd817bf26a22af45d532063b 100644 (file)
@@ -1,11 +1,22 @@
+/* $Id: fitoq.c,v 1.5 1999/05/28 13:44:06 jj Exp $
+ * arch/sparc64/math-emu/fitoq.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "quad.h"
 
 int FITOQ(void *rd, void *rs2)
 {
+       FP_DECL_EX;
        FP_DECL_Q(R);
        int a = *(int *)rs2;
 
        FP_FROM_INT_Q(R, a, 32, int);
-       return __FP_PACK_Q(rd, R);
+       FP_PACK_QP(rd, R);
+       return 0;
 }
index 9294a339e0611169c610c4382575fa223efb8dc3..ee5a7e4f50e34a3603538704578a3f15d9b4a23c 100644 (file)
@@ -1,3 +1,10 @@
+/* $Id: fmovq.c,v 1.2 1999/05/28 13:44:09 jj Exp $
+ * arch/sparc64/math-emu/fmovq.c
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@ultra.linux.cz)
+ *
+ */
+
 int FMOVQ(unsigned long *rd, unsigned long *rs2)
 {
        rd[0] = rs2[0];
index 707bb45c179e5464b531ee4ef4988251e202e3ad..2dde7c2714d507cc92c7e9ce640fe7a693d05a45 100644 (file)
@@ -1,12 +1,23 @@
+/* $Id: fmuld.c,v 1.4 1999/05/28 13:44:11 jj Exp $
+ * arch/sparc64/math-emu/fmuld.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "double.h"
 
 int FMULD(void *rd, void *rs2, void *rs1)
 {
+       FP_DECL_EX;
        FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R);
 
-       __FP_UNPACK_D(A, rs1);
-       __FP_UNPACK_D(B, rs2);
+       FP_UNPACK_DP(A, rs1);
+       FP_UNPACK_DP(B, rs2);
        FP_MUL_D(R, A, B);
-       return __FP_PACK_D(rd, R);
+       FP_PACK_DP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index 94400d023cbb9fa55c93c94e60d3c9b8025cbaac..227d1f928a6dea67a55878152ea721e8c8185dc4 100644 (file)
@@ -1,12 +1,23 @@
+/* $Id: fmulq.c,v 1.4 1999/05/28 13:44:14 jj Exp $
+ * arch/sparc64/math-emu/fmulq.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "quad.h"
 
 int FMULQ(void *rd, void *rs2, void *rs1)
 {
+       FP_DECL_EX;
        FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R);
 
-       __FP_UNPACK_Q(A, rs1);
-       __FP_UNPACK_Q(B, rs2);
+       FP_UNPACK_QP(A, rs1);
+       FP_UNPACK_QP(B, rs2);
        FP_MUL_Q(R, A, B);
-       return __FP_PACK_Q(rd, R);
+       FP_PACK_QP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index b16509964cf336edff374199f2924160e6e65ff4..623c4aa4c29db191f0523944be1a0e3497f36991 100644 (file)
@@ -1,12 +1,23 @@
+/* $Id: fmuls.c,v 1.4 1999/05/28 13:44:18 jj Exp $
+ * arch/sparc64/math-emu/fmuls.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "single.h"
 
 int FMULS(void *rd, void *rs2, void *rs1)
 {
+       FP_DECL_EX;
        FP_DECL_S(A); FP_DECL_S(B); FP_DECL_S(R);
 
-       __FP_UNPACK_S(A, rs1);
-       __FP_UNPACK_S(B, rs2);
+       FP_UNPACK_SP(A, rs1);
+       FP_UNPACK_SP(B, rs2);
        FP_MUL_S(R, A, B);
-       return __FP_PACK_S(rd, R);
+       FP_PACK_SP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index 745020ee3f3dd3095ab5259791f3ec70d09a2669..4e4a6879575afc5bd21ab0789817c05f204a4be4 100644 (file)
@@ -1,7 +1,13 @@
+/* $Id: fnegq.c,v 1.6 1999/05/28 13:44:21 jj Exp $
+ * arch/sparc64/math-emu/fnegq.c
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@ultra.linux.cz)
+ *
+ */
+
 int FNEGQ(unsigned long *rd, unsigned long *rs2)
 {
        rd[0] = rs2[0] ^ 0x8000000000000000UL;
        rd[1] = rs2[1];
        return 0;
 }
-
index 29e41cf6abe5ebb38b922435c965c038c62b25ef..55b6d44432f23a2a8b7af59f9d2368c68894dddc 100644 (file)
@@ -1,12 +1,23 @@
+/* $Id: fqtod.c,v 1.4 1999/05/28 13:44:24 jj Exp $
+ * arch/sparc64/math-emu/fqtod.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "quad.h"
 #include "double.h"
 
 int FQTOD(void *rd, void *rs2)
 {
+       FP_DECL_EX;
        FP_DECL_Q(A); FP_DECL_D(R);
 
-       __FP_UNPACK_Q(A, rs2);
+       FP_UNPACK_QP(A, rs2);
        FP_CONV(D,Q,1,2,R,A);
-       return __FP_PACK_D(rd, R);
+       FP_PACK_DP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index 1bb213f19bbc9ac2ef6269d398f9fc1e05d01513..a1b8ea74192eebbc575ddd2dee29f70c66f391c4 100644 (file)
@@ -1,13 +1,25 @@
+/* $Id: fqtoi.c,v 1.4 1999/05/28 13:44:26 jj Exp $
+ * arch/sparc64/math-emu/fqtoi.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#define FP_ROUNDMODE FP_RND_ZERO
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "quad.h"
 
-int FQTOI(unsigned *rd, void *rs2)
+int FQTOI(int *rd, void *rs2)
 {
+       FP_DECL_EX;
        FP_DECL_Q(A);
-       unsigned r;
+       int r;
 
-       __FP_UNPACK_Q(A, rs2);
+       FP_UNPACK_QP(A, rs2);
        FP_TO_INT_Q(r, A, 32, 1);
-       *rd = r;
-       return 0;
+       if (!FP_INHIBIT_RESULTS)
+               *rd = r;
+       FP_HANDLE_EXCEPTIONS;
 }
index 382912d1164e2492cab0a87093d7d17b77ce6462..6edb6aaca9851b4f1aabf23d6a0af650f6e69026 100644 (file)
@@ -1,12 +1,23 @@
+/* $Id: fqtos.c,v 1.4 1999/05/28 13:44:30 jj Exp $
+ * arch/sparc64/math-emu/fqtos.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "quad.h"
 #include "single.h"
 
 int FQTOS(void *rd, void *rs2)
 {
+       FP_DECL_EX;
        FP_DECL_Q(A); FP_DECL_S(R);
 
-       __FP_UNPACK_Q(A, rs2);
+       FP_UNPACK_QP(A, rs2);
        FP_CONV(S,Q,1,2,R,A);
-       return __FP_PACK_S(rd, R);
+       FP_PACK_SP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index 484ca6900b15fdb42233a5c7a9ab0043faaa538d..458061fb0be90b8bfbc682432a955d7df828ea0a 100644 (file)
@@ -1,13 +1,25 @@
+/* $Id: fqtox.c,v 1.4 1999/05/28 13:44:34 jj Exp $
+ * arch/sparc64/math-emu/fqtox.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#define FP_ROUNDMODE FP_RND_ZERO
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "quad.h"
 
-int FQTOX(unsigned long *rd, void *rs2)
+int FQTOX(long *rd, void *rs2)
 {
+       FP_DECL_EX;
        FP_DECL_Q(A);
-       unsigned long r;
+       long r;
 
-       __FP_UNPACK_Q(A, rs2);
+       FP_UNPACK_QP(A, rs2);
        FP_TO_INT_Q(r, A, 64, 1);
-       *rd = r;
-       return 0;
+       if (!FP_INHIBIT_RESULTS)
+               *rd = r;
+       FP_HANDLE_EXCEPTIONS;
 }
index b6bf61b0f3b40b9bcaac30a7223a1d3db9acb276..92b86288fe5a20aea7c16448f9a9e116b59e0db3 100644 (file)
@@ -1,15 +1,26 @@
+/* $Id: fsmuld.c,v 1.4 1999/05/28 13:44:37 jj Exp $
+ * arch/sparc64/math-emu/fsmuld.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "double.h"
 #include "single.h"
 
 int FSMULD(void *rd, void *rs2, void *rs1)
 {
+       FP_DECL_EX;
        FP_DECL_S(IN); FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R);
 
-       __FP_UNPACK_S(IN, rs1);
+       FP_UNPACK_SP(IN, rs1);
        FP_CONV(D,S,1,1,A,IN);
-       __FP_UNPACK_S(IN, rs2);
+       FP_UNPACK_SP(IN, rs2);
        FP_CONV(D,S,1,1,B,IN);
        FP_MUL_D(R, A, B);
-       return __FP_PACK_D(rd, R);
+       FP_PACK_DP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index b022f7d371d226744264690918db84c82086fce6..5d02ed5c0e7834d8d65026fba89a3e9a28011faf 100644 (file)
@@ -1,11 +1,22 @@
+/* $Id: fsqrtd.c,v 1.4 1999/05/28 13:44:39 jj Exp $
+ * arch/sparc64/math-emu/fsqrtd.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "double.h"
 
 int FSQRTD(void *rd, void *rs2)
 {
+       FP_DECL_EX;
        FP_DECL_D(A); FP_DECL_D(R);
         
-       __FP_UNPACK_D(A, rs2);
+       FP_UNPACK_DP(A, rs2);
        FP_SQRT_D(R, A);
-       return __FP_PACK_D(rd, R);
+       FP_PACK_DP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index 7e620079fa74c5d954bdd1ed07caaee20890c790..bb2e6c51ebef636454f59f8f8d642188513289f5 100644 (file)
@@ -1,11 +1,22 @@
+/* $Id: fsqrtq.c,v 1.5 1999/05/28 13:44:44 jj Exp $
+ * arch/sparc64/math-emu/fsqrtq.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "quad.h"
 
 int FSQRTQ(void *rd, void *rs2)
 {
+       FP_DECL_EX;
        FP_DECL_Q(A); FP_DECL_Q(R);
         
-       __FP_UNPACK_Q(A, rs2);
+       FP_UNPACK_QP(A, rs2);
        FP_SQRT_Q(R, A);
-       return __FP_PACK_Q(rd, R);
+       FP_PACK_QP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index 62ff0b7824350359984d19d0a410b8c92b0c484f..ee32737edcf11bb6e4b7bc4f161e95f80fbf8a00 100644 (file)
@@ -1,11 +1,22 @@
+/* $Id: fsqrts.c,v 1.4 1999/05/28 13:44:48 jj Exp $
+ * arch/sparc64/math-emu/fsqrts.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "single.h"
 
 int FSQRTS(void *rd, void *rs2)
 {
+       FP_DECL_EX;
        FP_DECL_S(A); FP_DECL_S(R);
         
-       __FP_UNPACK_S(A, rs2);
+       FP_UNPACK_SP(A, rs2);
        FP_SQRT_S(R, A);
-       return __FP_PACK_S(rd, R);
+       FP_PACK_SP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index 91935f78eb3469d72346d45104ca1252348062ff..3c7a974cab2f163f94ababb1558704f74ebec7a8 100644 (file)
@@ -1,12 +1,23 @@
+/* $Id: fstod.c,v 1.4 1999/05/28 13:44:51 jj Exp $
+ * arch/sparc64/math-emu/fstod.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "double.h"
 #include "single.h"
 
 int FSTOD(void *rd, void *rs2)
 {
+       FP_DECL_EX;
        FP_DECL_S(A); FP_DECL_D(R);
 
-       __FP_UNPACK_S(A, rs2);
+       FP_UNPACK_SP(A, rs2);
        FP_CONV(D,S,1,1,R,A);
-       return __FP_PACK_D(rd, R);
+       FP_PACK_DP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index 5ff3854cc3d949edd2833a93e499477e8070275c..40ef2badd1fae71cc96b000e1764112843c0c695 100644 (file)
@@ -1,13 +1,25 @@
+/* $Id: fstoi.c,v 1.3 1999/05/28 13:44:54 jj Exp $
+ * arch/sparc64/math-emu/fstoi.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#define FP_ROUNDMODE FP_RND_ZERO
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "single.h"
 
-int FSTOI(unsigned *rd, void *rs2)
+int FSTOI(int *rd, void *rs2)
 {
+       FP_DECL_EX;
        FP_DECL_S(A);
-       unsigned r;
+       int r;
 
-       __FP_UNPACK_S(A, rs2);
+       FP_UNPACK_SP(A, rs2);
        FP_TO_INT_S(r, A, 32, 1);
-       *rd = r;
-       return 0;
+       if (!FP_INHIBIT_RESULTS)
+               *rd = r;
+       FP_HANDLE_EXCEPTIONS;
 }
index 1a56e0055bb15030e28abbabb66eee03b13cb360..d23e187c6c07a35bafd866278d2c8b3d3e08cfc5 100644 (file)
@@ -1,12 +1,23 @@
+/* $Id: fstoq.c,v 1.4 1999/05/28 13:44:58 jj Exp $
+ * arch/sparc64/math-emu/fstoq.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "quad.h"
 #include "single.h"
 
 int FSTOQ(void *rd, void *rs2)
 {
+       FP_DECL_EX;
        FP_DECL_S(A); FP_DECL_Q(R);
 
-       __FP_UNPACK_S(A, rs2);
+       FP_UNPACK_SP(A, rs2);
        FP_CONV(Q,S,2,1,R,A);
-       return __FP_PACK_Q(rd, R);
+       FP_PACK_QP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index fa2135f8b2a4e2c5969c0d27e2ed2bf861c2059b..fecca41d375a17d1ad0de544c241539fe9083226 100644 (file)
@@ -1,13 +1,25 @@
+/* $Id: fstox.c,v 1.3 1999/05/28 13:45:01 jj Exp $
+ * arch/sparc64/math-emu/fstox.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#define FP_ROUNDMODE FP_RND_ZERO
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "single.h"
 
-int FSTOX(unsigned long *rd, void *rs2)
+int FSTOX(long *rd, void *rs2)
 {
+       FP_DECL_EX;
        FP_DECL_S(A);
-       unsigned long r;
+       long r;
 
-       __FP_UNPACK_S(A, rs2);
+       FP_UNPACK_SP(A, rs2);
        FP_TO_INT_S(r, A, 64, 1);
-       *rd = r;
-       return 0;
+       if (!FP_INHIBIT_RESULTS)
+               *rd = r;
+       FP_HANDLE_EXCEPTIONS;
 }
index bbd11c611e28a596a00b32ba0529722b7716dfdf..66a7c5664cb0023d17f5fa6c08a54a225082dc89 100644 (file)
@@ -1,14 +1,25 @@
+/* $Id: fsubd.c,v 1.4 1999/05/28 13:45:04 jj Exp $
+ * arch/sparc64/math-emu/fsubd.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "double.h"
 
 int FSUBD(void *rd, void *rs2, void *rs1)
 {
+       FP_DECL_EX;
        FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R);
 
-       __FP_UNPACK_D(A, rs1);
-       __FP_UNPACK_D(B, rs2);
+       FP_UNPACK_DP(A, rs1);
+       FP_UNPACK_DP(B, rs2);
        if (B_c != FP_CLS_NAN)
                B_s ^= 1;
        FP_ADD_D(R, A, B);
-       return __FP_PACK_D(rd, R);
+       FP_PACK_DP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index d5cc260cfd777035c2997b8982e7d679851f52fb..96b2e08ddd3b2d2e05677295d46d2e3de2701525 100644 (file)
@@ -1,14 +1,25 @@
+/* $Id: fsubq.c,v 1.4 1999/05/28 13:45:09 jj Exp $
+ * arch/sparc64/math-emu/fsubq.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "quad.h"
 
 int FSUBQ(void *rd, void *rs2, void *rs1)
 {
+       FP_DECL_EX;
        FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R);
 
-       __FP_UNPACK_Q(A, rs1);
-       __FP_UNPACK_Q(B, rs2);
+       FP_UNPACK_QP(A, rs1);
+       FP_UNPACK_QP(B, rs2);
        if (B_c != FP_CLS_NAN)
                B_s ^= 1;
        FP_ADD_Q(R, A, B);
-       return __FP_PACK_Q(rd, R);
+       FP_PACK_QP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index ff8fa12b1bcda26a1f201e954c318bd1872f90fe..3eef72572b59a2f9a026ba157288df6836087007 100644 (file)
@@ -1,14 +1,25 @@
+/* $Id: fsubs.c,v 1.4 1999/05/28 13:45:12 jj Exp $
+ * arch/sparc64/math-emu/fsubs.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "single.h"
 
 int FSUBS(void *rd, void *rs2, void *rs1)
 {
+       FP_DECL_EX;
        FP_DECL_S(A); FP_DECL_S(B); FP_DECL_S(R);
 
-       __FP_UNPACK_S(A, rs1);
-       __FP_UNPACK_S(B, rs2);
+       FP_UNPACK_SP(A, rs1);
+       FP_UNPACK_SP(B, rs2);
        if (B_c != FP_CLS_NAN)
                B_s ^= 1;
        FP_ADD_S(R, A, B);
-       return __FP_PACK_S(rd, R);
+       FP_PACK_SP(rd, R);
+       FP_HANDLE_EXCEPTIONS;
 }
index 411e515715c638b6cefc927baeaba0af58d4829d..205567cd9b5a8b12e0deb0250fc801461aec652b 100644 (file)
@@ -1,11 +1,22 @@
+/* $Id: fxtoq.c,v 1.5 1999/05/28 13:45:15 jj Exp $
+ * arch/sparc64/math-emu/fxtoq.c
+ *
+ * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include "sfp-util.h"
 #include "soft-fp.h"
 #include "quad.h"
 
 int FXTOQ(void *rd, void *rs2)
 {
+       FP_DECL_EX;
        FP_DECL_Q(R);
        long a = *(long *)rs2;
 
        FP_FROM_INT_Q(R, a, 64, long);
-       return __FP_PACK_Q(rd, R);
+       FP_PACK_QP(rd, R);
+       return 0;
 }
index f4493e224facffa617f0b49d03378d07a1f11f70..9f2a21f9f0842ade6129d80b9689ffcd8d8cc96d 100644 (file)
@@ -1,7 +1,7 @@
-/* $Id: math.c,v 1.7 1999/02/10 14:16:26 davem Exp $
+/* $Id: math.c,v 1.8 1999/05/28 13:43:11 jj Exp $
  * arch/sparc64/math-emu/math.c
  *
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997,1999 Jakub Jelinek (jj@ultra.linux.cz)
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
  *
  * Emulation routines originate from soft-fp package, which is part
@@ -15,6 +15,7 @@
 #include <asm/ptrace.h>
 #include <asm/uaccess.h>
 
+#include "sfp-util.h"
 #include "soft-fp.h"
 
 #define FLOATFUNC(x) extern int x(void *,void *,void *);
@@ -84,46 +85,36 @@ static int record_exception(struct pt_regs *regs, int eflag)
        if(would_trap != 0) {
                eflag &= ((fsr & FSR_TEM_MASK) >> FSR_TEM_SHIFT);
                if((eflag & (eflag - 1)) != 0) {
-                       if(eflag & EFLAG_INVALID)
-                               eflag = EFLAG_INVALID;
-                       else if(eflag & EFLAG_DIVZERO)
-                               eflag = EFLAG_DIVZERO;
-                       else if(eflag & EFLAG_INEXACT)
-                               eflag = EFLAG_INEXACT;
+                       if(eflag & FP_EX_INVALID)
+                               eflag = FP_EX_INVALID;
+                       else if(eflag & FP_EX_OVERFLOW)
+                               eflag = FP_EX_OVERFLOW;
+                       else if(eflag & FP_EX_UNDERFLOW)
+                               eflag = FP_EX_UNDERFLOW;
+                       else if(eflag & FP_EX_DIVZERO)
+                               eflag = FP_EX_DIVZERO;
+                       else if(eflag & FP_EX_INEXACT)
+                               eflag = FP_EX_INEXACT;
                }
        }
 
-       /* Set CEXC, here are the rules:
+       /* Set CEXC, here is the rule:
         *
-        * 1) In general all FPU ops will set one and only one
+        *    In general all FPU ops will set one and only one
         *    bit in the CEXC field, this is always the case
         *    when the IEEE exception trap is enabled in TEM.
-        *
-        * 2) As a special case, if an overflow or underflow
-        *    is being signalled, AND the trap is not enabled
-        *    in TEM, then the inexact field shall also be set.
         */
        fsr &= ~(FSR_CEXC_MASK);
-       if(would_trap ||
-          (eflag & (EFLAG_OVERFLOW | EFLAG_UNDERFLOW)) == 0) {
-               fsr |= ((long)eflag << FSR_CEXC_SHIFT);
-       } else {
-               fsr |= (((long)eflag << FSR_CEXC_SHIFT) |
-                       (EFLAG_INEXACT << FSR_CEXC_SHIFT));
-       }
+       fsr |= ((long)eflag << FSR_CEXC_SHIFT);
 
-       /* Set the AEXC field, rules are:
+       /* Set the AEXC field, rule is:
         *
-        * 1) If a trap would not be generated, the
+        *    If a trap would not be generated, the
         *    CEXC just generated is OR'd into the
         *    existing value of AEXC.
-        *
-        * 2) When a trap is generated, AEXC is cleared.
         */
        if(would_trap == 0)
                fsr |= ((long)eflag << FSR_AEXC_SHIFT);
-       else
-               fsr &= ~(FSR_AEXC_MASK);
 
        /* If trapping, indicate fault trap type IEEE. */
        if(would_trap != 0)
@@ -242,7 +233,7 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f)
                }
                freg = ((insn >> 25) & 0x1f);
                switch ((type >> 4) & 0x3) {
-               case 0: rd = (void *)(((long)&current->tss.xfsr[0]) | (freg & 3)); break;
+               case 0: rd = (void *)(long)(freg & 3); break;
                case 3: if (freg & 2) {
                                current->tss.xfsr[0] |= (6 << 14) /* invalid_fp_register */;
                                goto err;
index 87960c28753246df9a2458cbac46fb3717f835fe..fe83d376a7caec75faa99ac6b2258eb57d8789d3 100644 (file)
@@ -1,6 +1,26 @@
-/*
- * Basic one-word fraction declaration and manipulation.
- */
+/* Software floating-point emulation.
+   Basic one-word fraction declaration and manipulation.
+   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+                 Jakub Jelinek (jj@ultra.linux.cz),
+                 David S. Miller (davem@redhat.com) and
+                 Peter Maydell (pmaydell@chiark.greenend.org.uk).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #define _FP_FRAC_DECL_1(X)     _FP_W_TYPE X##_f
 #define _FP_FRAC_COPY_1(D,S)   (D##_f = S##_f)
@@ -28,6 +48,7 @@
 
 #define _FP_FRAC_ADD_1(R,X,Y)  (R##_f = X##_f + Y##_f)
 #define _FP_FRAC_SUB_1(R,X,Y)  (R##_f = X##_f - Y##_f)
+#define _FP_FRAC_DEC_1(X,Y)    (X##_f -= Y##_f)
 #define _FP_FRAC_CLZ_1(z, X)   __FP_CLZ(z, X##_f)
 
 /* Predicates */
@@ -40,6 +61,7 @@
 
 #define _FP_ZEROFRAC_1         0
 #define _FP_MINFRAC_1          1
+#define _FP_MAXFRAC_1          (~(_FP_WS_TYPE)0)
 
 /*
  * Unpack the raw bits of a native fp value.  Do not classify or
     X##_s = _flo.bits.sign;                                    \
   } while (0)
 
+#define _FP_UNPACK_RAW_1_P(fs, X, val)                         \
+  do {                                                         \
+    union _FP_UNION_##fs *_flo =                               \
+      (union _FP_UNION_##fs *)(val);                           \
+                                                               \
+    X##_f = _flo->bits.frac;                                   \
+    X##_e = _flo->bits.exp;                                    \
+    X##_s = _flo->bits.sign;                                   \
+  } while (0)
 
 /*
  * Repack the raw bits of a native fp value.
     (val) = _flo.flt;                                          \
   } while (0)
 
+#define _FP_PACK_RAW_1_P(fs, val, X)                           \
+  do {                                                         \
+    union _FP_UNION_##fs *_flo =                               \
+      (union _FP_UNION_##fs *)(val);                           \
+                                                               \
+    _flo->bits.frac = X##_f;                                   \
+    _flo->bits.exp  = X##_e;                                   \
+    _flo->bits.sign = X##_s;                                   \
+  } while (0)
+
 
 /*
  * Multiplication algorithms:
  
 #define _FP_SQRT_MEAT_1(R, S, T, X, q)                 \
   do {                                                 \
-    while (q)                                          \
+    while (q != _FP_WORK_ROUND)                                \
       {                                                        \
         T##_f = S##_f + q;                             \
         if (T##_f <= X##_f)                            \
         _FP_FRAC_SLL_1(X, 1);                          \
         q >>= 1;                                       \
       }                                                        \
+    if (X##_f)                                         \
+      {                                                        \
+       if (S##_f < X##_f)                              \
+         R##_f |= _FP_WORK_ROUND;                      \
+       R##_f |= _FP_WORK_STICKY;                       \
+      }                                                        \
   } while (0)
 
 /*
   do {                                                                 \
     D##_f = S##_f;                                                     \
     if (_FP_WFRACBITS_##sfs > _FP_WFRACBITS_##dfs)                     \
-      _FP_FRAC_SRS_1(D, (_FP_WFRACBITS_##sfs-_FP_WFRACBITS_##dfs),     \
-                    _FP_WFRACBITS_##sfs);                              \
+      {                                                                        \
+       if (S##_c != FP_CLS_NAN)                                        \
+         _FP_FRAC_SRS_1(D, (_FP_WFRACBITS_##sfs-_FP_WFRACBITS_##dfs),  \
+                        _FP_WFRACBITS_##sfs);                          \
+       else                                                            \
+         _FP_FRAC_SRL_1(D, (_FP_WFRACBITS_##sfs-_FP_WFRACBITS_##dfs)); \
+      }                                                                        \
     else                                                               \
       D##_f <<= _FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs;             \
   } while (0)
index 8ac63188ca2416769cbfedbc9eafb37039f8aa58..9735244a545746a81a7686211b3cd1f9b0e9e99d 100644 (file)
@@ -1,6 +1,26 @@
-/*
- * Basic two-word fraction declaration and manipulation.
- */
+/* Software floating-point emulation.
+   Basic two-word fraction declaration and manipulation.
+   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+                 Jakub Jelinek (jj@ultra.linux.cz),
+                 David S. Miller (davem@redhat.com) and
+                 Peter Maydell (pmaydell@chiark.greenend.org.uk).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #define _FP_FRAC_DECL_2(X)     _FP_W_TYPE X##_f0, X##_f1
 #define _FP_FRAC_COPY_2(D,S)   (D##_f0 = S##_f0, D##_f1 = S##_f1)
   do {                                                                 \
     if ((N) < _FP_W_TYPE_SIZE)                                         \
       {                                                                        \
-        if (__builtin_constant_p(N) && (N) == 1)                       \
-          {                                                            \
-            X##_f1 = X##_f1 + X##_f1 + (((_FP_WS_TYPE)(X##_f0)) < 0);  \
-            X##_f0 += X##_f0;                                          \
-          }                                                            \
-        else                                                           \
-          {                                                            \
+       if (__builtin_constant_p(N) && (N) == 1)                        \
+                                                                     \
+           X##_f1 = X##_f1 + X##_f1 + (((_FP_WS_TYPE)(X##_f0)) < 0);   \
+           X##_f0 += X##_f0;                                           \
+                                                                     \
+       else                                                            \
+                                                                     \
            X##_f1 = X##_f1 << (N) | X##_f0 >> (_FP_W_TYPE_SIZE - (N)); \
            X##_f0 <<= (N);                                             \
          }                                                             \
     else                                                               \
       {                                                                        \
        X##_f0 = (X##_f1 >> ((N) - _FP_W_TYPE_SIZE) |                   \
-                 (((X##_f1 << (sz - (N))) | X##_f0) != 0));            \
+                 (((X##_f1 << (sz - (N))) | X##_f0) != 0));            \
        X##_f1 = 0;                                                     \
       }                                                                        \
   } while (0)
 
-#define _FP_FRAC_ADDI_2(X,I) \
+#define _FP_FRAC_ADDI_2(X,I)   \
   __FP_FRAC_ADDI_2(X##_f1, X##_f0, I)
 
-#define _FP_FRAC_ADD_2(R,X,Y) \
+#define _FP_FRAC_ADD_2(R,X,Y)  \
   __FP_FRAC_ADD_2(R##_f1, R##_f0, X##_f1, X##_f0, Y##_f1, Y##_f0)
 
-#define _FP_FRAC_SUB_2(R,X,Y) \
+#define _FP_FRAC_SUB_2(R,X,Y)  \
   __FP_FRAC_SUB_2(R##_f1, R##_f0, X##_f1, X##_f0, Y##_f1, Y##_f0)
 
+#define _FP_FRAC_DEC_2(X,Y)    \
+  __FP_FRAC_DEC_2(X##_f1, X##_f0, Y##_f1, Y##_f0)
+
 #define _FP_FRAC_CLZ_2(R,X)    \
   do {                         \
     if (X##_f1)                        \
 /* Predicates */
 #define _FP_FRAC_NEGP_2(X)     ((_FP_WS_TYPE)X##_f1 < 0)
 #define _FP_FRAC_ZEROP_2(X)    ((X##_f1 | X##_f0) == 0)
-#define _FP_FRAC_OVERP_2(fs,X) (X##_f1 & _FP_OVERFLOW_##fs)
+#define _FP_FRAC_OVERP_2(fs,X) (_FP_FRAC_HIGH_##fs(X) & _FP_OVERFLOW_##fs)
 #define _FP_FRAC_EQ_2(X, Y)    (X##_f1 == Y##_f1 && X##_f0 == Y##_f0)
 #define _FP_FRAC_GT_2(X, Y)    \
   (X##_f1 > Y##_f1 || X##_f1 == Y##_f1 && X##_f0 > Y##_f0)
 
 #define _FP_ZEROFRAC_2         0, 0
 #define _FP_MINFRAC_2          0, 1
+#define _FP_MAXFRAC_2          (~(_FP_WS_TYPE)0), (~(_FP_WS_TYPE)0)
 
 /*
  * Internals 
 #define __FP_CLZ_2(R, xh, xl)  \
   do {                         \
     if (xh)                    \
-      __FP_CLZ(R,xl);          \
+      __FP_CLZ(R,xh);          \
     else                       \
     {                          \
       __FP_CLZ(R,xl);          \
 #if 0
 
 #ifndef __FP_FRAC_ADDI_2
-#define __FP_FRAC_ADDI_2(xh, xl, i) \
+#define __FP_FRAC_ADDI_2(xh, xl, i)    \
   (xh += ((xl += i) < i))
 #endif
 #ifndef __FP_FRAC_ADD_2
-#define __FP_FRAC_ADD_2(rh, rl, xh, xl, yh, yl) \
+#define __FP_FRAC_ADD_2(rh, rl, xh, xl, yh, yl)        \
   (rh = xh + yh + ((rl = xl + yl) < xl))
 #endif
 #ifndef __FP_FRAC_SUB_2
-#define __FP_FRAC_SUB_2(rh, rl, xh, xl, yh, yl) \
+#define __FP_FRAC_SUB_2(rh, rl, xh, xl, yh, yl)        \
   (rh = xh - yh - ((rl = xl - yl) > xl))
 #endif
+#ifndef __FP_FRAC_DEC_2
+#define __FP_FRAC_DEC_2(xh, xl, yh, yl)        \
+  do {                                 \
+    UWtype _t = xl;                    \
+    xh -= yh + ((xl -= yl) > _t);      \
+  } while (0)
+#endif
 
 #else
 
 #define __FP_FRAC_ADD_2                        add_ssaaaa
 #undef __FP_FRAC_SUB_2
 #define __FP_FRAC_SUB_2                        sub_ddmmss
+#undef __FP_FRAC_DEC_2
+#define __FP_FRAC_DEC_2(xh, xl, yh, yl)        sub_ddmmss(xh, xl, xh, xl, yh, yl)
 
 #endif
 
     X##_s  = _flo.bits.sign;                           \
   } while (0)
 
+#define _FP_UNPACK_RAW_2_P(fs, X, val)                 \
+  do {                                                 \
+    union _FP_UNION_##fs *_flo =                       \
+      (union _FP_UNION_##fs *)(val);                   \
+                                                       \
+    X##_f0 = _flo->bits.frac0;                         \
+    X##_f1 = _flo->bits.frac1;                         \
+    X##_e  = _flo->bits.exp;                           \
+    X##_s  = _flo->bits.sign;                          \
+  } while (0)
+
 
 /*
  * Repack the raw bits of a native fp value.
     (val) = _flo.flt;                                  \
   } while (0)
 
+#define _FP_PACK_RAW_2_P(fs, val, X)                   \
+  do {                                                 \
+    union _FP_UNION_##fs *_flo =                       \
+      (union _FP_UNION_##fs *)(val);                   \
+                                                       \
+    _flo->bits.frac0 = X##_f0;                         \
+    _flo->bits.frac1 = X##_f1;                         \
+    _flo->bits.exp   = X##_e;                          \
+    _flo->bits.sign  = X##_s;                          \
+  } while (0)
+
 
 /*
  * Multiplication algorithms:
   do {                                                                 \
     _FP_FRAC_DECL_4(_z); _FP_FRAC_DECL_2(_b); _FP_FRAC_DECL_2(_c);     \
                                                                        \
-    doit(_FP_FRAC_WORD_4(_z,1), _FP_FRAC_WORD_4(_z,0), X##_f0, Y##_f0); \
+    doit(_FP_FRAC_WORD_4(_z,1), _FP_FRAC_WORD_4(_z,0), X##_f0, Y##_f0);        \
     doit(_b_f1, _b_f0, X##_f0, Y##_f1);                                        \
     doit(_c_f1, _c_f0, X##_f1, Y##_f0);                                        \
-    doit(_FP_FRAC_WORD_4(_z,3), _FP_FRAC_WORD_4(_z,2), X##_f1, Y##_f1); \
+    doit(_FP_FRAC_WORD_4(_z,3), _FP_FRAC_WORD_4(_z,2), X##_f1, Y##_f1);        \
                                                                        \
-    __FP_FRAC_ADD_4(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),       \
-                   _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0),        \
-                   0, _b_f1, _b_f0, 0,                                 \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),       \
+                   _FP_FRAC_WORD_4(_z,1), 0, _b_f1, _b_f0,             \
                    _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),        \
-                   _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0));       \
-    __FP_FRAC_ADD_4(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),       \
-                   _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0),        \
-                   0, _c_f1, _c_f0, 0,                                 \
+                   _FP_FRAC_WORD_4(_z,1));                             \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),       \
+                   _FP_FRAC_WORD_4(_z,1), 0, _c_f1, _c_f0,             \
                    _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),        \
-                   _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0));       \
+                   _FP_FRAC_WORD_4(_z,1));                             \
+                                                                       \
+    /* Normalize since we know where the msb of the multiplicands      \
+       were (bit B), we know that the msb of the of the product is     \
+       at either 2B or 2B-1.  */                                       \
+    _FP_FRAC_SRS_4(_z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs);    \
+    R##_f0 = _FP_FRAC_WORD_4(_z,0);                                    \
+    R##_f1 = _FP_FRAC_WORD_4(_z,1);                                    \
+  } while (0)
+
+/* Given a 1W * 1W => 2W primitive, do the extended multiplication.
+   Do only 3 multiplications instead of four. This one is for machines
+   where multiplication is much more expensive than subtraction.  */
+
+#define _FP_MUL_MEAT_2_wide_3mul(fs, R, X, Y, doit)                    \
+  do {                                                                 \
+    _FP_FRAC_DECL_4(_z); _FP_FRAC_DECL_2(_b); _FP_FRAC_DECL_2(_c);     \
+    _FP_W_TYPE _d;                                                     \
+    int _c1, _c2;                                                      \
+                                                                       \
+    _b_f0 = X##_f0 + X##_f1;                                           \
+    _c1 = _b_f0 < X##_f0;                                              \
+    _b_f1 = Y##_f0 + Y##_f1;                                           \
+    _c2 = _b_f1 < Y##_f0;                                              \
+    doit(_d, _FP_FRAC_WORD_4(_z,0), X##_f0, Y##_f0);                   \
+    doit(_FP_FRAC_WORD_4(_z,2), _FP_FRAC_WORD_4(_z,1), _b_f0, _b_f1);  \
+    doit(_c_f1, _c_f0, X##_f1, Y##_f1);                                        \
+                                                                       \
+    _b_f0 &= -_c2;                                                     \
+    _b_f1 &= -_c1;                                                     \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),       \
+                   _FP_FRAC_WORD_4(_z,1), (_c1 & _c2), 0, _d,          \
+                   0, _FP_FRAC_WORD_4(_z,2), _FP_FRAC_WORD_4(_z,1));   \
+    __FP_FRAC_ADDI_2(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),      \
+                    _b_f0);                                            \
+    __FP_FRAC_ADDI_2(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),      \
+                    _b_f1);                                            \
+    __FP_FRAC_DEC_3(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),       \
+                   _FP_FRAC_WORD_4(_z,1),                              \
+                   0, _d, _FP_FRAC_WORD_4(_z,0));                      \
+    __FP_FRAC_DEC_3(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2),       \
+                   _FP_FRAC_WORD_4(_z,1), 0, _c_f1, _c_f0);            \
+    __FP_FRAC_ADD_2(_FP_FRAC_WORD_4(_z,3), _FP_FRAC_WORD_4(_z,2),      \
+                   _c_f1, _c_f0,                                       \
+                   _FP_FRAC_WORD_4(_z,3), _FP_FRAC_WORD_4(_z,2));      \
                                                                        \
     /* Normalize since we know where the msb of the multiplicands      \
        were (bit B), we know that the msb of the of the product is     \
     R##_f1 = _FP_FRAC_WORD_4(_z,1);                                    \
   } while (0)
 
-/* This next macro appears to be totally broken. Fortunately nowhere
- * seems to use it :-> The problem is that we define _z[4] but
- * then use it in _FP_FRAC_SRS_4, which will attempt to access
- * _z_f[n] which will cause an error. The fix probably involves 
- * declaring it with _FP_FRAC_DECL_4, see previous macro. -- PMM 02/1998 
- */
 #define _FP_MUL_MEAT_2_gmp(fs, R, X, Y)                                        \
   do {                                                                 \
-    _FP_W_TYPE _x[2], _y[2], _z[4];                                    \
+    _FP_FRAC_DECL_4(_z);                                               \
+    _FP_W_TYPE _x[2], _y[2];                                           \
     _x[0] = X##_f0; _x[1] = X##_f1;                                    \
     _y[0] = Y##_f0; _y[1] = Y##_f1;                                    \
                                                                        \
-    mpn_mul_n(_z, _x, _y, 2);                                          \
+    mpn_mul_n(_z_f, _x, _y, 2);                                                \
                                                                        \
     /* Normalize since we know where the msb of the multiplicands      \
        were (bit B), we know that the msb of the of the product is     \
        at either 2B or 2B-1.  */                                       \
     _FP_FRAC_SRS_4(_z, _FP_WFRACBITS##_fs-1, 2*_FP_WFRACBITS_##fs);    \
-    R##_f0 = _z[0];                                                    \
-    R##_f1 = _z[1];                                                    \
+    R##_f0 = _z_f[0];                                                  \
+    R##_f1 = _z_f[1];                                                  \
   } while (0)
 
 
 /*
  * Division algorithms:
- * This seems to be giving me difficulties -- PMM 
- * Look, NetBSD seems to be able to comment algorithms. Can't you?
- * I've thrown printks at the problem.
- * This now appears to work, but I still don't really know why.
- * Also, I don't think the result is properly normalised...
  */
 
-#define _FP_DIV_MEAT_2_udiv_64(fs, R, X, Y)                            \
+#define _FP_DIV_MEAT_2_udiv(fs, R, X, Y)                               \
   do {                                                                 \
-    extern void _fp_udivmodti4(_FP_W_TYPE q[2], _FP_W_TYPE r[2],       \
-                              _FP_W_TYPE n1, _FP_W_TYPE n0,            \
-                              _FP_W_TYPE d1, _FP_W_TYPE d0);           \
-    _FP_W_TYPE _n_f3, _n_f2, _n_f1, _n_f0, _r_f1, _r_f0;               \
-    _FP_W_TYPE _q_f1, _q_f0, _m_f1, _m_f0;                             \
-    _FP_W_TYPE _rmem[2], _qmem[2];                                     \
-    /* I think this check is to ensure that the result is normalised.   \
-     * Assuming X,Y normalised (ie in [1.0,2.0)) X/Y will be in         \
-     * [0.5,2.0). Furthermore, it will be less than 1.0 iff X < Y.      \
-     * In this case we tweak things. (this is based on comments in      \
-     * the NetBSD FPU emulation code. )                                 \
-     * We know X,Y are normalised because we ensure this as part of     \
-     * the unpacking process. -- PMM                                    \
-     */                                                                        \
+    _FP_W_TYPE _n_f2, _n_f1, _n_f0, _r_f1, _r_f0, _m_f1, _m_f0;                \
     if (_FP_FRAC_GT_2(X, Y))                                           \
       {                                                                        \
-/*     R##_e++; */                                                     \
-       _n_f3 = X##_f1 >> 1;                                            \
-       _n_f2 = X##_f1 << (_FP_W_TYPE_SIZE - 1) | X##_f0 >> 1;          \
-       _n_f1 = X##_f0 << (_FP_W_TYPE_SIZE - 1);                        \
-       _n_f0 = 0;                                                      \
+       _n_f2 = X##_f1 >> 1;                                            \
+       _n_f1 = X##_f1 << (_FP_W_TYPE_SIZE - 1) | X##_f0 >> 1;          \
+       _n_f0 = X##_f0 << (_FP_W_TYPE_SIZE - 1);                        \
       }                                                                        \
     else                                                               \
       {                                                                        \
        R##_e--;                                                        \
-       _n_f3 = X##_f1;                                                 \
-       _n_f2 = X##_f0;                                                 \
-       _n_f1 = _n_f0 = 0;                                              \
+       _n_f2 = X##_f1;                                                 \
+       _n_f1 = X##_f0;                                                 \
+       _n_f0 = 0;                                                      \
       }                                                                        \
                                                                        \
     /* Normalize, i.e. make the most significant bit of the            \
-       denominator set.  CHANGED: - 1 to nothing -- PMM */             \
-    _FP_FRAC_SLL_2(Y, _FP_WFRACXBITS_##fs /* -1 */);                   \
-                                                                       \
-    /* Do the 256/128 bit division given the 128-bit _fp_udivmodtf4    \
-       primitive snagged from libgcc2.c.  */                           \
+       denominator set. */                                             \
+    _FP_FRAC_SLL_2(Y, _FP_WFRACXBITS_##fs);                            \
                                                                        \
-    _fp_udivmodti4(_qmem, _rmem, _n_f3, _n_f2, 0, Y##_f1);             \
-    _q_f1 = _qmem[0];                                                  \
-    umul_ppmm(_m_f1, _m_f0, _q_f1, Y##_f0);                            \
-    _r_f1 = _rmem[0];                                                  \
-    _r_f0 = _n_f1;                                                     \
+    udiv_qrnnd(R##_f1, _r_f1, _n_f2, _n_f1, Y##_f1);                   \
+    umul_ppmm(_m_f1, _m_f0, R##_f1, Y##_f0);                           \
+    _r_f0 = _n_f0;                                                     \
     if (_FP_FRAC_GT_2(_m, _r))                                         \
       {                                                                        \
-       _q_f1--;                                                        \
-       _FP_FRAC_ADD_2(_r, _r, Y);                                      \
+       R##_f1--;                                                       \
+       _FP_FRAC_ADD_2(_r, Y, _r);                                      \
        if (_FP_FRAC_GE_2(_r, Y) && _FP_FRAC_GT_2(_m, _r))              \
          {                                                             \
-           _q_f1--;                                                    \
-           _FP_FRAC_ADD_2(_r, _r, Y);                                  \
+           R##_f1--;                                                   \
+           _FP_FRAC_ADD_2(_r, Y, _r);                                  \
          }                                                             \
       }                                                                        \
-    _FP_FRAC_SUB_2(_r, _r, _m);                                                \
+    _FP_FRAC_DEC_2(_r, _m);                                            \
                                                                        \
-    _fp_udivmodti4(_qmem, _rmem, _r_f1, _r_f0, 0, Y##_f1);             \
-    _q_f0 = _qmem[0];                                                  \
-    umul_ppmm(_m_f1, _m_f0, _q_f0, Y##_f0);                            \
-    _r_f1 = _rmem[0];                                                  \
-    _r_f0 = _n_f0;                                                     \
-    if (_FP_FRAC_GT_2(_m, _r))                                         \
+    if (_r_f1 == Y##_f1)                                               \
       {                                                                        \
-       _q_f0--;                                                        \
-       _FP_FRAC_ADD_2(_r, _r, Y);                                      \
-       if (_FP_FRAC_GE_2(_r, Y) && _FP_FRAC_GT_2(_m, _r))              \
+       /* This is a special case, not an optimization                  \
+          (_r/Y##_f1 would not fit into UWtype).                       \
+          As _r is guaranteed to be < Y,  R##_f0 can be either         \
+          (UWtype)-1 or (UWtype)-2.  But as we know what kind          \
+          of bits it is (sticky, guard, round),  we don't care.        \
+          We also don't care what the reminder is,  because the        \
+          guard bit will be set anyway.  -jj */                        \
+       R##_f0 = -1;                                                    \
+      }                                                                        \
+    else                                                               \
+      {                                                                        \
+       udiv_qrnnd(R##_f0, _r_f1, _r_f1, _r_f0, Y##_f1);                \
+       umul_ppmm(_m_f1, _m_f0, R##_f0, Y##_f0);                        \
+       _r_f0 = 0;                                                      \
+       if (_FP_FRAC_GT_2(_m, _r))                                      \
          {                                                             \
-           _q_f0--;                                                    \
-           _FP_FRAC_ADD_2(_r, _r, Y);                                  \
+           R##_f0--;                                                   \
+           _FP_FRAC_ADD_2(_r, Y, _r);                                  \
+           if (_FP_FRAC_GE_2(_r, Y) && _FP_FRAC_GT_2(_m, _r))          \
+             {                                                         \
+               R##_f0--;                                               \
+               _FP_FRAC_ADD_2(_r, Y, _r);                              \
+             }                                                         \
          }                                                             \
+       if (!_FP_FRAC_EQ_2(_r, _m))                                     \
+         R##_f0 |= _FP_WORK_STICKY;                                    \
       }                                                                        \
-    _FP_FRAC_SUB_2(_r, _r, _m);                                                \
-                                                                       \
-    R##_f1 = _q_f1;                                                    \
-    R##_f0 = _q_f0 | ((_r_f1 | _r_f0) != 0);                           \
-    /* adjust so answer is normalized again. I'm not sure what the     \
-     * final sz param should be. In practice it's never used since      \
-     * N is 1 which is always going to be < _FP_W_TYPE_SIZE...         \
-     */                                                                        \
-    /* _FP_FRAC_SRS_2(R,1,_FP_WFRACBITS_##fs); */                      \
   } while (0)
 
 
     if (_FP_FRAC_GT_2(X, Y))                                           \
       {                                                                        \
        R##_e++;                                                        \
-       _x[1] = (X##_f0 << (_FP_WFRACBITS-1 - _FP_W_TYPE_SIZE) |        \
+       _x[1] = (X##_f0 << (_FP_WFRACBITS_##fs-1 - _FP_W_TYPE_SIZE) |   \
                 X##_f1 >> (_FP_W_TYPE_SIZE -                           \
-                           (_FP_WFRACBITS-1 - _FP_W_TYPE_SIZE)));      \
-       _x[2] = X##_f1 << (_FP_WFRACBITS-1 - _FP_W_TYPE_SIZE);          \
+                           (_FP_WFRACBITS_##fs-1 - _FP_W_TYPE_SIZE))); \
+       _x[2] = X##_f1 << (_FP_WFRACBITS_##fs-1 - _FP_W_TYPE_SIZE);     \
       }                                                                        \
     else                                                               \
       {                                                                        \
-       _x[1] = (X##_f0 << (_FP_WFRACBITS - _FP_W_TYPE_SIZE) |          \
+       _x[1] = (X##_f0 << (_FP_WFRACBITS_##fs - _FP_W_TYPE_SIZE) |     \
                 X##_f1 >> (_FP_W_TYPE_SIZE -                           \
-                           (_FP_WFRACBITS - _FP_W_TYPE_SIZE)));        \
-       _x[2] = X##_f1 << (_FP_WFRACBITS - _FP_W_TYPE_SIZE);            \
+                           (_FP_WFRACBITS_##fs - _FP_W_TYPE_SIZE)));   \
+       _x[2] = X##_f1 << (_FP_WFRACBITS_##fs - _FP_W_TYPE_SIZE);       \
       }                                                                        \
                                                                        \
     (void) mpn_divrem (_z, 0, _x, 4, _y, 2);                           \
   do {                                                 \
     while (q)                                          \
       {                                                        \
-        T##_f1 = S##_f1 + q;                           \
-        if (T##_f1 <= X##_f1)                          \
-          {                                            \
-            S##_f1 = T##_f1 + q;                       \
-            X##_f1 -= T##_f1;                          \
-            R##_f1 += q;                               \
-          }                                            \
-        _FP_FRAC_SLL_2(X, 1);                          \
-        q >>= 1;                                       \
+       T##_f1 = S##_f1 + q;                            \
+       if (T##_f1 <= X##_f1)                           \
+                                                     \
+           S##_f1 = T##_f1 + q;                        \
+           X##_f1 -= T##_f1;                           \
+           R##_f1 += q;                                \
+                                                     \
+       _FP_FRAC_SLL_2(X, 1);                           \
+       q >>= 1;                                        \
       }                                                        \
     q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1);                \
-    while (q)                                          \
+    while (q != _FP_WORK_ROUND)                                \
       {                                                        \
-        T##_f0 = S##_f0 + q;                           \
-        T##_f1 = S##_f1;                               \
-        if (T##_f1 < X##_f1 ||                                 \
-            (T##_f1 == X##_f1 && T##_f0 < X##_f0))     \
-          {                                            \
-            S##_f0 = T##_f0 + q;                       \
-            if (((_FP_WS_TYPE)T##_f0) < 0 &&           \
-                ((_FP_WS_TYPE)S##_f0) >= 0)            \
-              S##_f1++;                                        \
-            _FP_FRAC_SUB_2(X, X, T);                   \
-            R##_f0 += q;                               \
-          }                                            \
-        _FP_FRAC_SLL_2(X, 1);                          \
-        q >>= 1;                                       \
+       T##_f0 = S##_f0 + q;                            \
+       T##_f1 = S##_f1;                                \
+       if (T##_f1 < X##_f1 ||                          \
+           (T##_f1 == X##_f1 && T##_f0 <= X##_f0))     \
+         {                                             \
+           S##_f0 = T##_f0 + q;                        \
+           S##_f1 += (T##_f0 > S##_f0);                \
+           _FP_FRAC_DEC_2(X, T);                       \
+           R##_f0 += q;                                \
+         }                                             \
+       _FP_FRAC_SLL_2(X, 1);                           \
+       q >>= 1;                                        \
+      }                                                        \
+    if (X##_f0 | X##_f1)                               \
+      {                                                        \
+       if (S##_f1 < X##_f1 ||                          \
+           (S##_f1 == X##_f1 && S##_f0 < X##_f0))      \
+         R##_f0 |= _FP_WORK_ROUND;                     \
+       R##_f0 |= _FP_WORK_STICKY;                      \
       }                                                        \
   } while (0)
 
 
 #define _FP_FRAC_CONV_1_2(dfs, sfs, D, S)                              \
   do {                                                                 \
-    _FP_FRAC_SRS_2(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs),     \
-                  _FP_WFRACBITS_##sfs);                                \
+    if (S##_c != FP_CLS_NAN)                                           \
+      _FP_FRAC_SRS_2(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs),   \
+                    _FP_WFRACBITS_##sfs);                              \
+    else                                                               \
+      _FP_FRAC_SRL_2(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs));  \
     D##_f = S##_f0;                                                    \
   } while (0)
 
index 5f7099271f731e0979513709b942920a0b6d40b9..7f027d580c1f7de5703c051982318bfab65eed12 100644 (file)
@@ -1,41 +1,31 @@
-/*
- * Basic four-word fraction declaration and manipulation.
- *
- * When adding quadword support for 32 bit machines, we need
- * to be a little careful as double multiply uses some of these
- * macros: (in op-2.h)
- * _FP_MUL_MEAT_2_wide() uses _FP_FRAC_DECL_4, _FP_FRAC_WORD_4,
- * _FP_FRAC_ADD_4, _FP_FRAC_SRS_4
- * _FP_MUL_MEAT_2_gmp() uses _FP_FRAC_SRS_4 (and should use
- * _FP_FRAC_DECL_4: it appears to be broken and is not used 
- * anywhere anyway. )
- *
- * I've now fixed all the macros that were here from the sparc64 code.
- * [*none* of the shift macros were correct!] -- PMM 02/1998
- * 
- * The only quadword stuff that remains to be coded is: 
- * 1) the conversion to/from ints, which requires 
- * that we check (in op-common.h) that the following do the right thing
- * for quadwords: _FP_TO_INT(Q,4,r,X,rsz,rsg), _FP_FROM_INT(Q,4,X,r,rs,rt)
- * 2) multiply, divide and sqrt, which require:
- * _FP_MUL_MEAT_4_*(R,X,Y), _FP_DIV_MEAT_4_*(R,X,Y), _FP_SQRT_MEAT_4(R,S,T,X,q),
- * This also needs _FP_MUL_MEAT_Q and _FP_DIV_MEAT_Q to be defined to
- * some suitable _FP_MUL_MEAT_4_* macros in sfp-machine.h.
- * [we're free to choose whatever FP_MUL_MEAT_4_* macros we need for
- * these; they are used nowhere else. ]
- */
+/* Software floating-point emulation.
+   Basic four-word fraction declaration and manipulation.
+   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+                 Jakub Jelinek (jj@ultra.linux.cz),
+                 David S. Miller (davem@redhat.com) and
+                 Peter Maydell (pmaydell@chiark.greenend.org.uk).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #define _FP_FRAC_DECL_4(X)     _FP_W_TYPE X##_f[4]
 #define _FP_FRAC_COPY_4(D,S)                   \
   (D##_f[0] = S##_f[0], D##_f[1] = S##_f[1],   \
    D##_f[2] = S##_f[2], D##_f[3] = S##_f[3])
-/* The _FP_FRAC_SET_n(X,I) macro is intended for use with another
- * macro such as _FP_ZEROFRAC_n which returns n comma separated values.
- * The result is that we get an expansion of __FP_FRAC_SET_n(X,I0,I1,I2,I3)
- * which just assigns the In values to the array X##_f[]. 
- * This is why the number of parameters doesn't appear to match
- * at first glance...      -- PMM 
- */
 #define _FP_FRAC_SET_4(X,I)    __FP_FRAC_SET_4(X, I)
 #define _FP_FRAC_HIGH_4(X)     (X##_f[3])
 #define _FP_FRAC_LOW_4(X)      (X##_f[0])
     _skip = (N) / _FP_W_TYPE_SIZE;                                     \
     _up = (N) % _FP_W_TYPE_SIZE;                                       \
     _down = _FP_W_TYPE_SIZE - _up;                                     \
-    for (_i = 3; _i > _skip; --_i)                                     \
-      X##_f[_i] = X##_f[_i-_skip] << _up | X##_f[_i-_skip-1] >> _down; \
-/* bugfixed: was X##_f[_i] <<= _up;  -- PMM 02/1998 */                  \
-    X##_f[_i] = X##_f[0] << _up;                                       \
-    for (--_i; _i >= 0; --_i)                                          \
+    if (!_up)                                                          \
+      for (_i = 3; _i >= _skip; --_i)                                  \
+       X##_f[_i] = X##_f[_i-_skip];                                    \
+    else                                                               \
+      {                                                                        \
+       for (_i = 3; _i > _skip; --_i)                                  \
+         X##_f[_i] = X##_f[_i-_skip] << _up                            \
+                     | X##_f[_i-_skip-1] >> _down;                     \
+       X##_f[_i--] = X##_f[0] << _up;                                  \
+      }                                                                        \
+    for (; _i >= 0; --_i)                                              \
       X##_f[_i] = 0;                                                   \
   } while (0)
 
     _skip = (N) / _FP_W_TYPE_SIZE;                                     \
     _down = (N) % _FP_W_TYPE_SIZE;                                     \
     _up = _FP_W_TYPE_SIZE - _down;                                     \
-    for (_i = 0; _i < 3-_skip; ++_i)                                   \
-      X##_f[_i] = X##_f[_i+_skip] >> _down | X##_f[_i+_skip+1] << _up; \
-    X##_f[_i] = X##_f[3] >> _down;                                     \
-    for (++_i; _i < 4; ++_i)                                           \
+    if (!_down)                                                                \
+      for (_i = 0; _i <= 3-_skip; ++_i)                                        \
+       X##_f[_i] = X##_f[_i+_skip];                                    \
+    else                                                               \
+      {                                                                        \
+       for (_i = 0; _i < 3-_skip; ++_i)                                \
+         X##_f[_i] = X##_f[_i+_skip] >> _down                          \
+                     | X##_f[_i+_skip+1] << _up;                       \
+       X##_f[_i++] = X##_f[3] >> _down;                                \
+      }                                                                        \
+    for (; _i < 4; ++_i)                                               \
       X##_f[_i] = 0;                                                   \
   } while (0)
 
     for (_s = _i = 0; _i < _skip; ++_i)                                        \
       _s |= X##_f[_i];                                                 \
     _s |= X##_f[_i] << _up;                                            \
-/* s is now != 0 if we want to set the LSbit */                         \
-    for (_i = 0; _i < 3-_skip; ++_i)                                   \
-      X##_f[_i] = X##_f[_i+_skip] >> _down | X##_f[_i+_skip+1] << _up; \
-    X##_f[_i] = X##_f[3] >> _down;                                     \
-    for (++_i; _i < 4; ++_i)                                           \
+/* s is now != 0 if we want to set the LSbit */                                \
+    if (!_down)                                                                \
+      for (_i = 0; _i <= 3-_skip; ++_i)                                        \
+       X##_f[_i] = X##_f[_i+_skip];                                    \
+    else                                                               \
+      {                                                                        \
+       for (_i = 0; _i < 3-_skip; ++_i)                                \
+         X##_f[_i] = X##_f[_i+_skip] >> _down                          \
+                     | X##_f[_i+_skip+1] << _up;                       \
+       X##_f[_i++] = X##_f[3] >> _down;                                \
+      }                                                                        \
+    for (; _i < 4; ++_i)                                               \
       X##_f[_i] = 0;                                                   \
-    /* don't fix the LSB until the very end when we're sure f[0] is stable */ \
-    X##_f[0] |= (_s != 0);                                              \
+    /* don't fix the LSB until the very end when we're sure f[0] is stable */  \
+    X##_f[0] |= (_s != 0);                                             \
   } while (0)
 
 #define _FP_FRAC_ADD_4(R,X,Y)                                          \
                  X##_f[3], X##_f[2], X##_f[1], X##_f[0],               \
                  Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0])
 
-#define _FP_FRAC_SUB_4(R,X,Y)                                           \
+#define _FP_FRAC_SUB_4(R,X,Y)                                          \
   __FP_FRAC_SUB_4(R##_f[3], R##_f[2], R##_f[1], R##_f[0],              \
                  X##_f[3], X##_f[2], X##_f[1], X##_f[0],               \
                  Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0])
 
-#define _FP_FRAC_ADDI_4(X,I)                                            \
+#define _FP_FRAC_DEC_4(X,Y)                                            \
+  __FP_FRAC_DEC_4(X##_f[3], X##_f[2], X##_f[1], X##_f[0],              \
+                 Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0])
+
+#define _FP_FRAC_ADDI_4(X,I)                                           \
   __FP_FRAC_ADDI_4(X##_f[3], X##_f[2], X##_f[1], X##_f[0], I)
 
 #define _FP_ZEROFRAC_4  0,0,0,0
 #define _FP_MINFRAC_4   0,0,0,1
+#define _FP_MAXFRAC_4  (~(_FP_WS_TYPE)0), (~(_FP_WS_TYPE)0), (~(_FP_WS_TYPE)0), (~(_FP_WS_TYPE)0)
 
 #define _FP_FRAC_ZEROP_4(X)     ((X##_f[0] | X##_f[1] | X##_f[2] | X##_f[3]) == 0)
 #define _FP_FRAC_NEGP_4(X)      ((_FP_WS_TYPE)X##_f[3] < 0)
-#define _FP_FRAC_OVERP_4(fs,X)  (X##_f[0] & _FP_OVERFLOW_##fs)
+#define _FP_FRAC_OVERP_4(fs,X)  (_FP_FRAC_HIGH_##fs(X) & _FP_OVERFLOW_##fs)
 
-#define _FP_FRAC_EQ_4(X,Y)                              \
- (X##_f[0] == Y##_f[0] && X##_f[1] == Y##_f[1]          \
+#define _FP_FRAC_EQ_4(X,Y)                             \
+ (X##_f[0] == Y##_f[0] && X##_f[1] == Y##_f[1]         \
   && X##_f[2] == Y##_f[2] && X##_f[3] == Y##_f[3])
 
-#define _FP_FRAC_GT_4(X,Y)                              \
- (X##_f[3] > Y##_f[3] ||                                \
-  (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] ||      \
-   (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] ||     \
-    (X##_f[1] == Y##_f[1] && X##_f[0] > Y##_f[0])       \
-   ))                                                   \
-  ))                                                    \
+#define _FP_FRAC_GT_4(X,Y)                             \
+ (X##_f[3] > Y##_f[3] ||                               \
+  (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] ||     \
+   (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] ||    \
+    (X##_f[1] == Y##_f[1] && X##_f[0] > Y##_f[0])      \
+   ))                                                  \
+  ))                                                   \
  )
 
-#define _FP_FRAC_GE_4(X,Y)                              \
- (X##_f[3] > Y##_f[3] ||                                \
-  (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] ||      \
-   (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] ||     \
-    (X##_f[1] == Y##_f[1] && X##_f[0] >= Y##_f[0])      \
-   ))                                                   \
-  ))                                                    \
+#define _FP_FRAC_GE_4(X,Y)                             \
+ (X##_f[3] > Y##_f[3] ||                               \
+  (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] ||     \
+   (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] ||    \
+    (X##_f[1] == Y##_f[1] && X##_f[0] >= Y##_f[0])     \
+   ))                                                  \
+  ))                                                   \
  )
 
 
-#define _FP_FRAC_CLZ_4(R,X)             \
-  do {                                  \
-    if (X##_f[3])                       \
-    {                                   \
-        __FP_CLZ(R,X##_f[3]);           \
-    }                                   \
-    else if (X##_f[2])                  \
-    {                                   \
-        __FP_CLZ(R,X##_f[2]);           \
-        R += _FP_W_TYPE_SIZE;           \
-    }                                   \
-    else if (X##_f[1])                  \
-    {                                   \
-        __FP_CLZ(R,X##_f[2]);           \
-        R += _FP_W_TYPE_SIZE*2;         \
-    }                                   \
-    else                                \
-    {                                   \
-        __FP_CLZ(R,X##_f[0]);           \
-        R += _FP_W_TYPE_SIZE*3;         \
-    }                                   \
+#define _FP_FRAC_CLZ_4(R,X)            \
+  do {                                 \
+    if (X##_f[3])                      \
+    {                                  \
+       __FP_CLZ(R,X##_f[3]);           \
+    }                                  \
+    else if (X##_f[2])                 \
+    {                                  \
+       __FP_CLZ(R,X##_f[2]);           \
+       R += _FP_W_TYPE_SIZE;           \
+    }                                  \
+    else if (X##_f[1])                 \
+    {                                  \
+       __FP_CLZ(R,X##_f[2]);           \
+       R += _FP_W_TYPE_SIZE*2;         \
+    }                                  \
+    else                               \
+    {                                  \
+       __FP_CLZ(R,X##_f[0]);           \
+       R += _FP_W_TYPE_SIZE*3;         \
+    }                                  \
   } while(0)
 
 
-#define _FP_UNPACK_RAW_4(fs, X, val)                            \
-  do {                                                          \
-    union _FP_UNION_##fs _flo; _flo.flt = (val);               \
-    X##_f[0] = _flo.bits.frac0;                                 \
-    X##_f[1] = _flo.bits.frac1;                                 \
-    X##_f[2] = _flo.bits.frac2;                                 \
-    X##_f[3] = _flo.bits.frac3;                                 \
-    X##_e  = _flo.bits.exp;                                     \
-    X##_s  = _flo.bits.sign;                                    \
+#define _FP_UNPACK_RAW_4(fs, X, val)                           \
+  do {                                                         \
+    union _FP_UNION_##fs _flo; _flo.flt = (val);               \
+    X##_f[0] = _flo.bits.frac0;                                        \
+    X##_f[1] = _flo.bits.frac1;                                        \
+    X##_f[2] = _flo.bits.frac2;                                        \
+    X##_f[3] = _flo.bits.frac3;                                        \
+    X##_e  = _flo.bits.exp;                                    \
+    X##_s  = _flo.bits.sign;                                   \
+  } while (0)
+
+#define _FP_UNPACK_RAW_4_P(fs, X, val)                         \
+  do {                                                         \
+    union _FP_UNION_##fs *_flo =                               \
+      (union _FP_UNION_##fs *)(val);                           \
+                                                               \
+    X##_f[0] = _flo->bits.frac0;                               \
+    X##_f[1] = _flo->bits.frac1;                               \
+    X##_f[2] = _flo->bits.frac2;                               \
+    X##_f[3] = _flo->bits.frac3;                               \
+    X##_e  = _flo->bits.exp;                                   \
+    X##_s  = _flo->bits.sign;                                  \
   } while (0)
 
-#define _FP_PACK_RAW_4(fs, val, X)                              \
-  do {                                                          \
+#define _FP_PACK_RAW_4(fs, val, X)                             \
+  do {                                                         \
     union _FP_UNION_##fs _flo;                                 \
-    _flo.bits.frac0 = X##_f[0];                                 \
-    _flo.bits.frac1 = X##_f[1];                                 \
-    _flo.bits.frac2 = X##_f[2];                                 \
-    _flo.bits.frac3 = X##_f[3];                                 \
-    _flo.bits.exp   = X##_e;                                    \
-    _flo.bits.sign  = X##_s;                                    \
-    (val) = _flo.flt;                                          \
+    _flo.bits.frac0 = X##_f[0];                                        \
+    _flo.bits.frac1 = X##_f[1];                                        \
+    _flo.bits.frac2 = X##_f[2];                                        \
+    _flo.bits.frac3 = X##_f[3];                                        \
+    _flo.bits.exp   = X##_e;                                   \
+    _flo.bits.sign  = X##_s;                                   \
+    (val) = _flo.flt;                                          \
+  } while (0)
+
+#define _FP_PACK_RAW_4_P(fs, val, X)                           \
+  do {                                                         \
+    union _FP_UNION_##fs *_flo =                               \
+      (union _FP_UNION_##fs *)(val);                           \
+                                                               \
+    _flo->bits.frac0 = X##_f[0];                               \
+    _flo->bits.frac1 = X##_f[1];                               \
+    _flo->bits.frac2 = X##_f[2];                               \
+    _flo->bits.frac3 = X##_f[3];                               \
+    _flo->bits.exp   = X##_e;                                  \
+    _flo->bits.sign  = X##_s;                                  \
+  } while (0)
+
+/*
+ * Multiplication algorithms:
+ */
+
+/* Given a 1W * 1W => 2W primitive, do the extended multiplication.  */
+
+#define _FP_MUL_MEAT_4_wide(fs, R, X, Y, doit)                             \
+  do {                                                                     \
+    _FP_FRAC_DECL_8(_z); _FP_FRAC_DECL_2(_b); _FP_FRAC_DECL_2(_c);         \
+    _FP_FRAC_DECL_2(_d); _FP_FRAC_DECL_2(_e); _FP_FRAC_DECL_2(_f);         \
+                                                                           \
+    doit(_FP_FRAC_WORD_8(_z,1), _FP_FRAC_WORD_8(_z,0), X##_f[0], Y##_f[0]); \
+    doit(_b_f1, _b_f0, X##_f[0], Y##_f[1]);                                \
+    doit(_c_f1, _c_f0, X##_f[1], Y##_f[0]);                                \
+    doit(_d_f1, _d_f0, X##_f[1], Y##_f[1]);                                \
+    doit(_e_f1, _e_f0, X##_f[0], Y##_f[2]);                                \
+    doit(_f_f1, _f_f0, X##_f[2], Y##_f[0]);                                \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,3),_FP_FRAC_WORD_8(_z,2),           \
+                   _FP_FRAC_WORD_8(_z,1), 0,_b_f1,_b_f0,                   \
+                   0,0,_FP_FRAC_WORD_8(_z,1));                             \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,3),_FP_FRAC_WORD_8(_z,2),           \
+                   _FP_FRAC_WORD_8(_z,1), 0,_c_f1,_c_f0,                   \
+                   _FP_FRAC_WORD_8(_z,3),_FP_FRAC_WORD_8(_z,2),            \
+                   _FP_FRAC_WORD_8(_z,1));                                 \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3),           \
+                   _FP_FRAC_WORD_8(_z,2), 0,_d_f1,_d_f0,                   \
+                   0,_FP_FRAC_WORD_8(_z,3),_FP_FRAC_WORD_8(_z,2));         \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3),           \
+                   _FP_FRAC_WORD_8(_z,2), 0,_e_f1,_e_f0,                   \
+                   _FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3),            \
+                   _FP_FRAC_WORD_8(_z,2));                                 \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3),           \
+                   _FP_FRAC_WORD_8(_z,2), 0,_f_f1,_f_f0,                   \
+                   _FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3),            \
+                   _FP_FRAC_WORD_8(_z,2));                                 \
+    doit(_b_f1, _b_f0, X##_f[0], Y##_f[3]);                                \
+    doit(_c_f1, _c_f0, X##_f[3], Y##_f[0]);                                \
+    doit(_d_f1, _d_f0, X##_f[1], Y##_f[2]);                                \
+    doit(_e_f1, _e_f0, X##_f[2], Y##_f[1]);                                \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4),           \
+                   _FP_FRAC_WORD_8(_z,3), 0,_b_f1,_b_f0,                   \
+                   0,_FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3));         \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4),           \
+                   _FP_FRAC_WORD_8(_z,3), 0,_c_f1,_c_f0,                   \
+                   _FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4),            \
+                   _FP_FRAC_WORD_8(_z,3));                                 \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4),           \
+                   _FP_FRAC_WORD_8(_z,3), 0,_d_f1,_d_f0,                   \
+                   _FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4),            \
+                   _FP_FRAC_WORD_8(_z,3));                                 \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4),           \
+                   _FP_FRAC_WORD_8(_z,3), 0,_e_f1,_e_f0,                   \
+                   _FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4),            \
+                   _FP_FRAC_WORD_8(_z,3));                                 \
+    doit(_b_f1, _b_f0, X##_f[2], Y##_f[2]);                                \
+    doit(_c_f1, _c_f0, X##_f[1], Y##_f[3]);                                \
+    doit(_d_f1, _d_f0, X##_f[3], Y##_f[1]);                                \
+    doit(_e_f1, _e_f0, X##_f[2], Y##_f[3]);                                \
+    doit(_f_f1, _f_f0, X##_f[3], Y##_f[2]);                                \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5),           \
+                   _FP_FRAC_WORD_8(_z,4), 0,_b_f1,_b_f0,                   \
+                   0,_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4));         \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5),           \
+                   _FP_FRAC_WORD_8(_z,4), 0,_c_f1,_c_f0,                   \
+                   _FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5),            \
+                   _FP_FRAC_WORD_8(_z,4));                                 \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5),           \
+                   _FP_FRAC_WORD_8(_z,4), 0,_d_f1,_d_f0,                   \
+                   _FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5),            \
+                   _FP_FRAC_WORD_8(_z,4));                                 \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6),           \
+                   _FP_FRAC_WORD_8(_z,5), 0,_e_f1,_e_f0,                   \
+                   0,_FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5));         \
+    __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6),           \
+                   _FP_FRAC_WORD_8(_z,5), 0,_f_f1,_f_f0,                   \
+                   _FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6),            \
+                   _FP_FRAC_WORD_8(_z,5));                                 \
+    doit(_b_f1, _b_f0, X##_f[3], Y##_f[3]);                                \
+    __FP_FRAC_ADD_2(_FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6),           \
+                   _b_f1,_b_f0,                                            \
+                   _FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6));           \
+                                                                           \
+    /* Normalize since we know where the msb of the multiplicands          \
+       were (bit B), we know that the msb of the of the product is         \
+       at either 2B or 2B-1.  */                                           \
+    _FP_FRAC_SRS_8(_z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs);        \
+    __FP_FRAC_SET_4(R, _FP_FRAC_WORD_8(_z,3), _FP_FRAC_WORD_8(_z,2),       \
+                   _FP_FRAC_WORD_8(_z,1), _FP_FRAC_WORD_8(_z,0));          \
+  } while (0)
+
+#define _FP_MUL_MEAT_4_gmp(fs, R, X, Y)                                            \
+  do {                                                                     \
+    _FP_FRAC_DECL_8(_z);                                                   \
+                                                                           \
+    mpn_mul_n(_z_f, _x_f, _y_f, 4);                                        \
+                                                                           \
+    /* Normalize since we know where the msb of the multiplicands          \
+       were (bit B), we know that the msb of the of the product is         \
+       at either 2B or 2B-1.  */                                           \
+    _FP_FRAC_SRS_8(_z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs);        \
+    __FP_FRAC_SET_4(R, _FP_FRAC_WORD_8(_z,3), _FP_FRAC_WORD_8(_z,2),       \
+                   _FP_FRAC_WORD_8(_z,1), _FP_FRAC_WORD_8(_z,0));          \
+  } while (0)
+
+/*
+ * Helper utility for _FP_DIV_MEAT_4_udiv:
+ * pppp = m * nnn
+ */
+#define umul_ppppmnnn(p3,p2,p1,p0,m,n2,n1,n0)                              \
+  do {                                                                     \
+    UWtype _t;                                                             \
+    umul_ppmm(p1,p0,m,n0);                                                 \
+    umul_ppmm(p2,_t,m,n1);                                                 \
+    __FP_FRAC_ADDI_2(p2,p1,_t);                                                    \
+    umul_ppmm(p3,_t,m,n2);                                                 \
+    __FP_FRAC_ADDI_2(p3,p2,_t);                                                    \
+  } while (0)
+
+/*
+ * Division algorithms:
+ */
+
+#define _FP_DIV_MEAT_4_udiv(fs, R, X, Y)                                   \
+  do {                                                                     \
+    int _i;                                                                \
+    _FP_FRAC_DECL_4(_n); _FP_FRAC_DECL_4(_m);                              \
+    _FP_FRAC_SET_4(_n, _FP_ZEROFRAC_4);                                            \
+    if (_FP_FRAC_GT_4(X, Y))                                               \
+      {                                                                            \
+       _n_f[3] = X##_f[0] << (_FP_W_TYPE_SIZE - 1);                        \
+       _FP_FRAC_SRL_4(X, 1);                                               \
+      }                                                                            \
+    else                                                                   \
+      R##_e--;                                                             \
+                                                                           \
+    /* Normalize, i.e. make the most significant bit of the                \
+       denominator set. */                                                 \
+    _FP_FRAC_SLL_4(Y, _FP_WFRACXBITS_##fs);                                \
+                                                                           \
+    for (_i = 3; ; _i--)                                                   \
+      {                                                                            \
+        if (X##_f[3] == Y##_f[3])                                          \
+          {                                                                \
+            /* This is a special case, not an optimization                 \
+               (X##_f[3]/Y##_f[3] would not fit into UWtype).              \
+               As X## is guaranteed to be < Y,  R##_f[_i] can be either            \
+               (UWtype)-1 or (UWtype)-2.  */                               \
+            R##_f[_i] = -1;                                                \
+            if (!_i)                                                       \
+             break;                                                        \
+            __FP_FRAC_SUB_4(X##_f[3], X##_f[2], X##_f[1], X##_f[0],        \
+                           Y##_f[2], Y##_f[1], Y##_f[0], 0,                \
+                           X##_f[2], X##_f[1], X##_f[0], _n_f[_i]);        \
+            _FP_FRAC_SUB_4(X, Y, X);                                       \
+            if (X##_f[3] > Y##_f[3])                                       \
+              {                                                                    \
+                R##_f[_i] = -2;                                                    \
+                _FP_FRAC_ADD_4(X, Y, X);                                   \
+              }                                                                    \
+          }                                                                \
+        else                                                               \
+          {                                                                \
+            udiv_qrnnd(R##_f[_i], X##_f[3], X##_f[3], X##_f[2], Y##_f[3]);  \
+            umul_ppppmnnn(_m_f[3], _m_f[2], _m_f[1], _m_f[0],              \
+                         R##_f[_i], Y##_f[2], Y##_f[1], Y##_f[0]);         \
+            X##_f[2] = X##_f[1];                                           \
+            X##_f[1] = X##_f[0];                                           \
+            X##_f[0] = _n_f[_i];                                           \
+            if (_FP_FRAC_GT_4(_m, X))                                      \
+              {                                                                    \
+                R##_f[_i]--;                                               \
+                _FP_FRAC_ADD_4(X, Y, X);                                   \
+                if (_FP_FRAC_GE_4(X, Y) && _FP_FRAC_GT_4(_m, X))           \
+                  {                                                        \
+                   R##_f[_i]--;                                            \
+                   _FP_FRAC_ADD_4(X, Y, X);                                \
+                  }                                                        \
+              }                                                                    \
+            _FP_FRAC_DEC_4(X, _m);                                         \
+            if (!_i)                                                       \
+             {                                                             \
+               if (!_FP_FRAC_EQ_4(X, _m))                                  \
+                 R##_f[0] |= _FP_WORK_STICKY;                              \
+               break;                                                      \
+             }                                                             \
+          }                                                                \
+      }                                                                            \
+  } while (0)
+
+
+/*
+ * Square root algorithms:
+ * We have just one right now, maybe Newton approximation
+ * should be added for those machines where division is fast.
+ */
+#define _FP_SQRT_MEAT_4(R, S, T, X, q)                         \
+  do {                                                         \
+    while (q)                                                  \
+      {                                                                \
+       T##_f[3] = S##_f[3] + q;                                \
+       if (T##_f[3] <= X##_f[3])                               \
+         {                                                     \
+           S##_f[3] = T##_f[3] + q;                            \
+           X##_f[3] -= T##_f[3];                               \
+           R##_f[3] += q;                                      \
+         }                                                     \
+       _FP_FRAC_SLL_4(X, 1);                                   \
+       q >>= 1;                                                \
+      }                                                                \
+    q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1);                        \
+    while (q)                                                  \
+      {                                                                \
+       T##_f[2] = S##_f[2] + q;                                \
+       T##_f[3] = S##_f[3];                                    \
+       if (T##_f[3] < X##_f[3] ||                              \
+           (T##_f[3] == X##_f[3] && T##_f[2] <= X##_f[2]))     \
+         {                                                     \
+           S##_f[2] = T##_f[2] + q;                            \
+           S##_f[3] += (T##_f[2] > S##_f[2]);                  \
+           __FP_FRAC_DEC_2(X##_f[3], X##_f[2],                 \
+                           T##_f[3], T##_f[2]);                \
+           R##_f[2] += q;                                      \
+         }                                                     \
+       _FP_FRAC_SLL_4(X, 1);                                   \
+       q >>= 1;                                                \
+      }                                                                \
+    q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1);                        \
+    while (q)                                                  \
+      {                                                                \
+       T##_f[1] = S##_f[1] + q;                                \
+       T##_f[2] = S##_f[2];                                    \
+       T##_f[3] = S##_f[3];                                    \
+       if (T##_f[3] < X##_f[3] ||                              \
+           (T##_f[3] == X##_f[3] && (T##_f[2] < X##_f[2] ||    \
+            (T##_f[2] == X##_f[2] && T##_f[1] <= X##_f[1]))))  \
+         {                                                     \
+           S##_f[1] = T##_f[1] + q;                            \
+           S##_f[2] += (T##_f[1] > S##_f[1]);                  \
+           S##_f[3] += (T##_f[2] > S##_f[2]);                  \
+           __FP_FRAC_DEC_3(X##_f[3], X##_f[2], X##_f[1],       \
+                           T##_f[3], T##_f[2], T##_f[1]);      \
+           R##_f[1] += q;                                      \
+         }                                                     \
+       _FP_FRAC_SLL_4(X, 1);                                   \
+       q >>= 1;                                                \
+      }                                                                \
+    q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1);                        \
+    while (q != _FP_WORK_ROUND)                                        \
+      {                                                                \
+       T##_f[0] = S##_f[0] + q;                                \
+       T##_f[1] = S##_f[1];                                    \
+       T##_f[2] = S##_f[2];                                    \
+       T##_f[3] = S##_f[3];                                    \
+       if (_FP_FRAC_GE_4(X,T))                                 \
+         {                                                     \
+           S##_f[0] = T##_f[0] + q;                            \
+           S##_f[1] += (T##_f[0] > S##_f[0]);                  \
+           S##_f[2] += (T##_f[1] > S##_f[1]);                  \
+           S##_f[3] += (T##_f[2] > S##_f[2]);                  \
+           _FP_FRAC_DEC_4(X, T);                               \
+           R##_f[0] += q;                                      \
+         }                                                     \
+       _FP_FRAC_SLL_4(X, 1);                                   \
+       q >>= 1;                                                \
+      }                                                                \
+    if (!_FP_FRAC_ZEROP_4(X))                                  \
+      {                                                                \
+       if (_FP_FRAC_GT_4(X,S))                                 \
+         R##_f[0] |= _FP_WORK_ROUND;                           \
+       R##_f[0] |= _FP_WORK_STICKY;                            \
+      }                                                                \
   } while (0)
 
 
 #define __FP_FRAC_SET_4(X,I3,I2,I1,I0)                                 \
   (X##_f[3] = I3, X##_f[2] = I2, X##_f[1] = I1, X##_f[0] = I0)
 
+#ifndef __FP_FRAC_ADD_3
+#define __FP_FRAC_ADD_3(r2,r1,r0,x2,x1,x0,y2,y1,y0)                    \
+  (r0 = x0 + y0,                                                       \
+   r1 = x1 + y1 + (r0 < x0),                                           \
+   r2 = x2 + y2 + (r1 < x1))
+#endif
+
 #ifndef __FP_FRAC_ADD_4
 #define __FP_FRAC_ADD_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0)           \
   (r0 = x0 + y0,                                                       \
    r3 = x3 + y3 + (r2 < x2))
 #endif
 
+#ifndef __FP_FRAC_SUB_3
+#define __FP_FRAC_SUB_3(r2,r1,r0,x2,x1,x0,y2,y1,y0)                    \
+  (r0 = x0 - y0,                                                       \
+   r1 = x1 - y1 - (r0 > x0),                                           \
+   r2 = x2 - y2 - (r1 > x1))
+#endif
+
 #ifndef __FP_FRAC_SUB_4
 #define __FP_FRAC_SUB_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0)           \
-  (r0 = x0 - y0,                                                        \
-   r1 = x1 - y1 - (r0 > x0),                                            \
-   r2 = x2 - y2 - (r1 > x1),                                            \
+  (r0 = x0 - y0,                                                       \
+   r1 = x1 - y1 - (r0 > x0),                                           \
+   r2 = x2 - y2 - (r1 > x1),                                           \
    r3 = x3 - y3 - (r2 > x2))
 #endif
 
+#ifndef __FP_FRAC_DEC_3
+#define __FP_FRAC_DEC_3(x2,x1,x0,y2,y1,y0)                             \
+  do {                                                                 \
+    UWtype _t0, _t1;                                                   \
+    _t0 = x0;                                                          \
+    x0 -= y0;                                                          \
+    _t1 = x1;                                                          \
+    x1 -= y1 + (x0 > _t0);                                             \
+    x2 -= y2 + (x1 > _t1);                                             \
+  } while (0)
+#endif
+
+#ifndef __FP_FRAC_DEC_4
+#define __FP_FRAC_DEC_4(x3,x2,x1,x0,y3,y2,y1,y0)                       \
+  do {                                                                 \
+    UWtype _t0, _t1;                                                   \
+    _t0 = x0;                                                          \
+    x0 -= y0;                                                          \
+    _t1 = x1;                                                          \
+    x1 -= y1 + (x0 > _t0);                                             \
+    _t0 = x2;                                                          \
+    x2 -= y2 + (x1 > _t1);                                             \
+    x3 -= y3 + (x2 > _t0);                                             \
+  } while (0)
+#endif
+
 #ifndef __FP_FRAC_ADDI_4
-/* I always wanted to be a lisp programmer :-> */
-#define __FP_FRAC_ADDI_4(x3,x2,x1,x0,i)                                 \
-  (x3 += ((x2 += ((x1 += ((x0 += i) < x0)) < x1) < x2)))
+#define __FP_FRAC_ADDI_4(x3,x2,x1,x0,i)                                        \
+  do {                                                                 \
+    UWtype _t;                                                         \
+    _t = ((x0 += i) < i);                                              \
+    x1 += _t; _t = (x1 < _t);                                          \
+    x2 += _t; _t = (x2 < _t);                                          \
+    x3 += _t;                                                          \
+  } while (0)
 #endif
 
 /* Convert FP values between word sizes. This appears to be more
  * internally [eg, that 2 word vars are X_f0 and x_f1]. But so do
  * the ones in op-2.h and op-1.h. 
  */
-#define _FP_FRAC_CONV_1_4(dfs, sfs, D, S)                               \
-   do {                                                                 \
-     _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs),     \
-                        _FP_WFRACBITS_##sfs);                           \
-     D##_f = S##_f[0];                                                   \
+#define _FP_FRAC_CONV_1_4(dfs, sfs, D, S)                              \
+   do {                                                                        \
+     if (S##_c != FP_CLS_NAN)                                          \
+       _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs),  \
+                         _FP_WFRACBITS_##sfs);                         \
+     else                                                              \
+       _FP_FRAC_SRL_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs)); \
+     D##_f = S##_f[0];                                                 \
   } while (0)
 
-#define _FP_FRAC_CONV_2_4(dfs, sfs, D, S)                               \
-   do {                                                                 \
-     _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs),     \
-                        _FP_WFRACBITS_##sfs);                           \
-     D##_f0 = S##_f[0];                                                  \
-     D##_f1 = S##_f[1];                                                  \
+#define _FP_FRAC_CONV_2_4(dfs, sfs, D, S)                              \
+   do {                                                                        \
+     if (S##_c != FP_CLS_NAN)                                          \
+       _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs),  \
+                     _FP_WFRACBITS_##sfs);                             \
+     else                                                              \
+       _FP_FRAC_SRL_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs)); \
+     D##_f0 = S##_f[0];                                                        \
+     D##_f1 = S##_f[1];                                                        \
   } while (0)
 
 /* Assembly/disassembly for converting to/from integral types.  
  * No shifting or overflow handled here.
  */
 /* Put the FP value X into r, which is an integer of size rsize. */
-#define _FP_FRAC_ASSEMBLE_4(r, X, rsize)                                \
-  do {                                                                  \
-    if (rsize <= _FP_W_TYPE_SIZE)                                       \
-      r = X##_f[0];                                                     \
-    else if (rsize <= 2*_FP_W_TYPE_SIZE)                                \
-    {                                                                   \
-      r = X##_f[1];                                                     \
-      r <<= _FP_W_TYPE_SIZE;                                            \
-      r += X##_f[0];                                                    \
-    }                                                                   \
-    else                                                                \
-    {                                                                   \
-      /* I'm feeling lazy so we deal with int == 3words (implausible)*/ \
-      /* and int == 4words as a single case.                         */ \
-      r = X##_f[3];                                                     \
-      r <<= _FP_W_TYPE_SIZE;                                            \
-      r += X##_f[2];                                                    \
-      r <<= _FP_W_TYPE_SIZE;                                            \
-      r += X##_f[1];                                                    \
-      r <<= _FP_W_TYPE_SIZE;                                            \
-      r += X##_f[0];                                                    \
-    }                                                                   \
+#define _FP_FRAC_ASSEMBLE_4(r, X, rsize)                               \
+  do {                                                                 \
+    if (rsize <= _FP_W_TYPE_SIZE)                                      \
+      r = X##_f[0];                                                    \
+    else if (rsize <= 2*_FP_W_TYPE_SIZE)                               \
+    {                                                                  \
+      r = X##_f[1];                                                    \
+      r <<= _FP_W_TYPE_SIZE;                                           \
+      r += X##_f[0];                                                   \
+    }                                                                  \
+    else                                                               \
+    {                                                                  \
+      /* I'm feeling lazy so we deal with int == 3words (implausible)*/        \
+      /* and int == 4words as a single case.                    */     \
+      r = X##_f[3];                                                    \
+      r <<= _FP_W_TYPE_SIZE;                                           \
+      r += X##_f[2];                                                   \
+      r <<= _FP_W_TYPE_SIZE;                                           \
+      r += X##_f[1];                                                   \
+      r <<= _FP_W_TYPE_SIZE;                                           \
+      r += X##_f[0];                                                   \
+    }                                                                  \
   } while (0)
 
 /* "No disassemble Number Five!" */
  * the _f[] array consisting of words of size _FP_W_TYPE_SIZE to avoid
  * having to mask the values we store into it.
  */
-#define _FP_FRAC_DISASSEMBLE_4(X, r, rsize)                             \
-  do {                                                                  \
-    X##_f[0] = r;                                                       \
-    X##_f[1] = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE);   \
+#define _FP_FRAC_DISASSEMBLE_4(X, r, rsize)                            \
+  do {                                                                 \
+    X##_f[0] = r;                                                      \
+    X##_f[1] = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE);  \
     X##_f[2] = (rsize <= 2*_FP_W_TYPE_SIZE ? 0 : r >> 2*_FP_W_TYPE_SIZE); \
     X##_f[3] = (rsize <= 3*_FP_W_TYPE_SIZE ? 0 : r >> 3*_FP_W_TYPE_SIZE); \
   } while (0);
 
-#define _FP_FRAC_CONV_4_1(dfs, sfs, D, S)                               \
-   do {                                                                 \
-     D##_f[0] = S##_f;                                                  \
-     D##_f[1] = D##_f[2] = D##_f[3] = 0;                                \
-     _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs));    \
+#define _FP_FRAC_CONV_4_1(dfs, sfs, D, S)                              \
+   do {                                                                        \
+     D##_f[0] = S##_f;                                                 \
+     D##_f[1] = D##_f[2] = D##_f[3] = 0;                               \
+     _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs));   \
    } while (0)
 
-#define _FP_FRAC_CONV_4_2(dfs, sfs, D, S)                               \
-   do {                                                                 \
-     D##_f[0] = S##_f0;                                                 \
-     D##_f[1] = S##_f1;                                                 \
-     D##_f[2] = D##_f[3] = 0;                                           \
-     _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs));    \
+#define _FP_FRAC_CONV_4_2(dfs, sfs, D, S)                              \
+   do {                                                                        \
+     D##_f[0] = S##_f0;                                                        \
+     D##_f[1] = S##_f1;                                                        \
+     D##_f[2] = D##_f[3] = 0;                                          \
+     _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs));   \
    } while (0)
 
-/* FIXME! This has to be written */
-#define _FP_SQRT_MEAT_4(R, S, T, X, q)
diff --git a/arch/sparc64/math-emu/op-8.h b/arch/sparc64/math-emu/op-8.h
new file mode 100644 (file)
index 0000000..a9d7dbf
--- /dev/null
@@ -0,0 +1,103 @@
+/* Software floating-point emulation.
+   Basic eight-word fraction declaration and manipulation.
+   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+                 Jakub Jelinek (jj@ultra.linux.cz) and
+                 Peter Maydell (pmaydell@chiark.greenend.org.uk).
+                                                         
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* We need just a few things from here for op-4, if we ever need some
+   other macros, they can be added. */
+#define _FP_FRAC_DECL_8(X)     _FP_W_TYPE X##_f[8]
+#define _FP_FRAC_HIGH_8(X)     (X##_f[7])
+#define _FP_FRAC_LOW_8(X)      (X##_f[0])
+#define _FP_FRAC_WORD_8(X,w)   (X##_f[w])
+
+#define _FP_FRAC_SLL_8(X,N)                                            \
+  do {                                                                 \
+    _FP_I_TYPE _up, _down, _skip, _i;                                  \
+    _skip = (N) / _FP_W_TYPE_SIZE;                                     \
+    _up = (N) % _FP_W_TYPE_SIZE;                                       \
+    _down = _FP_W_TYPE_SIZE - _up;                                     \
+    if (!_up)                                                          \
+      for (_i = 7; _i >= _skip; --_i)                                  \
+       X##_f[_i] = X##_f[_i-_skip];                                    \
+    else                                                               \
+      {                                                                        \
+       for (_i = 7; _i > _skip; --_i)                                  \
+         X##_f[_i] = X##_f[_i-_skip] << _up                            \
+                     | X##_f[_i-_skip-1] >> _down;                     \
+       X##_f[_i--] = X##_f[0] << _up;                                  \
+      }                                                                        \
+    for (; _i >= 0; --_i)                                              \
+      X##_f[_i] = 0;                                                   \
+  } while (0)
+
+#define _FP_FRAC_SRL_8(X,N)                                            \
+  do {                                                                 \
+    _FP_I_TYPE _up, _down, _skip, _i;                                  \
+    _skip = (N) / _FP_W_TYPE_SIZE;                                     \
+    _down = (N) % _FP_W_TYPE_SIZE;                                     \
+    _up = _FP_W_TYPE_SIZE - _down;                                     \
+    if (!_down)                                                                \
+      for (_i = 0; _i <= 7-_skip; ++_i)                                        \
+       X##_f[_i] = X##_f[_i+_skip];                                    \
+    else                                                               \
+      {                                                                        \
+       for (_i = 0; _i < 7-_skip; ++_i)                                \
+         X##_f[_i] = X##_f[_i+_skip] >> _down                          \
+                     | X##_f[_i+_skip+1] << _up;                       \
+       X##_f[_i++] = X##_f[7] >> _down;                                \
+      }                                                                        \
+    for (; _i < 8; ++_i)                                               \
+      X##_f[_i] = 0;                                                   \
+  } while (0)
+
+
+/* Right shift with sticky-lsb. 
+ * What this actually means is that we do a standard right-shift,
+ * but that if any of the bits that fall off the right hand side
+ * were one then we always set the LSbit.
+ */
+#define _FP_FRAC_SRS_8(X,N,size)                                       \
+  do {                                                                 \
+    _FP_I_TYPE _up, _down, _skip, _i;                                  \
+    _FP_W_TYPE _s;                                                     \
+    _skip = (N) / _FP_W_TYPE_SIZE;                                     \
+    _down = (N) % _FP_W_TYPE_SIZE;                                     \
+    _up = _FP_W_TYPE_SIZE - _down;                                     \
+    for (_s = _i = 0; _i < _skip; ++_i)                                        \
+      _s |= X##_f[_i];                                                 \
+    _s |= X##_f[_i] << _up;                                            \
+/* s is now != 0 if we want to set the LSbit */                                \
+    if (!_down)                                                                \
+      for (_i = 0; _i <= 7-_skip; ++_i)                                        \
+       X##_f[_i] = X##_f[_i+_skip];                                    \
+    else                                                               \
+      {                                                                        \
+       for (_i = 0; _i < 7-_skip; ++_i)                                \
+         X##_f[_i] = X##_f[_i+_skip] >> _down                          \
+                     | X##_f[_i+_skip+1] << _up;                       \
+       X##_f[_i++] = X##_f[7] >> _down;                                \
+      }                                                                        \
+    for (; _i < 8; ++_i)                                               \
+      X##_f[_i] = 0;                                                   \
+    /* don't fix the LSB until the very end when we're sure f[0] is stable */  \
+    X##_f[0] |= (_s != 0);                                             \
+  } while (0)
+
index 6090e0213755fcdeb88b0fc733bfde77e6f122ba..529f0e4b2d17c1d72e7c55bffe5aae788f24bc35 100644 (file)
@@ -1,3 +1,25 @@
+/* Software floating-point emulation. Common operations.
+   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+                 Jakub Jelinek (jj@ultra.linux.cz),
+                 David S. Miller (davem@redhat.com) and
+                 Peter Maydell (pmaydell@chiark.greenend.org.uk).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #define _FP_DECL(wc, X)                        \
   _FP_I_TYPE X##_c, X##_s, X##_e;      \
@@ -13,7 +35,7 @@ do {                                                                  \
   switch (X##_e)                                                       \
   {                                                                    \
   default:                                                             \
-    _FP_FRAC_HIGH_##wc(X) |= _FP_IMPLBIT_##fs;                         \
+    _FP_FRAC_HIGH_RAW_##fs(X) |= _FP_IMPLBIT_##fs;                     \
     _FP_FRAC_SLL_##wc(X, _FP_WORKBITS);                                        \
     X##_e -= _FP_EXPBIAS_##fs;                                         \
     X##_c = FP_CLS_NORMAL;                                             \
@@ -31,6 +53,7 @@ do {                                                                  \
        _FP_FRAC_SLL_##wc(X, (_shift+_FP_WORKBITS));                    \
        X##_e -= _FP_EXPBIAS_##fs - 1 + _shift;                         \
        X##_c = FP_CLS_NORMAL;                                          \
+       FP_SET_EXCEPTION(FP_EX_DENORM);                                 \
       }                                                                        \
     break;                                                             \
                                                                        \
@@ -38,13 +61,16 @@ do {                                                                        \
     if (_FP_FRAC_ZEROP_##wc(X))                                                \
       X##_c = FP_CLS_INF;                                              \
     else                                                               \
-      /* we don't differentiate between signaling and quiet nans */    \
-      X##_c = FP_CLS_NAN;                                              \
+      {                                                                        \
+       X##_c = FP_CLS_NAN;                                             \
+       /* Check for signaling NaN */                                   \
+       if (!(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs))            \
+         FP_SET_EXCEPTION(FP_EX_INVALID);                              \
+      }                                                                        \
     break;                                                             \
   }                                                                    \
 } while (0)
 
-
 /*
  * Before packing the bits back into the native fp result, take care
  * of such mundane things as rounding and overflow.  Also, for some
@@ -53,14 +79,14 @@ do {                                                                        \
  */
 
 #define _FP_PACK_CANONICAL(fs, wc, X)                          \
-({int __ret = 0;                                               \
+do {                                                           \
   switch (X##_c)                                               \
   {                                                            \
   case FP_CLS_NORMAL:                                          \
     X##_e += _FP_EXPBIAS_##fs;                                 \
     if (X##_e > 0)                                             \
       {                                                                \
-       __ret |= _FP_ROUND(wc, X);                              \
+       _FP_ROUND(wc, X);                                       \
        if (_FP_FRAC_OVERP_##wc(fs, X))                         \
          {                                                     \
            _FP_FRAC_SRL_##wc(X, (_FP_WORKBITS+1));             \
@@ -70,10 +96,33 @@ do {                                                                        \
          _FP_FRAC_SRL_##wc(X, _FP_WORKBITS);                   \
        if (X##_e >= _FP_EXPMAX_##fs)                           \
          {                                                     \
-           /* overflow to infinity */                          \
-           X##_e = _FP_EXPMAX_##fs;                            \
-           _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);            \
-            __ret |= EFLAG_OVERFLOW;                           \
+           /* overflow */                                      \
+           switch (FP_ROUNDMODE)                               \
+             {                                                 \
+             case FP_RND_NEAREST:                              \
+               X##_c = FP_CLS_INF;                             \
+               break;                                          \
+             case FP_RND_PINF:                                 \
+               if (!X##_s) X##_c = FP_CLS_INF;                 \
+               break;                                          \
+             case FP_RND_MINF:                                 \
+               if (X##_s) X##_c = FP_CLS_INF;                  \
+               break;                                          \
+             }                                                 \
+           if (X##_c == FP_CLS_INF)                            \
+             {                                                 \
+               /* Overflow to infinity */                      \
+               X##_e = _FP_EXPMAX_##fs;                        \
+               _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);        \
+             }                                                 \
+           else                                                \
+             {                                                 \
+               /* Overflow to maximum normal */                \
+               X##_e = _FP_EXPMAX_##fs - 1;                    \
+               _FP_FRAC_SET_##wc(X, _FP_MAXFRAC_##wc);         \
+             }                                                 \
+           FP_SET_EXCEPTION(FP_EX_OVERFLOW);                   \
+            FP_SET_EXCEPTION(FP_EX_INEXACT);                   \
          }                                                     \
       }                                                                \
     else                                                       \
@@ -83,9 +132,9 @@ do {                                                                 \
        if (X##_e <= _FP_WFRACBITS_##fs)                        \
          {                                                     \
            _FP_FRAC_SRS_##wc(X, X##_e, _FP_WFRACBITS_##fs);    \
-           __ret |= _FP_ROUND(wc, X);                          \
-           _FP_FRAC_SLL_##wc(X, 1);                            \
-           if (_FP_FRAC_OVERP_##wc(fs, X))                     \
+           _FP_ROUND(wc, X);                                   \
+           if (_FP_FRAC_HIGH_##fs(X)                           \
+               & (_FP_OVERFLOW_##fs >> 1))                     \
              {                                                 \
                X##_e = 1;                                      \
                _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);        \
@@ -93,16 +142,21 @@ do {                                                                       \
            else                                                \
              {                                                 \
                X##_e = 0;                                      \
-               _FP_FRAC_SRL_##wc(X, _FP_WORKBITS+1);           \
-                __ret |= EFLAG_UNDERFLOW;                      \
+               _FP_FRAC_SRL_##wc(X, _FP_WORKBITS);             \
+               FP_SET_EXCEPTION(FP_EX_UNDERFLOW);              \
              }                                                 \
          }                                                     \
        else                                                    \
          {                                                     \
            /* underflow to zero */                             \
            X##_e = 0;                                          \
-           _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);            \
-            __ret |= EFLAG_UNDERFLOW;                          \
+           if (!_FP_FRAC_ZEROP_##wc(X))                        \
+             {                                                 \
+               _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc);         \
+               _FP_ROUND(wc, X);                               \
+               _FP_FRAC_LOW_##wc(X) >>= (_FP_WORKBITS);        \
+             }                                                 \
+           FP_SET_EXCEPTION(FP_EX_UNDERFLOW);                  \
          }                                                     \
       }                                                                \
     break;                                                     \
@@ -122,16 +176,33 @@ do {                                                                      \
     if (!_FP_KEEPNANFRACP)                                     \
       {                                                                \
        _FP_FRAC_SET_##wc(X, _FP_NANFRAC_##fs);                 \
-       X##_s = 0;                                              \
+       X##_s = _FP_NANSIGN_##fs;                               \
       }                                                                \
     else                                                       \
-      _FP_FRAC_HIGH_##wc(X) |= _FP_QNANBIT_##fs;               \
+      _FP_FRAC_HIGH_RAW_##fs(X) |= _FP_QNANBIT_##fs;           \
     break;                                                     \
   }                                                            \
+} while (0)
+
+/* This one accepts raw argument and not cooked,  returns
+ * 1 if X is a signaling NaN.
+ */
+#define _FP_ISSIGNAN(fs, wc, X)                                        \
+({                                                             \
+  int __ret = 0;                                               \
+  if (X##_e == _FP_EXPMAX_##fs)                                        \
+    {                                                          \
+      if (!_FP_FRAC_ZEROP_##wc(X)                              \
+         && !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs))   \
+       __ret = 1;                                              \
+    }                                                          \
   __ret;                                                       \
 })
 
 
+
+
+
 /*
  * Main addition routine.  The input values should be cooked.
  */
@@ -152,8 +223,6 @@ do {                                                                             \
            _FP_FRAC_SRS_##wc(X, diff, _FP_WFRACBITS_##fs);                  \
          else if (!_FP_FRAC_ZEROP_##wc(X))                                  \
            _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc);                          \
-         else                                                               \
-           _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);                         \
          R##_e = Y##_e;                                                     \
        }                                                                    \
       else                                                                  \
@@ -164,8 +233,6 @@ do {                                                                             \
                _FP_FRAC_SRS_##wc(Y, diff, _FP_WFRACBITS_##fs);              \
              else if (!_FP_FRAC_ZEROP_##wc(Y))                              \
                _FP_FRAC_SET_##wc(Y, _FP_MINFRAC_##wc);                      \
-             else                                                           \
-               _FP_FRAC_SET_##wc(Y, _FP_ZEROFRAC_##wc);                     \
            }                                                                \
          R##_e = X##_e;                                                     \
        }                                                                    \
@@ -245,8 +312,9 @@ do {                                                                             \
       {                                                                             \
        /* +INF + -INF => NAN */                                             \
        _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);                              \
-       R##_s = X##_s ^ Y##_s;                                               \
+       R##_s = _FP_NANSIGN_##fs;                                            \
        R##_c = FP_CLS_NAN;                                                  \
+       FP_SET_EXCEPTION(FP_EX_INVALID);                                     \
        break;                                                               \
       }                                                                             \
     /* FALLTHRU */                                                          \
@@ -343,8 +411,10 @@ do {                                                       \
                                                        \
   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):                \
   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF):                \
+    R##_s = _FP_NANSIGN_##fs;                          \
     R##_c = FP_CLS_NAN;                                        \
     _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);            \
+    FP_SET_EXCEPTION(FP_EX_INVALID);                   \
     break;                                             \
                                                        \
   default:                                             \
@@ -396,6 +466,7 @@ do {                                                        \
     break;                                             \
                                                        \
   case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO):     \
+    FP_SET_EXCEPTION(FP_EX_DIVZERO);                   \
   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO):                \
   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL):      \
     R##_c = FP_CLS_INF;                                        \
@@ -403,8 +474,10 @@ do {                                                       \
                                                        \
   case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF):         \
   case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO):       \
+    R##_s = _FP_NANSIGN_##fs;                          \
     R##_c = FP_CLS_NAN;                                        \
     _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);            \
+    FP_SET_EXCEPTION(FP_EX_INVALID);                   \
     break;                                             \
                                                        \
   default:                                             \
@@ -485,15 +558,17 @@ do {                                                                      \
     switch (X##_c)                                                     \
     {                                                                  \
     case FP_CLS_NAN:                                                   \
-       R##_s = 0;                                                      \
+       _FP_FRAC_COPY_##wc(R, X);                                       \
+       R##_s = X##_s;                                                  \
        R##_c = FP_CLS_NAN;                                             \
-       _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc);                        \
        break;                                                          \
     case FP_CLS_INF:                                                   \
        if (X##_s)                                                      \
          {                                                             \
-           R##_s = 0;                                                  \
-           R##_c = FP_CLS_NAN; /* sNAN */                              \
+           R##_s = _FP_NANSIGN_##fs;                                   \
+           R##_c = FP_CLS_NAN; /* NAN */                               \
+           _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);                     \
+           FP_SET_EXCEPTION(FP_EX_INVALID);                            \
          }                                                             \
        else                                                            \
          {                                                             \
@@ -503,13 +578,16 @@ do {                                                                      \
        break;                                                          \
     case FP_CLS_ZERO:                                                  \
        R##_s = X##_s;                                                  \
-       R##_c = FP_CLS_ZERO; /* sqrt(+-0) = +-0 */                      \
+       R##_c = FP_CLS_ZERO; /* sqrt(+-0) = +-0 */                      \
        break;                                                          \
     case FP_CLS_NORMAL:                                                        \
        R##_s = 0;                                                      \
         if (X##_s)                                                     \
           {                                                            \
            R##_c = FP_CLS_NAN; /* sNAN */                              \
+           R##_s = _FP_NANSIGN_##fs;                                   \
+           _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs);                     \
+           FP_SET_EXCEPTION(FP_EX_INVALID);                            \
            break;                                                      \
           }                                                            \
        R##_c = FP_CLS_NORMAL;                                          \
@@ -518,10 +596,8 @@ do {                                                                       \
         R##_e = X##_e >> 1;                                            \
         _FP_FRAC_SET_##wc(S, _FP_ZEROFRAC_##wc);                       \
         _FP_FRAC_SET_##wc(R, _FP_ZEROFRAC_##wc);                       \
-        q = _FP_OVERFLOW_##fs;                                         \
-        _FP_FRAC_SLL_##wc(X, 1);                                       \
+        q = _FP_OVERFLOW_##fs >> 1;                                    \
         _FP_SQRT_MEAT_##wc(R, S, T, X, q);                             \
-        _FP_FRAC_SRL_##wc(R, 1);                                       \
     }                                                                  \
   } while (0)
 
@@ -529,28 +605,15 @@ do {                                                                      \
  * Convert from FP to integer
  */
 
-/* "When a NaN, infinity, large positive argument >= 2147483648.0, or 
- * large negative argument <= -2147483649.0 is converted to an integer,
- * the invalid_current bit...should be set and fp_exception_IEEE_754 should
- * be raised. If the floating point invalid trap is disabled, no trap occurs
- * and a numerical result is generated: if the sign bit of the operand
- * is 0, the result is 2147483647; if the sign bit of the operand is 1,
- * the result is -2147483648."
- * Similarly for conversion to extended ints, except that the boundaries
- * are >= 2^63, <= -(2^63 + 1), and the results are 2^63 + 1 for s=0 and
- * -2^63 for s=1.
- * -- SPARC Architecture Manual V9, Appendix B, which specifies how
- * SPARCs resolve implementation dependencies in the IEEE-754 spec.
- * I don't believe that the code below follows this. I'm not even sure
- * it's right! 
- * It doesn't cope with needing to convert to an n bit integer when there
- * is no n bit integer type. Fortunately gcc provides long long so this
- * isn't a problem for sparc32.
- * I have, however, fixed its NaN handling to conform as above.
- *         -- PMM 02/1998
- * NB: rsigned is not 'is r declared signed?' but 'should the value stored
- * in r be signed or unsigned?'. r is always(?) declared unsigned.
- * Comments below are mine, BTW -- PMM 
+/* RSIGNED can have following values:
+ * 0:  the number is required to be 0..(2^rsize)-1, if not, NV is set plus
+ *     the result is either 0 or (2^rsize)-1 depending on the sign in such case.
+ * 1:  the number is required to be -(2^(rsize-1))..(2^(rsize-1))-1, if not, NV is
+ *     set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1 depending
+ *     on the sign in such case.
+ * -1: the number is required to be -(2^(rsize-1))..(2^rsize)-1, if not, NV is
+ *     set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1 depending
+ *     on the sign in such case.
  */
 #define _FP_TO_INT(fs, wc, r, X, rsize, rsigned)                               \
   do {                                                                         \
@@ -559,26 +622,26 @@ do {                                                                      \
       case FP_CLS_NORMAL:                                                      \
        if (X##_e < 0)                                                          \
          {                                                                     \
-         /* case FP_CLS_NAN: see above! */                                     \
+           FP_SET_EXCEPTION(FP_EX_INEXACT);                                    \
          case FP_CLS_ZERO:                                                     \
            r = 0;                                                              \
          }                                                                     \
-       else if (X##_e >= rsize - (rsigned != 0))                               \
+       else if (X##_e >= rsize - (rsigned > 0 || X##_s)                        \
+                || (!rsigned && X##_s))                                        \
          {     /* overflow */                                                  \
          case FP_CLS_NAN:                                                      \
-          case FP_CLS_INF:                                                     \
+         case FP_CLS_INF:                                                      \
            if (rsigned)                                                        \
              {                                                                 \
                r = 1;                                                          \
                r <<= rsize - 1;                                                \
                r -= 1 - X##_s;                                                 \
-             }                                                                 \
-           else                                                                \
-             {                                                                 \
+             } else {                                                          \
                r = 0;                                                          \
-               if (!X##_s)                                                     \
+               if (X##_s)                                                      \
                  r = ~r;                                                       \
              }                                                                 \
+           FP_SET_EXCEPTION(FP_EX_INVALID);                                    \
          }                                                                     \
        else                                                                    \
          {                                                                     \
@@ -591,8 +654,14 @@ do {                                                                       \
              {                                                                 \
                if (X##_e >= _FP_WFRACBITS_##fs)                                \
                  _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1));       \
-               else                                                            \
-                 _FP_FRAC_SRL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1));       \
+               else if (X##_e < _FP_WFRACBITS_##fs - 1)                        \
+                 {                                                             \
+                   _FP_FRAC_SRS_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 2),      \
+                                     _FP_WFRACBITS_##fs);                      \
+                   if (_FP_FRAC_LOW_##wc(X) & 1)                               \
+                     FP_SET_EXCEPTION(FP_EX_INEXACT);                          \
+                   _FP_FRAC_SRL_##wc(X, 1);                                    \
+                 }                                                             \
                _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);                            \
              }                                                                 \
            if (rsigned && X##_s)                                               \
@@ -610,8 +679,6 @@ do {                                                                        \
                                                                        \
        if ((X##_s = (r < 0)))                                          \
          r = -r;                                                       \
-       /* Note that `r' is now considered unsigned, so we don't have   \
-          to worry about the single signed overflow case.  */          \
                                                                        \
        if (rsize <= _FP_W_TYPE_SIZE)                                   \
          __FP_CLZ(X##_e, r);                                           \
@@ -624,7 +691,7 @@ do {                                                                        \
                                                                        \
        if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs < X##_e)    \
          __FP_FRAC_SRS_1(r, (X##_e - _FP_WFRACBITS_##fs), rsize);      \
-       r &= ~((_FP_W_TYPE)1 << X##_e);                                 \
+       r &= ~((rtype)1 << X##_e);                                      \
        _FP_FRAC_DISASSEMBLE_##wc(X, ((unsigned rtype)r), rsize);       \
        _FP_FRAC_SLL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1));         \
       }                                                                        \
index 48fcc798c3158bd64a195ca7f1815f1de1682b7a..4392a38c181a565ba4b49dd349d4772598cbb2c1 100644 (file)
@@ -1,13 +1,32 @@
-/*
- * Definitions for IEEE Quad Precision
- */
+/* Software floating-point emulation.
+   Definitions for IEEE Quad Precision.
+   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+                 Jakub Jelinek (jj@ultra.linux.cz),
+                 David S. Miller (davem@redhat.com) and
+                 Peter Maydell (pmaydell@chiark.greenend.org.uk).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
 #if _FP_W_TYPE_SIZE < 32
-/* It appears to be traditional to abuse 16bitters in these header files... */
 #error "Here's a nickel, kid. Go buy yourself a real computer."
 #endif
 
 #if _FP_W_TYPE_SIZE < 64
-/* This is all terribly experimental and I don't know if it'll work properly -- PMM 02/1998 */
 #define _FP_FRACTBITS_Q         (4*_FP_W_TYPE_SIZE)
 #else
 #define _FP_FRACTBITS_Q                (2*_FP_W_TYPE_SIZE)
@@ -56,7 +75,13 @@ union _FP_UNION_Q
 
 #define FP_DECL_Q(X)           _FP_DECL(4,X)
 #define FP_UNPACK_RAW_Q(X,val) _FP_UNPACK_RAW_4(Q,X,val)
+#define FP_UNPACK_RAW_QP(X,val)        _FP_UNPACK_RAW_4_P(Q,X,val)
 #define FP_PACK_RAW_Q(val,X)   _FP_PACK_RAW_4(Q,val,X)
+#define FP_PACK_RAW_QP(val,X)          \
+  do {                                 \
+    if (!FP_INHIBIT_RESULTS)           \
+      _FP_PACK_RAW_4_P(Q,val,X);       \
+  } while (0)
 
 #define FP_UNPACK_Q(X,val)             \
   do {                                 \
@@ -64,28 +89,46 @@ union _FP_UNION_Q
     _FP_UNPACK_CANONICAL(Q,4,X);       \
   } while (0)
 
+#define FP_UNPACK_QP(X,val)            \
+  do {                                 \
+    _FP_UNPACK_RAW_4_P(Q,X,val);       \
+    _FP_UNPACK_CANONICAL(Q,4,X);       \
+  } while (0)
+
 #define FP_PACK_Q(val,X)               \
   do {                                 \
     _FP_PACK_CANONICAL(Q,4,X);         \
     _FP_PACK_RAW_4(Q,val,X);           \
   } while (0)
 
+#define FP_PACK_QP(val,X)              \
+  do {                                 \
+    _FP_PACK_CANONICAL(Q,4,X);         \
+    if (!FP_INHIBIT_RESULTS)           \
+      _FP_PACK_RAW_4_P(Q,val,X);       \
+  } while (0)
+
+#define FP_ISSIGNAN_Q(X)       _FP_ISSIGNAN(Q,4,X)
 #define FP_NEG_Q(R,X)          _FP_NEG(Q,4,R,X)
 #define FP_ADD_Q(R,X,Y)                _FP_ADD(Q,4,R,X,Y)
 /* single.h and double.h define FP_SUB_t this way too. However, _FP_SUB is
  * never defined in op-common.h! Fortunately nobody seems to use the FP_SUB_t 
  * macros: I suggest a combination of FP_NEG and FP_ADD :-> -- PMM 02/1998
  */
-#define FP_SUB_Q(R,X,Y)                _FP_SUB(Q,4,R,X,Y)
-#define FP_MUL_Q(R,X,Y)                _FP_MUL(Q,4,R,X,Y)
-#define FP_DIV_Q(R,X,Y)                _FP_DIV(Q,4,R,X,Y)
-#define FP_SQRT_Q(R,X)         _FP_SQRT(Q,4,R,X)
+#define FP_SUB_Q(R,X,Y)                        _FP_SUB(Q,4,R,X,Y)
+#define FP_MUL_Q(R,X,Y)                        _FP_MUL(Q,4,R,X,Y)
+#define FP_DIV_Q(R,X,Y)                        _FP_DIV(Q,4,R,X,Y)
+#define FP_SQRT_Q(R,X)                 _FP_SQRT(Q,4,R,X)
+#define _FP_SQRT_MEAT_Q(R,S,T,X,Q)     _FP_SQRT_MEAT_4(R,S,T,X,Q)
 
 #define FP_CMP_Q(r,X,Y,un)     _FP_CMP(Q,4,r,X,Y,un)
 #define FP_CMP_EQ_Q(r,X,Y)     _FP_CMP_EQ(Q,4,r,X,Y)
 
-#define FP_TO_INT_Q(r,X,rsz,rsg)  _FP_TO_INT(Q,4,r,X,rsz,rsg)
-#define FP_FROM_INT_Q(X,r,rs,rt)  _FP_FROM_INT(Q,4,X,r,rs,rt)
+#define FP_TO_INT_Q(r,X,rsz,rsg)       _FP_TO_INT(Q,4,r,X,rsz,rsg)
+#define FP_FROM_INT_Q(X,r,rs,rt)       _FP_FROM_INT(Q,4,X,r,rs,rt)
+
+#define _FP_FRAC_HIGH_Q(X)     _FP_FRAC_HIGH_4(X)
+#define _FP_FRAC_HIGH_RAW_Q(X) _FP_FRAC_HIGH_4(X)
 
 #else   /* not _FP_W_TYPE_SIZE < 64 */
 union _FP_UNION_Q
@@ -108,7 +151,13 @@ union _FP_UNION_Q
 
 #define FP_DECL_Q(X)           _FP_DECL(2,X)
 #define FP_UNPACK_RAW_Q(X,val) _FP_UNPACK_RAW_2(Q,X,val)
+#define FP_UNPACK_RAW_QP(X,val)        _FP_UNPACK_RAW_2_P(Q,X,val)
 #define FP_PACK_RAW_Q(val,X)   _FP_PACK_RAW_2(Q,val,X)
+#define FP_PACK_RAW_QP(val,X)          \
+  do {                                 \
+    if (!FP_INHIBIT_RESULTS)           \
+      _FP_PACK_RAW_2_P(Q,val,X);       \
+  } while (0)
 
 #define FP_UNPACK_Q(X,val)             \
   do {                                 \
@@ -116,23 +165,41 @@ union _FP_UNION_Q
     _FP_UNPACK_CANONICAL(Q,2,X);       \
   } while (0)
 
+#define FP_UNPACK_QP(X,val)            \
+  do {                                 \
+    _FP_UNPACK_RAW_2_P(Q,X,val);       \
+    _FP_UNPACK_CANONICAL(Q,2,X);       \
+  } while (0)
+
 #define FP_PACK_Q(val,X)               \
   do {                                 \
     _FP_PACK_CANONICAL(Q,2,X);         \
     _FP_PACK_RAW_2(Q,val,X);           \
   } while (0)
 
-#define FP_NEG_Q(R,X)          _FP_NEG(Q,2,R,X)
-#define FP_ADD_Q(R,X,Y)                _FP_ADD(Q,2,R,X,Y)
-#define FP_SUB_Q(R,X,Y)                _FP_SUB(Q,2,R,X,Y)
-#define FP_MUL_Q(R,X,Y)                _FP_MUL(Q,2,R,X,Y)
-#define FP_DIV_Q(R,X,Y)                _FP_DIV(Q,2,R,X,Y)
-#define FP_SQRT_Q(R,X)         _FP_SQRT(Q,2,R,X)
+#define FP_PACK_QP(val,X)              \
+  do {                                 \
+    _FP_PACK_CANONICAL(Q,2,X);         \
+    if (!FP_INHIBIT_RESULTS)           \
+      _FP_PACK_RAW_2_P(Q,val,X);       \
+  } while (0)
+
+#define FP_ISSIGNAN_Q(X)               _FP_ISSIGNAN(Q,2,X)
+#define FP_NEG_Q(R,X)                  _FP_NEG(Q,2,R,X)
+#define FP_ADD_Q(R,X,Y)                        _FP_ADD(Q,2,R,X,Y)
+#define FP_SUB_Q(R,X,Y)                        _FP_SUB(Q,2,R,X,Y)
+#define FP_MUL_Q(R,X,Y)                        _FP_MUL(Q,2,R,X,Y)
+#define FP_DIV_Q(R,X,Y)                        _FP_DIV(Q,2,R,X,Y)
+#define FP_SQRT_Q(R,X)                 _FP_SQRT(Q,2,R,X)
+#define _FP_SQRT_MEAT_Q(R,S,T,X,Q)     _FP_SQRT_MEAT_2(R,S,T,X,Q)
 
 #define FP_CMP_Q(r,X,Y,un)     _FP_CMP(Q,2,r,X,Y,un)
 #define FP_CMP_EQ_Q(r,X,Y)     _FP_CMP_EQ(Q,2,r,X,Y)
 
-#define FP_TO_INT_Q(r,X,rsz,rsg)  _FP_TO_INT(Q,2,r,X,rsz,rsg)
-#define FP_FROM_INT_Q(X,r,rs,rt)  _FP_FROM_INT(Q,2,X,r,rs,rt)
+#define FP_TO_INT_Q(r,X,rsz,rsg)       _FP_TO_INT(Q,2,r,X,rsz,rsg)
+#define FP_FROM_INT_Q(X,r,rs,rt)       _FP_FROM_INT(Q,2,X,r,rs,rt)
+
+#define _FP_FRAC_HIGH_Q(X)     _FP_FRAC_HIGH_2(X)
+#define _FP_FRAC_HIGH_RAW_Q(X) _FP_FRAC_HIGH_2(X)
 
 #endif /* not _FP_W_TYPE_SIZE < 64 */
index 3846ac4f9c6183a24503b176e585873c54eeee09..958d577861d811e9794513984c421d8f9579186b 100644 (file)
@@ -1,6 +1,10 @@
-/* Machine-dependent software floating-point definitions.  Sparc64 version.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+/* Machine-dependent software floating-point definitions.
+   Sparc64 kernel version.
+   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+                 Jakub Jelinek (jj@ultra.linux.cz) and
+                 David S. Miller (davem@redhat.com).
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public License as
@@ -17,6 +21,9 @@
    not, write to the Free Software Foundation, Inc.,
    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
+#ifndef _SFP_MACHINE_H
+#define _SFP_MACHINE_H
+   
 #define _FP_W_TYPE_SIZE                64
 #define _FP_W_TYPE             unsigned long
 #define _FP_WS_TYPE            signed long
 
 #define _FP_MUL_MEAT_S(R,X,Y)  _FP_MUL_MEAT_1_imm(S,R,X,Y)
 #define _FP_MUL_MEAT_D(R,X,Y)  _FP_MUL_MEAT_1_wide(D,R,X,Y,umul_ppmm)
-#define _FP_MUL_MEAT_Q(R,X,Y)  _FP_MUL_MEAT_2_wide(Q,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_Q(R,X,Y)  _FP_MUL_MEAT_2_wide_3mul(Q,R,X,Y,umul_ppmm)
 
 #define _FP_DIV_MEAT_S(R,X,Y)  _FP_DIV_MEAT_1_imm(S,R,X,Y,_FP_DIV_HELP_imm)
 #define _FP_DIV_MEAT_D(R,X,Y)  _FP_DIV_MEAT_1_udiv(D,R,X,Y)
-#define _FP_DIV_MEAT_Q(R,X,Y)  _FP_DIV_MEAT_2_udiv_64(Q,R,X,Y)
+#define _FP_DIV_MEAT_Q(R,X,Y)  _FP_DIV_MEAT_2_udiv(Q,R,X,Y)
 
-#define _FP_NANFRAC_S          _FP_QNANBIT_S
-#define _FP_NANFRAC_D          _FP_QNANBIT_D
-#define _FP_NANFRAC_Q          _FP_QNANBIT_Q, 0
+#define _FP_NANFRAC_S          ((_FP_QNANBIT_S << 1) - 1)
+#define _FP_NANFRAC_D          ((_FP_QNANBIT_D << 1) - 1)
+#define _FP_NANFRAC_Q          ((_FP_QNANBIT_Q << 1) - 1), -1
+#define _FP_NANSIGN_S          0
+#define _FP_NANSIGN_D          0
+#define _FP_NANSIGN_Q          0
 
 #define _FP_KEEPNANFRACP 1
+
+/* If one NaN is signaling and the other is not,
+ * we choose that one, otherwise we choose X.
+ */
+/* For _Qp_* and _Q_*, this should prefer X, for
+ * CPU instruction emulation this should prefer Y.
+ * (see SPAMv9 B.2.2 section).
+ */
 #define _FP_CHOOSENAN(fs, wc, R, X, Y)                         \
   do {                                                         \
-    R##_s = Y##_s;                                             \
-    _FP_FRAC_COPY_##wc(R,Y);                                   \
+    if ((_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs)         \
+       && !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs))     \
+      {                                                                \
+       R##_s = X##_s;                                          \
+       _FP_FRAC_COPY_##wc(R,X);                                \
+      }                                                                \
+    else                                                       \
+      {                                                                \
+       R##_s = Y##_s;                                          \
+       _FP_FRAC_COPY_##wc(R,Y);                                \
+      }                                                                \
     R##_c = FP_CLS_NAN;                                                \
   } while (0)
 
-#define __FP_UNPACK_RAW_1(fs, X, val)                          \
-  do {                                                         \
-    union _FP_UNION_##fs *_flo =                               \
-       (union _FP_UNION_##fs *)val;                            \
-                                                               \
-    X##_f = _flo->bits.frac;                                   \
-    X##_e = _flo->bits.exp;                                    \
-    X##_s = _flo->bits.sign;                                   \
-  } while (0)
-
-#define __FP_UNPACK_RAW_2(fs, X, val)                  \
-  do {                                                 \
-    union _FP_UNION_##fs *_flo =                       \
-       (union _FP_UNION_##fs *)val;                    \
-                                                       \
-    X##_f0 = _flo->bits.frac0;                         \
-    X##_f1 = _flo->bits.frac1;                         \
-    X##_e  = _flo->bits.exp;                           \
-    X##_s  = _flo->bits.sign;                          \
-  } while (0)
-
-#define __FP_UNPACK_S(X,val)           \
-  do {                                 \
-    __FP_UNPACK_RAW_1(S,X,val);                \
-    _FP_UNPACK_CANONICAL(S,1,X);       \
-  } while (0)
-
-#define __FP_UNPACK_D(X,val)           \
-  do {                                 \
-    __FP_UNPACK_RAW_1(D,X,val);                \
-    _FP_UNPACK_CANONICAL(D,1,X);       \
-  } while (0)
-
-#define __FP_UNPACK_Q(X,val)           \
-  do {                                 \
-    __FP_UNPACK_RAW_2(Q,X,val);                \
-    _FP_UNPACK_CANONICAL(Q,2,X);       \
-  } while (0)
-
-#define __FP_PACK_RAW_1(fs, val, X)                            \
-  do {                                                         \
-    union _FP_UNION_##fs *_flo =                               \
-       (union _FP_UNION_##fs *)val;                            \
-                                                               \
-    _flo->bits.frac = X##_f;                                   \
-    _flo->bits.exp  = X##_e;                                   \
-    _flo->bits.sign = X##_s;                                   \
-  } while (0)
-  
-#define __FP_PACK_RAW_2(fs, val, X)                    \
-  do {                                                 \
-    union _FP_UNION_##fs *_flo =                       \
-       (union _FP_UNION_##fs *)val;                    \
-                                                       \
-    _flo->bits.frac0 = X##_f0;                         \
-    _flo->bits.frac1 = X##_f1;                         \
-    _flo->bits.exp   = X##_e;                          \
-    _flo->bits.sign  = X##_s;                          \
-  } while (0)
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-
-/* We only actually write to the destination register
- * if exceptions signalled (if any) will not trap.
- */
-#define __FPU_TEM \
-       (((current->tss.xfsr[0])>>23)&0x1f)
-#define __FPU_TRAP_P(bits) \
-       ((__FPU_TEM & (bits)) != 0)
-
-#define __FP_PACK_S(val,X)                     \
-({  int __exc = _FP_PACK_CANONICAL(S,1,X);     \
-    if(!__exc || !__FPU_TRAP_P(__exc))         \
-        __FP_PACK_RAW_1(S,val,X);              \
-    __exc;                                     \
-})
-
-#define __FP_PACK_D(val,X)                     \
-({  int __exc = _FP_PACK_CANONICAL(D,1,X);     \
-    if(!__exc || !__FPU_TRAP_P(__exc))         \
-        __FP_PACK_RAW_1(D,val,X);              \
-    __exc;                                     \
-})
-
-#define __FP_PACK_Q(val,X)                     \
-({  int __exc = _FP_PACK_CANONICAL(Q,2,X);     \
-    if(!__exc || !__FPU_TRAP_P(__exc))         \
-        __FP_PACK_RAW_2(Q,val,X);              \
-    __exc;                                     \
-})
-
 /* Obtain the current rounding mode. */
+#ifndef FP_ROUNDMODE
 #define FP_ROUNDMODE   ((current->tss.xfsr[0] >> 30) & 0x3)
+#endif
 
-#include <linux/types.h>
-#include <asm/byteorder.h>
-
-#define add_ssaaaa(sh, sl, ah, al, bh, bl)                                             \
-  __asm__ ("addcc %4,%5,%1
-           add %2,%3,%0
-           bcs,a,pn %%xcc, 1f
-           add %0, 1, %0
-           1:"                                                                         \
-          : "=r" ((UDItype)(sh)),                                                      \
-            "=&r" ((UDItype)(sl))                                                      \
-          : "r" ((UDItype)(ah)),                                                       \
-            "r" ((UDItype)(bh)),                                                       \
-            "r" ((UDItype)(al)),                                                       \
-            "r" ((UDItype)(bl))                                                        \
-          : "cc")
-          
-#define sub_ddmmss(sh, sl, ah, al, bh, bl)                                             \
-  __asm__ ("subcc %4,%5,%1
-           sub %2,%3,%0
-           bcs,a,pn %%xcc, 1f
-           sub %0, 1, %0
-           1:"                                                                         \
-          : "=r" ((UDItype)(sh)),                                                      \
-            "=&r" ((UDItype)(sl))                                                      \
-          : "r" ((UDItype)(ah)),                                                       \
-            "r" ((UDItype)(bh)),                                                       \
-            "r" ((UDItype)(al)),                                                       \
-            "r" ((UDItype)(bl))                                                        \
-          : "cc")
-          
-#define umul_ppmm(wh, wl, u, v)                                                        \
-  do {                                                                                 \
-         __asm__ ("mulx %2,%3,%1
-                   srlx %2,32,%%g1
-                   srl %3,0,%%g2
-                   mulx %%g1,%%g2,%%g3
-                   srlx %3,32,%%g1
-                   srl %2,0,%%g2
-                   mulx %%g1,%%g2,%%g2
-                   srlx %2,32,%%g1
-                   add %%g2,%%g3,%%g3
-                   srlx %3,32,%%g2
-                   mulx %%g1,%%g2,%%g1
-                   srlx %%g3,32,%%g2
-                   add %%g1,%%g2,%0"                                                   \
-          : "=r" ((UDItype)(wh)),                                                      \
-            "=&r" ((UDItype)(wl))                                                      \
-          : "r" ((UDItype)(u)),                                                        \
-            "r" ((UDItype)(v))                                                         \
-          : "g1", "g2", "g3", "cc");                                                   \
-  } while (0)
-  
-#define udiv_qrnnd(q, r, n1, n0, d)                                                    \
-  do {                                                                                 \
-    UWtype __d1, __d0, __q1, __q0, __r1, __r0, __m;                                    \
-    __d1 = (d >> 32);                                                                  \
-    __d0 = (USItype)d;                                                                 \
-                                                                                       \
-    __r1 = (n1) % __d1;                                                                \
-    __q1 = (n1) / __d1;                                                                \
-    __m = (UWtype) __q1 * __d0;                                                        \
-    __r1 = (__r1 << 32) | (n0 >> 32);                                                          \
-    if (__r1 < __m)                                                                    \
-      {                                                                                \
-        __q1--, __r1 += (d);                                                           \
-        if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */            \
-          if (__r1 < __m)                                                              \
-            __q1--, __r1 += (d);                                                       \
-      }                                                                                \
-    __r1 -= __m;                                                                       \
-                                                                                       \
-    __r0 = __r1 % __d1;                                                                \
-    __q0 = __r1 / __d1;                                                                \
-    __m = (UWtype) __q0 * __d0;                                                        \
-    __r0 = (__r0 << 32) | ((USItype)n0);                                               \
-    if (__r0 < __m)                                                                    \
-      {                                                                                \
-        __q0--, __r0 += (d);                                                           \
-        if (__r0 >= (d))                                                               \
-          if (__r0 < __m)                                                              \
-            __q0--, __r0 += (d);                                                       \
-      }                                                                                \
-    __r0 -= __m;                                                                       \
-                                                                                       \
-    (q) = (UWtype) (__q1 << 32)  | __q0;                                               \
-    (r) = __r0;                                                                        \
-  } while (0)
+/* Exception flags. */
+#define FP_EX_INVALID          (1 << 4)
+#define FP_EX_OVERFLOW         (1 << 3)
+#define FP_EX_UNDERFLOW                (1 << 2)
+#define FP_EX_DIVZERO          (1 << 1)
+#define FP_EX_INEXACT          (1 << 0)
 
-#define UDIV_NEEDS_NORMALIZATION 1  
+#define FP_HANDLE_EXCEPTIONS return _fex
 
-#define abort()                                                                                \
-       return 0
+#define FP_INHIBIT_RESULTS ((current->tss.xfsr[0] >> 23) & _fex)
 
-#ifdef __BIG_ENDIAN
-#define __BYTE_ORDER __BIG_ENDIAN
-#else
-#define __BYTE_ORDER __LITTLE_ENDIAN
 #endif
-
-/* Exception flags. */
-#define EFLAG_INVALID          (1 << 4)
-#define EFLAG_OVERFLOW         (1 << 3)
-#define EFLAG_UNDERFLOW                (1 << 2)
-#define EFLAG_DIVZERO          (1 << 1)
-#define EFLAG_INEXACT          (1 << 0)
diff --git a/arch/sparc64/math-emu/sfp-util.h b/arch/sparc64/math-emu/sfp-util.h
new file mode 100644 (file)
index 0000000..1bf0ef2
--- /dev/null
@@ -0,0 +1,120 @@
+/* $Id: sfp-util.h,v 1.1 1999/05/28 13:43:07 jj Exp $
+ * arch/sparc64/math-emu/sfp-util.h
+ *
+ * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+#define add_ssaaaa(sh, sl, ah, al, bh, bl)                                             \
+  __asm__ ("addcc %4,%5,%1
+           add %2,%3,%0
+           bcs,a,pn %%xcc, 1f
+           add %0, 1, %0
+           1:"                                                                         \
+          : "=r" ((UDItype)(sh)),                                                      \
+            "=&r" ((UDItype)(sl))                                                      \
+          : "r" ((UDItype)(ah)),                                                       \
+            "r" ((UDItype)(bh)),                                                       \
+            "r" ((UDItype)(al)),                                                       \
+            "r" ((UDItype)(bl))                                                        \
+          : "cc")
+          
+#define sub_ddmmss(sh, sl, ah, al, bh, bl)                                             \
+  __asm__ ("subcc %4,%5,%1
+           sub %2,%3,%0
+           bcs,a,pn %%xcc, 1f
+           sub %0, 1, %0
+           1:"                                                                         \
+          : "=r" ((UDItype)(sh)),                                                      \
+            "=&r" ((UDItype)(sl))                                                      \
+          : "r" ((UDItype)(ah)),                                                       \
+            "r" ((UDItype)(bh)),                                                       \
+            "r" ((UDItype)(al)),                                                       \
+            "r" ((UDItype)(bl))                                                        \
+          : "cc")
+
+#define umul_ppmm(wh, wl, u, v)                                                                \
+  do {                                                                                 \
+         UDItype tmp1, tmp2, tmp3, tmp4;                                               \
+         __asm__ __volatile__ (                                                        \
+                  "srl %7,0,%3
+                   mulx %3,%6,%1
+                   srlx %6,32,%2
+                   mulx %2,%3,%4
+                   sllx %4,32,%5
+                   srl %6,0,%3
+                   sub %1,%5,%5
+                   srlx %5,32,%5
+                   addcc %4,%5,%4
+                   srlx %7,32,%5
+                   mulx %3,%5,%3
+                   mulx %2,%5,%5
+                   sethi 0x80000000,%2
+                   addcc %4,%3,%4
+                   srlx %4,32,%4
+                   add %2,%2,%2
+                   movcc %%xcc,%%g0,%2
+                   addcc %5,%4,%5
+                   sllx %3,32,%3
+                   add %1,%3,%1
+                   add %5,%2,%0"                                                       \
+          : "=r" ((UDItype)(wh)),                                                      \
+            "=&r" ((UDItype)(wl)),                                                     \
+            "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3), "=&r" (tmp4)                     \
+          : "r" ((UDItype)(u)),                                                        \
+            "r" ((UDItype)(v))                                                         \
+          : "cc");                                                                     \
+  } while (0)
+  
+#define udiv_qrnnd(q, r, n1, n0, d)                                                    \
+  do {                                                                                 \
+    UWtype __d1, __d0, __q1, __q0, __r1, __r0, __m;                                    \
+    __d1 = (d >> 32);                                                                  \
+    __d0 = (USItype)d;                                                                 \
+                                                                                       \
+    __r1 = (n1) % __d1;                                                                \
+    __q1 = (n1) / __d1;                                                                \
+    __m = (UWtype) __q1 * __d0;                                                        \
+    __r1 = (__r1 << 32) | (n0 >> 32);                                                          \
+    if (__r1 < __m)                                                                    \
+      {                                                                                \
+        __q1--, __r1 += (d);                                                           \
+        if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */            \
+          if (__r1 < __m)                                                              \
+            __q1--, __r1 += (d);                                                       \
+      }                                                                                \
+    __r1 -= __m;                                                                       \
+                                                                                       \
+    __r0 = __r1 % __d1;                                                                \
+    __q0 = __r1 / __d1;                                                                \
+    __m = (UWtype) __q0 * __d0;                                                        \
+    __r0 = (__r0 << 32) | ((USItype)n0);                                               \
+    if (__r0 < __m)                                                                    \
+      {                                                                                \
+        __q0--, __r0 += (d);                                                           \
+        if (__r0 >= (d))                                                               \
+          if (__r0 < __m)                                                              \
+            __q0--, __r0 += (d);                                                       \
+      }                                                                                \
+    __r0 -= __m;                                                                       \
+                                                                                       \
+    (q) = (UWtype) (__q1 << 32)  | __q0;                                               \
+    (r) = __r0;                                                                        \
+  } while (0)
+
+#define UDIV_NEEDS_NORMALIZATION 1  
+
+#define abort()                                                                                \
+       return 0
+
+#ifdef __BIG_ENDIAN
+#define __BYTE_ORDER __BIG_ENDIAN
+#else
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#endif
index f19d99451815ea638139159c061ab1bef5208978..6504e52834389b71f93ede096162dbda192c3f25 100644 (file)
@@ -1,6 +1,26 @@
-/*
- * Definitions for IEEE Single Precision
- */
+/* Software floating-point emulation.
+   Definitions for IEEE Single Precision.
+   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+                 Jakub Jelinek (jj@ultra.linux.cz),
+                 David S. Miller (davem@redhat.com) and
+                 Peter Maydell (pmaydell@chiark.greenend.org.uk).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #if _FP_W_TYPE_SIZE < 32
 #error "Here's a nickel kid.  Go buy yourself a real computer."
@@ -38,7 +58,13 @@ union _FP_UNION_S
 
 #define FP_DECL_S(X)           _FP_DECL(1,X)
 #define FP_UNPACK_RAW_S(X,val) _FP_UNPACK_RAW_1(S,X,val)
+#define FP_UNPACK_RAW_SP(X,val)        _FP_UNPACK_RAW_1_P(S,X,val)
 #define FP_PACK_RAW_S(val,X)   _FP_PACK_RAW_1(S,val,X)
+#define FP_PACK_RAW_SP(val,X)          \
+  do {                                 \
+    if (!FP_INHIBIT_RESULTS)           \
+      _FP_PACK_RAW_1_P(S,val,X);       \
+  } while (0)
 
 #define FP_UNPACK_S(X,val)             \
   do {                                 \
@@ -46,21 +72,39 @@ union _FP_UNION_S
     _FP_UNPACK_CANONICAL(S,1,X);       \
   } while (0)
 
+#define FP_UNPACK_SP(X,val)            \
+  do {                                 \
+    _FP_UNPACK_RAW_1_P(S,X,val);       \
+    _FP_UNPACK_CANONICAL(S,1,X);       \
+  } while (0)
+
 #define FP_PACK_S(val,X)               \
   do {                                 \
     _FP_PACK_CANONICAL(S,1,X);         \
     _FP_PACK_RAW_1(S,val,X);           \
   } while (0)
 
-#define FP_NEG_S(R,X)          _FP_NEG(S,1,R,X)
-#define FP_ADD_S(R,X,Y)                _FP_ADD(S,1,R,X,Y)
-#define FP_SUB_S(R,X,Y)                _FP_SUB(S,1,R,X,Y)
-#define FP_MUL_S(R,X,Y)                _FP_MUL(S,1,R,X,Y)
-#define FP_DIV_S(R,X,Y)                _FP_DIV(S,1,R,X,Y)
-#define FP_SQRT_S(R,X)         _FP_SQRT(S,1,R,X)
+#define FP_PACK_SP(val,X)              \
+  do {                                 \
+    _FP_PACK_CANONICAL(S,1,X);         \
+    if (!FP_INHIBIT_RESULTS)           \
+      _FP_PACK_RAW_1_P(S,val,X);       \
+  } while (0)
+
+#define FP_ISSIGNAN_S(X)               _FP_ISSIGNAN(S,1,X)
+#define FP_NEG_S(R,X)                  _FP_NEG(S,1,R,X)
+#define FP_ADD_S(R,X,Y)                        _FP_ADD(S,1,R,X,Y)
+#define FP_SUB_S(R,X,Y)                        _FP_SUB(S,1,R,X,Y)
+#define FP_MUL_S(R,X,Y)                        _FP_MUL(S,1,R,X,Y)
+#define FP_DIV_S(R,X,Y)                        _FP_DIV(S,1,R,X,Y)
+#define FP_SQRT_S(R,X)                 _FP_SQRT(S,1,R,X)
+#define _FP_SQRT_MEAT_S(R,S,T,X,Q)     _FP_SQRT_MEAT_1(R,S,T,X,Q)
 
 #define FP_CMP_S(r,X,Y,un)     _FP_CMP(S,1,r,X,Y,un)
 #define FP_CMP_EQ_S(r,X,Y)     _FP_CMP_EQ(S,1,r,X,Y)
 
-#define FP_TO_INT_S(r,X,rsz,rsg)  _FP_TO_INT(S,1,r,X,rsz,rsg)
-#define FP_FROM_INT_S(X,r,rs,rt)  _FP_FROM_INT(S,1,X,r,rs,rt)
+#define FP_TO_INT_S(r,X,rsz,rsg)       _FP_TO_INT(S,1,r,X,rsz,rsg)
+#define FP_FROM_INT_S(X,r,rs,rt)       _FP_FROM_INT(S,1,X,r,rs,rt)
+
+#define _FP_FRAC_HIGH_S(X)     _FP_FRAC_HIGH_1(X)
+#define _FP_FRAC_HIGH_RAW_S(X) _FP_FRAC_HIGH_1(X)
index b54f86217984f1e69988a7e838e68d3dabb0e143..3c5072e51662389e2a7b1e98d24b80d91e23480f 100644 (file)
@@ -1,8 +1,36 @@
+/* Software floating-point emulation.
+   Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+                 Jakub Jelinek (jj@ultra.linux.cz),
+                 David S. Miller (davem@redhat.com) and
+                 Peter Maydell (pmaydell@chiark.greenend.org.uk).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
 #ifndef SOFT_FP_H
 #define SOFT_FP_H
 
 #include "sfp-machine.h"
 
+/* Allow sfp-machine to have its own byte order definitions. */
+#ifndef __BYTE_ORDER
+#include <endian.h>
+#endif
+
 #define _FP_WORKBITS           3
 #define _FP_WORK_LSB           ((_FP_W_TYPE)1 << 3)
 #define _FP_WORK_ROUND         ((_FP_W_TYPE)1 << 2)
 #endif
 #endif
 
+/* By default don't care about exceptions. */
+#ifndef FP_EX_INVALID
+#define FP_EX_INVALID          0
+#endif
+#ifndef FP_EX_OVERFLOW
+#define FP_EX_OVERFLOW         0
+#endif
+#ifndef FP_EX_UNDERFLOW
+#define FP_EX_UNDERFLOW                
+#endif
+#ifndef FP_EX_DIVZERO
+#define FP_EX_DIVZERO          0
+#endif
+#ifndef FP_EX_INEXACT
+#define FP_EX_INEXACT          0
+#endif
+#ifndef FP_EX_DENORM
+#define FP_EX_DENORM           0
+#endif
+
+#ifdef _FP_DECL_EX
+#define FP_DECL_EX                                     \
+  int _fex = 0;                                                \
+  _FP_DECL_EX
+#else
+#define FP_DECL_EX int _fex = 0
+#endif
+  
+#ifndef FP_INIT_ROUNDMODE
+#define FP_INIT_ROUNDMODE do {} while (0)
+#endif
+
+#ifndef FP_HANDLE_EXCEPTIONS
+#define FP_HANDLE_EXCEPTIONS do {} while (0)
+#endif
+
+#ifndef FP_INHIBIT_RESULTS
+/* By default we write the results always.
+ * sfp-machine may override this and e.g.
+ * check if some exceptions are unmasked
+ * and inhibit it in such a case.
+ */
+#define FP_INHIBIT_RESULTS 0
+#endif
+
+#define FP_SET_EXCEPTION(ex)                           \
+  _fex |= (ex)
+  
+#define FP_UNSET_EXCEPTION(ex)                         \
+  _fex &= ~(ex)
+
+#define FP_CLEAR_EXCEPTIONS                            \
+  _fex = 0
+
 #define _FP_ROUND_NEAREST(wc, X)                       \
-({  int __ret = EFLAG_INEXACT;                         \
+do {                                                   \
     if ((_FP_FRAC_LOW_##wc(X) & 15) != _FP_WORK_ROUND) \
       _FP_FRAC_ADDI_##wc(X, _FP_WORK_ROUND);           \
-    else __ret = 0;                                    \
-    __ret;                                             \
-})
+} while (0)
 
-#define _FP_ROUND_ZERO(wc, X)          0 /* XXX */
+#define _FP_ROUND_ZERO(wc, X)          0
 
 #define _FP_ROUND_PINF(wc, X)                          \
-({  int __ret = EFLAG_INEXACT;                         \
+do {                                                   \
     if (!X##_s && (_FP_FRAC_LOW_##wc(X) & 7))          \
       _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB);             \
-    else __ret = 0;                                    \
-    __ret;                                             \
-})
+} while (0)
 
 #define _FP_ROUND_MINF(wc, X)                          \
-({  int __ret = EFLAG_INEXACT;                         \
+do {                                                   \
     if (X##_s && (_FP_FRAC_LOW_##wc(X) & 7))           \
       _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB);             \
-    else __ret = 0;                                    \
-    __ret;                                             \
-})
+} while (0)
 
 #define _FP_ROUND(wc, X)                       \
-({     int __ret = 0;                          \
+do {                                           \
+       if (_FP_FRAC_LOW_##wc(X) & 7)           \
+         FP_SET_EXCEPTION(FP_EX_INEXACT);      \
        switch (FP_ROUNDMODE)                   \
        {                                       \
          case FP_RND_NEAREST:                  \
-           __ret |= _FP_ROUND_NEAREST(wc,X);   \
+           _FP_ROUND_NEAREST(wc,X);            \
            break;                              \
          case FP_RND_ZERO:                     \
-           __ret |= _FP_ROUND_ZERO(wc,X);      \
+           _FP_ROUND_ZERO(wc,X);               \
            break;                              \
          case FP_RND_PINF:                     \
-           __ret |= _FP_ROUND_PINF(wc,X);      \
+           _FP_ROUND_PINF(wc,X);               \
            break;                              \
          case FP_RND_MINF:                     \
-           __ret |= _FP_ROUND_MINF(wc,X);      \
+           _FP_ROUND_MINF(wc,X);               \
            break;                              \
-       };                                      \
-       __ret;                                  \
-})
+       }                                       \
+} while (0)
 
 #define FP_CLS_NORMAL          0
 #define FP_CLS_ZERO            1
 #include "op-1.h"
 #include "op-2.h"
 #include "op-4.h"
+#include "op-8.h"
 #include "op-common.h"
 
 /* Sigh.  Silly things longlong.h needs.  */
@@ -91,4 +169,8 @@ typedef unsigned int UHWtype __attribute__((mode(HI)));
 typedef USItype UHWtype;
 #endif
 
+#ifndef umul_ppmm
+#include <stdlib/longlong.h>
+#endif
+
 #endif
diff --git a/arch/sparc64/math-emu/udivmodti4.c b/arch/sparc64/math-emu/udivmodti4.c
deleted file mode 100644 (file)
index 7e112dc..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-/* This has so very few changes over libgcc2's __udivmoddi4 it isn't funny.  */
-
-#include "soft-fp.h"
-
-#undef count_leading_zeros
-#define count_leading_zeros  __FP_CLZ
-
-void
-_fp_udivmodti4(_FP_W_TYPE q[2], _FP_W_TYPE r[2],
-              _FP_W_TYPE n1, _FP_W_TYPE n0,
-              _FP_W_TYPE d1, _FP_W_TYPE d0)
-{
-  _FP_W_TYPE q0, q1, r0, r1;
-  _FP_I_TYPE b, bm;
-
-  if (d1 == 0)
-    {
-#if !UDIV_NEEDS_NORMALIZATION
-      if (d0 > n1)
-       {
-         /* 0q = nn / 0D */
-
-         udiv_qrnnd (q0, n0, n1, n0, d0);
-         q1 = 0;
-
-         /* Remainder in n0.  */
-       }
-      else
-       {
-         /* qq = NN / 0d */
-
-         if (d0 == 0)
-           d0 = 1 / d0;        /* Divide intentionally by zero.  */
-
-         udiv_qrnnd (q1, n1, 0, n1, d0);
-         udiv_qrnnd (q0, n0, n1, n0, d0);
-
-         /* Remainder in n0.  */
-       }
-
-      r0 = n0;
-      r1 = 0;
-
-#else /* UDIV_NEEDS_NORMALIZATION */
-
-      if (d0 > n1)
-       {
-         /* 0q = nn / 0D */
-
-         count_leading_zeros (bm, d0);
-
-         if (bm != 0)
-           {
-             /* Normalize, i.e. make the most significant bit of the
-                denominator set.  */
-
-             d0 = d0 << bm;
-             n1 = (n1 << bm) | (n0 >> (_FP_W_TYPE_SIZE - bm));
-             n0 = n0 << bm;
-           }
-
-         udiv_qrnnd (q0, n0, n1, n0, d0);
-         q1 = 0;
-
-         /* Remainder in n0 >> bm.  */
-       }
-      else
-       {
-         /* qq = NN / 0d */
-
-         if (d0 == 0)
-           d0 = 1 / d0;        /* Divide intentionally by zero.  */
-
-         count_leading_zeros (bm, d0);
-
-         if (bm == 0)
-           {
-             /* From (n1 >= d0) /\ (the most significant bit of d0 is set),
-                conclude (the most significant bit of n1 is set) /\ (the
-                leading quotient digit q1 = 1).
-
-                This special case is necessary, not an optimization.
-                (Shifts counts of SI_TYPE_SIZE are undefined.)  */
-
-             n1 -= d0;
-             q1 = 1;
-           }
-         else
-           {
-             _FP_W_TYPE n2;
-
-             /* Normalize.  */
-
-             b = _FP_W_TYPE_SIZE - bm;
-
-             d0 = d0 << bm;
-             n2 = n1 >> b;
-             n1 = (n1 << bm) | (n0 >> b);
-             n0 = n0 << bm;
-
-             udiv_qrnnd (q1, n1, n2, n1, d0);
-           }
-
-         /* n1 != d0...  */
-
-         udiv_qrnnd (q0, n0, n1, n0, d0);
-
-         /* Remainder in n0 >> bm.  */
-       }
-
-      r0 = n0 >> bm;
-      r1 = 0;
-#endif /* UDIV_NEEDS_NORMALIZATION */
-    }
-  else
-    {
-      if (d1 > n1)
-       {
-         /* 00 = nn / DD */
-
-         q0 = 0;
-         q1 = 0;
-
-         /* Remainder in n1n0.  */
-         r0 = n0;
-         r1 = n1;
-       }
-      else
-       {
-         /* 0q = NN / dd */
-
-         count_leading_zeros (bm, d1);
-         if (bm == 0)
-           {
-             /* From (n1 >= d1) /\ (the most significant bit of d1 is set),
-                conclude (the most significant bit of n1 is set) /\ (the
-                quotient digit q0 = 0 or 1).
-
-                This special case is necessary, not an optimization.  */
-
-             /* The condition on the next line takes advantage of that
-                n1 >= d1 (true due to program flow).  */
-             if (n1 > d1 || n0 >= d0)
-               {
-                 q0 = 1;
-                 sub_ddmmss (n1, n0, n1, n0, d1, d0);
-               }
-             else
-               q0 = 0;
-
-             q1 = 0;
-
-             r0 = n0;
-             r1 = n1;
-           }
-         else
-           {
-             _FP_W_TYPE m1, m0, n2;
-
-             /* Normalize.  */
-
-             b = _FP_W_TYPE_SIZE - bm;
-
-             d1 = (d1 << bm) | (d0 >> b);
-             d0 = d0 << bm;
-             n2 = n1 >> b;
-             n1 = (n1 << bm) | (n0 >> b);
-             n0 = n0 << bm;
-
-             udiv_qrnnd (q0, n1, n2, n1, d1);
-             umul_ppmm (m1, m0, q0, d0);
-
-             if (m1 > n1 || (m1 == n1 && m0 > n0))
-               {
-                 q0--;
-                 sub_ddmmss (m1, m0, m1, m0, d1, d0);
-               }
-
-             q1 = 0;
-
-             /* Remainder in (n1n0 - m1m0) >> bm.  */
-             sub_ddmmss (n1, n0, n1, n0, m1, m0);
-             r0 = (n1 << b) | (n0 >> bm);
-             r1 = n1 >> bm;
-           }
-       }
-    }
-
-  q[0] = q0; q[1] = q1;
-  r[0] = r0, r[1] = r1;
-}
index 56cf5fb13a54a728b94cac8ae52bd54d71d00abe..26ffb26cac3da1a72a13d98d4b8e704d645de509 100644 (file)
@@ -504,6 +504,8 @@ static int loop_set_status(struct loop_device *lo, struct loop_info *arg)
        if ((unsigned int) info.lo_encrypt_key_size > LO_KEY_SIZE)
                return -EINVAL;
        type = info.lo_encrypt_type; 
+       if (info.lo_encrypt_key_size == 0 && type == LO_CRYPT_XOR)
+               return -EINVAL;
        if (type >= MAX_LO_CRYPT || xfer_funcs[type] == NULL)
                return -EINVAL;
        err = loop_release_xfer(lo);
index 439e288a1672511ebe8aac53fd56074359df0e00..71b4e236e38bd8617c3c3c007aecf1bd8fdffd7b 100644 (file)
@@ -49,8 +49,25 @@ static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
        new = use_dma ? ((new & ~other) | bit) : (new & ~bit);
 
        if (new != *old) {
+               unsigned char stat;
+
+               /*
+                * Don't change DMA engine settings while Write Buffers
+                * are busy.
+                */
+               (void) pci_read_config_byte(dev, 0x43, &stat);
+               while (stat & 0x03) {
+                       udelay(1);
+                       (void) pci_read_config_byte(dev, 0x43, &stat);
+               }
+
                *old = new;
                (void) pci_write_config_dword(dev, 0x40, new);
+
+               /*
+                * And let things settle...
+                */
+               udelay(10);
        }
 
        __restore_flags(flags); /* local CPU only */
index cdd37ef465a0d84a1abadb853e611ee72252376a..2c500e24820a7f4864219392b709844920f82bf3 100644 (file)
@@ -543,6 +543,8 @@ static struct tvcard tvcards[] =
         { 3, 1, 0, 2,15, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0}},
         /* Pixelview PlayTV (bt878) */
         { 3, 4, 0, 2, 0x01e000, { 2, 0, 1, 1}, {0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 }},
+        /* "Leadtek WinView 601", */
+        { 3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0}, {0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007}},
 };
 #define TVCARDS (sizeof(tvcards)/sizeof(tvcard))
 
@@ -2036,6 +2038,41 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                                I2CWrite(&(btv->i2c), I2C_TDA9850,
                                        TDA9850_CON3, con3, 1);
                        }
+                  
+                      /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */
+                       if (btv->type == BTTV_WINVIEW_601) { 
+                          int bits_out, loops, vol, data;
+
+                          /* 32 levels logarithmic */
+                          vol = 32 - ((v.volume>>11));
+                          /* units */
+                           bits_out = (PT2254_DBS_IN_2>>(vol%5));
+                          /* tens */
+                           bits_out |= (PT2254_DBS_IN_10>>(vol/5));
+                          bits_out |= PT2254_L_CHANEL | PT2254_R_CHANEL;
+                          data = btread(BT848_GPIO_DATA);
+                          data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA|
+                                     WINVIEW_PT2254_STROBE);
+                          for (loops = 17; loops >= 0 ; loops--) {
+                               if (bits_out & (1<<loops))
+                                  data |=  WINVIEW_PT2254_DATA;
+                               else
+                                  data &= ~WINVIEW_PT2254_DATA;
+                              btwrite(data, BT848_GPIO_DATA);
+                              udelay(5);
+                              data |= WINVIEW_PT2254_CLK;
+                              btwrite(data, BT848_GPIO_DATA);
+                              udelay(5);
+                              data &= ~WINVIEW_PT2254_CLK;
+                              btwrite(data, BT848_GPIO_DATA);
+                          }
+                          data |=  WINVIEW_PT2254_STROBE;
+                          data &= ~WINVIEW_PT2254_DATA;
+                          btwrite(data, BT848_GPIO_DATA);
+                          udelay(10);                     
+                          data &= ~WINVIEW_PT2254_STROBE;
+                          btwrite(data, BT848_GPIO_DATA);
+                       }
                        if (btv->have_msp3400) 
                        {
                                 i2c_control_device(&(btv->i2c),
@@ -3033,6 +3070,9 @@ static void idcard(int i)
                case BTTV_VHX:
                        strcpy(btv->video_dev.name,"BT848(Aimslab-VHX)");
                        break;
+               case BTTV_WINVIEW_601:
+                       strcpy(btv->video_dev.name,"BT848(Leadtek WinView 601)");
+                       break;     
        }
        printk("%s\n",btv->video_dev.name);
        audio(btv, AUDIO_MUTE);
index bd6721956d48a12cc6cb0cd56a486eb31c230191..a305a0bc8915941bbb78be00ff92054efde020f4 100644 (file)
@@ -210,6 +210,7 @@ struct bttv
 #define BTTV_VHX           0x0e
 #define BTTV_ZOLTRIX       0x0f
 #define BTTV_PIXVIEWPLAYTV 0x10
+#define BTTV_WINVIEW_601   0x11
 
 #define AUDIO_TUNER        0x00
 #define AUDIO_RADIO        0x01
@@ -260,4 +261,12 @@ struct bttv
 #define TEA6300_FA         0x04                /* fader control */
 #define TEA6300_SW         0x05                /* mute and source switch */
 
+#define PT2254_L_CHANEL 0x10
+#define PT2254_R_CHANEL 0x08
+#define PT2254_DBS_IN_2 0x400
+#define PT2254_DBS_IN_10 0x20000
+#define WINVIEW_PT2254_CLK  0x40
+#define WINVIEW_PT2254_DATA 0x20
+#define WINVIEW_PT2254_STROBE 0x80
+
 #endif
index a632d25edfd6118b1514bde7fa181d0acc7cdfdb..31f81ca76ff416d076d6d01daf8244a1e3b58e83 100644 (file)
@@ -2,6 +2,9 @@
 
 /*
  *  Copyright (C) 1995-1997  Jan "Yenya" Kasprzak <kas@fi.muni.cz>
+ * 
+ *     5/25/1999 : Marcelo Tosatti <marcelo@conectiva.com.br>
+ *             fixed a deadlock in cosa_sppp_open 
  *
  *  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
@@ -599,6 +602,7 @@ static int cosa_sppp_open(struct device *d)
        if (chan->usage != 0) {
                printk(KERN_WARNING "%s: sppp_open called with usage count %d\n",
                        chan->name, chan->usage);
+               spin_unlock_irqrestore(&chan->cosa->lock, flags);
                return -EBUSY;
        }
        chan->setup_rx = sppp_setup_rx;
index d94e0efd6e6acf036a7c469b42db75fc71943f17..51af63aa4f2f7314b9468dc01532ad392a5acc25 100644 (file)
  * ftp's, which is significantly better than I get in DOS, so the overhead of
  * stopping and restarting the CU with each transmit is not prohibitive in
  * practice.
+ *
+ * Update by David Woodhouse 11/5/99:
+ *
+ * I've seen "CU wedged" messages in 16-bit mode, on the Alpha architecture.
+ * I assume that this is because 16-bit accesses are actually handled as two
+ * 8-bit accesses.
  */
+
+#ifdef __alpha__
+#define LOCKUP16 1
+#endif
+#ifndef LOCKUP16
+#define LOCKUP16 0
+#endif
   
 #include <linux/config.h>
 #include <linux/module.h>
@@ -297,7 +310,7 @@ static inline void clear_loopback(struct device *dev)
        outb(inb(dev->base_addr + Config) & ~2, dev->base_addr + Config);
 }
 
-static inline short int SHADOW(short int addr)
+static inline unsigned short int SHADOW(short int addr)
 {
        addr &= 0x1f;
        if (addr > 0xf) addr += 0x3ff0;
@@ -400,7 +413,10 @@ static int eexp_close(struct device *dev)
        outb(0,ioaddr+SIGNAL_CA);
        free_irq(irq,dev);
        outb(i586_RST,ioaddr+EEPROM_Ctrl);
-       release_region(ioaddr,16);
+       release_region(ioaddr, EEXP_IO_EXTENT);
+       release_region(ioaddr+0x4000, 16);
+       release_region(ioaddr+0x8000, 16);
+       release_region(ioaddr+0xc000, 16);
 
        MOD_DEC_USE_COUNT;
        return 0;
@@ -887,7 +903,7 @@ static void eexp_hw_tx_pio(struct device *dev, unsigned short *buf,
        struct net_local *lp = (struct net_local *)dev->priv;
        unsigned short ioaddr = dev->base_addr;
 
-       if (lp->width) {
+       if (LOCKUP16 || lp->width) {
                /* Stop the CU so that there is no chance that it
                   jumps off to a bogus address while we are writing the
                   pointer to the next transmit packet in 8-bit mode -- 
@@ -927,7 +943,7 @@ static void eexp_hw_tx_pio(struct device *dev, unsigned short *buf,
        if (lp->tx_head != lp->tx_reap)
                dev->tbusy = 0;
 
-       if (lp->width) {
+       if (LOCKUP16 || lp->width) {
                /* Restart the CU so that the packet can actually
                   be transmitted. (Zoltan Szilagyi 10-12-96) */
                scb_command(dev, SCB_CUresume);
index 64f6c327e911199898977ef186b39307afdd744e..1a7831e83506f26f7cd55d62798cce846788fad6 100644 (file)
@@ -1,18 +1,24 @@
 mainmenu_option next_comment
 comment 'Infrared-port device drivers'
 
-dep_tristate 'IrTTY (uses serial driver)' CONFIG_IRTTY_SIR $CONFIG_IRDA
-if [ "$CONFIG_IRTTY_SIR" != "n" ]; then
-  comment '   Dongle support' 
-  bool '   Serial dongle support' CONFIG_DONGLE
-  if [ "$CONFIG_DONGLE" != "n" ]; then
-    dep_tristate '   ESI JetEye PC dongle' CONFIG_ESI_DONGLE $CONFIG_IRTTY_SIR
-    dep_tristate '   ACTiSYS IR-220L and IR220L+ dongle' CONFIG_ACTISYS_DONGLE $CONFIG_IRTTY_SIR
-    dep_tristate '   Tekram IrMate 210B dongle' CONFIG_TEKRAM_DONGLE $CONFIG_IRTTY_SIR
-    dep_tristate '   Greenwich GIrBIL dongle' CONFIG_GIRBIL_DONGLE $CONFIG_IRTTY_SIR
-  fi
+comment 'SIR device drivers'
+dep_tristate 'IrTTY (uses Linux serial driver)' CONFIG_IRTTY_SIR $CONFIG_IRDA
+dep_tristate 'IrPORT (IrDA serial driver)' CONFIG_IRPORT_SIR $CONFIG_IRDA
+
+comment 'FIR device drivers'
+dep_tristate 'NSC PC87108' CONFIG_NSC_FIR  $CONFIG_IRDA
+dep_tristate 'Winbond W83977AF (IR)' CONFIG_WINBOND_FIR $CONFIG_IRDA
+dep_tristate 'Sharp UIRCC' CONFIG_SHARP_FIR $CONFIG_IRDA
+dep_tristate 'Toshiba Type-O IR Port' CONFIG_TOSHIBA_FIR $CONFIG_IRDA
+
+comment 'Dongle support' 
+bool 'Serial dongle support' CONFIG_DONGLE
+if [ "$CONFIG_DONGLE" != "n" ]; then
+  dep_tristate '   ESI JetEye PC dongle' CONFIG_ESI_DONGLE $CONFIG_IRDA
+  dep_tristate '   ACTiSYS IR-220L and IR220L+ dongle' CONFIG_ACTISYS_DONGLE $CONFIG_IRDA
+  dep_tristate '   Tekram IrMate 210B dongle' CONFIG_TEKRAM_DONGLE $CONFIG_IRDA
+  dep_tristate '   Greenwich GIrBIL dongle' CONFIG_GIRBIL_DONGLE $CONFIG_IRDA
+  dep_tristate '   Parallax LiteLink dongle' CONFIG_LITELINK_DONGLE $CONFIG_IRDA
 fi
-dep_tristate '  NSC PC87108' CONFIG_NSC_FIR  $CONFIG_IRDA
-dep_tristate '  Winbond W83977AF (IR)' CONFIG_WINBOND_FIR $CONFIG_IRDA
-dep_tristate '  Sharp UIRCC' CONFIG_SHARP_FIR $CONFIG_IRDA
+
 endmenu
index 6a7920a6e1c56695e466ea104825cb5cc82d21ba..bd691dcae7fc0c830c8fd058257546edcd27d9f3 100644 (file)
@@ -20,6 +20,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_IRPORT_SIR),y)
+L_OBJS += irport.o
+else
+  ifeq ($(CONFIG_IRPORT_SIR),m)
+  M_OBJS += irport.o
+  endif
+endif
+
 ifeq ($(CONFIG_NSC_FIR),y)
 L_OBJS += pc87108.o
 else
@@ -44,6 +52,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_TOSHIBA_FIR),y)
+L_OBJS += toshoboe.o
+else
+  ifeq ($(CONFIG_TOSHIBA_FIR),m)
+  M_OBJS += toshoboe.o
+  endif
+endif
+
 ifeq ($(CONFIG_ESI_DONGLE),y)
 L_OBJS += esi.o
 else
@@ -76,6 +92,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_LITELINK_DONGLE),y)
+L_OBJS += litelink.o
+else
+  ifeq ($(CONFIG_LITELINK_DONGLE),m)
+  M_OBJS += litelink.o
+  endif
+endif
+
 include $(TOPDIR)/Rules.make
 
 clean:
index 46ce2badfb85d66119ce98b04386141683913097..11fde80062e4f08392671622696d31a33fbccc48 100644 (file)
@@ -1,16 +1,16 @@
 /*********************************************************************
  *                
  * Filename:      actisys.c
- * Version:       0.5
+ * Version:       0.8
  * Description:   Implementation for the ACTiSYS IR-220L and IR-220L+ 
  *                dongles
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Wed Oct 21 20:02:35 1998
- * Modified at:   Mon Apr 12 11:56:35 1999
+ * Modified at:   Mon May 10 15:12:54 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
 #include <net/irda/irda.h>
 #include <net/irda/irmod.h>
 #include <net/irda/irda_device.h>
-#include <net/irda/irtty.h>
 #include <net/irda/dongle.h>
 
-static void actisys_reset( struct irda_device *dev, int unused);
-static void actisys_open( struct irda_device *idev, int type);
-static void actisys_close( struct irda_device *dev);
+static void actisys_reset(struct irda_device *dev, int unused);
+static void actisys_open(struct irda_device *idev, int type);
+static void actisys_close(struct irda_device *dev);
 static void actisys_change_speed( struct irda_device *dev, int baudrate);
-static void actisys_reset( struct irda_device *dev, int unused);
-static void actisys_init_qos( struct irda_device *idev, struct qos_info *qos);
+static void actisys_reset(struct irda_device *dev, int unused);
+static void actisys_init_qos(struct irda_device *idev, struct qos_info *qos);
 
 /* These are the baudrates supported */
 static int baud_rates[] = { 9600, 19200, 57600, 115200, 38400};
@@ -58,17 +57,37 @@ static struct dongle dongle = {
        actisys_init_qos,
 };
 
-__initfunc(void actisys_init(void))
+static struct dongle dongle_plus = {
+       ACTISYS_PLUS_DONGLE,
+       actisys_open,
+       actisys_close,
+       actisys_reset,
+       actisys_change_speed,
+       actisys_init_qos,
+};
+
+__initfunc(int actisys_init(void))
 {
-       irtty_register_dongle(&dongle);
+       int ret;
+
+       ret = irda_device_register_dongle(&dongle);
+       if (ret < 0)
+               return ret;
+       ret = irda_device_register_dongle(&dongle_plus);
+       if (ret < 0) {
+               irda_device_unregister_dongle(&dongle);
+               return ret;
+       }       
+       return 0;
 }
 
 void actisys_cleanup(void)
 {
-       irtty_unregister_dongle(&dongle);
+       irda_device_unregister_dongle(&dongle);
+       irda_device_unregister_dongle(&dongle_plus);
 }
 
-static void actisys_open( struct irda_device *idev, int type)
+static void actisys_open(struct irda_device *idev, int type)
 {
        strcat(idev->description, " <-> actisys");
 
@@ -78,8 +97,11 @@ static void actisys_open( struct irda_device *idev, int type)
        MOD_INC_USE_COUNT;
 }
 
-static void actisys_close( struct irda_device *dev)
+static void actisys_close(struct irda_device *idev)
 {
+       /* Power off dongle */
+       irda_device_set_dtr_rts(idev, FALSE, FALSE);
+
        MOD_DEC_USE_COUNT;
 }
 
@@ -90,25 +112,16 @@ static void actisys_close( struct irda_device *dev)
  *    To cycle through the available baud rates, pulse RTS low for a few
  *    ms.  
  */
-static void actisys_change_speed( struct irda_device *idev, int baudrate)
+static void actisys_change_speed(struct irda_device *idev, int baudrate)
 {
-        struct irtty_cb *self;
-        struct tty_struct *tty;
-        struct termios old_termios;
-       int cflag;
         int current_baudrate;
         int index = 0;
        
-       DEBUG( 4, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
 
-       ASSERT( idev != NULL, return;);
-       ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
-       
-       self = (struct irtty_cb *) idev->priv;
+       ASSERT(idev != NULL, return;);
+       ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
        
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == IRTTY_MAGIC, return;);
-
        current_baudrate = idev->qos.baud_rate.value;
 
        /* Find the correct baudrate index for the currently used baudrate */
@@ -117,69 +130,34 @@ static void actisys_change_speed( struct irda_device *idev, int baudrate)
 
         DEBUG( 4, __FUNCTION__ "(), index=%d\n", index);
 
-       if ( !self->tty)
-               return;
-
-       tty = self->tty;
-
        /* Cycle through avaiable baudrates until we reach the correct one */
-        while ( current_baudrate != baudrate) {        
-                DEBUG( 4, __FUNCTION__ "(), current baudrate = %d\n",
-                       baud_rates[index]);
+        while (current_baudrate != baudrate) { 
+                DEBUG(4, __FUNCTION__ "(), current baudrate = %d\n",
+                     baud_rates[index]);
                
                /* Set DTR, clear RTS */
-               irtty_set_dtr_rts(tty, TRUE, FALSE);
+               irda_device_set_dtr_rts(idev, TRUE, FALSE);
                
                /* Wait at a few ms */
                current->state = TASK_INTERRUPTIBLE;
                schedule_timeout(2);
 
                /* Set DTR, Set RTS */
-               irtty_set_dtr_rts(tty, TRUE, TRUE);
+               irda_device_set_dtr_rts(idev, TRUE, TRUE);
                
                /* Wait at a few ms again */
                current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout( 2);
+               schedule_timeout(2);
 
                 /* Go to next baudrate */
-               if ( idev->io.dongle_id == ACTISYS_DONGLE)
+               if (idev->io.dongle_id == ACTISYS_DONGLE)
                         index = (index+1) % 4; /* IR-220L */
                else
                         index = (index+1) % 5; /* IR-220L+ */
 
                 current_baudrate = baud_rates[index];
         }
-       DEBUG(4, __FUNCTION__ "(), current baudrate = %d\n", 
-             baud_rates[index]);
-
-       /* Now change the speed of the serial port */
-       old_termios = *(tty->termios);
-       cflag = tty->termios->c_cflag;
-
-       cflag &= ~CBAUD;
-
-        switch ( baudrate) {
-        case 9600:
-        default:
-               cflag |= B9600;
-               break;
-       case 19200:
-               cflag |= B19200;
-               break;
-       case 38400:
-               cflag |= B38400;
-               break;
-       case 57600:
-               cflag |= B57600;
-               break;
-       case 115200:
-               cflag |= B115200;
-               break;
-       }
-
-       /* Change speed of serial port */
-       tty->termios->c_cflag = cflag;
-       tty->driver.set_termios( tty, &old_termios);
+       DEBUG(4, __FUNCTION__ "(), current baudrate = %d\n",baud_rates[index]);
 }
 
 /*
@@ -191,32 +169,20 @@ static void actisys_change_speed( struct irda_device *idev, int baudrate)
  *     1. Clear DTR for a few ms.
  *
  */
-static void actisys_reset( struct irda_device *idev, int unused)
+static void actisys_reset(struct irda_device *idev, int unused)
 {
-       struct irtty_cb *self;
-        struct tty_struct *tty;
-
-       ASSERT( idev != NULL, return;);
-       ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
-       
-       self = (struct irtty_cb *) idev->priv;
+       ASSERT(idev != NULL, return;);
+       ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
        
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == IRTTY_MAGIC, return;);
-
-       tty = self->tty;
-       if ( !tty)
-               return;
-
        /* Clear DTR */
-       irtty_set_dtr_rts(tty, FALSE, TRUE);
+       irda_device_set_dtr_rts(idev, FALSE, TRUE);
 
        /* Sleep 10-20 ms*/
        current->state = TASK_INTERRUPTIBLE;
        schedule_timeout(2);
        
        /* Go back to normal mode */
-       irtty_set_dtr_rts(tty, TRUE, TRUE);
+       irda_device_set_dtr_rts(idev, TRUE, TRUE);
        
        idev->qos.baud_rate.value = 9600;
 }
@@ -227,12 +193,12 @@ static void actisys_reset( struct irda_device *idev, int unused)
  *    Initialize QoS capabilities
  *
  */
-static void actisys_init_qos( struct irda_device *idev, struct qos_info *qos)
+static void actisys_init_qos(struct irda_device *idev, struct qos_info *qos)
 {
        qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
 
        /* Remove support for 38400 if this is not a 220L+ dongle */
-       if ( idev->io.dongle_id == ACTISYS_DONGLE)
+       if (idev->io.dongle_id == ACTISYS_DONGLE)
                qos->baud_rate.bits &= ~IR_38400;
        
        qos->min_turn_time.bits &= 0x40; /* Needs 0.01 ms */
@@ -251,8 +217,7 @@ MODULE_DESCRIPTION("ACTiSYS IR-220L and IR-220L+ dongle driver");
  */
 int init_module(void)
 {
-       actisys_init();
-       return(0);
+       return actisys_init();
 }
 
 /*
index 5395d2829688943e9797fe29c3092d69e83b8c85..b12885846bc74870a99673eabeaae4148005721b 100644 (file)
@@ -1,17 +1,17 @@
 /*********************************************************************
  *                
  * Filename:      esi.c
- * Version:       1.2
+ * Version:       1.4
  * Description:   Driver for the Extended Systems JetEye PC dongle
  * Status:        Experimental.
  * Author:        Thomas Davis, <ratbert@radiks.net>
  * Created at:    Sat Feb 21 18:54:38 1998
- * Modified at:   Mon Apr 12 11:55:30 1999
+ * Modified at:   Mon May 10 15:13:12 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:      esi.c
  *
+ *     Copyright (c) 1998-1999, Dag Brattli, <dagb@cs.uit.no>
  *     Copyright (c) 1998, Thomas Davis, <ratbert@radiks.net>,
- *     Copyright (c) 1998, Dag Brattli,  <dagb@cs.uit.no>
  *     All Rights Reserved.
  *
  *     This program is free software; you can redistribute it and/or
 #include <net/irda/irtty.h>
 #include <net/irda/dongle.h>
 
-static void esi_open( struct irda_device *idev, int type);
-static void esi_close( struct irda_device *driver);
-static void esi_change_speed( struct irda_device *idev, int baud);
-static void esi_reset( struct irda_device *idev, int unused);
-static void esi_qos_init( struct irda_device *idev, struct qos_info *qos);
+static void esi_open(struct irda_device *idev, int type);
+static void esi_close(struct irda_device *driver);
+static void esi_change_speed(struct irda_device *idev, int baud);
+static void esi_reset(struct irda_device *idev, int unused);
+static void esi_qos_init(struct irda_device *idev, struct qos_info *qos);
 
 static struct dongle dongle = {
        ESI_DONGLE,
@@ -58,17 +58,17 @@ static struct dongle dongle = {
 
 __initfunc(int esi_init(void))
 {
-       return irtty_register_dongle(&dongle);
+       return irda_device_register_dongle(&dongle);
 }
 
 void esi_cleanup(void)
 {
-       irtty_unregister_dongle( &dongle);
+       irda_device_unregister_dongle(&dongle);
 }
 
-static void esi_open( struct irda_device *idev, int type)
+static void esi_open(struct irda_device *idev, int type)
 {
-       strcat( idev->description, " <-> esi");
+       strcat(idev->description, " <-> esi");
 
        idev->io.dongle_id = type;
        idev->flags |= IFF_DONGLE;
@@ -76,8 +76,11 @@ static void esi_open( struct irda_device *idev, int type)
        MOD_INC_USE_COUNT;
 }
 
-static void esi_close( struct irda_device *driver)
-{
+static void esi_close(struct irda_device *idev)
+{              
+       /* Power off dongle */
+       irda_device_set_dtr_rts(idev, FALSE, FALSE);
+
        MOD_DEC_USE_COUNT;
 }
 
@@ -87,54 +90,30 @@ static void esi_close( struct irda_device *driver)
  *    Set the speed for the Extended Systems JetEye PC ESI-9680 type dongle
  *
  */
-static void esi_change_speed( struct irda_device *idev, int baud)
+static void esi_change_speed(struct irda_device *idev, int baud)
 {
-       struct irtty_cb *self;
-       struct tty_struct *tty;
        int dtr, rts;
-        struct termios old_termios;
-       int cflag;
-       
-       ASSERT( idev != NULL, return;);
-       ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
        
-       self = (struct irtty_cb *) idev->priv;
-       
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == IRTTY_MAGIC, return;);
-
-       if ( !self->tty)
-               return;
-
-       tty = self->tty;
+       ASSERT(idev != NULL, return;);
+       ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
        
-       old_termios = *(tty->termios);
-       cflag = tty->termios->c_cflag;
-
-       cflag &= ~CBAUD;
-
        switch (baud) {
        case 19200:
-               cflag |= B19200;
                dtr = TRUE;
                rts = FALSE;
                break;
        case 115200:
-               cflag |= B115200;
                dtr = rts = TRUE;
                break;
        case 9600:
        default:
-               cflag |= B9600;
                dtr = FALSE;
                rts = TRUE;
                break;
        }
-       /* Change speed of serial driver */
-       tty->termios->c_cflag = cflag;
-       tty->driver.set_termios(tty, &old_termios);
 
-       irtty_set_dtr_rts(tty, dtr, rts);
+       /* Change speed of dongle */
+       irda_device_set_dtr_rts(idev, dtr, rts);
 }
 
 static void esi_reset( struct irda_device *idev, int unused)
@@ -148,14 +127,17 @@ static void esi_reset( struct irda_device *idev, int unused)
  *    Init QoS capabilities for the dongle
  *
  */
-static void esi_qos_init( struct irda_device *idev, struct qos_info *qos)
+static void esi_qos_init(struct irda_device *idev, struct qos_info *qos)
 {
        qos->baud_rate.bits &= IR_9600|IR_19200|IR_115200;
        qos->min_turn_time.bits &= 0x01; /* Needs at least 10 ms */
 }
 
 #ifdef MODULE
-               
+
+MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
+MODULE_DESCRIPTION("Extended Systems JetEye PC dongle driver");
+
 /*
  * Function init_module (void)
  *
index 128b32a23e22d209800394063c55cb60f9423fcb..3b06f3838ad7dd925ca47aa42cda21e21d6700c7 100644 (file)
@@ -1,12 +1,12 @@
 /*********************************************************************
  *                
  * Filename:      girbil.c
- * Version:       1.0
+ * Version:       1.1
  * Description:   Implementation for the Greenwich GIrBIL dongle
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Feb  6 21:02:33 1999
- * Modified at:   Sat Apr 10 19:53:12 1999
+ * Modified at:   Mon May 10 16:01:33 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
@@ -80,19 +80,19 @@ static struct dongle dongle = {
        girbil_init_qos,
 };
 
-__initfunc(void girbil_init(void))
+__initfunc(int girbil_init(void))
 {
-       irtty_register_dongle(&dongle);
+       return irda_device_register_dongle(&dongle);
 }
 
 void girbil_cleanup(void)
 {
-       irtty_unregister_dongle(&dongle);
+       irda_device_unregister_dongle(&dongle);
 }
 
 static void girbil_open(struct irda_device *idev, int type)
 {
-       strcat( idev->description, " <-> girbil");
+       strcat(idev->description, " <-> girbil");
 
        idev->io.dongle_id = type;
        idev->flags |= IFF_DONGLE;
@@ -100,8 +100,11 @@ static void girbil_open(struct irda_device *idev, int type)
        MOD_INC_USE_COUNT;
 }
 
-static void girbil_close(struct irda_device *dev)
+static void girbil_close(struct irda_device *idev)
 {
+       /* Power off dongle */
+       irda_device_set_dtr_rts(idev, FALSE, FALSE);
+
        MOD_DEC_USE_COUNT;
 }
 
@@ -114,71 +117,42 @@ static void girbil_close(struct irda_device *dev)
  */
 static void girbil_change_speed(struct irda_device *idev, int speed)
 {
-       struct irtty_cb *self;
-       struct tty_struct *tty;
-       struct termios old_termios;
-       int cflag;
        __u8 control[2];
        
        ASSERT(idev != NULL, return;);
        ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
        
-       self = (struct irtty_cb *) idev->priv;
-       
-       ASSERT(self != NULL, return;); 
-       ASSERT(self->magic == IRTTY_MAGIC, return;);
-       
-       if (!self->tty)
-               return;
-
-       tty = self->tty;
-       
-       old_termios = *(tty->termios);
-       cflag = tty->termios->c_cflag;
-
-       cflag &= ~CBAUD;
-
        switch (speed) {
        case 9600:
        default:
-               cflag |= B9600;
                control[0] = GIRBIL_9600;
                break;
        case 19200:
-               cflag |= B19200;
                control[0] = GIRBIL_19200;
                break;
        case 34800:
-               cflag |= B38400;
                control[0] = GIRBIL_38400;
                break;
        case 57600:
-               cflag |= B57600;
                control[0] = GIRBIL_57600;
                break;
        case 115200:
-               cflag |= B115200;
                control[0] = GIRBIL_115200;
                break;
        }
        control[1] = GIRBIL_LOAD;
 
        /* Set DTR and Clear RTS to enter command mode */
-       irtty_set_dtr_rts(tty, FALSE, TRUE);
+       irda_device_set_dtr_rts(idev, FALSE, TRUE);
 
        /* Write control bytes */
-       if (tty->driver.write)
-               tty->driver.write(self->tty, 0, control, 2);
+       irda_device_raw_write(idev, control, 2);
 
        current->state = TASK_INTERRUPTIBLE;
        schedule_timeout(2);
        
        /* Go back to normal mode */
-       irtty_set_dtr_rts(tty, TRUE, TRUE);
-
-       /* Now change the speed of the serial port */
-       tty->termios->c_cflag = cflag;
-       tty->driver.set_termios(tty, &old_termios);     
+       irda_device_set_dtr_rts(idev, TRUE, TRUE);
 }
 
 /*
@@ -193,44 +167,32 @@ static void girbil_change_speed(struct irda_device *idev, int speed)
  */
 void girbil_reset(struct irda_device *idev, int unused)
 {
-       struct irtty_cb *self;
-       struct tty_struct *tty;
        __u8 control = GIRBIL_TXEN | GIRBIL_RXEN;
 
        ASSERT(idev != NULL, return;);
        ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
        
-       self = (struct irtty_cb *) idev->priv;
-       
-       ASSERT(self != NULL, return;);
-       ASSERT(self->magic == IRTTY_MAGIC, return;);
-
-       tty = self->tty;
-       if (!tty)
-               return;
-
        /* Reset dongle */
-       irtty_set_dtr_rts(tty, TRUE, FALSE);
+       irda_device_set_dtr_rts(idev, TRUE, FALSE);
 
        /* Sleep at least 5 ms */
        current->state = TASK_INTERRUPTIBLE;
        schedule_timeout(2);
        
        /* Set DTR and clear RTS to enter command mode */
-       irtty_set_dtr_rts(tty, FALSE, TRUE);
+       irda_device_set_dtr_rts(idev, FALSE, TRUE);
 
        current->state = TASK_INTERRUPTIBLE;
        schedule_timeout(2);
 
        /* Write control byte */
-       if (tty->driver.write)
-               tty->driver.write(self->tty, 0, &control, 1);
+       irda_device_raw_write(idev, &control, 1);
 
        current->state = TASK_INTERRUPTIBLE;
        schedule_timeout(2);
 
        /* Go back to normal mode */
-       irtty_set_dtr_rts(tty, TRUE, TRUE);
+       irda_device_set_dtr_rts(idev, TRUE, TRUE);
 }
 
 /*
@@ -258,8 +220,7 @@ MODULE_DESCRIPTION("Greenwich GIrBIL dongle driver");
  */
 int init_module(void)
 {
-       girbil_init();
-       return(0);
+       return girbil_init();
 }
 
 /*
index 5ea6dba738a0c0cdbef075191914c9cf5ad4d456..7c8864f5d79ef04cfb9d2525445b5e4545ca6bb3 100644 (file)
 
 #define IO_EXTENT 8
 
-/* static unsigned int io[]  = { 0x3e8, ~0, ~0, ~0 }; */
-/* static unsigned int irq[] = { 11, 0, 0, 0 }; */
+/* 
+ * Currently you'll need to set these values using insmod like this:
+ * insmod irport io=0x3e8 irq=11
+ */
+static unsigned int io[]  = { ~0, ~0, ~0, ~0 };
+static unsigned int irq[] = { 0, 0, 0, 0 };
+
+static unsigned int qos_mtt_bits = 0x03;
+
+static struct irda_device *dev_self[] = { NULL, NULL, NULL, NULL};
+static char *driver_name = "irport";
+
+static int irport_open(int i, unsigned int iobase, unsigned int irq);
+static int irport_close(struct irda_device *idev);
 
 static void irport_write_wakeup(struct irda_device *idev);
 static int  irport_write(int iobase, int fifo_size, __u8 *buf, int len);
 static void irport_receive(struct irda_device *idev);
 
+static int  irport_net_init(struct device *dev);
+static int  irport_net_open(struct device *dev);
+static int  irport_net_close(struct device *dev);
+static void irport_wait_until_sent(struct irda_device *idev);
+static int  irport_is_receiving(struct irda_device *idev);
+static void irport_set_dtr_rts(struct irda_device *idev, int dtr, int rts);
+static int  irport_raw_write(struct irda_device *idev, __u8 *buf, int len);
+
 __initfunc(int irport_init(void))
 {
-/*     int i; */
-
-/*     for ( i=0; (io[i] < 2000) && (i < 4); i++) { */
-/*             int ioaddr = io[i]; */
-/*             if (check_region(ioaddr, IO_EXTENT)) */
-/*                     continue; */
-/*             if (irport_open( i, io[i], io2[i], irq[i], dma[i]) == 0) */
-/*                     return 0; */
-/*     } */
-/*     return -ENODEV; */
-       return 0;
+       int i;
+
+       for (i=0; (io[i] < 2000) && (i < 4); i++) {
+               int ioaddr = io[i];
+               if (check_region(ioaddr, IO_EXTENT))
+                       continue;
+               if (irport_open(i, io[i], irq[i]) == 0)
+                       return 0;
+       }
+       /* 
+        * Maybe something failed, but we can still be usable for FIR drivers 
+        */
+       return 0;
 }
 
 /*
- * Function pc87108_cleanup ()
+ * Function irport_cleanup ()
  *
- *    Close all configured chips
+ *    Close all configured ports
  *
  */
 #ifdef MODULE
 static void irport_cleanup(void)
 {
-/*     int i; */
+       int i;
 
         DEBUG( 4, __FUNCTION__ "()\n");
 
-       /* for ( i=0; i < 4; i++) { */
-/*             if ( dev_self[i]) */
-/*                     irport_close( &(dev_self[i]->idev)); */
-/*     } */
+       for (i=0; i < 4; i++) {
+               if (dev_self[i])
+                       irport_close(dev_self[i]);
+       }
 }
 #endif /* MODULE */
 
-/*
- * Function irport_open (void)
- *
- *    Start IO port 
- *
- */
-int irport_open(int iobase)
+static int irport_open(int i, unsigned int iobase, unsigned int irq)
 {
-       DEBUG(4, __FUNCTION__ "(), iobase=%#x\n", iobase);
+       struct irda_device *idev;
+       int ret;
+
+       DEBUG( 0, __FUNCTION__ "()\n");
+
+/*     if (irport_probe(iobase, irq) == -1) */
+/*             return -1; */
+
+       /*
+        *  Allocate new instance of the driver
+        */
+       idev = kmalloc(sizeof(struct irda_device), GFP_KERNEL);
+       if (idev == NULL) {
+               printk( KERN_ERR "IrDA: Can't allocate memory for "
+                       "IrDA control block!\n");
+               return -ENOMEM;
+       }
+       memset(idev, 0, sizeof(struct irda_device));
+   
+       /* Need to store self somewhere */
+       dev_self[i] = idev;
+
+       /* Initialize IO */
+       idev->io.iobase2   = iobase;
+        idev->io.irq2      = irq;
+        idev->io.io_ext    = IO_EXTENT;
+        idev->io.fifo_size = 16;
+
+       /* Lock the port that we need */
+       ret = check_region(idev->io.iobase2, idev->io.io_ext);
+       if (ret < 0) { 
+               DEBUG( 0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
+                      idev->io.iobase2);
+               /* w83977af_cleanup( self->idev);  */
+               return -ENODEV;
+       }
+       request_region(idev->io.iobase2, idev->io.io_ext, idev->name);
+
+       /* Initialize QoS for this device */
+       irda_init_max_qos_capabilies(&idev->qos);
+       
+       idev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
+               IR_115200;
+
+       idev->qos.min_turn_time.bits = qos_mtt_bits;
+       irda_qos_bits_to_value(&idev->qos);
+       
+       idev->flags = IFF_SIR|IFF_PIO;
+
+       /* Specify which buffer allocation policy we need */
+       idev->rx_buff.flags = GFP_KERNEL;
+       idev->tx_buff.flags = GFP_KERNEL;
+
+       idev->rx_buff.truesize = 4000; 
+       idev->tx_buff.truesize = 4000;
+       
+       /* Initialize callbacks */
+       idev->change_speed    = irport_change_speed;
+       idev->wait_until_sent = irport_wait_until_sent;
+        idev->is_receiving    = irport_is_receiving;
+       idev->set_dtr_rts     = irport_set_dtr_rts;
+       idev->raw_write       = irport_raw_write;
+
+       /* Override the network functions we need to use */
+       idev->netdev.init            = irport_net_init;
+       idev->netdev.hard_start_xmit = irport_hard_xmit;
+       idev->netdev.open            = irport_net_open;
+       idev->netdev.stop            = irport_net_close;
+
+       /* Open the IrDA device */
+       irda_device_open(idev, driver_name, NULL);
+       
+       return 0;
+}
+
+static int irport_close(struct irda_device *idev)
+{
+       DEBUG(0, __FUNCTION__ "()\n");
+
+       ASSERT(idev != NULL, return -1;);
+       ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+
+       /* Release the PORT that this driver is using */
+       DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n", 
+             idev->io.iobase2);
+       release_region(idev->io.iobase2, idev->io.io_ext);
+
+       irda_device_close(idev);
+
+       kfree(idev);
+
+       return 0;
+}
 
+void irport_start(int iobase)
+{
        /* Initialize UART */
        outb(UART_LCR_WLEN8, iobase+UART_LCR);  /* Reset DLAB */
        outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase+UART_MCR);
@@ -123,24 +233,29 @@ int irport_open(int iobase)
        /* Turn on interrups */
        outb((UART_IER_RLSI | UART_IER_RDI), iobase+UART_IER);
 
-       return 0;
+}
+
+void irport_stop(int iobase)
+{
+       /* Reset UART */
+       outb(0, iobase+UART_MCR);
+       
+       /* Turn off interrupts */
+       outb(0, iobase+UART_IER);
 }
 
 /*
- * Function irport_cleanup ()
+ * Function irport_probe (void)
  *
- *    Stop IO port
+ *    Start IO port 
  *
  */
-void irport_close(int iobase) 
+int irport_probe(int iobase)
 {
-       DEBUG(4, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "(), iobase=%#x\n", iobase);
 
-       /* Reset UART */
-       outb(0, iobase+UART_MCR);
 
-       /* Turn off interrupts */
-       outb(0, iobase+UART_IER);
+       return 0;
 }
 
 /*
@@ -149,14 +264,23 @@ void irport_close(int iobase)
  *    Set speed of port to specified baudrate
  *
  */
-void irport_change_speed( int iobase, int speed) 
+void irport_change_speed(struct irda_device *idev, int speed)
 {
+       int iobase; 
        int fcr;    /* FIFO control reg */
        int lcr;    /* Line control reg */
        int divisor;
 
        DEBUG( 0, __FUNCTION__ "(), Setting speed to: %d\n", speed);
 
+       ASSERT(idev != NULL, return;);
+       ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
+
+       iobase = idev->io.iobase2;
+       
+       /* Update accounting for new speed */
+       idev->io.baudrate = speed;
+
        /* Turn off interrupts */
        outb(0, iobase+UART_IER); 
 
@@ -373,8 +497,145 @@ void irport_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        idev->netdev.interrupt = 0;
 }
 
+static int irport_net_init(struct device *dev)
+{
+       /* Set up to be a normal IrDA network device driver */
+       irda_device_setup(dev);
+
+       /* Insert overrides below this line! */
+
+       return 0;
+}
+
+/*
+ * Function irport_net_open (dev)
+ *
+ *    
+ *
+ */
+static int irport_net_open(struct device *dev)
+{
+       struct irda_device *idev;
+       int iobase;
+
+       ASSERT(dev != NULL, return -1;);
+       idev = (struct irda_device *) dev->priv;
+
+       iobase = idev->io.iobase2;
+
+       if (request_irq(idev->io.irq2, irport_interrupt, 0, idev->name, 
+                       (void *) idev)) {
+               return -EAGAIN;
+       }
+
+       /* Ready to play! */
+       dev->tbusy = 0;
+       dev->interrupt = 0;
+       dev->start = 1;
+
+       MOD_INC_USE_COUNT;
+
+       irport_start(iobase);
+
+       return 0;
+}
+
+/*
+ * Function irport_net_close (idev)
+ *
+ *    
+ *
+ */
+static int irport_net_close(struct device *dev)
+{
+       struct irda_device *idev;
+       int iobase;
+
+       ASSERT(dev != NULL, return -1;);
+       idev = (struct irda_device *) dev->priv;
+
+       DEBUG(4, __FUNCTION__ "()\n");
+
+       iobase = idev->io.iobase2;
+
+       irport_stop(iobase);
+
+       /* Stop device */
+       dev->tbusy = 1;
+       dev->start = 0;
+
+       free_irq(idev->io.irq2, idev);
+
+       MOD_DEC_USE_COUNT;
+
+       return 0;
+}
+
+static void irport_wait_until_sent(struct irda_device *idev)
+{
+       current->state = TASK_INTERRUPTIBLE;
+       schedule_timeout(60*HZ/1000);
+}
+
+static int irport_is_receiving(struct irda_device *idev)
+{
+       return (idev->rx_buff.state != OUTSIDE_FRAME);
+}
+
+/*
+ * Function irtty_set_dtr_rts (tty, dtr, rts)
+ *
+ *    This function can be used by dongles etc. to set or reset the status
+ *    of the dtr and rts lines
+ */
+static void irport_set_dtr_rts(struct irda_device *idev, int dtr, int rts)
+{
+       int iobase;
+
+       ASSERT(idev != NULL, return;);
+       ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
+
+       iobase = idev->io.iobase2;
+
+       if (dtr)
+               dtr = UART_MCR_DTR;
+       if (rts)
+               rts = UART_MCR_RTS;
+
+       outb(dtr|rts|UART_MCR_OUT2, iobase+UART_MCR);
+}
+
+static int irport_raw_write(struct irda_device *idev, __u8 *buf, int len)
+{
+       int iobase;
+       int actual = 0;
+
+       ASSERT(idev != NULL, return -1;);
+       ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+
+       iobase = idev->io.iobase2;
+
+       /* Tx FIFO should be empty! */
+       if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
+               DEBUG( 0, __FUNCTION__ "(), failed, fifo not empty!\n");
+               return -1;
+       }
+        
+       /* Fill FIFO with current frame */
+       while (actual < len) {
+               /* Transmit next byte */
+               outb(buf[actual], iobase+UART_TX);
+               actual++;
+       }
+
+       return actual;
+}
+
 #ifdef MODULE
 
+MODULE_PARM(io, "1-4i");
+MODULE_PARM(irq, "1-4i");
+
 /*
  * Function cleanup_module (void)
  *
@@ -393,11 +654,7 @@ void cleanup_module(void)
  */
 int init_module(void)
 {
-       if (irport_init() < 0) {
-               cleanup_module();
-               return 1;
-       }
-       return(0);
+       return irport_init();
 }
 
 #endif /* MODULE */
index cc7ab91a4c498c5016ac2accec3c6acd02774e3b..ad8d2dc0ef10483589e733ac54afa96033a54c02 100644 (file)
@@ -6,12 +6,12 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Dec  9 21:18:38 1997
- * Modified at:   Thu Apr 22 09:20:24 1999
+ * Modified at:   Mon May 10 15:45:50 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       slip.c by Laurence Culhane,   <loz@holmes.demon.co.uk>
  *                          Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  * 
- *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
 #include <net/irda/irlap.h>
 #include <net/irda/timer.h>
 #include <net/irda/irda_device.h>
-#include <linux/kmod.h>
 
 static hashbin_t *irtty = NULL;
-static hashbin_t *dongles = NULL;
 
 static struct tty_ldisc irda_ldisc;
 
-static int irtty_hard_xmit(struct sk_buff *skb, struct device *dev);
+static int qos_mtt_bits = 0x03;      /* 5 ms or more */
+
+static int  irtty_hard_xmit(struct sk_buff *skb, struct device *dev);
 static void irtty_wait_until_sent(struct irda_device *driver);
-static int irtty_is_receiving(struct irda_device *idev);
-static int irtty_net_init(struct device *dev);
-static int irtty_net_open(struct device *dev);
-static int irtty_net_close(struct device *dev);
+static int  irtty_is_receiving(struct irda_device *idev);
+static void irtty_set_dtr_rts(struct irda_device *idev, int dtr, int rts);
+static int  irtty_raw_write(struct irda_device *idev, __u8 *buf, int len);
+static int  irtty_net_init(struct device *dev);
+static int  irtty_net_open(struct device *dev);
+static int  irtty_net_close(struct device *dev);
 
 static int  irtty_open(struct tty_struct *tty);
 static void irtty_close(struct tty_struct *tty);
@@ -73,13 +75,6 @@ __initfunc(int irtty_init(void))
                return -ENOMEM;
        }
 
-       dongles = hashbin_new(HB_LOCAL);
-       if (dongles == NULL) {
-               printk(KERN_WARNING 
-                      "IrDA: Can't allocate dongles hashbin!\n");
-               return -ENOMEM;
-       }
-
        /* Fill in our line protocol discipline, and register it */
        memset(&irda_ldisc, 0, sizeof( irda_ldisc));
 
@@ -132,7 +127,6 @@ static void irtty_cleanup(void)
         *  function to hashbin_destroy().
         */
        hashbin_delete(irtty, NULL);
-       hashbin_delete(dongles, NULL);
 }
 #endif /* MODULE */
 
@@ -201,7 +195,7 @@ static int irtty_open(struct tty_struct *tty)
        /* The only value we must override it the baudrate */
        self->idev.qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
                IR_115200;
-       self->idev.qos.min_turn_time.bits = 0x0f;
+       self->idev.qos.min_turn_time.bits = qos_mtt_bits;
        self->idev.flags = IFF_SIR | IFF_PIO;
        irda_qos_bits_to_value(&self->idev.qos);
 
@@ -216,7 +210,8 @@ static int irtty_open(struct tty_struct *tty)
        /* Initialize callbacks */
        self->idev.change_speed    = irtty_change_speed;
        self->idev.is_receiving    = irtty_is_receiving;
-       /* self->idev.is_tbusy        = irtty_is_tbusy; */
+       self->idev.set_dtr_rts     = irtty_set_dtr_rts;
+       self->idev.raw_write       = irtty_raw_write;
        self->idev.wait_until_sent = irtty_wait_until_sent;
 
        /* Override the network functions we need to use */
@@ -248,10 +243,6 @@ static void irtty_close(struct tty_struct *tty)
        ASSERT(self != NULL, return;);
        ASSERT(self->magic == IRTTY_MAGIC, return;);
 
-       /* We are not using any dongle anymore! */
-       if (self->dongle_q)
-               self->dongle_q->dongle->close(&self->idev);
-
        /* Remove driver */
        irda_device_close(&self->idev);
 
@@ -358,68 +349,6 @@ static void irtty_change_speed(struct irda_device *idev, int baud)
        self->tty->driver.set_termios(self->tty, &old_termios);
 }
 
-/*
- * Function irtty_init_dongle (self, type)
- *
- *    Initialize attached dongle. Warning, must be called with a process
- *    context!
- */
-static void irtty_init_dongle(struct irtty_cb *self, int type)
-{
-       struct dongle_q *node;
-
-       ASSERT(self != NULL, return;);
-       ASSERT(self->magic == IRTTY_MAGIC, return;);
-
-#ifdef CONFIG_KMOD
-       /* Try to load the module needed */
-       switch( type) {
-       case ESI_DONGLE:
-               MESSAGE("IrDA: Trying to initialize ESI dongle!\n");
-               request_module("esi");
-               break;
-       case TEKRAM_DONGLE:
-               MESSAGE("IrDA: Trying to initialize Tekram dongle!\n");
-               request_module("tekram");
-               break;
-       case ACTISYS_DONGLE:     /* FALLTHROUGH */
-       case ACTISYS_PLUS_DONGLE:
-               MESSAGE("IrDA: Trying to initialize ACTiSYS dongle!\n");
-               request_module("actisys");
-               break;
-       case GIRBIL_DONGLE:
-               MESSAGE("IrDA: Trying to initialize GIrBIL dongle!\n");
-               request_module("girbil");
-               break;
-       default:
-               ERROR("Unknown dongle type!\n");
-               return;
-       }
-#endif /* CONFIG_KMOD */
-
-       node = hashbin_find(dongles, type, NULL);
-       if ( !node) {
-               ERROR("Unable to find requested dongle\n");
-               return;
-       }
-       self->dongle_q = node;
-
-       /* Use this change speed function instead of the default */
-       self->idev.change_speed = node->dongle->change_speed;
-
-       /*
-        * Now initialize the dongle!
-        */
-       node->dongle->open(&self->idev, type);
-       node->dongle->qos_init(&self->idev, &self->idev.qos);
-       
-       /* Reset dongle */
-       node->dongle->reset(&self->idev, 0);
-
-       /* Set to default baudrate */
-       node->dongle->change_speed(&self->idev, 9600);
-}
-
 /*
  * Function irtty_ioctl (tty, file, cmd, arg)
  *
@@ -452,7 +381,7 @@ static int irtty_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
                break;
        case IRTTY_IOCTDONGLE:
                /* Initialize dongle */
-               irtty_init_dongle(self, (int) arg);
+               irda_device_init_dongle(&self->idev, (int) arg);
                break;
        default:
                return -ENOIOCTLCMD;
@@ -645,54 +574,23 @@ static void irtty_wait_until_sent(struct irda_device *idev)
        tty_wait_until_sent(self->tty, 0);
 }
 
-int irtty_register_dongle(struct dongle *dongle)
-{
-       struct dongle_q *new;
-       
-       /* Check if this compressor has been registred before */
-       if ( hashbin_find ( dongles, dongle->type, NULL)) {
-               DEBUG( 0, __FUNCTION__ "(), Dongle already registered\n");
-                return 0;
-        }
-       
-       /* Make new IrDA dongle */
-        new = (struct dongle_q *) kmalloc(sizeof(struct dongle_q), GFP_KERNEL);
-        if (new == NULL)
-                return -1;
-               
-       memset(new, 0, sizeof( struct dongle_q));
-        new->dongle = dongle;
-
-       /* Insert IrDA dongle into hashbin */
-       hashbin_insert(dongles, (QUEUE *) new, dongle->type, NULL);
-       
-        return 0;
-}
-
-void irtty_unregister_dongle(struct dongle *dongle)
-{
-       struct dongle_q *node;
-
-       node = hashbin_remove(dongles, dongle->type, NULL);
-       if (!node) {
-               ERROR(__FUNCTION__ "(), dongle not found!\n");
-               return;
-       }
-       kfree(node);
-}
-
-
 /*
  * Function irtty_set_dtr_rts (tty, dtr, rts)
  *
  *    This function can be used by dongles etc. to set or reset the status
  *    of the dtr and rts lines
  */
-void irtty_set_dtr_rts(struct tty_struct *tty, int dtr, int rts)
+static void irtty_set_dtr_rts(struct irda_device *idev, int dtr, int rts)
 {
+       struct tty_struct *tty;
+       struct irtty_cb *self;
        mm_segment_t fs;
        int arg = 0;
 
+       self = (struct irtty_cb *) idev->priv;
+
+       tty = self->tty;
+
 #ifdef TIOCM_OUT2 /* Not defined for ARM */
        arg = TIOCM_OUT2;
 #endif
@@ -718,6 +616,25 @@ void irtty_set_dtr_rts(struct tty_struct *tty, int dtr, int rts)
        set_fs(fs);
 }
 
+static int irtty_raw_write(struct irda_device *idev, __u8 *buf, int len)
+{
+       struct irtty_cb *self;
+       int actual = 0;
+
+       ASSERT(idev != NULL, return 0;);
+       ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+       
+       self = (struct irtty_cb *) idev->priv;
+
+       ASSERT(self != NULL, return 0;);
+       ASSERT(self->magic == IRTTY_MAGIC, return 0;);
+
+       if (self->tty->driver.write)
+               actual = self->tty->driver.write(self->tty, 0, buf, len);
+
+       return actual;
+}
+
 static int irtty_net_init(struct device *dev)
 {
        /* Set up to be a normal IrDA network device driver */
@@ -760,6 +677,8 @@ static int irtty_net_close(struct device *dev)
 MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
 MODULE_DESCRIPTION("IrDA TTY device driver");
 
+MODULE_PARM(qos_mtt_bits, "i");
+
 /*
  * Function init_module (void)
  *
diff --git a/drivers/net/irda/litelink.c b/drivers/net/irda/litelink.c
new file mode 100644 (file)
index 0000000..e27bab1
--- /dev/null
@@ -0,0 +1,209 @@
+/*********************************************************************
+ *                
+ * Filename:      litelink.c
+ * Version:       1.0
+ * Description:   Driver for the Parallax LiteLink dongle
+ * Status:        Stable
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Fri May  7 12:50:33 1999
+ * Modified at:   Mon May 10 15:12:18 1999
+ * Modified by:   Dag Brattli <dagb@cs.uit.no>
+ * 
+ *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
+ *     
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version.
+ * 
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *     GNU General Public License for more details.
+ * 
+ *     You should have received a copy of the GNU General Public License 
+ *     along with this program; if not, write to the Free Software 
+ *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+ *     MA 02111-1307 USA
+ *     
+ ********************************************************************/
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <asm/ioctls.h>
+#include <asm/uaccess.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irmod.h>
+#include <net/irda/irda_device.h>
+#include <net/irda/dongle.h>
+
+static void litelink_reset(struct irda_device *dev, int unused);
+static void litelink_open(struct irda_device *idev, int type);
+static void litelink_close(struct irda_device *dev);
+static void litelink_change_speed( struct irda_device *dev, int baudrate);
+static void litelink_reset(struct irda_device *dev, int unused);
+static void litelink_init_qos(struct irda_device *idev, struct qos_info *qos);
+
+/* These are the baudrates supported */
+static int baud_rates[] = { 115200, 57600, 38400, 19200, 9600 };
+
+static struct dongle dongle = {
+       LITELINK_DONGLE,
+       litelink_open,
+       litelink_close,
+       litelink_reset,
+       litelink_change_speed,
+       litelink_init_qos,
+};
+
+__initfunc(int litelink_init(void))
+{
+       return irda_device_register_dongle(&dongle);
+}
+
+void litelink_cleanup(void)
+{
+       irda_device_unregister_dongle(&dongle);
+}
+
+static void litelink_open(struct irda_device *idev, int type)
+{
+       strcat(idev->description, " <-> litelink");
+
+        idev->io.dongle_id = type;
+       idev->flags |= IFF_DONGLE;
+
+       MOD_INC_USE_COUNT;
+}
+
+static void litelink_close(struct irda_device *idev)
+{
+       /* Power off dongle */
+       irda_device_set_dtr_rts(idev, FALSE, FALSE);
+
+       MOD_DEC_USE_COUNT;
+}
+
+/*
+ * Function litelink_change_speed (tty, baud)
+ *
+ *    Change speed of the Litelink dongle. To cycle through the available 
+ *    baud rates, pulse RTS low for a few ms.  
+ */
+static void litelink_change_speed(struct irda_device *idev, int baudrate)
+{
+        int i;
+       
+       ASSERT(idev != NULL, return;);
+       ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
+       
+       /* Clear RTS to reset dongle */
+       irda_device_set_dtr_rts(idev, TRUE, FALSE);
+
+       /* Sleep a minimum of 15 us */
+       udelay(15);
+
+       /* Go back to normal mode */
+       irda_device_set_dtr_rts(idev, TRUE, TRUE);
+       
+       /* Sleep a minimum of 15 us */
+       udelay(15);
+       
+       /* Cycle through avaiable baudrates until we reach the correct one */
+       for (i=0; i<5 && baud_rates[i] != baudrate; i++) {
+
+               /* Set DTR, clear RTS */
+               irda_device_set_dtr_rts(idev, FALSE, TRUE);
+               
+               /* Sleep a minimum of 15 us */
+               udelay(15);
+               
+               /* Set DTR, Set RTS */
+               irda_device_set_dtr_rts(idev, TRUE, TRUE);
+               
+               /* Sleep a minimum of 15 us */
+               udelay(15);
+        }
+}
+
+/*
+ * Function litelink_reset (dev)
+ *
+ *      Reset the Litelink type dongle. Warning, this function must only be
+ *      called with a process context!
+ *
+ */
+static void litelink_reset(struct irda_device *idev, int unused)
+{
+       struct irtty_cb *self;
+        struct tty_struct *tty;
+
+       ASSERT(idev != NULL, return;);
+       ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
+       
+       /* Power on dongle */
+       irda_device_set_dtr_rts(idev, TRUE, TRUE);
+
+       /* Sleep a minimum of 15 us */
+       udelay(15);
+
+       /* Clear RTS to reset dongle */
+       irda_device_set_dtr_rts(idev, TRUE, FALSE);
+
+       /* Sleep a minimum of 15 us */
+       udelay(15);
+
+       /* Go back to normal mode */
+       irda_device_set_dtr_rts(idev, TRUE, TRUE);
+       
+       /* Sleep a minimum of 15 us */
+       udelay(15);
+
+       /* This dongles speed defaults to 115200 bps */
+       idev->qos.baud_rate.value = 115200;
+}
+
+/*
+ * Function litelink_init_qos (qos)
+ *
+ *    Initialize QoS capabilities
+ *
+ */
+static void litelink_init_qos( struct irda_device *idev, struct qos_info *qos)
+{
+       qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+       qos->min_turn_time.bits &= 0x40; /* Needs 0.01 ms */
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
+MODULE_DESCRIPTION("Parallax Litelink dongle driver"); 
+               
+/*
+ * Function init_module (void)
+ *
+ *    Initialize Litelink module
+ *
+ */
+int init_module(void)
+{
+       return litelink_init();
+}
+
+/*
+ * Function cleanup_module (void)
+ *
+ *    Cleanup Litelink module
+ *
+ */
+void cleanup_module(void)
+{
+       litelink_cleanup();
+}
+
+#endif
index 878b2e33a84654498563b2fddba46e3acf0e8443..340f836e7b9c402e0b36d07b9ac69c92a00eaba3 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Nov  7 21:43:15 1998
- * Modified at:   Tue Apr 20 11:11:39 1999
+ * Modified at:   Sun May  9 12:57:46 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>
  *     Copyright (c) 1998 Lichen Wang, <lwang@actisys.com>
  *     Copyright (c) 1998 Actisys Corp., www.actisys.com
  *     All Rights Reserved
@@ -67,6 +67,7 @@
 #define BROKEN_DONGLE_ID
 
 static char *driver_name = "pc87108";
+static int qos_mtt_bits = 0x07;  /* 1 ms or more */
 
 #define CHIP_IO_EXTENT 8
 
@@ -219,7 +220,7 @@ static int pc87108_open( int i, unsigned int iobase, unsigned int board_addr,
        idev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
                IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8);
        
-       idev->qos.min_turn_time.bits = 0x07;
+       idev->qos.min_turn_time.bits = qos_mtt_bits;
        irda_qos_bits_to_value( &idev->qos);
        
        idev->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO|IFF_DONGLE;
@@ -259,8 +260,9 @@ static int pc87108_open( int i, unsigned int iobase, unsigned int board_addr,
  *    Close driver instance
  *
  */
-static int pc87108_close( struct irda_device *idev)
+static int pc87108_close(struct irda_device *idev)
 {
+       struct pc87108 *self;
        int iobase;
 
        DEBUG( 4, __FUNCTION__ "()\n");
@@ -269,13 +271,16 @@ static int pc87108_close( struct irda_device *idev)
        ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;);
 
         iobase = idev->io.iobase;
+       self = (struct pc87108 *) idev->priv;
 
        /* Release the PORT that this driver is using */
        DEBUG( 4, __FUNCTION__ "(), Releasing Region %03x\n", 
               idev->io.iobase);
-       release_region( idev->io.iobase, idev->io.io_ext);
+       release_region(idev->io.iobase, idev->io.io_ext);
+
+       irda_device_close(idev);
 
-       irda_device_close( idev);
+       kfree(self);
 
        return 0;
 }
@@ -805,7 +810,6 @@ static void pc87108_dma_write( struct irda_device *idev, int iobase)
        setup_dma(idev->io.dma, idev->tx_buff.data, idev->tx_buff.len, 
                  DMA_MODE_WRITE);
        
-       /* idev->media_busy = TRUE; */
        idev->io.direction = IO_XMIT;
        
        /* Choose transmit DMA channel  */ 
@@ -973,7 +977,7 @@ static int pc87108_dma_receive(struct irda_device *idev)
  *
  *    
  */
-static int pc87108_dma_receive_complete( struct irda_device *idev, int iobase)
+static int pc87108_dma_receive_complete(struct irda_device *idev, int iobase)
 {
        struct sk_buff *skb;
        struct pc87108 *self;
@@ -988,8 +992,6 @@ static int pc87108_dma_receive_complete( struct irda_device *idev, int iobase)
        /* Save current bank */
        bank = inb( iobase+BSR);
        
-       iobase = idev->io.iobase;
-
        /* Read status FIFO */
        switch_bank(iobase, BANK5);
        while (( status = inb( iobase+FRM_ST)) & FRM_ST_VLD) {
@@ -1003,18 +1005,18 @@ static int pc87108_dma_receive_complete( struct irda_device *idev, int iobase)
        }
        
        /* Try to process all entries in status FIFO */
-       switch_bank( iobase, BANK0);
-       while ( st_fifo->len) {
+       switch_bank(iobase, BANK0);
+       while (st_fifo->len) {
       
                /* Get first entry */
-               status = st_fifo->entries[ st_fifo->head].status;
-               len    = st_fifo->entries[ st_fifo->head].len;
+               status = st_fifo->entries[st_fifo->head].status;
+               len    = st_fifo->entries[st_fifo->head].len;
                st_fifo->head++;
                st_fifo->len--;
 
                /* Check for errors */
-               if ( status & FRM_ST_ERR_MSK) {
-                       if ( status & FRM_ST_LOST_FR) {
+               if (status & FRM_ST_ERR_MSK) {
+                       if (status & FRM_ST_LOST_FR) {
                                /* Add number of lost frames to stats */
                                idev->stats.rx_errors += len;   
                        } else {
@@ -1188,8 +1190,8 @@ static __u8 pc87108_fir_interrupt( struct irda_device *idev, int iobase,
        bank = inb( iobase+BSR);
        
        /* Status event, or end of frame detected in FIFO */
-       if ( eir & (EIR_SFIF_EV|EIR_LS_EV)) {
-               if ( pc87108_dma_receive_complete( idev, iobase)) {
+       if (eir & (EIR_SFIF_EV|EIR_LS_EV)) {
+               if (pc87108_dma_receive_complete( idev, iobase)) {
 
                        /* Wait for next status FIFO interrupt */
                        new_ier |= IER_SFIF_IE;
@@ -1460,6 +1462,11 @@ static int pc87108_net_close(struct device *dev)
 
 #ifdef MODULE
 
+MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
+MODULE_DESCRIPTION("NSC PC87108 IrDA Device Driver");
+
+MODULE_PARM(qos_mtt_bits, "i");
+
 /*
  * Function init_module (void)
  *
index de1a553a4aaf1605a2e3caab085840627839f298..e99cb0d445018121fe718d74e9c8644e7050ab8a 100644 (file)
@@ -1,15 +1,15 @@
 /*********************************************************************
  *                
  * Filename:      tekram.c
- * Version:       1.0
+ * Version:       1.1
  * Description:   Implementation of the Tekram IrMate IR-210B dongle
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Wed Oct 21 20:02:35 1998
- * Modified at:   Tue Apr 13 16:33:54 1999
+ * Modified at:   Mon May 10 16:10:17 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -62,15 +62,15 @@ static struct dongle dongle = {
 
 __initfunc(int tekram_init(void))
 {
-       return irtty_register_dongle(&dongle);
+       return irda_device_register_dongle(&dongle);
 }
 
 void tekram_cleanup(void)
 {
-       irtty_unregister_dongle( &dongle);
+       irda_device_unregister_dongle(&dongle);
 }
 
-static void tekram_open( struct irda_device *idev, int type)
+static void tekram_open(struct irda_device *idev, int type)
 {
        strcat(idev->description, " <-> tekram");
 
@@ -80,8 +80,11 @@ static void tekram_open( struct irda_device *idev, int type)
        MOD_INC_USE_COUNT;
 }
 
-static void tekram_close( struct irda_device *dev)
-{
+static void tekram_close(struct irda_device *idev)
+{              
+       /* Power off dongle */
+       irda_device_set_dtr_rts(idev, FALSE, FALSE);
+
        MOD_DEC_USE_COUNT;
 }
 
@@ -101,79 +104,49 @@ static void tekram_close( struct irda_device *dev)
  *    6. wait at least 50 us, new setting (baud rate, etc) takes effect here 
  *       after
  */
-static void tekram_change_speed( struct irda_device *dev, int baud)
+static void tekram_change_speed(struct irda_device *idev, int baud)
 {
-       struct irtty_cb *self;
-       struct tty_struct *tty;
-       struct termios old_termios;
-       int cflag;
        __u8 byte;
        
        DEBUG(4, __FUNCTION__ "()\n");
 
-       ASSERT(dev != NULL, return;);
-       ASSERT(dev->magic == IRDA_DEVICE_MAGIC, return;);
-       
-       self = (struct irtty_cb *) dev->priv;
-       
-       ASSERT(self != NULL, return;);
-       ASSERT(self->magic == IRTTY_MAGIC, return;);
-       
-       if (!self->tty)
-               return;
-
-       tty = self->tty;
+       ASSERT(idev != NULL, return;);
+       ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
        
-       old_termios = *(tty->termios);
-       cflag = tty->termios->c_cflag;
-
-       cflag &= ~CBAUD;
-
        switch (baud) {
        default:
-               /* FALLTHROUGH */
        case 9600:
-               cflag |= B9600;
                byte = TEKRAM_PW|TEKRAM_9600;
                break;
        case 19200:
-               cflag |= B19200;
                byte = TEKRAM_PW|TEKRAM_19200;
                break;
        case 34800:
-               cflag |= B38400;
                byte = TEKRAM_PW|TEKRAM_38400;
                break;
        case 57600:
-               cflag |= B57600;
                byte = TEKRAM_PW|TEKRAM_57600;
                break;
        case 115200:
-               cflag |= B115200;
                byte = TEKRAM_PW|TEKRAM_115200;
                break;
        }
 
        /* Set DTR, Clear RTS */
-       irtty_set_dtr_rts(tty, TRUE, FALSE);
+       irda_device_set_dtr_rts(idev, TRUE, FALSE);
        
        /* Wait at least 7us */
        udelay(7);
 
        /* Write control byte */
-       if (tty->driver.write)
-               tty->driver.write(self->tty, 0, &byte, 1);
+       irda_device_raw_write(idev, &byte, 1);
        
        /* Wait at least 100 ms */
        current->state = TASK_INTERRUPTIBLE;
        schedule_timeout(MSECS_TO_JIFFIES(100));
         
        /* Set DTR, Set RTS */
-       irtty_set_dtr_rts(tty, TRUE, TRUE);
-
-       /* Now change the speed of the serial port */
-       tty->termios->c_cflag = cflag;
-       tty->driver.set_termios(tty, &old_termios);     
+       irda_device_set_dtr_rts(idev, TRUE, TRUE);
 }
 
 /*
@@ -189,41 +162,27 @@ static void tekram_change_speed( struct irda_device *dev, int baud)
  *        3. clear DTR to SPACE state, wait at least 50 us for further 
  *         operation
  */
-void tekram_reset(struct irda_device *dev, int unused)
+void tekram_reset(struct irda_device *idev, int unused)
 {
-       struct irtty_cb *self;
-       struct tty_struct *tty;
-
-       DEBUG(4, __FUNCTION__ "()\n");
-
-       ASSERT(dev != NULL, return;);
-       ASSERT(dev->magic == IRDA_DEVICE_MAGIC, return;);
-       
-       self = (struct irtty_cb *) dev->priv;
+       ASSERT(idev != NULL, return;);
+       ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
        
-       ASSERT(self != NULL, return;);
-       ASSERT(self->magic == IRTTY_MAGIC, return;);
-
-       tty = self->tty;
-       if (!tty)
-               return;
-
        /* Power off dongle */
-       irtty_set_dtr_rts(tty, FALSE, FALSE);
+       irda_device_set_dtr_rts(idev, FALSE, FALSE);
 
        /* Sleep 50 ms */
        current->state = TASK_INTERRUPTIBLE;
        schedule_timeout(MSECS_TO_JIFFIES(50));
 
        /* Clear DTR, Set RTS */
-       irtty_set_dtr_rts(tty, FALSE, TRUE); 
+       irda_device_set_dtr_rts(idev, FALSE, TRUE); 
 
        /* Should sleep 1 ms, but 10-20 should not do any harm */
        current->state = TASK_INTERRUPTIBLE;
        schedule_timeout(MSECS_TO_JIFFIES(20));
 
        /* Set DTR, Set RTS */
-       irtty_set_dtr_rts(tty, TRUE, TRUE);
+       irda_device_set_dtr_rts(idev, TRUE, TRUE);
        
        udelay(50);
 
diff --git a/drivers/net/irda/toshoboe.c b/drivers/net/irda/toshoboe.c
new file mode 100644 (file)
index 0000000..c7ef984
--- /dev/null
@@ -0,0 +1,901 @@
+/*********************************************************************
+ *                
+ * Filename:      toshoboe.c
+ * Version:       0.1
+ * Description:   Driver for the Toshiba OBOE (or type-O or 700 or 701)
+ *                FIR Chipset. 
+ * Status:        Experimental.
+ * Author:        James McKenzie <james@fishsoup.dhs.org>
+ * Created at:    Sat May 8  12:35:27 1999
+ * 
+ *     Copyright (c) 1999 James McKenzie, All Rights Reserved.
+ *      
+ *     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.
+ *  
+ *     Neither James McKenzie nor Cambridge University admit liability nor
+ *     provide warranty for any of this software. This material is 
+ *     provided "AS-IS" and at no charge.
+ *
+ *     Applicable Models : Libretto 100CT. and many more
+ *     Toshiba refers to this chip as the type-O IR port.
+ *
+ ********************************************************************/
+
+/* This driver is experimental, I have only three ir devices */
+/* an olivetti notebook which doesn't have FIR, a toshiba libretto, and */
+/* an hp printer, this works fine at 4MBPS with my HP printer */
+
+static char *rcsid = "$Id: toshoboe.c,v 1.5 1999/05/12 12:24:39 root Exp root $";
+
+/* 
+ * $Log: toshoboe.c,v $
+ * Revision 1.5  1999/05/12 12:24:39  root
+ * *** empty log message ***
+ *
+ * Revision 1.4  1999/05/12 11:55:08  root
+ * *** empty log message ***
+ *
+ * Revision 1.3  1999/05/09 01:33:12  root
+ * *** empty log message ***
+ *
+ * Revision 1.2  1999/05/09 01:30:38  root
+ * *** empty log message ***
+ *
+ * Revision 1.1  1999/05/09 01:25:04  root
+ * Initial revision
+ * 
+ */
+
+/* Define this to have only one frame in the XMIT or RECV queue */
+/* Toshiba's drivers do this, but it disables back to back tansfers */
+/* I think that the chip may have some problems certainly, I have */
+/* seen it jump over tasks in the taskfile->xmit with this turned on */
+#define ONETASK
+
+/* To adjust the number of tasks in use edit toshoboe.h */
+
+/* Define this to enable FIR and MIR support */
+#define ENABLE_FAST
+
+/* Number of ports this driver can support, you also need to edit dev_self below */
+#define NSELFS 4
+
+/* Size of IO window */
+#define CHIP_IO_EXTENT 0x1f
+
+/* Transmit and receive buffer sizes, adjust at your peril */
+#define RX_BUF_SZ      4196
+#define TX_BUF_SZ      4196
+
+/* No user servicable parts below here */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include <net/irda/wrapper.h>
+#include <net/irda/irda.h>
+#include <net/irda/irmod.h>
+#include <net/irda/irlap_frame.h>
+#include <net/irda/irda_device.h>
+
+#include <net/irda/toshoboe.h>
+
+static char *driver_name = "toshoboe";
+
+static struct toshoboe_cb *dev_self[NSELFS + 1] =
+{NULL, NULL, NULL, NULL, NULL};
+
+/* Shutdown the chip and point the taskfile reg somewhere else */
+static void 
+toshoboe_stopchip (struct toshoboe_cb *self)
+{
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  outb_p (0x0e, OBOE_REG_11);
+
+  outb_p (0x00, OBOE_RST);
+  outb_p (0x3f, OBOE_TFP2);     /*Write the taskfile address */
+  outb_p (0xff, OBOE_TFP1);
+  outb_p (0xff, OBOE_TFP0);
+  outb_p (0x0f, OBOE_REG_1B);
+  outb_p (0xff, OBOE_REG_1A);
+  outb_p (0x00, OBOE_ISR);      /*FIXME: should i do this to disbale ints */
+  outb_p (0x80, OBOE_RST);
+  outb_p (0xe, OBOE_LOCK);
+}
+
+/*Set the baud rate */
+static void 
+toshoboe_setbaud (struct toshoboe_cb *self, int baud)
+{
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  printk (KERN_WARNING "ToshOboe: seting baud to %d\n", baud);
+
+  cli ();
+  switch (baud)
+    {
+    case 2400:
+      outb_p (OBOE_PMDL_SIR, OBOE_PMDL);
+      outb_p (OBOE_SMDL_SIR, OBOE_SMDL);
+      outb_p (0xbf, OBOE_UDIV);
+      break;
+    case 4800:
+      outb_p (OBOE_PMDL_SIR, OBOE_PMDL);
+      outb_p (OBOE_SMDL_SIR, OBOE_SMDL);
+      outb_p (0x5f, OBOE_UDIV);
+      break;
+    case 9600:
+      outb_p (OBOE_PMDL_SIR, OBOE_PMDL);
+      outb_p (OBOE_SMDL_SIR, OBOE_SMDL);
+      outb_p (0x2f, OBOE_UDIV);
+      break;
+    case 19200:
+      outb_p (OBOE_PMDL_SIR, OBOE_PMDL);
+      outb_p (OBOE_SMDL_SIR, OBOE_SMDL);
+      outb_p (0x17, OBOE_UDIV);
+      break;
+    case 38400:
+      outb_p (OBOE_PMDL_SIR, OBOE_PMDL);
+      outb_p (OBOE_SMDL_SIR, OBOE_SMDL);
+      outb_p (0xb, OBOE_UDIV);
+      break;
+    case 57600:
+      outb_p (OBOE_PMDL_SIR, OBOE_PMDL);
+      outb_p (OBOE_SMDL_SIR, OBOE_SMDL);
+      outb_p (0x7, OBOE_UDIV);
+      break;
+    case 115200:
+      outb_p (OBOE_PMDL_SIR, OBOE_PMDL);
+      outb_p (OBOE_SMDL_SIR, OBOE_SMDL);
+      outb_p (0x3, OBOE_UDIV);
+      break;
+    case 1152000:
+      outb_p (OBOE_PMDL_MIR, OBOE_PMDL);
+      outb_p (OBOE_SMDL_MIR, OBOE_SMDL);
+      outb_p (0x1, OBOE_UDIV);
+      break;
+    case 4000000:
+      outb_p (OBOE_PMDL_FIR, OBOE_PMDL);
+      outb_p (OBOE_SMDL_FIR, OBOE_SMDL);
+      outb_p (0x0, OBOE_UDIV);
+      break;
+    }
+
+  sti ();
+
+  outb_p (0x00, OBOE_RST);
+  outb_p (0x80, OBOE_RST);
+  outb_p (0x01, OBOE_REG_9);
+
+}
+
+/* Wake the chip up and get it looking at the taskfile */
+static void 
+toshoboe_startchip (struct toshoboe_cb *self)
+{
+  __u32 physaddr;
+
+  DEBUG (4, __FUNCTION__ "()\n");
+
+
+  outb_p (0, OBOE_LOCK);
+  outb_p (0, OBOE_RST);
+  outb_p (OBOE_NTR_VAL, OBOE_NTR);
+  outb_p (0xf0, OBOE_REG_D);
+  outb_p (0xff, OBOE_ISR);
+  outb_p (0x0f, OBOE_REG_1A);
+  outb_p (0xff, OBOE_REG_1B);
+
+
+  physaddr = virt_to_bus (self->taskfile);
+
+  outb_p ((physaddr >> 0x0a) & 0xff, OBOE_TFP0);
+  outb_p ((physaddr >> 0x12) & 0xff, OBOE_TFP1);
+  outb_p ((physaddr >> 0x1a) & 0x3f, OBOE_TFP2);
+
+  outb_p (0x0e, OBOE_REG_11);
+  outb_p (0x80, OBOE_RST);
+
+  toshoboe_setbaud (self, 9600);
+
+}
+
+/*Let the chip look at memory */
+static void 
+toshoboe_enablebm (struct toshoboe_cb *self)
+{
+  DEBUG (4, __FUNCTION__ "()\n");
+  pci_set_master (self->pdev);
+}
+
+/*Don't let the chip look at memory */
+static void 
+toshoboe_disablebm (struct toshoboe_cb *self)
+{
+  __u8 command;
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  pci_read_config_byte (self->pdev, PCI_COMMAND, &command);
+  command &= ~PCI_COMMAND_MASTER;
+  pci_write_config_byte (self->pdev, PCI_COMMAND, command);
+
+}
+
+/*setup the taskfile */
+static void 
+toshoboe_initbuffs (struct toshoboe_cb *self)
+{
+  int i;
+
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  cli ();
+
+  for (i = 0; i < TX_SLOTS; ++i)
+    {
+      self->taskfile->xmit[i].len = 0;
+      self->taskfile->xmit[i].control = 0x00;
+      self->taskfile->xmit[i].buffer = virt_to_bus (self->xmit_bufs[i]);
+    }
+
+  for (i = 0; i < RX_SLOTS; ++i)
+    {
+      self->taskfile->recv[i].len = 0;
+      self->taskfile->recv[i].control = 0x83;
+      self->taskfile->recv[i].buffer = virt_to_bus (self->recv_bufs[i]);
+    }
+
+  sti ();
+}
+
+
+/*Transmit something */
+static int 
+toshoboe_hard_xmit (struct sk_buff *skb, struct device *dev)
+{
+  struct irda_device *idev;
+  struct toshoboe_cb *self;
+  int mtt, len;
+
+  idev = (struct irda_device *) dev->priv;
+  ASSERT (idev != NULL, return 0;);
+  ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return 0;);
+
+  self = idev->priv;
+  ASSERT (self != NULL, return 0;);
+
+
+#ifdef ONETASK
+  if (self->txpending)
+    return -EBUSY;
+
+  self->txs = inb_p (OBOE_XMTT) - OBOE_XMTT_OFFSET;
+
+  self->txs &= 0x3f;
+
+#endif
+
+  if (self->taskfile->xmit[self->txs].control)
+    return -EBUSY;
+
+
+  if (inb_p (OBOE_RST) & OBOE_RST_WRAP)
+    {
+      len = async_wrap_skb (skb, self->xmit_bufs[self->txs], TX_BUF_SZ);
+    }
+  else
+    {
+      len = skb->len;
+      memcpy (self->xmit_bufs[self->txs], skb->data, len);
+    }
+  self->taskfile->xmit[self->txs].len = len & 0x0fff;
+
+
+
+  outb_p (0, OBOE_RST);
+  outb_p (0x1e, OBOE_REG_11);
+
+  self->taskfile->xmit[self->txs].control = 0x84;
+
+  mtt = irda_get_mtt (skb);
+  if (mtt)
+    udelay (mtt);
+
+  self->txpending++;
+
+  /*FIXME: ask about tbusy,media_busy stuff, for the moment */
+  /*tbusy means can't queue any more */
+#ifndef ONETASK
+  if (self->txpending == TX_SLOTS)
+    {
+#else
+  {
+#endif
+    if (irda_lock ((void *) &dev->tbusy) == FALSE)
+      return -EBUSY;
+  }
+
+  outb_p (0x80, OBOE_RST);
+  outb_p (1, OBOE_REG_9);
+
+  self->txs++;
+  self->txs %= TX_SLOTS;
+
+  dev_kfree_skb (skb);
+
+  return 0;
+}
+
+/*interrupt handler */
+static void 
+toshoboe_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+{
+  struct irda_device *idev = (struct irda_device *) dev_id;
+  struct toshoboe_cb *self;
+  __u8 irqstat;
+  struct sk_buff *skb;
+
+  if (idev == NULL)
+    {
+      printk (KERN_WARNING "%s: irq %d for unknown device.\n",
+              driver_name, irq);
+      return;
+    }
+
+  self = idev->priv;
+
+  if (!self)
+    return;
+
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  irqstat = inb_p (OBOE_ISR);
+
+/* woz it us */
+  if (!(irqstat & 0xf8))
+    return;
+
+  outb_p (irqstat, OBOE_ISR);   /*Acknologede it */
+
+
+/* Txdone */
+  if (irqstat & OBOE_ISR_TXDONE)
+    {
+      self->txpending--;
+
+      idev->stats.tx_packets++;
+
+      idev->media_busy = FALSE;
+      idev->netdev.tbusy = 0;
+
+      mark_bh (NET_BH);
+    }
+
+  if (irqstat & OBOE_ISR_RXDONE)
+    {
+
+#ifdef ONETASK
+      self->rxs = inb_p (OBOE_RCVT);
+      self->rxs += (RX_SLOTS - 1);
+      self->rxs %= RX_SLOTS;
+#else
+      while (self->taskfile->recv[self->rxs].control == 0)
+#endif
+        {
+          int len = self->taskfile->recv[self->rxs].len;
+       
+         if (len>2) len-=2;
+
+          skb = dev_alloc_skb (len + 1);
+          if (skb)
+            {
+              skb_reserve (skb, 1);
+
+              skb_put (skb, len);
+              memcpy (skb->data, self->recv_bufs[self->rxs], len);
+
+              idev->stats.rx_packets++;
+              skb->dev = &idev->netdev;
+              skb->mac.raw = skb->data;
+              skb->protocol = htons (ETH_P_IRDA);
+            }
+          else
+            {
+              printk (KERN_INFO __FUNCTION__
+                      "(), memory squeeze, dropping frame.\n");
+            }
+
+
+
+          self->taskfile->recv[self->rxs].control = 0x83;
+          self->taskfile->recv[self->rxs].len = 0x0;
+
+          self->rxs++;
+          self->rxs %= RX_SLOTS;
+
+          if (skb)
+            netif_rx (skb);
+
+        }
+
+    }
+
+  if (irqstat & OBOE_ISR_20)
+    {
+      printk (KERN_WARNING "Oboe_irq: 20\n");
+    }
+  if (irqstat & OBOE_ISR_10)
+    {
+      printk (KERN_WARNING "Oboe_irq: 10\n");
+    }
+  if (irqstat & 0x8)
+    {
+      /*FIXME: I think this is a TX or RX error of some sort */
+
+      idev->stats.tx_errors++;
+      idev->stats.rx_errors++;
+
+    }
+
+
+}
+
+
+
+/* Change the baud rate */
+static void 
+toshoboe_change_speed (struct irda_device *idev, int speed)
+{
+  struct toshoboe_cb *self;
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  ASSERT (idev != NULL, return;);
+  ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return;);
+
+  self = idev->priv;
+  ASSERT (self != NULL, return;);
+
+  idev->io.baudrate = speed;
+
+  toshoboe_setbaud (self, speed);
+
+}
+
+
+/* Check all xmit_tasks finished */
+static void 
+toshoboe_wait_until_sent (struct irda_device *idev)
+{
+  struct toshoboe_cb *self;
+  int i;
+
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  ASSERT (idev != NULL, return;);
+  ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return;);
+
+  self = idev->priv;
+  ASSERT (self != NULL, return;);
+
+  for (i = 0; i < TX_SLOTS; ++i)
+    {
+      while (self->taskfile->xmit[i].control)
+        {
+          current->state = TASK_INTERRUPTIBLE;
+          schedule_timeout (6);
+        }
+    }
+
+}
+
+static int 
+toshoboe_is_receiving (struct irda_device *idev)
+{
+  DEBUG (4, __FUNCTION__ "()\n");
+
+/*FIXME Can't tell! */
+  return (FALSE);
+}
+
+
+static int 
+toshoboe_net_init (struct device *dev)
+{
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  /* Setup to be a normal IrDA network device driver */
+  irda_device_setup (dev);
+
+  /* Insert overrides below this line! */
+  return 0;
+}
+
+
+
+
+static int 
+toshoboe_net_open (struct device *dev)
+{
+  struct irda_device *idev;
+  struct toshoboe_cb *self;
+
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  ASSERT (dev != NULL, return -1;);
+  idev = (struct irda_device *) dev->priv;
+
+  ASSERT (idev != NULL, return 0;);
+  ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return 0;);
+
+  self = idev->priv;
+  ASSERT (self != NULL, return 0;);
+
+  if (request_irq (idev->io.irq, toshoboe_interrupt,
+                   SA_SHIRQ | SA_INTERRUPT, idev->name, (void *) idev))
+    {
+
+      return -EAGAIN;
+    }
+
+  toshoboe_initbuffs (self);
+  toshoboe_enablebm (self);
+  toshoboe_startchip (self);
+
+
+  cli ();
+
+  /*FIXME: need to test this carefully to check which one */
+  /*of the two possible startup logics the chip uses */
+  /*although it won't make any difference if no-one xmits durining init */
+  /*and none what soever if using ONETASK */
+
+  self->rxs = inb_p (OBOE_RCVT);
+  self->txs = inb_p (OBOE_XMTT) - OBOE_XMTT_OFFSET;
+
+#ifdef 0
+  self->rxs = 0;
+  self->txs = 0;
+#endif
+#ifdef 0
+  self->rxs = RX_SLOTS - 1;
+  self->txs = 0;
+#endif
+
+
+  self->txpending = 0;
+
+  sti ();
+
+
+  dev->tbusy = 0;
+  dev->interrupt = 0;
+  dev->start = 1;
+
+  MOD_INC_USE_COUNT;
+
+  return 0;
+
+}
+
+static int 
+toshoboe_net_close (struct device *dev)
+{
+  struct irda_device *idev;
+  struct toshoboe_cb *self;
+
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  ASSERT (dev != NULL, return -1;);
+  idev = (struct irda_device *) dev->priv;
+
+  ASSERT (idev != NULL, return 0;);
+  ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return 0;);
+
+  dev->tbusy = 1;
+  dev->start = 0;
+
+
+  self = idev->priv;
+
+  ASSERT (self != NULL, return 0;);
+
+  free_irq (idev->io.irq, (void *) idev);
+
+  toshoboe_stopchip (self);
+  toshoboe_disablebm (self);
+
+  MOD_DEC_USE_COUNT;
+
+  return 0;
+
+}
+
+
+
+#ifdef MODULE
+
+static int 
+toshoboe_close (struct irda_device *idev)
+{
+  struct toshoboe_cb *self;
+  int i;
+
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  ASSERT (idev != NULL, return -1;);
+  ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+
+  self = idev->priv;
+
+  ASSERT (self != NULL, return -1;);
+
+  toshoboe_stopchip (self);
+
+  release_region (idev->io.iobase, idev->io.io_ext);
+
+
+  for (i = 0; i < TX_SLOTS; ++i)
+    {
+      kfree (self->xmit_bufs[i]);
+      self->xmit_bufs[i] = NULL;
+    }
+
+  for (i = 0; i < RX_SLOTS; ++i)
+    {
+      kfree (self->recv_bufs[i]);
+      self->recv_bufs[i] = NULL;
+    }
+
+
+  kfree (self->taskfilebuf);
+  self->taskfilebuf = NULL;
+  self->taskfile = NULL;
+
+
+  irda_device_close (idev);
+
+  return (0);
+
+}
+
+#endif
+
+
+
+static int 
+toshoboe_open (struct pci_dev *pci_dev)
+{
+  struct toshoboe_cb *self;
+  struct irda_device *idev;
+  int i = 0;
+  int ok=0;
+
+
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  while (dev_self[i])
+    i++;
+
+  if (i == NSELFS)
+    {
+      printk (KERN_ERR "Oboe: No more instances available");
+      return -ENOMEM;
+    }
+
+  self = kmalloc (sizeof (struct toshoboe_cb), GFP_KERNEL);
+
+  if (self == NULL)
+    {
+      printk (KERN_ERR "IrDA: Can't allocate memory for "
+              "IrDA control block!\n");
+      return -ENOMEM;
+    }
+
+  memset (self, 0, sizeof (struct toshoboe_cb));
+
+
+  dev_self[i] = self;
+
+  self->pdev = pci_dev;
+  self->base = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+
+  idev = &self->idev;
+
+  /*Setup idev */
+
+  idev->io.iobase = self->base;
+  idev->io.irq = pci_dev->irq;
+  idev->io.io_ext = CHIP_IO_EXTENT;
+
+  /* Lock the port that we need */
+  i = check_region (idev->io.iobase, idev->io.io_ext);
+  if (i < 0)
+    {
+      DEBUG (0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
+             idev->io.iobase);
+
+      dev_self[i] = NULL;
+      kfree (self);
+
+      return -ENODEV;
+    }
+
+  request_region (idev->io.iobase, idev->io.io_ext, driver_name);
+
+  irda_init_max_qos_capabilies (&idev->qos);
+
+  idev->qos.baud_rate.bits = IR_2400 | /*IR_4800 | */ IR_9600 | IR_19200 |
+    IR_115200;
+#ifdef ENABLE_FAST
+ idev->qos.baud_rate.bits|= IR_576000 | IR_1152000 | (IR_4000000 << 8);
+#endif
+
+  idev->qos.min_turn_time.bits = 0xff;  /*FIXME: what does this do? */
+
+  irda_qos_bits_to_value (&idev->qos);
+
+  idev->flags = IFF_SIR | IFF_DMA | IFF_PIO;
+
+#ifdef ENABLE_FAST
+  idev->flags |= IFF_FIR;
+#endif
+
+  /* These aren't much use as we need to have a whole panoply of
+   * buffers running */
+
+  idev->rx_buff.flags = 0;
+  idev->tx_buff.flags = 0;
+  idev->rx_buff.truesize = 0;
+  idev->rx_buff.truesize = 0;
+
+  idev->change_speed = toshoboe_change_speed;
+  idev->wait_until_sent = toshoboe_wait_until_sent;
+  idev->is_receiving = toshoboe_is_receiving;
+
+  idev->netdev.init = toshoboe_net_init;
+  idev->netdev.hard_start_xmit = toshoboe_hard_xmit;
+  idev->netdev.open = toshoboe_net_open;
+  idev->netdev.stop = toshoboe_net_close;
+
+
+  /* Now setup the endless buffers we need */
+
+  self->txs = 0;
+  self->rxs = 0;
+
+  self->taskfilebuf = kmalloc (OBOE_TASK_BUF_LEN, GFP_KERNEL | GFP_DMA);
+  if (!self->taskfilebuf) {
+       printk(KERN_ERR "toshoboe: kmalloc for DMA failed()\n");
+       kfree(self);
+       return -ENOMEM;
+  }
+
+
+  memset (self->taskfilebuf, 0, OBOE_TASK_BUF_LEN);
+
+  /*We need to align the taskfile on a taskfile size boundary */
+  {
+    __u32 addr;
+
+    addr = (__u32) self->taskfilebuf;
+    addr &= ~(sizeof (struct OboeTaskFile) - 1);
+    addr += sizeof (struct OboeTaskFile);
+
+    self->taskfile = (struct OboeTaskFile *) addr;
+  }
+
+  for (i = 0; i < TX_SLOTS; ++i)
+    {
+      self->xmit_bufs[i] = kmalloc (TX_BUF_SZ, GFP_KERNEL | GFP_DMA);
+      if (self->xmit_bufs[i]) ok++;
+    }
+
+  for (i = 0; i < RX_SLOTS; ++i)
+    {
+      self->recv_bufs[i] = kmalloc (TX_BUF_SZ, GFP_KERNEL | GFP_DMA);
+      if (self->recv_bufs[i]) ok++;
+    }
+
+  if (ok!=RX_SLOTS+TX_SLOTS) {
+       printk(KERN_ERR  "toshoboe: kmalloc for buffers failed()\n");
+
+
+  for (i = 0; i < TX_SLOTS; ++i) if (self->xmit_bufs[i]) kfree(self->xmit_bufs[i]);
+  for (i = 0; i < RX_SLOTS; ++i) if (self->recv_bufs[i]) kfree(self->recv_bufs[i]);
+
+       kfree(self);
+       return -ENOMEM;
+
+  }
+
+
+  irda_device_open (idev, driver_name, self);
+
+  printk (KERN_WARNING "ToshOboe: Using ");
+#ifdef ONETASK
+  printk ("single");
+#else
+  printk ("multiple");
+#endif
+  printk (" tasks, version %s\n", rcsid);
+
+  return (0);
+}
+
+__initfunc (int toshoboe_init (void))
+{
+  struct pci_dev *pci_dev = NULL;
+  int found = 0;
+
+  do
+    {
+      pci_dev = pci_find_device (PCI_VENDOR_ID_TOSHIBA,
+                                 PCI_DEVICE_ID_FIR701, pci_dev);
+      if (pci_dev)
+        {
+          printk (KERN_WARNING "ToshOboe: Found 701 chip at 0x%0lx irq %d\n",
+                  pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK,
+                  pci_dev->irq);
+
+          if (!toshoboe_open (pci_dev))
+            found++;
+        }
+
+    }
+  while (pci_dev);
+
+  if (found)
+    return 0;
+
+  return -ENODEV;
+}
+
+#ifdef MODULE
+
+static void 
+toshoboe_cleanup (void)
+{
+  int i;
+
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  for (i = 0; i < 4; i++)
+    {
+      if (dev_self[i])
+        toshoboe_close (&(dev_self[i]->idev));
+    }
+}
+
+
+
+int 
+init_module (void)
+{
+  return toshoboe_init ();
+}
+
+
+void 
+cleanup_module (void)
+{
+  toshoboe_cleanup ();
+}
+
+
+#endif
index 60c8e024a0d1fec5c56b44e05c48cf494d69c972..f3454c531d94e92d66f0888b423e8ac3adc39fa4 100644 (file)
@@ -7,10 +7,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Dec 26 10:59:03 1998
- * Modified at:   Tue Apr 20 11:15:52 1999
+ * Modified at:   Mon May 10 22:11:09 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -216,7 +216,7 @@ static int uircc_open(int i, unsigned int iobase, unsigned int iobase2,
        idev->netdev.open            = uircc_net_open;
        idev->netdev.stop            = uircc_net_close;
 
-       irport_open(iobase2);
+       irport_start(iobase2);
 
        /* Open the IrDA device */
        irda_device_open(idev, driver_name, self);
@@ -233,6 +233,7 @@ static int uircc_open(int i, unsigned int iobase, unsigned int iobase2,
 #ifdef MODULE
 static int uircc_close(struct irda_device *idev)
 {
+       struct uircc_cb *self;
        int iobase;
        int status;
 
@@ -242,6 +243,7 @@ static int uircc_close(struct irda_device *idev)
        ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
 
         iobase = idev->io.iobase;
+       self = (struct uircc_cb *) idev->priv;
 
        /* Some magic to disable FIR and enable SIR */
        uircc_toshiba_cmd(&status, 0xffff, 0x001b, 0x0000);
@@ -249,7 +251,7 @@ static int uircc_close(struct irda_device *idev)
        /* Disable modem */
        outb(0x00, iobase+UIRCC_CR10);
 
-       irport_close(idev->io.iobase2);
+       irport_stop(idev->io.iobase2);
 
        /* Release the PORT that this driver is using */
        DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", idev->io.iobase);
@@ -262,6 +264,8 @@ static int uircc_close(struct irda_device *idev)
        }
        irda_device_close(idev);
 
+       kfree(self);
+
        return 0;
 }
 #endif /* MODULE */
@@ -346,8 +350,8 @@ static void uircc_change_speed(struct irda_device *idev, int speed)
        case 37600:
        case 57600:
        case 115200:
-               irport_open(idev->io.iobase2);
-               irport_change_speed( idev->io.iobase2, speed);
+               irport_start(idev->io.iobase2);
+               irport_change_speed(idev, speed);
 
                /* Some magic to disable FIR and enable SIR */
                uircc_toshiba_cmd(&status, 0xffff, 0x001b, 0x0000);
@@ -363,7 +367,7 @@ static void uircc_change_speed(struct irda_device *idev, int speed)
                DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n");
                break;
        case 4000000:
-               irport_close(idev->io.iobase2);
+               irport_stop(idev->io.iobase2);
 
                /* Some magic to disable SIR and enable FIR */
                uircc_toshiba_cmd(&status, 0xffff, 0x001b, 0x0001);
index 9234c4a82022b5f2d96d60916379aba661f05114..f773172153e2dd3f0e19c9158d18d967a348a5a4 100644 (file)
@@ -1,16 +1,16 @@
 /*********************************************************************
  *                
  * Filename:      w83977af_ir.c
- * Version:       0.8
- * Description:   FIR/MIR driver for the Winbond W83977AF Super I/O chip
+ * Version:       1.0
+ * Description:   FIR driver for the Winbond W83977AF Super I/O chip
  * Status:        Experimental.
  * Author:        Paul VanderSpek
  * Created at:    Wed Nov  4 11:46:16 1998
- * Modified at:   Tue Apr 20 11:15:00 1999
+ * Modified at:   Thu May 13 08:03:27 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>
  *     Copyright (c) 1998 Corel Computer Corp.
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -40,7 +40,7 @@
  ********************************************************************/
 
 #include <linux/module.h>
-
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/skbuff.h>
 #include <net/irda/w83977af.h>
 #include <net/irda/w83977af_ir.h>
 
-#define NETWINDER
+#define CONFIG_NETWINDER                 /* Adjust to NetWinder differences */
+#undef  CONFIG_NETWINDER_TX_DMA_PROBLEMS /* Not needed */
+#define CONFIG_NETWINDER_RX_DMA_PROBLEMS /* Must have this one! */
+#undef  CONFIG_USE_INTERNAL_TIMER        /* Just cannot make that timer work */
+#define CONFIG_USE_W977_PNP              /* Currently needed */
+#define PIO_MAX_SPEED       115200 
 
 static char *driver_name = "w83977af_ir";
+static int  qos_mtt_bits = 0x07;           /* 1 ms or more */
 
 #define CHIP_IO_EXTENT 8
 
 static unsigned int io[] = { 0x180, ~0, ~0, ~0 };
 static unsigned int irq[] = { 6, 0, 0, 0 };
-static unsigned int dma[] = { 0, 0, 0, 0 };
-
-static struct irda_device *dev_self[] = { NULL, NULL, NULL, NULL};
+static unsigned int dma[] = 
+{ 1, 0, 0, 0 };
 
-/* For storing entries in the status FIFO */
-struct st_fifo_entry {
-       int status;
-       int len;
-};
+static struct w83977af_ir *dev_self[] = { NULL, NULL, NULL, NULL};
 
 static struct st_fifo_entry prev;
 
 /* Some prototypes */
-static int  w83977af_open( int i, unsigned int iobase, unsigned int irq, 
-                          unsigned int dma);
-static int  w83977af_close( struct irda_device *idev);
-static int  w83977af_probe( int iobase, int irq, int dma);
+static int  w83977af_open(int i, unsigned int iobase, unsigned int irq, 
+                          unsigned int dma);
+static int  w83977af_close(struct irda_device *idev);
+static int  w83977af_probe(int iobase, int irq, int dma);
 static int  w83977af_dma_receive(struct irda_device *idev); 
 static int  w83977af_dma_receive_complete(struct irda_device *idev);
-static int  w83977af_hard_xmit( struct sk_buff *skb, struct device *dev);
-static int  w83977af_pio_write( int iobase, __u8 *buf, int len, int fifo_size);
-static void w83977af_dma_write( struct irda_device *idev, int iobase);
-static void w83977af_change_speed( struct irda_device *idev, int baud);
+static int  w83977af_hard_xmit(struct sk_buff *skb, struct device *dev);
+static int  w83977af_pio_write(int iobase, __u8 *buf, int len, int fifo_size);
+static void w83977af_dma_write(struct irda_device *idev, int iobase);
+static void w83977af_change_speed(struct irda_device *idev, int baud);
 static void w83977af_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void w83977af_wait_until_sent( struct irda_device *idev);
-static int w83977af_is_receiving( struct irda_device *idev);
+static void w83977af_wait_until_sent(struct irda_device *idev);
+static int  w83977af_is_receiving(struct irda_device *idev);
 
-static int w83977af_net_init( struct device *dev);
-static int w83977af_net_open( struct device *dev);
-static int w83977af_net_close( struct device *dev);
+static int  w83977af_net_init(struct device *dev);
+static int  w83977af_net_open(struct device *dev);
+static int  w83977af_net_close(struct device *dev);
 
 /*
  * Function w83977af_init ()
@@ -108,13 +109,13 @@ static int w83977af_net_close( struct device *dev);
  */
 __initfunc(int w83977af_init(void))
 {
-       int i;
+        int i;
 
-       DEBUG( 0, __FUNCTION__ "()\n");
+       DEBUG(0, __FUNCTION__ "()\n");
 
        prev.status = 0;
 
-       for ( i=0; (io[i] < 2000) && (i < 4); i++) {
+       for (i=0; (io[i] < 2000) && (i < 4); i++) { 
                int ioaddr = io[i];
                if (check_region(ioaddr, CHIP_IO_EXTENT) < 0)
                        continue;
@@ -135,11 +136,11 @@ void w83977af_cleanup(void)
 {
        int i;
 
-        DEBUG( 4, __FUNCTION__ "()\n");
+        DEBUG(4, __FUNCTION__ "()\n");
 
-       for ( i=0; i < 4; i++) {
-               if ( dev_self[i])
-                       w83977af_close( dev_self[i]);
+       for (i=0; i < 4; i++) {
+               if (dev_self[i])
+                       w83977af_close(&(dev_self[i]->idev));
        }
 }
 #endif /* MODULE */
@@ -154,26 +155,29 @@ int w83977af_open( int i, unsigned int iobase, unsigned int irq,
                   unsigned int dma)
 {
        struct irda_device *idev;
+        struct w83977af_ir *self;
        int ret;
 
        DEBUG( 0, __FUNCTION__ "()\n");
 
-       if ( w83977af_probe( iobase, irq, dma) == -1)
+       if (w83977af_probe(iobase, irq, dma) == -1)
                return -1;
 
        /*
         *  Allocate new instance of the driver
         */
-       idev = kmalloc( sizeof(struct irda_device), GFP_KERNEL);
-       if ( idev == NULL) {
+       self = kmalloc(sizeof(struct w83977af_ir), GFP_KERNEL);
+       if (self == NULL) {
                printk( KERN_ERR "IrDA: Can't allocate memory for "
                        "IrDA control block!\n");
                return -ENOMEM;
        }
-       memset( idev, 0, sizeof(struct irda_device));
+       memset(self, 0, sizeof(struct w83977af_ir));
    
        /* Need to store self somewhere */
-       dev_self[i] = idev;
+       dev_self[i] = self;
+
+       idev = &self->idev;
 
        /* Initialize IO */
        idev->io.iobase    = iobase;
@@ -183,17 +187,17 @@ int w83977af_open( int i, unsigned int iobase, unsigned int irq,
         idev->io.fifo_size = 32;
 
        /* Lock the port that we need */
-       ret = check_region( idev->io.iobase, idev->io.io_ext);
-       if ( ret < 0) { 
+       ret = check_region(idev->io.iobase, idev->io.io_ext);
+       if (ret < 0) { 
                DEBUG( 0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
                       idev->io.iobase);
                /* w83977af_cleanup( self->idev);  */
                return -ENODEV;
        }
-       request_region( idev->io.iobase, idev->io.io_ext, idev->name);
+       request_region(idev->io.iobase, idev->io.io_ext, idev->name);
 
        /* Initialize QoS for this device */
-       irda_init_max_qos_capabilies( &idev->qos);
+       irda_init_max_qos_capabilies(&idev->qos);
        
        /* The only value we must override it the baudrate */
 
@@ -202,8 +206,8 @@ int w83977af_open( int i, unsigned int iobase, unsigned int irq,
                IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8);
 
        /* The HP HDLS-1100 needs 1 ms according to the specs */
-       idev->qos.min_turn_time.bits = 0x03; /* 1ms and more */
-       irda_qos_bits_to_value( &idev->qos);
+       idev->qos.min_turn_time.bits = qos_mtt_bits;
+       irda_qos_bits_to_value(&idev->qos);
        
        idev->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO;
 
@@ -221,13 +225,13 @@ int w83977af_open( int i, unsigned int iobase, unsigned int irq,
         idev->is_receiving    = w83977af_is_receiving;
 
        /* Override the network functions we need to use */
-       idev->netdev.init = w83977af_net_init;
+       idev->netdev.init            = w83977af_net_init;
        idev->netdev.hard_start_xmit = w83977af_hard_xmit;
-       idev->netdev.open = w83977af_net_open;
-       idev->netdev.stop = w83977af_net_close;
+       idev->netdev.open            = w83977af_net_open;
+       idev->netdev.stop            = w83977af_net_close;
 
        /* Open the IrDA device */
-       irda_device_open( idev, driver_name, NULL);
+       irda_device_open(idev, driver_name, self);
        
        return 0;
 }
@@ -240,15 +244,18 @@ int w83977af_open( int i, unsigned int iobase, unsigned int irq,
  */
 static int w83977af_close( struct irda_device *idev)
 {
+       struct w83977af_ir *self;
        int iobase;
 
-       DEBUG( 0, __FUNCTION__ "()\n");
+       DEBUG(0, __FUNCTION__ "()\n");
 
-       ASSERT( idev != NULL, return -1;);
-       ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+       ASSERT(idev != NULL, return -1;);
+       ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
 
         iobase = idev->io.iobase;
+       self = (struct w83977af_ir *) idev->priv;
 
+#ifdef CONFIG_USE_W977_PNP
        /* enter PnP configuration mode */
        w977_efm_enter();
 
@@ -258,13 +265,15 @@ static int w83977af_close( struct irda_device *idev)
        w977_write_reg(0x30, 0x00);
 
        w977_efm_exit();
-
+#endif /* CONFIG_USE_W977_PNP */
        /* Release the PORT that this driver is using */
        DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n", 
              idev->io.iobase);
-       release_region( idev->io.iobase, idev->io.io_ext);
+       release_region(idev->io.iobase, idev->io.io_ext);
+
+       irda_device_close(idev);
 
-       irda_device_close( idev);
+       kfree(self);
 
        return 0;
 }
@@ -280,7 +289,7 @@ int w83977af_probe( int iobase, int irq, int dma)
        int version;
        
        DEBUG( 0, __FUNCTION__ "()\n");
-
+#ifdef CONFIG_USE_W977_PNP
        /* Enter PnP configuration mode */
        w977_efm_enter();
 
@@ -289,14 +298,14 @@ int w83977af_probe( int iobase, int irq, int dma)
        /* Configure PnP port, IRQ, and DMA channel */
        w977_write_reg(0x60, (iobase >> 8) & 0xff);
        w977_write_reg(0x61, (iobase) & 0xff);
-       /* w977_write_reg(0x70, 0x06); */
+
        w977_write_reg(0x70, irq);
-#ifdef NETWINDER
-       w977_write_reg(0x74, dma+1); /* Netwinder uses one higher than Linux */
+#ifdef CONFIG_NETWINDER
+       w977_write_reg(0x74, dma+1); /* Netwinder uses 1 higher than Linux */
 #else
        w977_write_reg(0x74, dma);   
 #endif
-       w977_write_reg(0x75, dma);   /* Disable Tx DMA */
+       w977_write_reg(0x75, 0x04);  /* Disable Tx DMA */
        
        /* Set append hardware CRC, enable IR bank selection */ 
        w977_write_reg(0xf0, APEDCRC|ENBNKSEL);
@@ -305,26 +314,26 @@ int w83977af_probe( int iobase, int irq, int dma)
        w977_write_reg(0x30, 0x01);
 
        w977_efm_exit();
-
+#endif
        /* Disable Advanced mode */
-       switch_bank( iobase, SET2);
+       switch_bank(iobase, SET2);
        outb(iobase+2, 0x00);  
 
        /* Turn on UART (global) interrupts */
-       switch_bank( iobase, SET0);
-       outb( HCR_EN_IRQ, iobase+HCR);
+       switch_bank(iobase, SET0);
+       outb(HCR_EN_IRQ, iobase+HCR);
        
        /* Switch to advanced mode */
-       switch_bank( iobase, SET2);
-       outb( inb( iobase+ADCR1) | ADCR1_ADV_SL, iobase+ADCR1);
+       switch_bank(iobase, SET2);
+       outb(inb(iobase+ADCR1) | ADCR1_ADV_SL, iobase+ADCR1);
 
        /* Set default IR-mode */
-       switch_bank( iobase, SET0);
-       outb( HCR_SIR, iobase+HCR);
+       switch_bank(iobase, SET0);
+       outb(HCR_SIR, iobase+HCR);
 
        /* Read the Advanced IR ID */
        switch_bank(iobase, SET3);
-       version =  inb( iobase+AUID);
+       version = inb(iobase+AUID);
        
        /* Should be 0x1? */
        if (0x10 != (version & 0xf0)) {
@@ -333,18 +342,17 @@ int w83977af_probe( int iobase, int irq, int dma)
        }
        
        /* Set FIFO size to 32 */
-       switch_bank( iobase, SET2);
-       outb( ADCR2_RXFS32|ADCR2_TXFS32, iobase+ADCR2); 
+       switch_bank(iobase, SET2);
+       outb(ADCR2_RXFS32|ADCR2_TXFS32, iobase+ADCR2);  
        
        /* Set FIFO threshold to TX17, RX16 */
        switch_bank(iobase, SET0);      
        outb(UFR_RXTL|UFR_TXTL|UFR_TXF_RST|UFR_RXF_RST|UFR_EN_FIFO,iobase+UFR);
-/*     outb( 0xa7, iobase+UFR); */
 
        /* Receiver frame length */
-       switch_bank( iobase, SET4);
-       outb( 2048 & 0xff, iobase+6);
-       outb(( 2048 >> 8) & 0x1f, iobase+7);
+       switch_bank(iobase, SET4);
+       outb(2048 & 0xff, iobase+6);
+       outb((2048 >> 8) & 0x1f, iobase+7);
 
        /* 
         * Init HP HSDL-1100 transceiver. 
@@ -358,8 +366,8 @@ int w83977af_probe( int iobase, int irq, int dma)
         *   FIRRX pin 39 connected to receiver      (IRSL0) 
         *   CIRRX pin 40 connected to pin 37
         */
-       switch_bank( iobase, SET7);
-       outb( 0x40, iobase+7);
+       switch_bank(iobase, SET7);
+       outb(0x40, iobase+7);
                
        DEBUG(0, "W83977AF (IR) driver loaded. Version: 0x%02x\n", version);
        
@@ -372,16 +380,14 @@ int w83977af_probe( int iobase, int irq, int dma)
  *    Change the speed of the device
  *
  */
-void w83977af_change_speed( struct irda_device *idev, int speed)
+void w83977af_change_speed(struct irda_device *idev, int speed)
 {
        int ir_mode = HCR_SIR;
        int iobase; 
        __u8 set;
 
-       DEBUG( 0, __FUNCTION__ "()\n");
-
-       ASSERT( idev != NULL, return;);
-       ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
+       ASSERT(idev != NULL, return;);
+       ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
 
        iobase = idev->io.iobase;
 
@@ -389,22 +395,22 @@ void w83977af_change_speed( struct irda_device *idev, int speed)
        idev->io.baudrate = speed;
 
        /* Save current bank */
-       set = inb( iobase+SSR);
+       set = inb(iobase+SSR);
 
        /* Disable interrupts */
-       switch_bank( iobase, SET0);
-       outb( 0, iobase+ICR);
+       switch_bank(iobase, SET0);
+       outb(0, iobase+ICR);
 
        /* Select Set 2 */
-       switch_bank( iobase, SET2);
-
-       outb( 0x00, iobase+ABHL);
-       switch ( speed) {
-       case 9600:   outb( 0x0c, iobase+ABLL); break;
-       case 19200:  outb( 0x06, iobase+ABLL); break;
-       case 37600:  outb( 0x03, iobase+ABLL); break;
-       case 57600:  outb( 0x02, iobase+ABLL); break;
-       case 115200: outb( 0x01, iobase+ABLL); break;
+       switch_bank(iobase, SET2);
+       outb(0x00, iobase+ABHL);
+
+       switch (speed) {
+       case 9600:   outb(0x0c, iobase+ABLL); break;
+       case 19200:  outb(0x06, iobase+ABLL); break;
+       case 37600:  outb(0x03, iobase+ABLL); break;
+       case 57600:  outb(0x02, iobase+ABLL); break;
+       case 115200: outb(0x01, iobase+ABLL); break;
        case 576000:
                ir_mode = HCR_MIR_576;
                DEBUG(0, __FUNCTION__ "(), handling baud of 576000\n");
@@ -419,34 +425,37 @@ void w83977af_change_speed( struct irda_device *idev, int speed)
                break;
        default:
                ir_mode = HCR_FIR;
-               DEBUG( 0, __FUNCTION__ "(), unknown baud rate of %d\n", speed);
+               DEBUG(0, __FUNCTION__ "(), unknown baud rate of %d\n", speed);
                break;
        }
 
        /* Set speed mode */
        switch_bank(iobase, SET0);
-       outb( ir_mode, iobase+HCR);
+       outb(ir_mode, iobase+HCR);
 
        /* set FIFO size to 32 */
-       switch_bank( iobase, SET2);
-       outb( ADCR2_RXFS32|ADCR2_TXFS32, iobase+ADCR2); 
+       switch_bank(iobase, SET2);
+       outb(ADCR2_RXFS32|ADCR2_TXFS32, iobase+ADCR2);  
        
        /* set FIFO threshold to TX17, RX16 */
        switch_bank(iobase, SET0);
-       outb(UFR_RXTL|UFR_TXTL|UFR_TXF_RST|UFR_RXF_RST|UFR_EN_FIFO, iobase+UFR);
-       
+
+       outb(0x00, iobase+UFR);        /* Reset */
+       outb(UFR_EN_FIFO, iobase+UFR); /* First we must enable FIFO */
+       outb(0xa7, iobase+UFR);
+
        idev->netdev.tbusy = 0;
        
        /* Enable some interrupts so we can receive frames */
        switch_bank(iobase, SET0);
-       if ( speed > 115200) {
-               outb( ICR_EFSFI, iobase+ICR);
-               w83977af_dma_receive( idev);
+       if (speed > PIO_MAX_SPEED) {
+               outb(ICR_EFSFI, iobase+ICR);
+               w83977af_dma_receive(idev);
        } else
-               outb( ICR_ERBRI, iobase+ICR);
+               outb(ICR_ERBRI, iobase+ICR);
        
        /* Restore SSR */
-       outb( set, iobase+SSR);
+       outb(set, iobase+SSR);
 }
 
 /*
@@ -455,7 +464,7 @@ void w83977af_change_speed( struct irda_device *idev, int speed)
  *    Sets up a DMA transfer to send the current frame.
  *
  */
-int w83977af_hard_xmit( struct sk_buff *skb, struct device *dev)
+int w83977af_hard_xmit(struct sk_buff *skb, struct device *dev)
 {
        struct irda_device *idev;
        int iobase;
@@ -474,20 +483,21 @@ int w83977af_hard_xmit( struct sk_buff *skb, struct device *dev)
        /* Lock transmit buffer */
        if (irda_lock((void *) &dev->tbusy) == FALSE)
                return -EBUSY;
-       
+
        /* Save current set */
        set = inb(iobase+SSR);
        
        /* Decide if we should use PIO or DMA transfer */
-       if (idev->io.baudrate > 115200) {
+       if (idev->io.baudrate > PIO_MAX_SPEED) {
+               idev->tx_buff.data = idev->tx_buff.head;
                memcpy(idev->tx_buff.data, skb->data, skb->len);
                idev->tx_buff.len = skb->len;
-               idev->tx_buff.data = idev->tx_buff.head;
                
                mtt = irda_get_mtt(skb);
+#ifdef CONFIG_USE_INTERNAL_TIMER
                if (mtt > 50) {
                        /* Adjust for timer resolution */
-                       mtt = mtt / 1000 + 1;
+                       mtt /= 1000+1;
 
                        /* Setup timer */
                        switch_bank(iobase, SET4);
@@ -502,6 +512,8 @@ int w83977af_hard_xmit( struct sk_buff *skb, struct device *dev)
                        switch_bank(iobase, SET0);
                        outb(ICR_ETMRI, iobase+ICR);
                } else {
+#endif
+                       DEBUG(4,__FUNCTION__ "(%ld), mtt=%d\n", jiffies, mtt);
                        if (mtt)
                                udelay(mtt);
 
@@ -509,7 +521,9 @@ int w83977af_hard_xmit( struct sk_buff *skb, struct device *dev)
                        switch_bank(iobase, SET0);
                        outb(ICR_EDMAI, iobase+ICR);
                        w83977af_dma_write(idev, iobase);
+#ifdef CONFIG_USE_INTERNAL_TIMER
                }
+#endif
        } else {
                idev->tx_buff.data = idev->tx_buff.head;
                idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data, 
@@ -527,41 +541,57 @@ int w83977af_hard_xmit( struct sk_buff *skb, struct device *dev)
        return 0;
 }
 
-
 /*
  * Function w83977af_dma_write (idev, iobase)
  *
- *    
+ *    Send frame using DMA
  *
  */
-static void w83977af_dma_write( struct irda_device *idev, int iobase)
+static void w83977af_dma_write(struct irda_device *idev, int iobase)
 {
        __u8 set;
-
-        DEBUG( 4, __FUNCTION__ "()\n");
+#ifdef CONFIG_NETWINDER_TX_DMA_PROBLEMS
+       unsigned long flags;
+       __u8 hcr;
+#endif
+        DEBUG(4, __FUNCTION__ "(), len=%d\n", idev->tx_buff.len);
 
        /* Save current set */
-       set = inb( iobase+SSR);
+       set = inb(iobase+SSR);
 
        /* Disable DMA */
        switch_bank(iobase, SET0);
-       outb( inb( iobase+HCR) & ~HCR_EN_DMA, iobase+HCR);
-       
-       setup_dma(idev->io.dma, idev->tx_buff.data, idev->tx_buff.len, 
-                 DMA_MODE_WRITE);
-       
-       /* idev->media_busy = TRUE; */
-       idev->io.direction = IO_XMIT;
-       
+       outb(inb(iobase+HCR) & ~HCR_EN_DMA, iobase+HCR);
+
        /* Choose transmit DMA channel  */ 
        switch_bank(iobase, SET2);
-       outb(inb(iobase+ADCR1) | ADCR1_D_CHSW|ADCR1_DMA_F|ADCR1_ADV_SL, 
-            iobase+ADCR1);
+       outb(ADCR1_D_CHSW|/*ADCR1_DMA_F|*/ADCR1_ADV_SL, iobase+ADCR1);
+#ifdef CONFIG_NETWINDER_TX_DMA_PROBLEMS
+       save_flags(flags);
+       cli();
+
+       disable_dma(idev->io.dma);
+       clear_dma_ff(idev->io.dma);
+       set_dma_mode(idev->io.dma, DMA_MODE_READ);
+       set_dma_addr(idev->io.dma, virt_to_bus(idev->tx_buff.data));
+       set_dma_count(idev->io.dma, idev->tx_buff.len);
+#else
+       setup_dma(idev->io.dma, idev->tx_buff.data, idev->tx_buff.len, 
+                 DMA_MODE_WRITE);      
+#endif
+       idev->io.direction = IO_XMIT;
        
        /* Enable DMA */
        switch_bank(iobase, SET0);
-       outb(inb(iobase+HCR) | HCR_EN_DMA, iobase+HCR);
-       
+#ifdef CONFIG_NETWINDER_TX_DMA_PROBLEMS
+       hcr = inb(iobase+HCR);
+       outb(hcr | HCR_EN_DMA, iobase+HCR);
+       enable_dma(idev->io.dma);
+       restore_flags(flags);
+#else  
+       outb(inb(iobase+HCR) | HCR_EN_DMA | HCR_TX_WT, iobase+HCR);
+#endif
+
        /* Restore set register */
        outb(set, iobase+SSR);
 }
@@ -577,17 +607,17 @@ static int w83977af_pio_write(int iobase, __u8 *buf, int len, int fifo_size)
        int actual = 0;
        __u8 set;
        
-       DEBUG( 4, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
 
        /* Save current bank */
-       set = inb( iobase+SSR);
+       set = inb(iobase+SSR);
 
-       switch_bank( iobase, SET0);
+       switch_bank(iobase, SET0);
        if (!(inb_p(iobase+USR) & USR_TSRE)) {
-               DEBUG( 4, __FUNCTION__ "(), warning, FIFO not empty yet!\n");
+               DEBUG(4, __FUNCTION__ "(), warning, FIFO not empty yet!\n");
 
                fifo_size -= 17;
-               DEBUG( 4, __FUNCTION__ "%d bytes left in tx fifo\n", fifo_size);
+               DEBUG(4, __FUNCTION__ "%d bytes left in tx fifo\n", fifo_size);
        }
 
        /* Fill FIFO with current frame */
@@ -597,7 +627,7 @@ static int w83977af_pio_write(int iobase, __u8 *buf, int len, int fifo_size)
        }
         
        DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", 
-             fifo_size, actual, len);
+              fifo_size, actual, len);
 
        /* Restore bank */
        outb(set, iobase+SSR);
@@ -617,7 +647,7 @@ void w83977af_dma_xmit_complete(struct irda_device *idev)
        int iobase;
        __u8 set;
 
-       DEBUG(4, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "(%ld)\n", jiffies);
 
        ASSERT(idev != NULL, return;);
        ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
@@ -663,9 +693,10 @@ void w83977af_dma_xmit_complete(struct irda_device *idev)
  */
 int w83977af_dma_receive(struct irda_device *idev) 
 {
+       struct w83977af_ir *self;
        int iobase;
        __u8 set;
-#ifdef NETWINDER
+#ifdef CONFIG_NETWINDER_RX_DMA_PROBLEMS
        unsigned long flags;
        __u8 hcr;
 #endif
@@ -673,62 +704,60 @@ int w83977af_dma_receive(struct irda_device *idev)
        ASSERT(idev != NULL, return -1;);
        ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
 
-       DEBUG(0, __FUNCTION__ "\n");
+       DEBUG(4, __FUNCTION__ "\n");
 
+       self = idev->priv;
        iobase= idev->io.iobase;
 
        /* Save current set */
-       set = inb( iobase+SSR);
+       set = inb(iobase+SSR);
 
        /* Disable DMA */
-       switch_bank( iobase, SET0);
-       outb( inb( iobase+HCR) & ~HCR_EN_DMA, iobase+HCR);
+       switch_bank(iobase, SET0);
+       outb(inb(iobase+HCR) & ~HCR_EN_DMA, iobase+HCR);
 
-#ifdef NETWINDER
+       /* Choose DMA Rx, DMA Fairness, and Advanced mode */
+       switch_bank(iobase, SET2);
+       outb((inb(iobase+ADCR1) & ~ADCR1_D_CHSW)/*|ADCR1_DMA_F*/|ADCR1_ADV_SL,
+            iobase+ADCR1);
+
+       idev->io.direction = IO_RECV;
+       idev->rx_buff.data = idev->rx_buff.head;
+
+#ifdef CONFIG_NETWINDER_RX_DMA_PROBLEMS
        save_flags(flags);
        cli();
 
-       disable_dma( idev->io.dma);
-       clear_dma_ff( idev->io.dma);
-       set_dma_mode( idev->io.dma, DMA_MODE_READ);
-       set_dma_addr( idev->io.dma, virt_to_bus(idev->rx_buff.data));
-       set_dma_count( idev->io.dma, idev->rx_buff.truesize);
+       disable_dma(idev->io.dma);
+       clear_dma_ff(idev->io.dma);
+       set_dma_mode(idev->io.dma, DMA_MODE_READ);
+       set_dma_addr(idev->io.dma, virt_to_bus(idev->rx_buff.data));
+       set_dma_count(idev->io.dma, idev->rx_buff.truesize);
 #else
-       setup_dma(idev->io.dma, idev->rx_buff.data, 
-                 idev->rx_buff.truesize, DMA_MODE_READ);
+       setup_dma(idev->io.dma, idev->rx_buff.data, idev->rx_buff.truesize, 
+                 DMA_MODE_READ);
 #endif
-       /* driver->media_busy = FALSE; */
-       idev->io.direction = IO_RECV;
-       idev->rx_buff.data = idev->rx_buff.head;
-
        /* 
         * Reset Rx FIFO. This will also flush the ST_FIFO, it's very 
         * important that we don't reset the Tx FIFO since it might not
         * be finished transmitting yet
         */
-       outb( UFR_RXTL|UFR_TXTL|UFR_RXF_RST|UFR_EN_FIFO, iobase+UFR);
-       prev.status = 0;
-
-       /* Choose DMA Rx, DMA Fairness, and Advanced mode */
-       switch_bank(iobase, SET2);
-       outb(( inb( iobase+ADCR1) & ~ADCR1_D_CHSW)|ADCR1_DMA_F|ADCR1_ADV_SL,
-            iobase+ADCR1);
+       switch_bank(iobase, SET0);
+       outb(UFR_RXTL|UFR_TXTL|UFR_RXF_RST|UFR_EN_FIFO, iobase+UFR);
+       self->st_fifo.len = self->st_fifo.tail = self->st_fifo.head = 0;
        
        /* Enable DMA */
        switch_bank(iobase, SET0);
-#ifdef NETWINDER
-       hcr = inb( iobase+HCR);
-       enable_dma( idev->io.dma);
-       outb( hcr | HCR_EN_DMA, iobase+HCR);
+#ifdef CONFIG_NETWINDER_RX_DMA_PROBLEMS
+       hcr = inb(iobase+HCR);
+       outb(hcr | HCR_EN_DMA, iobase+HCR);
+       enable_dma(idev->io.dma);
        restore_flags(flags);
 #else  
-       outb( inb( iobase+HCR) | HCR_EN_DMA, iobase+HCR);
+       outb(inb(iobase+HCR) | HCR_EN_DMA, iobase+HCR);
 #endif
-       
        /* Restore set */
-       outb( set, iobase+SSR);
-
-       DEBUG( 4, __FUNCTION__ "(), done!\n");  
+       outb(set, iobase+SSR);
 
        return 0;
 }
@@ -742,12 +771,17 @@ int w83977af_dma_receive(struct irda_device *idev)
 int w83977af_dma_receive_complete(struct irda_device *idev)
 {
        struct sk_buff *skb;
+       struct w83977af_ir *self;
+       struct st_fifo *st_fifo;
        int len;
        int iobase;
        __u8 set;
        __u8 status;
 
-       DEBUG(0, __FUNCTION__ "\n");
+       DEBUG(4, __FUNCTION__ "\n");
+
+       self = idev->priv;
+       st_fifo = &self->st_fifo;
 
        iobase = idev->io.iobase;
 
@@ -756,22 +790,28 @@ int w83977af_dma_receive_complete(struct irda_device *idev)
        
        iobase = idev->io.iobase;
 
+       /* Read status FIFO */
        switch_bank(iobase, SET5);
-       if (prev.status & FS_FO_FSFDR) {
-               status = prev.status;
-               len = prev.len;
+       while ((status = inb(iobase+FS_FO)) & FS_FO_FSFDR) {
+               st_fifo->entries[st_fifo->tail].status = status;
                
-               prev.status = 0;
-       } else {
-               status = inb(iobase+FS_FO);
-               len = inb(iobase+RFLFL);
-               len |= inb(iobase+RFLFH) << 8;
+               st_fifo->entries[st_fifo->tail].len  = inb(iobase+RFLFL);
+               st_fifo->entries[st_fifo->tail].len |= inb(iobase+RFLFH) << 8;
+               
+               st_fifo->tail++;
+               st_fifo->len++;
        }
+       
+       while (st_fifo->len) {
+               /* Get first entry */
+               status = st_fifo->entries[st_fifo->head].status;
+               len    = st_fifo->entries[st_fifo->head].len;
+               st_fifo->head++;
+               st_fifo->len--;
 
-       while (status & FS_FO_FSFDR) {
                /* Check for errors */
                if (status & FS_FO_ERR_MSK) {
-                       if ( status & FS_FO_LST_FR) {
+                       if (status & FS_FO_LST_FR) {
                                /* Add number of lost frames to stats */
                                idev->stats.rx_errors += len;   
                        } else {
@@ -800,14 +840,20 @@ int w83977af_dma_receive_complete(struct irda_device *idev)
                        /* Check if we have transfered all data to memory */
                        switch_bank(iobase, SET0);
                        if (inb(iobase+USR) & USR_RDR) {
+#ifdef CONFIG_USE_INTERNAL_TIMER
                                /* Put this entry back in fifo */
-                               prev.status = status;
-                               prev.len = len;
-
+                               st_fifo->head--;
+                               st_fifo->len++;
+                               st_fifo->entries[st_fifo->head].status = status;
+                               st_fifo->entries[st_fifo->head].len = len;
+                               
                                /* Restore set register */
-                               outb( set, iobase+SSR);
+                               outb(set, iobase+SSR);
                        
                                return FALSE;   /* I'll be back! */
+#else
+                               udelay(80); /* Should be enough!? */
+#endif
                        }
                                                
                        skb = dev_alloc_skb(len+1);
@@ -824,28 +870,23 @@ int w83977af_dma_receive_complete(struct irda_device *idev)
                        skb_reserve(skb, 1); 
                        
                        /* Copy frame without CRC */
-                       if ( idev->io.baudrate < 4000000) {
-                               skb_put( skb, len-2);
-                               memcpy( skb->data, idev->rx_buff.data, len-2);
+                       if (idev->io.baudrate < 4000000) {
+                               skb_put(skb, len-2);
+                               memcpy(skb->data, idev->rx_buff.data, len-2);
                        } else {
-                               skb_put( skb, len-4);
-                               memcpy( skb->data, idev->rx_buff.data, len-4);
+                               skb_put(skb, len-4);
+                               memcpy(skb->data, idev->rx_buff.data, len-4);
                        }
 
                        /* Move to next frame */
                        idev->rx_buff.data += len;
+                       idev->stats.rx_packets++;
                        
                        skb->dev = &idev->netdev;
                        skb->mac.raw  = skb->data;
                        skb->protocol = htons(ETH_P_IRDA);
-                       netif_rx( skb);
-                       idev->stats.rx_packets++;
+                       netif_rx(skb);
                }
-               /* Read next entry in ST_FIFO */
-               switch_bank(iobase, SET5);
-               status = inb( iobase+FS_FO);
-               len = inb( iobase+RFLFL);
-               len |= inb( iobase+RFLFH) << 8;
        }
        /* Restore set register */
        outb(set, iobase+SSR);
@@ -875,7 +916,6 @@ static void w83977af_pio_receive(struct irda_device *idev)
        do {
                byte = inb(iobase+RBR);
                async_unwrap_char(idev, byte);
-
        } while (inb(iobase+USR) & USR_RDR); /* Data available */       
 }
 
@@ -889,9 +929,12 @@ static __u8 w83977af_sir_interrupt(struct irda_device *idev, int isr)
 {
        int actual;
        __u8 new_icr = 0;
+       __u8 set;
+       int iobase;
 
        DEBUG(4, __FUNCTION__ "(), isr=%#x\n", isr);
        
+       iobase = idev->io.iobase;
        /* Transmit FIFO low on data */
        if (isr & ISR_TXTH_I) {
                /* Write data left in transmit buffer */
@@ -899,16 +942,21 @@ static __u8 w83977af_sir_interrupt(struct irda_device *idev, int isr)
                                            idev->tx_buff.data, 
                                            idev->tx_buff.len, 
                                            idev->io.fifo_size);
+
                idev->tx_buff.data += actual;
                idev->tx_buff.len  -= actual;
                
                idev->io.direction = IO_XMIT;
 
                /* Check if finished */
-               if (idev->tx_buff.len > 0)
+               if (idev->tx_buff.len > 0) {
                        new_icr |= ICR_ETXTHI;
-               else { 
-                       DEBUG( 4, __FUNCTION__ "(), finished with frame!\n");
+               } else {
+                       set = inb(iobase+SSR);
+                       switch_bank(iobase, SET0);
+                       outb(AUDR_SFEND, iobase+AUDR);
+                       outb(set, iobase+SSR); 
+
                        idev->netdev.tbusy = 0; /* Unlock */
                        idev->stats.tx_packets++;
 
@@ -917,7 +965,6 @@ static __u8 w83977af_sir_interrupt(struct irda_device *idev, int isr)
 
                        new_icr |= ICR_ETBREI;
                }
-               
        }
        /* Check if transmission has completed */
        if (isr & ISR_TXEMP_I) {
@@ -943,22 +990,20 @@ static __u8 w83977af_sir_interrupt(struct irda_device *idev, int isr)
  *    Handle MIR/FIR interrupt
  *
  */
-static __u8 w83977af_fir_interrupt( struct irda_device *idev, int isr)
+static __u8 w83977af_fir_interrupt(struct irda_device *idev, int isr)
 {
        __u8 new_icr = 0;
        __u8 set;
        int iobase;
 
-       DEBUG( 4, __FUNCTION__ "(), isr=%#x\n", isr);
-
        iobase = idev->io.iobase;
-
        set = inb(iobase+SSR);
        
        /* End of frame detected in FIFO */
        if (isr & (ISR_FEND_I|ISR_FSF_I)) {
                if (w83977af_dma_receive_complete(idev)) {
                        
+                       /* Wait for next status FIFO interrupt */
                        new_icr |= ICR_EFSFI;
                } else {
                        /* DMA not finished yet */
@@ -982,7 +1027,7 @@ static __u8 w83977af_fir_interrupt( struct irda_device *idev, int isr)
 
                /* Clear timer event */
                /* switch_bank(iobase, SET0); */
-/*             outb( ASCR_CTE, iobase+ASCR); */
+/*             outb(ASCR_CTE, iobase+ASCR); */
 
                /* Check if this is a TX timer interrupt */
                if (idev->io.direction == IO_XMIT) {
@@ -998,15 +1043,18 @@ static __u8 w83977af_fir_interrupt( struct irda_device *idev, int isr)
        }       
        /* Finished with DMA */
        if (isr & ISR_DMA_I) {
-               w83977af_dma_xmit_complete( idev);
-               
+               w83977af_dma_xmit_complete(idev);
+
                /* Check if there are more frames to be transmitted */
-               if (irda_device_txqueue_empty( idev)) {
+               /* if (irda_device_txqueue_empty(idev)) { */
                
-                       /* Prepare for receive */
-                       w83977af_dma_receive(idev);
-                       new_icr = ICR_EFSFI;
-               }
+               /* Prepare for receive 
+                * 
+                * ** Netwinder Tx DMA likes that we do this anyway **
+                */
+               w83977af_dma_receive(idev);
+               new_icr = ICR_EFSFI;
+              /* } */
        }
        
        /* Restore set */
@@ -1030,7 +1078,7 @@ static void w83977af_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
        if (idev == NULL) {
                printk(KERN_WARNING "%s: irq %d for unknown device.\n", 
-                      driver_name, irq);
+                       driver_name, irq);
                return;
        }
 
@@ -1049,7 +1097,7 @@ static void w83977af_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        
        if (isr) {
                /* Dispatch interrupt handler for the current speed */
-               if ( idev->io.baudrate > 115200)
+               if (idev->io.baudrate > PIO_MAX_SPEED )
                        icr = w83977af_fir_interrupt(idev, isr);
                else
                        icr = w83977af_sir_interrupt(idev, isr);
@@ -1070,7 +1118,7 @@ static void w83977af_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 static void w83977af_wait_until_sent(struct irda_device *idev)
 {
        current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(6);
+       schedule_timeout(60*HZ/1000);
 }
 
 /*
@@ -1085,16 +1133,16 @@ static int w83977af_is_receiving(struct irda_device *idev)
        int iobase;
        __u8 set;
 
-       ASSERT( idev != NULL, return FALSE;);
-       ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return FALSE;);
+       ASSERT(idev != NULL, return FALSE;);
+       ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return FALSE;);
 
-       if ( idev->io.baudrate > 115200) {
+       if (idev->io.baudrate > 115200) {
                iobase = idev->io.iobase;
 
                /* Check if rx FIFO is not empty */
                set = inb(iobase+SSR);
-               switch_bank( iobase, SET2);
-               if (( inb( iobase+RXFDTH) & 0x3f) != 0) {
+               switch_bank(iobase, SET2);
+               if ((inb(iobase+RXFDTH) & 0x3f) != 0) {
                        /* We are receiving something */
                        status =  TRUE;
                }
@@ -1111,12 +1159,12 @@ static int w83977af_is_receiving(struct irda_device *idev)
  *    
  *
  */
-static int w83977af_net_init( struct device *dev)
+static int w83977af_net_init(struct device *dev)
 {
        DEBUG(0, __FUNCTION__ "()\n");
 
        /* Set up to be a normal IrDA network device driver */
-       irda_device_setup( dev);
+       irda_device_setup(dev);
 
        /* Insert overrides below this line! */
 
@@ -1130,7 +1178,7 @@ static int w83977af_net_init( struct device *dev)
  *    Start the device
  *
  */
-static int w83977af_net_open( struct device *dev)
+static int w83977af_net_open(struct device *dev)
 {
        struct irda_device *idev;
        int iobase;
@@ -1147,7 +1195,7 @@ static int w83977af_net_open( struct device *dev)
        iobase = idev->io.iobase;
 
        if (request_irq(idev->io.irq, w83977af_interrupt, 0, idev->name, 
-                       (void *) idev)) {
+                        (void *) idev)) {
                return -EAGAIN;
        }
        /*
@@ -1170,13 +1218,13 @@ static int w83977af_net_open( struct device *dev)
        /* Enable some interrupts so we can receive frames again */
        switch_bank(iobase, SET0);
        if (idev->io.baudrate > 115200) {
-               outb( ICR_EFSFI, iobase+ICR);
-               w83977af_dma_receive( idev);
+               outb(ICR_EFSFI, iobase+ICR);
+               w83977af_dma_receive(idev);
        } else
-               outb( ICR_ERBRI, iobase+ICR);
+               outb(ICR_ERBRI, iobase+ICR);
 
        /* Restore bank register */
-       outb( set, iobase+SSR);
+       outb(set, iobase+SSR);
 
        MOD_INC_USE_COUNT;
 
@@ -1195,34 +1243,34 @@ static int w83977af_net_close(struct device *dev)
        int iobase;
        __u8 set;
 
-       DEBUG( 0, __FUNCTION__ "()\n");
+       DEBUG(0, __FUNCTION__ "()\n");
        
        /* Stop device */
        dev->tbusy = 1;
        dev->start = 0;
 
-       ASSERT( dev != NULL, return -1;);
+       ASSERT(dev != NULL, return -1;);
        idev = (struct irda_device *) dev->priv;
        
-       ASSERT( idev != NULL, return 0;);
-       ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;);
+       ASSERT(idev != NULL, return 0;);
+       ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return 0;);
        
        iobase = idev->io.iobase;
 
-       disable_dma( idev->io.dma);
+       disable_dma(idev->io.dma);
 
        /* Save current set */
-       set = inb( iobase+SSR);
+       set = inb(iobase+SSR);
        
        /* Disable interrupts */
-       switch_bank( iobase, SET0);
-       outb( 0, iobase+ICR); 
+       switch_bank(iobase, SET0);
+       outb(0, iobase+ICR); 
 
-       free_irq( idev->io.irq, idev);
-       free_dma( idev->io.dma);
+       free_irq(idev->io.irq, idev);
+       free_dma(idev->io.dma);
 
        /* Restore bank register */
-       outb( set, iobase+SSR);
+       outb(set, iobase+SSR);
 
        MOD_DEC_USE_COUNT;
 
@@ -1231,6 +1279,11 @@ static int w83977af_net_close(struct device *dev)
 
 #ifdef MODULE
 
+MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
+MODULE_DESCRIPTION("Winbond W83977AF IrDA Device Driver");
+
+MODULE_PARM(qos_mtt_bits, "i");
+
 /*
  * Function init_module (void)
  *
index 8bf83997d91d509734a3cc833f41c627097299f4..5939c43ab1deedd1ec68493c4500091ce60e6c57 100644 (file)
@@ -5,32 +5,31 @@
 # Right now hubs, mice and keyboards work - at least with UHCI.
 # But that may be more a lucky coincidence than anything else..
 #
-# This was all developed modularly, but I've been lazy in cleaning
-# it up, so right now they are all bools. 
-#
 mainmenu_option next_comment
 comment 'USB drivers - not for the faint of heart'
 
 tristate 'Support for USB (EXPERIMENTAL!)' CONFIG_USB
 if [ ! "$CONFIG_USB" = "n" ]; then
-  bool 'UHCI (intel PIIX4 and others) support?' CONFIG_USB_UHCI
+  dep_tristate 'UHCI (intel PIIX4 and others) support' CONFIG_USB_UHCI \
+       $CONFIG_USB
+    dep_tristate 'OHCI (compaq and some others) support' CONFIG_USB_OHCI \
+       $CONFIG_USB
 
-  bool 'OHCI (compaq and some others) support?' CONFIG_USB_OHCI
-  if [ "$CONFIG_USB_OHCI" = "y" ]; then
-     bool '  Enable tons of OHCI debugging output?' CONFIG_USB_OHCI_DEBUG
+  if [ "$CONFIG_USB_OHCI" != "n" ]; then
+     bool '  Enable tons of OHCI debugging output' CONFIG_USB_OHCI_DEBUG
   fi
-
-  bool 'OHCI-HCD (other OHCI opt. Virt. Root Hub) support?' CONFIG_USB_OHCI_HCD
-  if [ "$CONFIG_USB_OHCI_HCD" = "y" ]; then
-     bool 'OHCI-HCD Virtual Root Hub' CONFIG_USB_OHCI_VROOTHUB
+  dep_tristate 'OHCI-HCD (other OHCI opt. Virt. Root Hub) support' \
+               CONFIG_USB_OHCI_HCD $CONFIG_USB
+  if [ "$CONFIG_USB_OHCI_HCD" != "n" ]; then
+       bool '  OHCI-HCD Virtual Root Hub' CONFIG_USB_OHCI_VROOTHUB
   fi
 
-  bool 'USB mouse support' CONFIG_USB_MOUSE
-  bool 'USB keyboard support' CONFIG_USB_KBD
-  bool 'USB audio parsing support' CONFIG_USB_AUDIO
-  bool 'USB Abstract Control Model support' CONFIG_USB_ACM
-  bool 'USB printer support' CONFIG_USB_PRINTER
-  
+  dep_tristate 'USB hub support' CONFIG_USB_HUB $CONFIG_USB
+  dep_tristate 'USB mouse support' CONFIG_USB_MOUSE $CONFIG_USB
+  dep_tristate 'USB keyboard support' CONFIG_USB_KBD $CONFIG_USB
+  dep_tristate 'USB audio parsing support' CONFIG_USB_AUDIO $CONFIG_USB
+  dep_tristate 'USB Abstract Control Model support' CONFIG_USB_ACM $CONFIG_USB
+  dep_tristate 'Preliminary USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
 fi
 
 endmenu
index 0d910eecb1535ec5902ed10143065c8ce93675e1..447354398294398d2d63778dc51dcd618cdc5a54 100644 (file)
@@ -7,8 +7,6 @@
 #
 # Note 2! The CFLAGS definitions are now inherited from the
 # parent makes..
-#
-# This isn't actually supported yet. Don't try to use it.
 
 SUB_DIRS     :=
 MOD_SUB_DIRS := $(SUB_DIRS)
@@ -17,71 +15,100 @@ ALL_SUB_DIRS := $(SUB_DIRS)
 L_TARGET := usb.a
 M_OBJS   :=
 L_OBJS   :=
-LX_OBJS  :=
-USBX_OBJS := usb.o hub.o usb-debug.o
+
+ifeq ($(CONFIG_USB),y)
+  L_OBJS +=usbcore.o
+endif
+ifeq ($(CONFIG_USB),m)
+  M_OBJS +=usbcore.o
+  MIX_OBJS +=usb.o usb-debug.o usb-core.o
+endif
+
+ifeq ($(CONFIG_USB_UHCI),y)
+    L_OBJS += uhci.o uhci-debug.o
+endif
+
+ifeq ($(CONFIG_USB_UHCI),m)
+      M_OBJS += usb-uhci.o
+    MIX_OBJS += uhci.o uhci-debug.o
+endif
+
+ifeq ($(CONFIG_USB_OHCI),y)
+    L_OBJS += ohci.o ohci-debug.o
+endif
+ifeq ($(CONFIG_USB_OHCI),m)
+      M_OBJS += usb-ohci.o
+      MIX_OBJS += ohci.o ohci-debug.o
+endif
+
+ifeq ($(CONFIG_USB_OHCI_HCD),y)
+    L_OBJS += ohci-hcd.o ohci-root-hub.o
+endif
+ifeq ($(CONFIG_USB_OHCI_HCD),m)
+      M_OBJS += usb-ohci-hcd.o
+      MIX_OBJS += ohci-hcd.o ohci-root-hub.o
+endif
 
 ifeq ($(CONFIG_USB_MOUSE),y)
-  USBX_OBJS += mouse.o
+  L_OBJS += mouse.o
+endif
+ifeq ($(CONFIG_USB_MOUSE),m)
+  M_OBJS  +=mouse.o    
+  MIX_OBJS +=mouse.o
+endif
+
+ifeq ($(CONFIG_USB_HUB),y)
+  L_OBJS += hub.o
+endif
+ifeq ($(CONFIG_USB_HUB),m)
+  M_OBJS  +=hub.o
+  MIX_OBJS +=hub.o     
 endif
 
 ifeq ($(CONFIG_USB_ACM),y)
-  USBX_OBJS += acm.o
+  L_OBJS += acm.o
+endif
+ifeq ($(CONFIG_USB_ACM),m)
+  M_OBJS += acm.o
+  MIX_OBJS +=acm.o
 endif
 
-ifeq ($(CONFIG_USB_KBD),y)
-  USBX_OBJS += keyboard.o keymap.o
+ifeq ($(CONFIG_USB_PRINTER),y)
+  L_OBJS += printer.o
 endif
 
-ifeq ($(CONFIG_USB_AUDIO),y)
-  USBX_OBJS += audio.o
+ifeq ($(CONFIG_USB_PRINTER),m)
+  M_OBJS += printer.o
+  MIX_OBJS += printer.o  
 endif
 
-ifeq ($(CONFIG_USB_CPIA),y)
-  USBX_OBJS += cpia.o
+ifeq ($(CONFIG_USB_KBD),y)
+  L_OBJS += keyboard.o keymap.o
 endif
 
-ifeq ($(CONFIG_USB_PRINTER),y)
-  USBX_OBJS += printer.o
+ifeq ($(CONFIG_USB_KBD),m)
+  M_OBJS += usb-keyboard.o
+  MIX_OBJS += keyboard.o keymap.o
 endif
 
-ifeq ($(CONFIG_USB), y)
-  L_OBJS += $(USBX_OBJS)
+ifeq ($(CONFIG_USB_AUDIO),y)
+  L_OBJS += audio.o
 endif
 
-ifeq ($(CONFIG_USB_UHCI),y)
-  ifeq ($(CONFIG_USB), y)
-    L_OBJS += uhci.o uhci-debug.o
-  else
-    ifeq ($(CONFIG_USB),m)
-      M_OBJS += usb-uhci.o
-      MIX_OBJS += $(USBX_OBJS)
-    endif
-  endif
+ifeq ($(CONFIG_USB_AUDIO),m)
+  M_OBJS += audio.o
+  MIX_OBJS += audio.o
 endif
 
-ifeq ($(CONFIG_USB_OHCI),y)
-  ifeq ($(CONFIG_USB), y)
-    L_OBJS += ohci.o ohci-debug.o
-  else
-    ifeq ($(CONFIG_USB),m)
-      USBO_OBJS += ohci.o ohci-debug.o
-      M_OBJS += usb-ohci.o
-      MIX_OBJS += $(USBX_OBJS)
-    endif
-  endif
+ifeq ($(CONFIG_USB_CPIA),y)
+  L_OBJS += cpia.o
 endif
 
-ifeq ($(CONFIG_USB_OHCI_HCD),y)
-  ifeq ($(CONFIG_USB), y)
-    L_OBJS += ohci-hcd.o ohci-root-hub.o
-  else
-    ifeq ($(CONFIG_USB),m)
-      USBO_OBJS += ohci-hcd.o ohci-root-hub.o
-      M_OBJS += usb-ohci-hcd.o
-      MIX_OBJS += $(USBX_OBJS)
-    endif
-  endif
+ifeq ($(CONFIG_USB_CPIA),m)
+  M_OBJS += cpia.o
+  MIX_OBJS += cpia.o
 endif
+
 include $(TOPDIR)/Rules.make
 
 keymap.o: keymap.c
@@ -89,12 +116,19 @@ keymap.o: keymap.c
 keymap.c: maps/serial.map maps/usb.map maps/fixup.map
        ./mkmap > $@
 
-usb-uhci.o: uhci.o uhci-debug.o $(USBX_OBJS)
-       $(LD) $(LD_RFLAG) -r -o $@  uhci.o uhci-debug.o $(USBX_OBJS)
+usb-keyboard.o: keymap.o keyboard.o
+       $(LD) $(LD_RFLAG) -r -o $@  keymap.o keyboard.o 
 
-usb-ohci.o: ohci.o ohci-debug.o $(USBX_OBJS)
-       $(LD) $(LD_RFLAG) -r -o $@ ohci.o ohci-debug.o $(USBX_OBJS)
+usb-uhci.o: uhci.o uhci-debug.o 
+       $(LD) $(LD_RFLAG) -r -o $@  uhci.o uhci-debug.o 
+
+usb-ohci.o: ohci.o ohci-debug.o 
+       $(LD) $(LD_RFLAG) -r -o $@ ohci.o ohci-debug.o 
+       
+usb-ohci-hcd.o: ohci-hcd.o ohci-root-hub.o 
+       $(LD) $(LD_RFLAG) -r -o $@ ohci-hcd.o ohci-root-hub.o 
+       
+usbcore.o: usb.o usb-debug.o usb-core.o
+       $(LD) $(LD_RFLAG) -r -o $@ usb.o usb-debug.o usb-core.o
 
-usb-ohci-hcd.o: ohci-hcd.o ohci-root-hub.o $(USBX_OBJS)
-       $(LD) $(LD_RFLAG) -r -o $@ ohci-hcd.o ohci-root-hub.o $(USBX_OBJS)
        
index 840adfe08fce849b1a6a325e6f8703d0cc2bd49d..de6015eb3131a675b134ab03ef364ee04ff0e987 100644 (file)
@@ -3,9 +3,19 @@
  *
  * Armin Fuerst 5/8/1999
  *
- * version 0.0: Driver sets up configuration, setus up data pipes, opens misc
+ * version 0.2: Improved Bulk transfer. TX led now flashes every time data is
+ * sent. Send Encapsulated Data is not needed, nor does it do anything.
+ * Why's that ?!? Thanks to Thomas Sailer for his close look at the bulk code.
+ * He told me about some importand bugs. (5/21/99)
+ *
+ * version 0.1: Bulk transfer for uhci seems to work now, no dangling tds any
+ * more. TX led of the ISDN TA flashed the first time. Does this mean it works?
+ * The interrupt of the ctrl endpoint crashes the kernel => no read possible
+ * (5/19/99)
+ *
+ * version 0.0: Driver sets up configuration, sets up data pipes, opens misc
  * device. No actual data transfer is done, since we don't have bulk transfer,
- * yet. Purely skeleton for now.
+ * yet. Purely skeleton for now. (5/8/99)
  */
 
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/errno.h>
 #include <linux/miscdevice.h>
-#include <linux/random.h>
 #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/malloc.h>
+#include <linux/config.h>
+#include <linux/module.h>
 
 #include <asm/spinlock.h>
 
 struct acm_state {
        int present; /* this acm is plugged in */
        int active; /* someone is has this acm's device open */
+       int serstate; /* Status of the serial port (rate, handshakelines,...) */
        struct usb_device *dev;
-       unsigned int readpipe,writepipe;
+       unsigned ctrlbuffer;    /*buffer for control messages*/
+       unsigned int readendp,writeendp,ctrlendp;
+       unsigned int readpipe,writepipe,ctrlpipe;
+       char buffer;
 };
 
 static struct acm_state static_acm_state;
@@ -37,16 +52,44 @@ spinlock_t usb_acm_lock = SPIN_LOCK_UNLOCKED;
 
 static int acm_irq(int state, void *__buffer, void *dev_id)
 {
-/*
-       signed char *data = __buffer;
+//     unsigned char *data = __buffer;
         struct acm_state *acm = &static_acm_state; 
+        devrequest *dr;
+
+        dr=__buffer;
+       printk("ACM_USB_IRQ\n");
+        printk("reqtype: %02X\n",dr->requesttype);
+        printk("request: %02X\n",dr->request);
+       printk("wValue: %02X\n",dr->value);
+       printk("wIndex: %02X\n",dr->index);
+       printk("wLength: %02X\n",dr->length);
+       
+       switch(dr->request) {
+         //Network connection 
+         case 0x00:
+           printk("Network connection: ");
+           if (dr->request==0) printk("disconnected\n");
+           if (dr->request==1) printk("connected\n");
+           break;
+
+         //Response available
+         case 0x01:
+           printk("Response available\n");
+           acm->buffer=1;
+           break;
+       
+         //Set serial line state
+         case 0x20:
+           if ((dr->index==1)&&(dr->length==2)) {
+             acm->serstate=acm->ctrlbuffer;
+             printk("Serstate: %02X\n",acm->ctrlbuffer);
+           }
+           break;
+       }
+/*
        if(!acm->active)
                return 1;
 */
-
-       /*We should so something useful here*/
-       printk("ACM_USB_IRQ\n");
-
        return 1;
 }
 
@@ -76,22 +119,48 @@ static int open_acm(struct inode * inode, struct file * file)
 static ssize_t write_acm(struct file * file,
        const char * buffer, size_t count, loff_t *ppos)
 {
-        char * buffer="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+        devrequest dr;
        struct acm_state *acm = &static_acm_state;
+       unsigned long retval;           
+
        printk("USB_FILE_WRITE\n");
-               printk("writing:>%s<\n",buffer);
-               acm->dev->bus->op->bulk_msg(acm->dev,acm->writepipe,buffer, 26);
-               printk("done:>%s<\n",buffer);
-               printk("reading:>%s<\n",buffer);
-               acm->dev->bus->op->bulk_msg(acm->dev,acm->readpipe,buffer, 26);
-               printk("done:>%s<\n",buffer);
+//Huh, i seem to got that wrong, we don't need this ?!?
+/*
+       dr.requesttype = USB_TYPE_CLASS | USB_RT_ENDPOINT;
+       dr.request = 0;
+       dr.value = 0;
+       dr.index = acm->writeendp;
+       dr.length = count;
+       acm->dev->bus->op->control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), &dr, NULL, 0);
+*/     
+
+       acm->dev->bus->op->bulk_msg(acm->dev,&acm->writepipe,buffer, count, &retval);
        return -EINVAL;
 }
 
-static ssize_t read_acm(struct file * file, char * buffer, size_t count, loff_t *ppos)
+
+static ssize_t read_acm(struct file * file, const char * buffer, size_t count, loff_t *ppos)
 {
+       devrequest dr;
+        struct acm_state *acm = &static_acm_state;
+       unsigned long retval;
        printk("USB_FILE_READ\n");
-       return -EINVAL;
+//        if (!acm->buffer) return -1;
+       acm->buffer=0;
+//We don't need this
+/*
+       printk("writing control msg\n");
+       dr.requesttype = USB_TYPE_CLASS | USB_RT_ENDPOINT | 0x80;
+       dr.request = 1;
+       dr.value = 0;
+       dr.index = acm->readendp;
+       dr.length = 0;
+       acm->dev->bus->op->control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), &dr, NULL, 0);
+*/
+       printk("reading:>%s<\n",buffer);
+       acm->dev->bus->op->bulk_msg(acm->dev,&acm->readpipe,buffer, 1,&retval);
+       printk("done:>%s<\n",buffer);
+       return 1;
 }
 
 struct file_operations usb_acm_fops = {
@@ -165,10 +234,14 @@ static int acm_probe(struct usb_device *dev)
                printk("USB ACM found\n");
                usb_set_configuration(dev, dev->config[cfgnum].bConfigurationValue);
                acm->dev=dev;
-               acm->readpipe=__create_pipe(dev,&dev->config[cfgnum].interface[1].endpoint[0]);
-               acm->writepipe=__create_pipe(dev,&dev->config[cfgnum].interface[1].endpoint[1]);
-               usb_request_irq(dev, usb_rcvctrlpipe(dev,&dev->config[cfgnum].interface[0].endpoint[0]), acm_irq, endpoint->bInterval, NULL);
+               acm->readendp=dev->config[cfgnum].interface[1].endpoint[0].bEndpointAddress;
+               acm->writeendp=dev->config[cfgnum].interface[1].endpoint[1].bEndpointAddress;
+               acm->ctrlendp=dev->config[cfgnum].interface[0].endpoint[0].bEndpointAddress;
+               acm->readpipe=usb_rcvbulkpipe(dev,acm->readendp);
+               acm->writepipe=usb_sndbulkpipe(dev,acm->writeendp);
+               usb_request_irq(dev,acm->ctrlpipe=usb_rcvctrlpipe(dev,acm->ctrlendp), acm_irq, dev->config[cfgnum].interface[0].endpoint[0].bInterval, &acm->ctrlbuffer);
                acm->present = 1;
+               acm->buffer=0;
                return 0;
        }
 
@@ -203,7 +276,7 @@ int usb_acm_init(void)
        return 0;
 }
 
-#if 0
+#ifdef MODULE
 
 int init_module(void)
 {
index 8b0c9d15c7485cc5dd2138264e1bf6c07b22cca3..0a99237d20b76082144ec5bde7f88c5a66be4143 100644 (file)
@@ -3,6 +3,9 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/sched.h>
+#include <linux/config.h>
+#include <linux/module.h>
+
 #include "usb.h"
 
 static int usb_audio_probe(struct usb_device *dev);
@@ -124,3 +127,15 @@ void usb_audio_endpoint(struct usb_endpoint_descriptor *interface, u8 *data)
 {
 }
 
+#ifdef MODULE
+int init_module(void)
+{
+       return usb_audio_init();
+}
+
+void module_cleanup(void)
+{
+       usb_deregister(&usb_audio_driver);
+}
+
+#endif
index 7fb36cf79cbef76272113f878923642142cea787..88ada6cfc5349aef847f94a934b80580a4c3cd2b 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/videodev.h>
 #include <linux/vmalloc.h>
 #include <linux/wrapper.h>
+#include <linux/config.h>
+#include <linux/module.h>
 
 #include <asm/spinlock.h>
 #include <asm/io.h>
@@ -1253,3 +1255,13 @@ int usb_cpia_init(void)
        return 0;
 }
 
+#ifdef MODULE
+int init_module(void)
+{
+       return usb_cpia_init();
+}
+void module_cleanup(void)
+{
+}
+#endif
+
index 9d3b428c0679bc223b66725591a4653a38186ec5..9886a6d5774d74cdc679e6569c1fdce5aa429c07 100644 (file)
@@ -1,10 +1,6 @@
 /*
  * USB hub driver.
  *
- * This is horrible, it knows about the UHCI driver
- * internals, but it's just meant as a rough example,
- * let's do the virtualization later when this works.
- *
  * (C) Copyright 1999 Linus Torvalds
  * (C) Copyright 1999 Johannes Erdfelt
  */
 #include <linux/list.h>
 #include <linux/malloc.h>
 #include <linux/smp_lock.h>
+#include <linux/config.h>
+#include <linux/module.h>
 
 #include <asm/spinlock.h>
 
 #include "usb.h"
-#include "uhci.h"
 #include "hub.h"
 
-extern struct usb_operations uhci_device_operations;
-
 /* Wakes up khubd */
 static DECLARE_WAIT_QUEUE_HEAD(usb_hub_wait);
 static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED;
@@ -413,10 +408,20 @@ int usb_hub_init(void)
        return 0;
 }
 
-void hub_cleanup(void)
+void usb_hub_cleanup(void)
 {
        if (khubd_pid >= 0)
                kill_proc(khubd_pid, SIGINT, 1);
 
        usb_deregister(&hub_driver);
 }
+
+#ifdef MODULE
+int init_module(void){
+       return usb_hub_init();
+}
+
+void module_cleanup(void){
+       usb_hub_cleanup();
+}
+#endif
index ade33b5baf39836b019c5dfdf60c6d26b71342d1..115994fed950edfb067d62135863702183ec8948 100644 (file)
@@ -1,8 +1,7 @@
-int bp_mouse_init(void);
 int usb_kbd_init(void);
 int usb_audio_init(void);
-int hub_init(void);
+int usb_hub_init(void);
 int usb_acm_init(void);
 int usb_printer_init(void);
-void hub_cleanup(void);
+void usb_hub_cleanup(void);
 void usb_mouse_cleanup(void);
index c60c812a587eb4dec32ab319701b219919f7e7af..609f2ca5e7ca3cf3f3c83b33c57c68f16abfac96 100644 (file)
@@ -3,6 +3,9 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/sched.h>
+#include <linux/config.h>
+#include <linux/module.h>
+
 #include <linux/kbd_ll.h>
 #include "usb.h"
 
@@ -218,9 +221,21 @@ usb_kbd_disconnect(struct usb_device *dev)
     printk(KERN_INFO "USB HID boot protocol keyboard removed.\n");
 }
 
-int
-usb_kbd_init(void)
+int usb_kbd_init(void)
 {
     usb_register(&usb_kbd_driver);
     return 0;
 }
+
+#ifdef MODULE
+int init_module(void)
+{
+       return usb_kbd_init();
+}
+
+void module_cleanup(void)
+{
+       usb_deregister(&usb_kbd_driver);
+}
+#endif
+
index b9621d2566a5c07146e9b5a30b4afd9441fefb49..6017f905e84f5390335e9994b14a2d9d0d349017 100644 (file)
@@ -33,6 +33,8 @@
 #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/malloc.h>
+#include <linux/config.h>
+#include <linux/module.h>
 
 #include <asm/spinlock.h>
 
@@ -285,6 +287,7 @@ static void mouse_disconnect(struct usb_device *dev)
 
        /* this might need work */
        mouse->present = 0;
+       printk("Mouse disconnected\n");
 }
 
 static struct usb_driver mouse_driver = {
@@ -315,3 +318,15 @@ void usb_mouse_cleanup(void)
        usb_deregister(&mouse_driver);
        misc_deregister(&usb_mouse);
 }
+
+#ifdef MODULE
+int init_module(void)
+{
+       return usb_mouse_init();
+}
+
+void cleanup_module(void)
+{
+       usb_mouse_cleanup();
+}
+#endif
index d02efe49cc0a5b1b6fc42c89581b274d8e0ec8c5..820efc5dcb49f9e21e97e4a5f34c2dd7679c44fc 100644 (file)
@@ -3,12 +3,14 @@
  *
  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
  *
- * The OHCI HCD layer is a simple but nearly complete implementation of what the
- * USB people would call a HCD  for the OHCI. 
+ * The OHCI HCD layer is a simple but nearly complete implementation of what 
+ * the USB people would call a HCD  for the OHCI. 
  * (ISO comming soon, Bulk disabled, INT u. CTRL transfers enabled)
- * The layer on top of it, is for interfacing to the alternate-usb device-drivers.
+ * The layer on top of it, is for interfacing to the alternate-usb 
+ * device-drivers.
  * 
- * [ This is based on Linus' UHCI code and gregs OHCI fragments (0.03c source tree). ]
+ * [ This is based on Linus' UHCI code and gregs OHCI fragments 
+ * (0.03c source tree). ]
  * [ Open Host Controller Interface driver for USB. ]
  * [ (C) Copyright 1999 Linus Torvalds (uhci.c) ]
  * [ (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com> ]
@@ -51,9 +53,6 @@
 
 #include "usb.h"
 #include "ohci-hcd.h"
-#include "inits.h" 
-
 
 #ifdef CONFIG_APM
 #include <linux/apm_bios.h>
@@ -1000,15 +999,15 @@ void start_hc(struct ohci *ohci)
 
        struct usb_device * usb_dev;
        struct ohci_device *dev;
-
-       usb_dev = sohci_usb_allocate(ohci->root_hub->usb);
+       struct ohci_device *tmp_root_hub= usb_to_ohci(ohci->bus->root_hub);
+       usb_dev = sohci_usb_allocate(tmp_root_hub->usb);
        dev = usb_dev->hcpriv; 
 
        dev->ohci = ohci; 
 
        usb_connect(usb_dev);
 
-       ohci->root_hub->usb->children[0] = usb_dev;
+       tmp_root_hub->usb->children[0] = usb_dev;
 
        usb_new_device(usb_dev);
        }
@@ -1085,6 +1084,7 @@ static void ohci_connect_change(struct ohci *ohci, unsigned int port_nr)
 {
        struct usb_device *usb_dev;
     struct ohci_device *dev;
+       struct ohci_device *tmp_root_hub=usb_to_ohci(ohci->bus->root_hub);
        OHCI_DEBUG(printk("uhci_connect_change: called for %d stat %x\n", port_nr,readl(&ohci->regs->roothub.portstatus[port_nr]) );)
 
        /*
@@ -1094,7 +1094,7 @@ static void ohci_connect_change(struct ohci *ohci, unsigned int port_nr)
         *
         * So start off by getting rid of any old devices..
         */
-       usb_disconnect(&ohci->root_hub->usb->children[port_nr]);
+       usb_disconnect(&tmp_root_hub->usb->children[port_nr]);
 
         if(!(readl(&ohci->regs->roothub.portstatus[port_nr]) & RH_PS_CCS)) {
                writel(RH_PS_CCS, &ohci->regs->roothub.portstatus[port_nr]);
@@ -1104,11 +1104,11 @@ static void ohci_connect_change(struct ohci *ohci, unsigned int port_nr)
         * Ok, we got a new connection. Allocate a device to it,
         * and find out what it wants to do..
         */
-       usb_dev = sohci_usb_allocate(ohci->root_hub->usb);
+       usb_dev = sohci_usb_allocate(tmp_root_hub->usb);
        dev = usb_dev->hcpriv; 
        dev->ohci = ohci; 
        usb_connect(dev->usb);
-       ohci->root_hub->usb->children[port_nr] = usb_dev;
+       tmp_root_hub->usb->children[port_nr] = usb_dev;
        wait_ms(200); /* wait for powerup */
     /* reset port/device */
        writel(RH_PS_PRS, &ohci->regs->roothub.portstatus[port_nr]); /* reset port */
@@ -1253,10 +1253,9 @@ static struct ohci *alloc_ohci(void* mem_base)
        if (!usb)
                return NULL;
 
-       dev = ohci->root_hub = usb_to_ohci(usb);
-
+       dev = usb_to_ohci(usb);
        usb->bus = bus;
-       /* bus->root_hub = ohci_to_usb(ohci->root_hub); */
+       bus->root_hub = usb;
        dev->ohci = ohci;
        
        /* Initialize the root hub */
@@ -1275,10 +1274,11 @@ static struct ohci *alloc_ohci(void* mem_base)
 static void release_ohci(struct ohci *ohci)
 {
        int i;
+       struct ohci_device *tmp_root_hub=usb_to_ohci(ohci->bus->root_hub);
        union ep_addr_ ep_addr;
        ep_addr.iep = 0;
        
-    OHCI_DEBUG(printk("USB HC release ohci \n");)
+       OHCI_DEBUG(printk("USB HC release ohci \n"););
     
        if (ohci->irq >= 0) {
                free_irq(ohci->irq, ohci);
@@ -1296,25 +1296,22 @@ static void release_ohci(struct ohci *ohci)
        ohci_rm_eds(ohci); /* remove eds */
        
     /* disconnect all devices */    
-       if(ohci->root_hub)
-               for(i = 0; i < ohci->root_hub->usb->maxchild; i++)
-                         usb_disconnect(ohci->root_hub->usb->children + i);
+       if(ohci->bus->root_hub)
+               for(i = 0; i < tmp_root_hub->usb->maxchild; i++)
+                       usb_disconnect(tmp_root_hub->usb->children + i);
            
-    USB_FREE(ohci->root_hub->usb);
-    USB_FREE(ohci->root_hub);
+    usb_deregister_bus(ohci->bus);
+    USB_FREE(tmp_root_hub->usb);
+    USB_FREE(tmp_root_hub);
     USB_FREE(ohci->bus);
     
        /* unmap the IO address space */
        iounmap(ohci->regs);
        
-       
        free_pages((unsigned int) ohci->hc_area, 1);
        
 }
 
-void cleanup_drivers(void);
-
 static int ohci_roothub_thread(void * __ohci)
 {
         struct ohci *ohci = (struct ohci *)__ohci;
@@ -1336,6 +1333,7 @@ static int ohci_roothub_thread(void * __ohci)
                start_hc(ohci);
                writel( 0x10000, &ohci->regs->roothub.status);
                wait_ms(50); /* root hub power on */
+       usb_register_bus(ohci->bus);
          do {
 #ifdef CONFIG_APM
                if (apm_resume) {
@@ -1345,7 +1343,7 @@ static int ohci_roothub_thread(void * __ohci)
                }
 #endif
         
-         OHCI_DEBUG(printk("USB RH tasks: int: %x\n", ohci->intrstatus); )
+               OHCI_DEBUG(printk("USB RH tasks: int: %x\n",ohci->intrstatus););
 #ifndef VROOTHUB
                /*      if (ohci->intrstatus & OHCI_INTR_RHSC)  */
                        {
@@ -1380,9 +1378,6 @@ static int ohci_roothub_thread(void * __ohci)
         return 0;
 }
 
-
-
 /*
  * Increment the module usage count, start the control thread and
  * return success.
@@ -1480,20 +1475,6 @@ static int handle_apm_event(apm_event_t event)
 }
 #endif
 
-
-#ifdef MODULE
-
-void cleanup_module(void)
-{
-#ifdef CONFIG_APM
-       apm_unregister_callback(&handle_apm_event);
-#endif
-}
-
-#define ohci_hcd_init init_module
-
-#endif
-
 #define PCI_CLASS_SERIAL_USB_OHCI 0x0C0310
 #define PCI_CLASS_SERIAL_USB_OHCI_PG 0x10
  
@@ -1519,3 +1500,17 @@ int ohci_hcd_init(void)
   }
   return retval;
 }
+
+#ifdef MODULE
+int init_module(void){
+       return ohci_hcd_init();
+}
+
+void cleanup_module(void)
+{
+#      ifdef CONFIG_APM
+       apm_unregister_callback(&handle_apm_event);
+#      endif
+}
+#endif //MODULE
+
index aa782bb1df7f05ee5c92905138ebb1f393ecbb99..27d07c93291c5a5f1ca1b8900407c1e8a12b19c3 100644 (file)
@@ -307,7 +307,6 @@ struct ohci {
         struct usb_ohci_ed * ed_bulktail;       /* last endpoint of bulk list */
         struct usb_ohci_ed * ed_controltail;    /* last endpoint of control list */
         struct usb_ohci_ed * ed_isotail;        /* last endpoint of iso list */
-        struct ohci_device * root_hub;
         struct usb_ohci_ed ed_rh_ep0;
         struct usb_ohci_ed ed_rh_epi;
         struct ohci_rep_td *td_rh_epi;
index 330b249eba9dffe5a112ebc43cc80376a88fe6dc..792d6188bba5aae300ede6cc681be2fea3605fc2 100644 (file)
@@ -49,7 +49,6 @@
 #include <asm/system.h>
 
 #include "ohci.h"
-#include "inits.h"
 
 #ifdef CONFIG_APM
 #include <linux/apm_bios.h>
@@ -63,9 +62,7 @@ static DECLARE_WAIT_QUEUE_HEAD(ohci_configure);
 #define OHCI_DEBUG    /* to make typing it easier.. */
 #endif
 
-#ifdef OHCI_DEBUG
 int MegaDebug = 0;     /* SIGUSR2 to the control thread toggles this */
-#endif
 
 
 #ifdef OHCI_TIMER
@@ -207,12 +204,13 @@ void ohci_add_bulk_ed(struct ohci *ohci, struct ohci_ed *ed)
 void ohci_add_periodic_ed(struct ohci *ohci, struct ohci_ed *ed, int period)
 {
        struct ohci_ed *int_ed;
+       struct ohci_device *root_hub=usb_to_ohci(ohci->bus->root_hub);
        unsigned long flags;
 
        /*
         * Pick a good frequency endpoint based on the requested period
         */
-       int_ed = &ohci->root_hub->ed[ms_to_ed_int(period)];
+       int_ed = &root_hub->ed[ms_to_ed_int(period)];
 #ifdef OHCI_DEBUG
        printk("usb-ohci: Using INT ED queue %d for %dms period\n",
                        ms_to_ed_int(period), period);
@@ -632,7 +630,7 @@ static int ohci_request_irq(struct usb_device *usb, unsigned int pipe,
         * Set the max packet size, device speed, endpoint number, usb
         * device number (function address), and type of TD.
         */
-       ohci_fill_ed(dev, interrupt_ed, usb_maxpacket(pipe), usb_pipeslow(pipe),
+       ohci_fill_ed(dev, interrupt_ed, usb_maxpacket(usb,pipe), usb_pipeslow(pipe),
                usb_pipe_endpdev(pipe), 0 /* normal TDs */);
 
        /* Fill in the TD */
@@ -732,7 +730,7 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe, void *cmd
         * device number (function address), and type of TD.
         *
         */
-       ohci_fill_ed(dev, control_ed, usb_maxpacket(pipe), usb_pipeslow(pipe),
+       ohci_fill_ed(dev, control_ed, usb_maxpacket(usb,pipe), usb_pipeslow(pipe),
                usb_pipe_endpdev(pipe), 0 /* normal TDs */);
 
        /*
@@ -1015,6 +1013,8 @@ static int start_hc(struct ohci *ohci)
        int fminterval;
        __u32 what_to_enable;
 
+       struct ohci_device *root_hub=usb_to_ohci(ohci->bus->root_hub);
+
        fminterval = readl(&ohci->regs->fminterval) & 0x3fff;
 #if 0
        printk(KERN_DEBUG "entering start_hc %p\n", ohci);
@@ -1024,7 +1024,7 @@ static int start_hc(struct ohci *ohci)
                return -1;
 
        /* restore registers cleared by the reset */
-       writel(virt_to_bus(ohci->root_hub->hcca), &ohci->regs->hcca);
+       writel(virt_to_bus(root_hub->hcca), &ohci->regs->hcca);
 
        /*
         * XXX Should fminterval also be set here?
@@ -1120,6 +1120,7 @@ static void ohci_connect_change(struct ohci * ohci, int port)
 {
        struct usb_device *usb_dev;
        struct ohci_device *dev;
+       struct ohci_device *root_hub=usb_to_ohci(ohci->bus->root_hub);
        /* memory I/O address of the port status register */
        __u32 *portaddr = &ohci->regs->roothub.portstatus[port];
        int portstatus; 
@@ -1133,7 +1134,7 @@ static void ohci_connect_change(struct ohci * ohci, int port)
         * everything we think we know about the device
         * on this root hub port.  It may have changed.
         */
-       usb_disconnect(ohci->root_hub->usb->children + port);
+       usb_disconnect(root_hub->usb->children + port);
 
        portstatus = readl(portaddr);
 
@@ -1154,7 +1155,7 @@ static void ohci_connect_change(struct ohci * ohci, int port)
        /*
         * Allocate a device for the new thingy that's been attached
         */
-       usb_dev = ohci_usb_allocate(ohci->root_hub->usb);
+       usb_dev = ohci_usb_allocate(root_hub->usb);
        dev = usb_dev->hcpriv;
 
        dev->ohci = ohci;
@@ -1162,7 +1163,7 @@ static void ohci_connect_change(struct ohci * ohci, int port)
        usb_connect(dev->usb);
 
        /* link it into the bus's device tree */
-       ohci->root_hub->usb->children[port] = usb_dev;
+       root_hub->usb->children[port] = usb_dev;
 
        wait_ms(200); /* wait for powerup; XXX is this needed? */
        ohci_reset_port(ohci, port);
@@ -1220,10 +1221,12 @@ static void ohci_check_configuration(struct ohci *ohci)
  */
 static void ohci_root_hub_events(struct ohci *ohci)
 {
-       if (waitqueue_active(&ohci_configure)) {
                int num = 0;
-               int maxport = ohci->root_hub->usb->maxchild;
+       struct ohci_device *root_hub=usb_to_ohci(ohci->bus->root_hub);
+       int maxport = root_hub->usb->maxchild;
 
+       if (!waitqueue_active(&ohci_configure))
+               return;
                do {
                        __u32 *portstatus_p = &ohci->regs->roothub.portstatus[num];
                        if (readl(portstatus_p) & PORT_CSC) {
@@ -1232,7 +1235,7 @@ static void ohci_root_hub_events(struct ohci *ohci)
                                return;
                        }
                } while (++num < maxport);
-       }
+       
 } /* ohci_root_hub_events() */
 
 
@@ -1248,7 +1251,8 @@ static void ohci_root_hub_events(struct ohci *ohci)
 static struct ohci_td * ohci_reverse_donelist(struct ohci * ohci)
 {
        __u32 td_list_hc;
-       struct ohci_hcca *hcca = ohci->root_hub->hcca;
+       struct ohci_device *root_hub=usb_to_ohci(ohci->bus->root_hub);
+       struct ohci_hcca *hcca = root_hub->hcca;
        struct ohci_td *td_list = NULL;
        struct ohci_td *td_rev = NULL;
        
@@ -1326,7 +1330,8 @@ static void ohci_interrupt(int irq, void *__ohci, struct pt_regs *r)
 {
        struct ohci *ohci = __ohci;
        struct ohci_regs *regs = ohci->regs;
-       struct ohci_hcca *hcca = ohci->root_hub->hcca;
+       struct ohci_device *root_hub=usb_to_ohci(ohci->bus->root_hub);
+       struct ohci_hcca *hcca = root_hub->hcca;
        __u32 status, context;
 
        /* Save the status of the interrupts that are enabled */
@@ -1481,8 +1486,8 @@ static struct ohci *alloc_ohci(void* mem_base)
        if (!usb)
                return NULL;
 
-       dev = ohci->root_hub = usb_to_ohci(usb);
-
+       dev = usb_to_ohci(usb);
+       ohci->bus->root_hub= ohci_to_usb(dev);
        usb->bus = bus;
 
        /* Initialize the root hub */
@@ -1588,13 +1593,14 @@ static void release_ohci(struct ohci *ohci)
        /* stop all OHCI interrupts */
        writel(~0x0, &ohci->regs->intrdisable);
 
-       if (ohci->root_hub) {
+       if (ohci->bus->root_hub) {
+               struct ohci_device *root_hub=usb_to_ohci(ohci->bus->root_hub);
                /* ensure that HC is stopped before releasing the HCCA */
                writel(OHCI_USB_SUSPEND, &ohci->regs->control);
-               free_page((unsigned long) ohci->root_hub->hcca);
-               kfree(ohci->root_hub);
-               ohci->root_hub->hcca = NULL;
-               ohci->root_hub = NULL;
+               free_page((unsigned long) root_hub->hcca);
+               kfree(ohci->bus->root_hub);
+               root_hub->hcca = NULL;
+               ohci->bus->root_hub = NULL;
        }
 
        /* unmap the IO address space */
@@ -1634,12 +1640,15 @@ static int ohci_control_thread(void * __ohci)
 
        strcpy(current->comm, "ohci-control");
 
+       usb_register_bus(ohci->bus);
+
        /*
         * Damn the torpedoes, full speed ahead
         */
        if (start_hc(ohci) < 0) {
                printk("usb-ohci: failed to start the controller\n");
                release_ohci(ohci);
+               usb_deregister_bus(ohci->bus);
                printk(KERN_INFO "leaving ohci_control_thread %p\n", __ohci);
                return 0;
        }
@@ -1697,7 +1706,7 @@ static int ohci_control_thread(void * __ohci)
 
        reset_hc(ohci);
        release_ohci(ohci);
-
+       usb_deregister_bus(ohci->bus);
        printk(KERN_INFO "ohci-control thread for 0x%p exiting\n", __ohci);
 
        return 0;
@@ -1864,26 +1873,6 @@ static int init_ohci(struct pci_dev *dev)
        return 0;
 } /* init_ohci() */
 
-#ifdef MODULE
-/*
- *  Clean up when unloading the module
- */
-void cleanup_module(void)
-{
-#ifdef CONFIG_APM
-       apm_unregister_callback(&handle_apm_event);
-#endif
-#ifdef CONFIG_USB_MOUSE
-       usb_mouse_cleanup();
-#endif
-       printk("usb-ohci: module unloaded\n");
-}
-
-#define ohci_init init_module
-
-#endif
-
-
 /* TODO this should be named following Linux convention and go in pci.h */
 #define PCI_CLASS_SERIAL_USB_OHCI ((PCI_CLASS_SERIAL_USB << 8) | 0x0010)
 
@@ -1935,3 +1924,21 @@ int ohci_init(void)
 
 /* vim:sw=8
  */
+
+#ifdef MODULE
+/*
+ *  Clean up when unloading the module
+ */
+void module_cleanup(void){
+#      ifdef CONFIG_APM
+       apm_unregister_callback(&handle_apm_event);
+#      endif
+       printk("usb-ohci: module unloaded\n");
+}
+
+int init_module(void){
+       return ohci_init();
+}
+#endif //MODULE
+
+
index ca071ee012006a7b3c5631090f9d0927f529568a..ab0b7e92e79f15a4623d0cf910ced47f6bee0dd3 100644 (file)
@@ -367,7 +367,6 @@ struct ohci {
        int irq;
        struct ohci_regs *regs;                 /* OHCI controller's memory */
        struct usb_bus *bus;
-       struct ohci_device *root_hub;           /* Root hub & controller */
        struct list_head interrupt_list;        /* List of interrupt active TDs for this OHCI */
 };
 
index 9a9ee7e3fef74eacf931364e280c5bdbc7ab48e5..7c577a58f7b93c670b0fc11c14bd96fff9f1e2af 100644 (file)
@@ -147,9 +147,9 @@ void show_queue(struct uhci_qh *qh)
 int is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh)
 {
        int j;
-
+       struct uhci_device * root_hub=usb_to_uhci(uhci->bus->root_hub);
        for (j = 0; j < UHCI_MAXQH; j++)
-               if (qh == uhci->root_hub->qh + j)
+               if (qh == root_hub->qh + j)
                        return 1;
 
        return 0;
@@ -165,15 +165,16 @@ void show_queues(struct uhci *uhci)
 {
        int i;
        struct uhci_qh *qh;
+       struct uhci_device * root_hub=usb_to_uhci(uhci->bus->root_hub);
 
        for (i = 0; i < UHCI_MAXQH; ++i) {
                printk("  %s:\n", qh_names[i]);
 #if 0
-               printk("  qh #%d, %p\n", i, virt_to_bus(uhci->root_hub->qh + i));
+               printk("  qh #%d, %p\n", i, virt_to_bus(root_hub->qh + i));
                show_queue(uhci->root_hub->qh + i);
 #endif
 
-               qh = uhci_link_to_qh(uhci->root_hub->qh[i].link);
+               qh = uhci_link_to_qh(root_hub->qh[i].link);
                for (; qh; qh = uhci_link_to_qh(qh->link)) {
                        if (is_skeleton_qh(uhci, qh))
                                break;
@@ -182,4 +183,3 @@ void show_queues(struct uhci *uhci)
                }
        }
 }
-
index 95bed335b0a580255d7d82a3e42b612f381925ac..c4621cb29dc4f2d0ec7cd1b2bfda1b22155bd747 100644 (file)
 #include <linux/smp_lock.h>
 #include <linux/errno.h>
 
+#include <linux/sched.h>
+#include <linux/unistd.h>
+#include <linux/smp_lock.h>
+
+#include <asm/uaccess.h>
+
+
 #include <asm/spinlock.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
 
 #include "uhci.h"
-#include "inits.h"
 
 #ifdef CONFIG_APM
 #include <linux/apm_bios.h>
@@ -317,6 +323,7 @@ static void uhci_remove_irq_list(struct uhci_td *td)
 static int uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
 {
        struct uhci_device *dev = usb_to_uhci(usb_dev);
+       struct uhci_device *root_hub=usb_to_uhci(dev->uhci->bus->root_hub);
        struct uhci_td *td = uhci_td_allocate(dev);
        struct uhci_qh *interrupt_qh = uhci_qh_allocate(dev);
 
@@ -338,14 +345,14 @@ static int uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_d
        td->buffer = virt_to_bus(dev->data);
        td->first = td;
        td->qh = interrupt_qh;
-       interrupt_qh->skel = &dev->uhci->root_hub->skel_int8_qh;
+       interrupt_qh->skel = &root_hub->skel_int8_qh;
 
        uhci_add_irq_list(dev->uhci, td, handler, dev_id);
 
        uhci_insert_td_in_qh(interrupt_qh, td);
 
        /* Add it into the skeleton */
-       uhci_insert_qh(&dev->uhci->root_hub->skel_int8_qh, interrupt_qh);
+       uhci_insert_qh(&root_hub->skel_int8_qh, interrupt_qh);
        return 0;
 }
 
@@ -567,7 +574,7 @@ static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, stru
        DECLARE_WAITQUEUE(wait, current);
        struct uhci_qh *ctrl_qh = uhci_qh_allocate(dev);
        struct uhci_td *curtd;
-
+       struct uhci_device *root_hub=usb_to_uhci(dev->uhci->bus->root_hub);
        current->state = TASK_UNINTERRUPTIBLE;
        add_wait_queue(&control_wakeup, &wait);
 
@@ -595,10 +602,19 @@ static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, stru
        uhci_insert_tds_in_qh(ctrl_qh, first, last);
 
        /* Add it into the skeleton */
-       uhci_insert_qh(&dev->uhci->root_hub->skel_control_qh, ctrl_qh);
+       uhci_insert_qh(&root_hub->skel_control_qh, ctrl_qh);
+
+//     control should be full here...  
+//     printk("control\n");
+//     show_status(dev->uhci);
+//     show_queues(dev->uhci);
 
        schedule_timeout(HZ/10);
 
+//     control should be empty here... 
+//     show_status(dev->uhci);
+//     show_queues(dev->uhci);
+
        remove_wait_queue(&control_wakeup, &wait);
 
        /* Clean up in case it failed.. */
@@ -609,7 +625,7 @@ static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, stru
 #endif
 
        /* Remove it from the skeleton */
-       uhci_remove_qh(&dev->uhci->root_hub->skel_control_qh, ctrl_qh);
+       uhci_remove_qh(&root_hub->skel_control_qh, ctrl_qh);
 
        uhci_qh_deallocate(ctrl_qh);
 
@@ -772,8 +788,7 @@ static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct
        DECLARE_WAITQUEUE(wait, current);
        struct uhci_qh *bulk_qh = uhci_qh_allocate(dev);
        struct uhci_td *curtd;
-
-
+       struct uhci_device *root_hub=usb_to_uhci(dev->uhci->bus->root_hub);
 
        current->state = TASK_UNINTERRUPTIBLE;
        add_wait_queue(&bulk_wakeup, &wait);
@@ -801,19 +816,17 @@ static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct
 
        uhci_insert_tds_in_qh(bulk_qh, first, last);
 
-//     bulk0 is empty here...  
-//     show_status(dev->uhci);
-//     show_queues(dev->uhci);
-       
        /* Add it into the skeleton */
-       /*WARNING! HUB HAS NO BULK QH TIL NOW!!!!!!!!!!!*/
-       uhci_insert_qh(&dev->uhci->root_hub->skel_bulk0_qh, bulk_qh);
+       uhci_insert_qh(&root_hub->skel_bulk0_qh, bulk_qh);
 
 //     now we're in the queue... but don't ask WHAT is in there ;-(
+//     printk("bulk\n");
 //     show_status(dev->uhci);
 //     show_queues(dev->uhci);
 
        schedule_timeout(HZ/10);
+//     show_status(dev->uhci);
+//     show_queues(dev->uhci);
 
        remove_wait_queue(&bulk_wakeup, &wait);
 
@@ -825,7 +838,7 @@ static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct
 #endif
 
        /* Remove it from the skeleton */
-       uhci_remove_qh(&dev->uhci->root_hub->skel_bulk0_qh, bulk_qh);
+       uhci_remove_qh(&root_hub->skel_bulk0_qh, bulk_qh);
 
        uhci_qh_deallocate(bulk_qh);
 
@@ -866,10 +879,10 @@ static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da
          I FORGOT WHAT IT EXACTLY DOES
        */
        if (usb_pipeout(pipe)) {
-               destination = (pipe & 0x0007ff00) | 0xE1;
+               destination = (pipe & 0x000Aff00) | 0xE1;
        }
        else {
-               destination = (pipe & 0x0007ff00) | 0x69;
+               destination = (pipe & 0x000Aff00) | 0x69;
        }
 
        /* Status:    slow/fast,       Active,    Short Packet Detect     Three Errors */
@@ -883,7 +896,6 @@ static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da
        while (len > 0) {
                /* Build the TD for control status */
                int pktsze = len;
-
                if (pktsze > maxsze)
                        pktsze = maxsze;
 
@@ -906,7 +918,12 @@ static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da
                /* Alternate Data0/1 (start with Data0) */
                usb_dotoggle(usb_dev, usb_pipeendpoint(pipe));
        }
-       td->link = 1;                                   /* Terminate */
+       prevtd->link = 1;                               /* Terminate */
+       prevtd->status = status | (1 << 24);            /* IOC */
+       prevtd->first = first;
+       uhci_td_deallocate(td);
+
+       /* CHANGE DIRECTION HERE! SAVE IT SOMEWHERE IN THE ENDPOINT!!! */
 
        /* Start it up.. */
        ret = uhci_run_bulk(dev, first, td, rval);
@@ -1064,7 +1081,7 @@ static void uhci_connect_change(struct uhci *uhci, unsigned int port, unsigned i
        struct usb_device *usb_dev;
        struct uhci_device *dev;
        unsigned short status;
-
+       struct uhci_device *root_hub=usb_to_uhci(uhci->bus->root_hub);
        printk("uhci_connect_change: called for %d\n", nr);
 
        /*
@@ -1074,7 +1091,7 @@ static void uhci_connect_change(struct uhci *uhci, unsigned int port, unsigned i
         *
         * So start off by getting rid of any old devices..
         */
-       usb_disconnect(&uhci->root_hub->usb->children[nr]);
+       usb_disconnect(&root_hub->usb->children[nr]);
 
        status = inw(port);
 
@@ -1089,14 +1106,14 @@ static void uhci_connect_change(struct uhci *uhci, unsigned int port, unsigned i
         * Ok, we got a new connection. Allocate a device to it,
         * and find out what it wants to do..
         */
-       usb_dev = uhci_usb_allocate(uhci->root_hub->usb);
+       usb_dev = uhci_usb_allocate(root_hub->usb);
        dev = usb_dev->hcpriv;
 
        dev->uhci = uhci;
 
        usb_connect(usb_dev);
 
-       uhci->root_hub->usb->children[nr] = usb_dev;
+       root_hub->usb->children[nr] = usb_dev;
 
        wait_ms(200); /* wait for powerup */
        uhci_reset_port(port);
@@ -1119,8 +1136,9 @@ static void uhci_connect_change(struct uhci *uhci, unsigned int port, unsigned i
  */
 static void uhci_check_configuration(struct uhci *uhci)
 {
+       struct uhci_device * root_hub=usb_to_uhci(uhci->bus->root_hub);
        unsigned int io_addr = uhci->io_addr + USBPORTSC1;
-       int maxchild = uhci->root_hub->usb->maxchild;
+       int maxchild = root_hub->usb->maxchild;
        int nr = 0;
 
        do {
@@ -1184,7 +1202,8 @@ static void uhci_interrupt_notify(struct uhci *uhci)
 static void uhci_root_hub_events(struct uhci *uhci, unsigned int io_addr)
 {
        if (waitqueue_active(&uhci_configure)) {
-               int ports = uhci->root_hub->usb->maxchild;
+               struct uhci_device * root_hub=usb_to_uhci(uhci->bus->root_hub);
+               int ports = root_hub->usb->maxchild;
                io_addr += USBPORTSC1;
                do {
                        if (inw(io_addr) & USBPORTSC_CSC) {
@@ -1227,7 +1246,7 @@ static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs)
  */
 static void uhci_init_ticktd(struct uhci *uhci)
 {
-       struct uhci_device *dev = uhci->root_hub;
+       struct uhci_device *dev = usb_to_uhci(uhci->bus->root_hub);
        struct uhci_td *td = uhci_td_allocate(dev);
 
        td->link = 1;
@@ -1344,10 +1363,9 @@ static struct uhci *alloc_uhci(unsigned int io_addr)
        if (!usb)
                return NULL;
 
-       dev = uhci->root_hub = usb_to_uhci(usb);
-
        usb->bus = bus;
-
+       dev = usb_to_uhci(usb);
+       uhci->bus->root_hub=uhci_to_usb(dev);
        /* Initialize the root hub */
        /* UHCI specs says devices must have 2 ports, but goes on to say */
        /* they may have more but give no way to determine how many they */
@@ -1428,9 +1446,9 @@ static void release_uhci(struct uhci *uhci)
        }
 
 #if 0
-       if (uhci->root_hub) {
-               uhci_usb_deallocate(uhci_to_usb(uhci->root_hub));
-               uhci->root_hub = NULL;
+       if (uhci->bus->root_hub) {
+               uhci_usb_deallocate(uhci_to_usb(uhci->bus->root_hub));
+               uhci->bus->root_hub = NULL;
        }
 #endif
 
@@ -1443,12 +1461,10 @@ static void release_uhci(struct uhci *uhci)
        kfree(uhci);
 }
 
-void cleanup_drivers(void);
-
 static int uhci_control_thread(void * __uhci)
 {
        struct uhci *uhci = (struct uhci *)__uhci;
-
+       struct uhci_device * root_hub =usb_to_uhci(uhci->bus->root_hub);
        lock_kernel();
        request_region(uhci->io_addr, 32, "usb-uhci");
 
@@ -1467,6 +1483,7 @@ static int uhci_control_thread(void * __uhci)
         * Ok, all systems are go..
         */
        start_hc(uhci);
+       usb_register_bus(uhci->bus);
        for(;;) {
                siginfo_t info;
                int unsigned long signr;
@@ -1498,12 +1515,12 @@ static int uhci_control_thread(void * __uhci)
 
        {
        int i;
-       if(uhci->root_hub)
-               for(i = 0; i < uhci->root_hub->usb->maxchild; i++)
-                       usb_disconnect(uhci->root_hub->usb->children + i);
+       if(root_hub)
+               for(i = 0; i < root_hub->usb->maxchild; i++)
+                       usb_disconnect(root_hub->usb->children + i);
        }
 
-       cleanup_drivers();
+       usb_deregister_bus(uhci->bus);
 
        reset_hc(uhci);
        release_region(uhci->io_addr, 32);
@@ -1534,10 +1551,10 @@ static int found_uhci(int irq, unsigned int io_addr)
        retval = -EBUSY;
        if (request_irq(irq, uhci_interrupt, SA_SHIRQ, "usb", uhci) == 0) {
                int pid;
-
                MOD_INC_USE_COUNT;
                uhci->irq = irq;
-               pid = kernel_thread(uhci_control_thread, uhci, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+               pid = kernel_thread(uhci_control_thread, uhci,
+                       CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
                if (pid >= 0)
                        return 0;
 
@@ -1602,21 +1619,6 @@ static int handle_apm_event(apm_event_t event)
 }
 #endif
 
-#ifdef MODULE
-
-void cleanup_module(void)
-{
-#ifdef CONFIG_APM
-       apm_unregister_callback(&handle_apm_event);
-#endif
-}
-
-int init_modules(void)
-{
-       return uhci_init();
-}
-
-#endif
 
 int uhci_init(void)
 {
@@ -1645,3 +1647,17 @@ int uhci_init(void)
        }
        return retval;
 }
+
+#ifdef MODULE
+int init_module(void)
+{
+       return uhci_init();
+}
+
+void cleanup_module(void)
+{
+#ifdef CONFIG_APM
+       apm_unregister_callback(&handle_apm_event);
+#endif
+}
+#endif //MODULE
index 3f511eedb5affb9f14c5adfda9c36eadc6a462b3..38f74784a608d07d83812b0259c93a360488e405 100644 (file)
@@ -225,8 +225,6 @@ struct uhci {
        /* These are "standard" QH's for the entire bus */
        struct uhci_qh qh[UHCI_MAXQH];
 #endif
-       struct uhci_device *root_hub;           /* Root hub device descriptor.. */
-
        struct uhci_framelist *fl;              /* Frame list */
        struct list_head interrupt_list;        /* List of interrupt-active TD's for this uhci */
 };
diff --git a/drivers/usb/usb-core.c b/drivers/usb/usb-core.c
new file mode 100644 (file)
index 0000000..637736e
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * driver/usb/usb-core.c
+ *
+ * (C) Copyright David Waite 1999
+ * based on code from usb.c, by Linus Torvolds
+ *
+ * The purpose of this file is to pull any and all generic modular code from
+ * usb.c and put it in a separate file. This way usb.c is kept as a generic
+ * library, while this file handles starting drivers, etc.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include "inits.h"
+#include "usb.h"
+
+#ifndef CONFIG_USB_MODULE
+#      ifdef CONFIG_USB_UHCI
+               int uhci_init(void);
+#      endif
+#      ifdef CONFIG_USB_OHCI
+               int ohci_init(void);
+#      endif
+#      ifdef CONFIG_USB_OHCI_HCD
+               int ohci_hcd_init(void);
+#      endif
+#endif
+
+int usb_init(void)
+{
+#ifndef CONFIG_USB_MODULE
+#      ifdef CONFIG_USB_UHCI
+               uhci_init();
+#      endif
+#      ifdef CONFIG_USB_OHCI
+               ohci_init();
+#      endif
+#      ifdef CONFIG_USB_OHCI_HCD
+               ohci_hcd_init(); 
+#      endif
+#      ifdef CONFIG_USB_MOUSE
+               usb_mouse_init();
+#      endif
+#      ifdef CONFIG_USB_KBD
+               usb_kbd_init();
+#      endif
+#      ifdef CONFIG_USB_AUDIO
+               usb_audio_init();
+#      endif
+#      ifdef CONFIG_USB_ACM
+               usb_acm_init();
+#      endif
+#      ifdef CONFIG_USB_PRINTER
+               usb_print_init();
+#      endif
+#      ifdef CONFIG_USB_CPIA
+               usb_cpia_init();
+#      endif
+#      ifdef CONFIG_USB_HUB
+               usb_hub_init();
+#      endif
+#endif
+       return 0;
+}
+/*
+ *  Clean up when unloading the module
+ */
+void cleanup_drivers(void)
+{
+#ifndef MODULE
+#      ifdef CONFIG_USB_HUB
+               usb_hub_cleanup();
+#      endif
+#      ifdef CONFIG_USB_MOUSE
+               usb_mouse_cleanup();
+#      endif
+#endif
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+       return usb_init();
+}
+void module_cleanup(void)
+{
+       cleanup_drivers();
+}
+#endif
+
+
index 4536c7ce6dfc31a3b8256749e91493084cc11cbf..26e070802f3ce0e9c76ba97aa520c0648b786684 100644 (file)
 
 #include "usb.h"
 
-#ifdef CONFIG_USB_UHCI
-int uhci_init(void);
-#endif
-#ifdef CONFIG_USB_OHCI
-int ohci_init(void);
-#endif
-#ifdef CONFIG_USB_OHCI_HCD
-int ohci_hcd_init(void);
-#endif
-
-int usb_init(void)
-{
-#ifdef CONFIG_USB_UHCI
-       uhci_init();
-#endif
-#ifdef CONFIG_USB_OHCI
-       ohci_init();
-#endif
-#ifdef CONFIG_USB_OHCI_HCD
-       ohci_hcd_init(); 
-#endif
-#ifdef CONFIG_USB_MOUSE
-       usb_mouse_init();
-#endif
-#ifdef CONFIG_USB_KBD
-       usb_kbd_init();
-#endif
-#ifdef CONFIG_USB_AUDIO
-       usb_audio_init();
-#endif
-#ifdef CONFIG_USB_ACM
-       usb_acm_init();
-#endif
-#ifdef CONFIG_USB_CPIA
-       usb_cpia_init();
-#endif
-#ifdef CONFIG_USB_PRINTER
-       usb_printer_init();
-#endif
-
-       usb_hub_init();
-       return 0;
-}
-
-void cleanup_drivers(void)
-{
-       hub_cleanup();
-#ifdef CONFIG_USB_MOUSE
-       usb_mouse_cleanup();
-#endif
-}
-
 /*
  * We have a per-interface "registered driver" list.
  */
 static LIST_HEAD(usb_driver_list);
+static LIST_HEAD(usb_bus_list);
 
 int usb_register(struct usb_driver *new_driver)
 {
+       struct list_head *tmp = usb_bus_list.next;
        /* Add it to the list of known drivers */
        list_add(&new_driver->driver_list, &usb_driver_list);
 
        /*
-        * We should go through all existing devices, and see if any of
-        * them would be acceptable to the new driver.. Let's do that
-        * in version 2.0.
+         * We go through all existing devices, and see if any of them would
+         * be acceptable to the new driver.. This is done using a depth-first
+         * search for devices without a registered driver already, then 
+        * running 'probe' with each of the drivers registered on every one 
+        * of these.
         */
+        while (tmp!= &usb_bus_list) {
+               struct usb_bus * bus = list_entry(tmp,struct
+                       usb_bus,bus_list);
+               tmp=tmp->next;  
+               usb_check_support(bus->root_hub);
+        }
        return 0;
 }
 
 void usb_deregister(struct usb_driver *driver)
 {
+      struct list_head *tmp = usb_bus_list.next;
+      /*first we remove the driver, to be sure it doesn't get used by
+       *another thread while we are stepping through removing entries
+       */
        list_del(&driver->driver_list);
+      printk("usbcore: deregistering driver\n");
+      while (tmp!= &usb_bus_list) {
+              struct usb_bus * bus = list_entry(tmp,struct 
+                       usb_bus,bus_list);
+              tmp=tmp->next;
+              usb_driver_purge(driver,bus->root_hub);
+      }
+}
+
+/* This function is part of a depth-first search down the device tree,
+ * removing any instances of a device driver.
+ */
+void usb_driver_purge(struct usb_driver *driver,struct usb_device *dev)
+{
+       int i;
+       if (dev==NULL){
+               printk("null device being passed in!!!\n");
+               return;
+       }
+       for (i=0;i<USB_MAXCHILDREN;i++)
+               if (dev->children[i]!=NULL)
+                       usb_driver_purge(driver,dev->children[i]);
+       /*now we check this device*/
+       if(dev->driver==driver) {
+               /*
+                * Note: this is not the correct way to do this, this
+                * uninitializes and reinitializes EVERY driver
+                */
+               printk("disconnecting driverless device\n");
+               dev->driver->disconnect(dev);
+               dev->driver=NULL;
+               /* This will go back through the list looking for a driver
+                * that can handle the device
+               */
+               usb_device_descriptor(dev);
+      }
+}
+
+/*
+ * New functions for (de)registering a controller
+ */
+void usb_register_bus(struct usb_bus *new_bus)
+{
+      /* Add it to the list of buses */
+      list_add(&new_bus->bus_list, &usb_bus_list);
+      printk("New bus registered");
+}
+
+void usb_deregister_bus(struct usb_bus *bus)
+{
+        /* NOTE: make sure that all the devices are removed by the
+         * controller code, as well as having it call this when cleaning
+        * itself up
+         */
+       list_del(&bus->bus_list);
 }
 
+/*
+ * This function is for doing a depth-first search for devices which
+ * have support, for dynamic loading of driver modules.
+ */
+void usb_check_support(struct usb_device *dev)
+{
+      int i;
+      if (dev==NULL)
+      {
+              printk("null device being passed in!!!\n");
+              return;
+      }
+      for (i=0;i<USB_MAXCHILDREN;i++)
+              if ((dev->children[i]!=NULL)&&
+                      (dev->children[i]->driver==NULL))
+                      usb_check_support(dev->children[i]);
+      /*now we check this device*/
+      usb_device_descriptor(dev);
+}
 /*
  * This entrypoint gets called for each new device.
  *
@@ -125,25 +161,24 @@ void usb_deregister(struct usb_driver *driver)
  * looking for one that will accept this device as
  * his..
  */
-void usb_device_descriptor(struct usb_device *dev)
+int usb_device_descriptor(struct usb_device *dev)
 {
        struct list_head *tmp = usb_driver_list.next;
 
        while (tmp != &usb_driver_list) {
-               struct usb_driver *driver = list_entry(tmp, struct usb_driver, driver_list);
+               struct usb_driver *driver = list_entry(tmp, struct usb_driver,
+                                                      driver_list);
                tmp = tmp->next;
                if (driver->probe(dev))
                        continue;
                dev->driver = driver;
-               return;
+               return 1;
        }
-
        /*
         * Ok, no driver accepted the device, so show the info
         * for debugging..
         */
-       printk("Unknown new USB device:\n");
-       usb_show_device(dev);
+       return 0;
 }
 
 /*
@@ -882,7 +917,15 @@ void usb_new_device(struct usb_device *dev)
        printk("Product: %X\n", dev->descriptor.idProduct);
 #endif
 
-       usb_device_descriptor(dev);
+       if (usb_device_descriptor(dev)==0)
+       {
+               /*
+                * Ok, no driver accepted the device, so show the info for
+                * debugging
+                */
+               printk ("Unknown new USB device:\n");
+               usb_show_device(dev);
+       }
 }
 
 int usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
index 62667457213ee2161bebdbfe1e833be608eb9b2e..06efc1a2810181977b0e6546fea3fd8d143c8e4d 100644 (file)
@@ -220,7 +220,7 @@ struct usb_operations {
        struct usb_device *(*allocate)(struct usb_device *);
        int (*deallocate)(struct usb_device *);
        int (*control_msg)(struct usb_device *, unsigned int, void *, void *, int);
-       int (*bulk_msg)(struct usb_device *, unsigned int, void *, int, unsigned long *);
+       int (*bulk_msg)(struct usb_device *, unsigned int, void *, int,unsigned long *);
        int (*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *);
 };
 
@@ -231,6 +231,7 @@ struct usb_bus {
        struct usb_devmap devmap;       /* Device map */
        struct usb_operations *op;      /* Operations (specific to the HC) */
        struct usb_device *root_hub;    /* Root hub */
+       struct list_head bus_list;
        void *hcpriv;                   /* Host Controller private data */
 };
 
@@ -259,7 +260,7 @@ struct usb_device {
         * (if this is a hub device), or different instances
         * of this same device.
         *
-        * Each instance needs its own set of data structuctures.
+        * Each instance needs its own set of data structures.
         */
 
        int maxchild;                   /* Number of ports if hub */
@@ -272,13 +273,18 @@ struct usb_device {
 extern int usb_register(struct usb_driver *);
 extern void usb_deregister(struct usb_driver *);
 
+extern void usb_register_bus(struct usb_bus *);
+extern void usb_deregister_bus(struct usb_bus *);
+
 extern int usb_request_irq(struct usb_device *, unsigned int, usb_device_irq, int, void *);
 
 extern void usb_init_root_hub(struct usb_device *dev);
 extern void usb_connect(struct usb_device *dev);
 extern void usb_disconnect(struct usb_device **);
-extern void usb_device_descriptor(struct usb_device *dev);
 
+extern int usb_device_descriptor(struct usb_device *dev);
+void usb_check_support(struct usb_device *);
+void usb_driver_purge(struct usb_driver *,struct usb_device *);
 extern int  usb_parse_configuration(struct usb_device *dev, void *buf, int len);
 extern void usb_destroy_configuration(struct usb_device *dev);
 
@@ -357,8 +363,6 @@ static inline unsigned int __default_pipe(struct usb_device *dev)
 #define usb_snddefctrl(dev)            ((2 << 30) | __default_pipe(dev))
 #define usb_rcvdefctrl(dev)            ((2 << 30) | __default_pipe(dev) | 0x80)
 
-/* Create .. */
-
 /*
  * Send and receive control messages..
  */
index 9c8e9bf94fce9755629e53fa04dd4d68bac7148e..518e5c4d800d532a1594081e81fc94cc77018a21 100644 (file)
@@ -231,24 +231,6 @@ extern void ip_masq_put(struct ip_masq *ms);
 
 extern rwlock_t __ip_masq_lock;
 
-#ifdef __SMP__
-#define read_lock_bh(lock)     do { start_bh_atomic(); read_lock(lock); \
-                                       } while (0)
-#define read_unlock_bh(lock)   do { read_unlock(lock); end_bh_atomic(); \
-                                       } while (0)
-#define write_lock_bh(lock)    do { start_bh_atomic(); write_lock(lock); \
-                                       } while (0)
-#define write_unlock_bh(lock)  do { write_unlock(lock); end_bh_atomic(); \
-                                       } while (0)
-#else
-#define read_lock_bh(lock)     start_bh_atomic()
-#define read_unlock_bh(lock)   end_bh_atomic()
-#define write_lock_bh(lock)    start_bh_atomic()
-#define write_unlock_bh(lock)  end_bh_atomic()
-#endif 
-/*
- *
- */
 
 /*
  *     Debugging stuff
index d4ee011e4ef5203d308b0e1ab92193e186361d4a..61a5a648864d5bd0e0f8a1b7d391f7f929fd6d08 100644 (file)
@@ -6,25 +6,28 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Tue Dec 15 22:18:53 1998
+ * Modified at:   Sun May  2 20:25:23 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  ********************************************************************/
 
-#ifndef IR_CRC_H
-#define IR_CRC_H
+#ifndef IRDA_CRC_H
+#define IRDA_CRC_H
 
 #include <linux/types.h>
 
 #define INIT_FCS  0xffff   /* Initial FCS value */
 #define GOOD_FCS  0xf0b8   /* Good final FCS value */
 
+extern __u16 const irda_crc16_table[];
+
 /* Recompute the FCS with one more character appended. */
-#define IR_FCS(fcs, c) (((fcs) >> 8) ^ irda_crc16_table[((fcs) ^ (c)) & 0xff])
+static inline __u16 irda_fcs(__u16 fcs, __u8 c)
+{
+       return (((fcs) >> 8) ^ irda_crc16_table[((fcs) ^ (c)) & 0xff]);
+}
 
 /* Recompute the FCS with len bytes appended. */
 unsigned short crc_calc( __u16 fcs, __u8 const *buf, size_t len);
 
-extern __u16 const irda_crc16_table[];
-
 #endif
index d8983c009d2c0d1791478918368bbeba7ba7ff8d..64496d67191e7fb7c21e470338d6498fb413194b 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Wed Oct 21 22:47:12 1998
- * Modified at:   Sat Feb  6 07:37:49 1999
+ * Modified at:   Mon May 10 14:51:06 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -26,7 +26,6 @@
 #define DONGLE_H
 
 #include <net/irda/qos.h>
-#include <net/irda/irda_device.h>
 
 /* These are the currently known dongles */
 typedef enum {
@@ -35,8 +34,11 @@ typedef enum {
        ACTISYS_DONGLE,
        ACTISYS_PLUS_DONGLE,
        GIRBIL_DONGLE,
+       LITELINK_DONGLE,
 } DONGLE_T;
 
+struct irda_device;
+
 struct dongle {
        DONGLE_T type;
        void (*open)(struct irda_device *, int type);
index d92761c13571f13f27acb49b61cbd89ec938b1a2..c709024cf9224fa935509d2d74cf6f1cf53f4381 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Takahide Higuchi <thiguchi@pluto.dti.ne.jp>
  *
- *     Copyright (c) 1998, Takahide Higuchi, <thiguchi@pluto.dti.ne.jp>,
+ *     Copyright (c) 1998-1999, Takahide Higuchi, <thiguchi@pluto.dti.ne.jp>,
  *     All Rights Reserved.
  *
  *     This program is free software; you can redistribute it and/or
@@ -78,7 +78,7 @@ typedef enum {
 #define IRCOMM_MAGIC            0x434f4d4d
 #define COMM_INIT_CTRL_PARAM    3          /* length of initial control parameters */
 #define COMM_HEADER             1          /* length of clen field */
-#define COMM_HEADER_SIZE        (LAP_HEADER+LMP_HEADER+TTP_HEADER+COMM_HEADER)
+#define COMM_HEADER_SIZE        (TTP_MAX_HEADER+COMM_HEADER)
 #define COMM_DEFAULT_DATA_SIZE  64
 #define IRCOMM_MAX_CONNECTION   1          /* Don't change for now */
 
@@ -167,7 +167,7 @@ typedef enum {
 #define LSR_BI     0x01    /* Break interrupt indicator */
 
 
-struct ircomm_cb{
+struct ircomm_cb {
        int magic;
        int state;          /* Current state of IrCOMM layer: 
                             *  DISCOVERY,COMM_IDLE, COMM_WAITR,
@@ -178,7 +178,8 @@ struct ircomm_cb{
        int ttp_stop;
 
        int max_txbuff_size;          
-       __u32 maxsdusize;
+       __u32 max_sdu_size;
+       __u8 max_header_size;
 
        __u32 daddr;        /* Device address of the peer device */ 
        __u32 saddr;
@@ -211,8 +212,6 @@ struct ircomm_cb{
        int                 pending_control_tuples;
        int                 ignored_control_tuples;
 
-
-
        __u8 pi ;            /* instruction of control channel*/ 
 
        __u8 port_type;
@@ -253,8 +252,6 @@ struct ircomm_cb{
        int port_name_critical;
 };
 
-
-
 void ircomm_connect_request(struct ircomm_cb *self, __u8 servicetype);
 void ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata,
                             __u32 maxsdusize);
index cb47fce3a0181411c7bb88cb1ae33639458a9161..b0e67385b985840ac332208e63d3098992dac3d6 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Dec  9 21:13:12 1997
- * Modified at:   Wed Apr 21 17:49:00 1999
+ * Modified at:   Mon May 10 09:51:13 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -109,6 +109,8 @@ struct irda_sock {
        
        __u32 max_sdu_size_rx;
        __u32 max_sdu_size_tx;
+       __u32 max_data_size;
+       __u8  max_header_size;
        struct qos_info qos_tx;
 
        __u16 mask;           /* Hint bits mask */
@@ -225,10 +227,10 @@ struct notify_t {
        int (*udata_indication)(void *priv, void *sap, struct sk_buff *skb);
        void (*connect_confirm)(void *instance, void *sap, 
                                struct qos_info *qos, __u32 max_sdu_size,
-                               struct sk_buff *skb);
+                               __u8 max_header_size, struct sk_buff *skb);
        void (*connect_indication)(void *instance, void *sap, 
                                   struct qos_info *qos, __u32 max_sdu_size,
-                                  struct sk_buff *skb);
+                                  __u8 max_header_size, struct sk_buff *skb);
        void (*disconnect_indication)(void *instance, void *sap, 
                                      LM_REASON reason, struct sk_buff *);
        void (*flow_indication)(void *instance, void *sap, LOCAL_FLOW flow);
index a3dcf2d6e78ffb15886d92cb7705f123177a8bd4..21b12e4ff4e70441ffd6a2d7f8bb4f9f5a387685 100644 (file)
@@ -4,24 +4,29 @@
  * Version:       
  * Description:   
  * Status:        Experimental.
- * Author:        Haris Zukanovic <haris@stud.cs.uit.no>
+ * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Apr 14 12:41:42 1998
- * Modified at:   Tue Apr 20 11:06:28 1999
+ * Modified at:   Mon May 10 15:46:02 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Haris Zukanovic, <haris@stud.cs.uit.no>
- *     Copyright (c) 1998 Dag Brattli, <dagb@cs.uit.no>
+ *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
  *     Copyright (c) 1998 Thomas Davis, <ratbert@radiks.net>,
- *     All Rights Reserved.
- *      
+ *     Copyright (c) 1998 Haris Zukanovic, <haris@stud.cs.uit.no>
+ *
  *     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.
- *  
- *     Neither Haris Zukanovic nor University of Tromsø admit liability nor
- *     provide warranty for any of this software. This material is 
- *     provided "AS-IS" and at no charge.
+ * 
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *     GNU General Public License for more details.
+ * 
+ *     You should have received a copy of the GNU General Public License 
+ *     along with this program; if not, write to the Free Software 
+ *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+ *     MA 02111-1307 USA
  *     
  ********************************************************************/
 
@@ -35,6 +40,7 @@
 
 #include <net/irda/irda.h>
 #include <net/irda/qos.h>
+#include <net/irda/dongle.h>
 #include <net/irda/irqueue.h>
 #include <net/irda/irlap_frame.h>
 
 #define IO_XMIT 0x01
 #define IO_RECV 0x02
 
+struct dongle_q {
+       QUEUE q;
+       struct dongle *dongle;
+};
+
 /* Chip specific info */
 struct chipio_t {
         int iobase, iobase2;  /* IO base */
@@ -111,6 +122,8 @@ struct irda_device {
        struct iobuff_t tx_buff;
        struct iobuff_t rx_buff;
 
+       struct dongle *dongle; /* Dongle driver */
+
        /* spinlock_t lock; */ /* For serializing operations */
        
        /* Media busy stuff */
@@ -120,7 +133,8 @@ struct irda_device {
        /* Callbacks for driver specific implementation */
         void (*change_speed)(struct irda_device *driver, int baud);
        int  (*is_receiving)(struct irda_device *);    /* receiving? */
-       /* int (*is_tbusy)(struct irda_device *); */   /* transmitting? */
+       void (*set_dtr_rts)(struct irda_device *idev, int dtr, int rts);
+       int  (*raw_write)(struct irda_device *idev, __u8 *buf, int len);
        void (*wait_until_sent)(struct irda_device *);
        void (*set_caddr)(struct irda_device *);      /* Set connection addr */
 };
@@ -142,6 +156,9 @@ inline void irda_device_change_speed(struct irda_device *, int);
 
 inline struct qos_info *irda_device_get_qos(struct irda_device *self);
 int irda_device_txqueue_empty(struct irda_device *self);
+void irda_device_init_dongle(struct irda_device *self, int type);
+void irda_device_unregister_dongle(struct dongle *dongle);
+int irda_device_register_dongle(struct dongle *dongle);
 
 int irda_device_setup(struct device *dev);
 
@@ -153,7 +170,7 @@ void setup_dma(int channel, char *buffer, int count, int mode);
  *    Utility function for getting the minimum turnaround time out of 
  *    the skb, where it has been hidden in the cb field.
  */
-inline static __u16 irda_get_mtt(struct sk_buff *skb)
+extern inline __u16 irda_get_mtt(struct sk_buff *skb)
 {
        __u16 mtt;
 
@@ -167,6 +184,23 @@ inline static __u16 irda_get_mtt(struct sk_buff *skb)
        return mtt;
 }
 
+extern inline void irda_device_set_dtr_rts(struct irda_device *self, int dtr,
+                                          int rts)
+{
+       if (self->set_dtr_rts)
+               self->set_dtr_rts(self, dtr, rts);
+}
+
+extern inline int irda_device_raw_write(struct irda_device *self, __u8 *buf,
+                                       int len)
+{
+       int ret = -1;
+
+       if (self->raw_write)
+               ret = self->raw_write(self, buf, len);
+       return ret;
+}
+
 #endif
 
 
index 071ed8561b0c4ea225e0e12f03d20686f9fca716..355751afa05746a8131edc46eef0c798d45c6ebf 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Thu Aug 21 00:02:07 1997
- * Modified at:   Wed Apr 21 16:37:21 1999
+ * Modified at:   Sun May  9 10:56:57 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1997 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
+ *     Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -81,6 +81,8 @@ struct iriap_cb {
        CONFIRM_CALLBACK confirm;
        void *priv;
 
+       __u8 max_header_size;
+       
        struct timer_list watchdog_timer;
 };
 
@@ -92,8 +94,6 @@ void iriap_getvaluebyclass_request( char *name, char *attr,
 void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb);
 
 void iriap_send_ack( struct iriap_cb *self);
-void iriap_connect_confirm(void *instance, void *sap, struct qos_info *qos, 
-                          __u32 max_sdu_size, struct sk_buff *skb);
 void iriap_call_indication(struct iriap_cb *self, struct sk_buff *skb);
 
 void iriap_register_server(void);
index 35d83096faf55907a468b02fc6b0da13727373ab..131e3f9235a0010c36a5c6fda14518dbed891536 100644 (file)
@@ -6,10 +6,11 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Thu Apr 22 14:30:37 1999
+ * Modified at:   Sun May  9 11:45:33 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
+ *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -98,7 +99,7 @@
 #define IRLAN_SHORT  1
 #define IRLAN_ARRAY  2
 
-#define IRLAN_MAX_HEADER (TTP_HEADER+LMP_HEADER+LAP_HEADER)
+#define IRLAN_MAX_HEADER (TTP_HEADER+LMP_HEADER+LAP_MAX_HEADER)
 
 /*
  *  IrLAN client
@@ -109,7 +110,10 @@ struct irlan_client_cb {
        int open_retries;
 
        struct tsap_cb *tsap_ctrl;
+       __u32 max_sdu_size;
+       __u8  max_header_size;
        
+       int access_type;         /* Access type of provider */
        __u8 reconnect_key[255];
        __u8 key_len;
        
@@ -130,6 +134,8 @@ struct irlan_provider_cb {
        int state;
        
        struct tsap_cb *tsap_ctrl;
+       __u32 max_sdu_size;
+       __u8  max_header_size;
 
        /*
         *  Store some values here which are used by the provider to parse
@@ -140,42 +146,45 @@ struct irlan_provider_cb {
        int filter_mode;
        int filter_operation;
        int filter_entry;
-
+       int access_type;     /* Access type */
        __u16 send_arb_val;
 
        __u8 mac_address[6]; /* Generated MAC address for peer device */
 };
 
 /*
- *  IrLAN
+ *  IrLAN control block
  */
 struct irlan_cb {
        QUEUE queue; /* Must be first */
 
        int    magic;
        char   ifname[9];
-       struct device dev;  /* Ethernet device structure*/
+       struct device dev;        /* Ethernet device structure*/
        struct enet_statistics stats;
 
-       __u32 saddr;        /* Source devcie address */
-       __u32 daddr;        /* Destination device address */
+       __u32 saddr;              /* Source devcie address */
+       __u32 daddr;              /* Destination device address */
        int   netdev_registered;
        int   notify_irmanager;
        
-       int media;          /* Media type */
-       int access_type;    /* Currently used access type */
-       __u8 version[2];    /* IrLAN version */
+       int media;                /* Media type */
+       __u8 version[2];          /* IrLAN version */
        
        struct tsap_cb *tsap_data;
 
-       int  use_udata;  /* Use Unit Data transfers */
+       int  master;              /* Master instance? */
+       int  use_udata;           /* Use Unit Data transfers */
 
-       __u8 stsap_sel_data; /* Source data TSAP selector */
-       __u8 dtsap_sel_data; /* Destination data TSAP selector */
-       __u8 dtsap_sel_ctrl; /* Destination ctrl TSAP selector */
+       __u8 stsap_sel_data;      /* Source data TSAP selector */
+       __u8 dtsap_sel_data;      /* Destination data TSAP selector */
+       __u8 dtsap_sel_ctrl;      /* Destination ctrl TSAP selector */
 
-       struct irlan_client_cb client;     /* Client specific fields */
+       struct irlan_client_cb   client;   /* Client specific fields */
        struct irlan_provider_cb provider; /* Provider specific fields */
+
+       __u32 max_sdu_size;
+       __u8  max_header_size;
        
        struct timer_list watchdog_timer;
 };
index aafbf9141245192ae45f5522e268c12bf05c3c99..ca51d5b7c999871e8acbd222f8ee15e74c4f9d28 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Thu Apr 22 14:29:16 1999
+ * Modified at:   Sun May  9 12:26:11 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -36,13 +36,7 @@ void irlan_provider_ctrl_disconnect_indication(void *instance, void *sap,
                                               LM_REASON reason, 
                                               struct sk_buff *skb);
 
-void irlan_provider_ctrl_data_indication(void *instance, void *sap,
-                                        struct sk_buff *skb);
 
-void irlan_provider_connect_indication(void *instance, void *sap, 
-                                      struct qos_info *qos, 
-                                      __u32 max_sdu_size,
-                                      struct sk_buff *skb);
 void irlan_provider_connect_response(struct irlan_cb *, struct tsap_cb *);
 
 int irlan_parse_open_data_cmd(struct irlan_cb *self, struct sk_buff *skb);
index f3b26110f646efbc3114ab7128c13548a0575540..c5767397ea8c76a4114e41eb9d06914acf79f038 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Fri Apr 23 09:51:15 1999
+ * Modified at:   Sun May  9 11:38:18 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
 #define LAP_COMP_HEADER 1  /* IrLAP Compression Header */
 
 #ifdef CONFIG_IRDA_COMPRESSION
-#  define LAP_HEADER  (LAP_ADDR_HEADER + LAP_CTRL_HEADER + LAP_COMP_HEADER)
+#  define LAP_MAX_HEADER  (LAP_ADDR_HEADER + LAP_CTRL_HEADER + LAP_COMP_HEADER)
 #  define IRDA_COMPRESSED 1
 #  define IRDA_NORMAL     0
 #else
-#define LAP_HEADER (LAP_ADDR_HEADER + LAP_CTRL_HEADER)
+#define LAP_MAX_HEADER (LAP_ADDR_HEADER + LAP_CTRL_HEADER)
 #endif
 
 #define BROADCAST  0xffffffff /* Broadcast device address */
@@ -138,7 +138,7 @@ struct irlap_cb {
 
        __u8    vs;           /* Next frame to be sent */
        __u8    vr;           /* Next frame to be received */
-       int     tmp;
+/*     int     tmp; */
        __u8    va;           /* Last frame acked */
        int     window;       /* Nr of I-frames allowed to send */
        int     window_size;  /* Current negotiated window size */
@@ -155,8 +155,7 @@ struct irlap_cb {
        __u8    s;           /* Current slot */
        int     frame_sent;  /* Have we sent reply? */
 
-       int discovery_count;
-       hashbin_t *discovery_log;
+       hashbin_t   *discovery_log;
        discovery_t *discovery_cmd;
 
        struct qos_info qos_tx;    /* QoS requested by peer */
@@ -227,4 +226,9 @@ void irlap_init_qos_capabilities(struct irlap_cb *, struct qos_info *);
 void irlap_apply_default_connection_parameters(struct irlap_cb *self);
 void irlap_apply_connection_parameters(struct irlap_cb *, struct qos_info *);
 
+extern inline __u8 irlap_get_header_size(struct irlap_cb *self)
+{
+       return 2;
+}
+
 #endif
index 31785883a584b6c92947f9c749403e46bb64a2d8..e879c6b9413c2df034a20f6c16b7bb4223867942 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 17 20:54:32 1997
- * Modified at:   Fri Apr 23 09:15:07 1999
+ * Modified at:   Sun May  9 11:01:34 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -52,7 +52,7 @@
 
 #define LMP_HEADER          2    /* Dest LSAP + Source LSAP */
 #define LMP_CONTROL_HEADER  4
-#define LMP_MAX_HEADER      (LAP_HEADER+LMP_HEADER)
+#define LMP_MAX_HEADER      (LMP_CONTROL_HEADER+LAP_MAX_HEADER)
 
 #define LM_MAX_CONNECTIONS  10
 
index 999cdd35fb58f468da19d1c35c1cb1226eb1584f..25ad8ef0190b1de2cb2dd650cb14b43af0172b0d 100644 (file)
@@ -158,7 +158,8 @@ struct irlpt_cb {
        struct miscdevice ir_dev; /* used to register the misc device. */
 
        int count;                /* open count */
-       int irlap_data_size;    /* max frame size we can send */
+       int max_data_size;      /* max frame size we can send */
+       int max_header_size;    /* how much header space is needed */
        int pkt_count;          /* how many packets are queued up */
 
        wait_queue_head_t read_wait;    /* wait queues */
index c4a036a4d91f992154573eedc402401280d1da87..81981273b97096255c7e1b6edf264fd015df1a57 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug  3 13:49:59 1997
- * Modified at:   Thu Jan  7 14:17:31 1999
+ * Modified at:   Mon May 10 22:12:56 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1997, 1998 Dag Brattli <dagb@cs.uit.no>
+ *     Copyright (c) 1997, 1998-1999 Dag Brattli <dagb@cs.uit.no>
  *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
 
 #define FRAME_MAX_SIZE 2048
 
-void irport_close( int iobase);
-int  irport_open( int iobase);
-int  irport_detect(struct irda_device *idev);
+void irport_start(int iobase);
+void irport_stop(int iobase);
+int  irport_probe(int iobase);
 
-void irport_change_speed( int iobase, int speed);
+void irport_change_speed(struct irda_device *idev, int speed);
 void irport_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 
-int  irport_hard_xmit( struct sk_buff *skb, struct device *dev);
+int  irport_hard_xmit(struct sk_buff *skb, struct device *dev);
 
 #endif
index aec1d57dc15738e09be0a111bbf7158a2ec255d0..3e6511ceae5bcd73951e9c1875422a35a5fa7092 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:31 1997
- * Modified at:   Sat Apr 10 10:19:56 1999
+ * Modified at:   Mon May 10 19:14:51 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -36,7 +36,8 @@
 
 #define TTP_MAX_CONNECTIONS    LM_MAX_CONNECTIONS
 #define TTP_HEADER             1
-#define TTP_HEADER_WITH_SAR    6
+#define TTP_MAX_HEADER         (TTP_HEADER + LMP_MAX_HEADER)
+#define TTP_SAR_HEADER         5
 #define TTP_PARAMETERS         0x80
 #define TTP_MORE               0x80
 
@@ -61,8 +62,6 @@ struct tsap_cb {
        QUEUE queue;          /* For linking it into the hashbin */
        int  magic;           /* Just in case */
 
-       int max_seg_size;     /* Max data that fit into an IrLAP frame */
-
        __u8 stsap_sel;       /* Source TSAP */
        __u8 dtsap_sel;       /* Destination TSAP */
 
@@ -88,6 +87,9 @@ struct tsap_cb {
        struct irda_statistics stats;
        struct timer_list todo_timer; 
        
+       __u32 max_seg_size;     /* Max data that fit into an IrLAP frame */
+       __u8  max_header_size;
+
        int   rx_sdu_busy;     /* RxSdu.busy */
        __u32 rx_sdu_size;     /* Current size of a partially received frame */
        __u32 rx_max_sdu_size; /* Max receive user data size */
@@ -120,8 +122,6 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
                          __u32 saddr, __u32 daddr,
                          struct qos_info *qos, __u32 max_sdu_size, 
                          struct sk_buff *userdata);
-void irttp_connect_confirm(void *instance, void *sap, struct qos_info *qos, 
-                          __u32 max_sdu_size, struct sk_buff *skb);
 void irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, 
                            struct sk_buff *userdata);
 struct tsap_cb *irttp_dup(struct tsap_cb *self, void *instance);
index 920909600e54f3051d68b095c92d096beece9051..38b5c4d81cd7c6cea37b0136af0c9e5ea9d2afb3 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Dec  9 21:13:12 1997
- * Modified at:   Sun Feb  7 01:57:33 1999
+ * Modified at:   Mon May 10 13:22:23 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  *  
- *     Copyright (c) 1997 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1997, 1999 Dag Brattli, All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -33,8 +33,6 @@
 #include <net/irda/irqueue.h>
 #include <net/irda/irda_device.h>
 
-#include <net/irda/dongle.h>
-
 #define IRTTY_IOC_MAGIC 'e'
 #define IRTTY_IOCTDONGLE  _IO(IRTTY_IOC_MAGIC, 1)
 #define IRTTY_IOC_MAXNR   1
 #define N_IRDA         11   /* This one should go in </asm/termio.h> */
 #endif
 
-struct dongle_q {
-       QUEUE q;
-
-       struct dongle *dongle;
-};
-
 struct irtty_cb {
        QUEUE q; /* Must be first */
 
-/*     char name[16]; */
-
        int     magic;
        
        struct  tty_struct  *tty;  /* Ptr to TTY structure */
        struct  irda_device idev;
-
-       struct dongle_q *dongle_q; /* Has this tty got a dongle attached? */
 };
  
-int irtty_register_dongle( struct dongle *dongle);
-void irtty_unregister_dongle( struct dongle *dongle);
-
-void irtty_set_dtr_rts(struct tty_struct *tty, int dtr, int rts);
+int irtty_register_dongle(struct dongle *dongle);
+void irtty_unregister_dongle(struct dongle *dongle);
 
 #endif
+
+
+
+
+
diff --git a/include/net/irda/toshoboe.h b/include/net/irda/toshoboe.h
new file mode 100644 (file)
index 0000000..b2f5b95
--- /dev/null
@@ -0,0 +1,165 @@
+/*********************************************************************
+ *                
+ * Filename:      toshoboe.h
+ * Version:       0.1
+ * Description:   Driver for the Toshiba OBOE (or type-O)
+ *                FIR Chipset. 
+ * Status:        Experimental.
+ * Author:        James McKenzie <james@fishsoup.dhs.org>
+ * Created at:    Sat May 8  12:35:27 1999
+ * 
+ *     Copyright (c) 1999 James McKenzie, All Rights Reserved.
+ *      
+ *     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.
+ *  
+ *     Neither James McKenzie nor Cambridge University admit liability nor
+ *     provide warranty for any of this software. This material is 
+ *     provided "AS-IS" and at no charge.
+ *
+ *     Applicable Models : Libretto 100CT. and many more
+ *
+ ********************************************************************/
+
+/*
+ * $Log: toshoboe.h,v $
+ * Revision 1.2  1999/05/09 01:43:08  root
+ * *** empty log message ***
+ *
+ * Revision 1.1  1999/05/09 01:25:58  root
+ * Initial revision
+ *
+ */
+
+#ifndef TOSHOBOE_H
+#define TOSHOBOE_H
+
+/* Registers */
+/*Receive and transmit task registers (read only) */
+#define OBOE_RCVT      (0x00+(self->base))
+#define OBOE_XMTT      (0x01+(self->base))
+#define OBOE_XMTT_OFFSET       0x40
+
+/*Page pointers to the TaskFile structure */
+#define OBOE_TFP2      (0x02+(self->base))
+#define OBOE_TFP0      (0x04+(self->base))
+#define OBOE_TFP1      (0x05+(self->base))
+
+/*Dunno */
+#define OBOE_REG_3     (0x03+(self->base))
+
+/*Number of tasks to use in Xmit and Recv queues */
+#define OBOE_NTR       (0x07+(self->base))
+#define OBOE_NTR_XMIT4 0x00
+#define OBOE_NTR_XMIT8 0x10
+#define OBOE_NTR_XMIT16        0x30
+#define OBOE_NTR_XMIT32        0x70
+#define OBOE_NTR_XMIT64        0xf0
+#define OBOE_NTR_RECV4 0x00
+#define OBOE_NTR_RECV8 0x01
+#define OBOE_NTR_RECV6 0x03
+#define OBOE_NTR_RECV32        0x07
+#define OBOE_NTR_RECV64        0x0f
+
+/* Dunno */
+#define OBOE_REG_9     (0x09+(self->base))
+
+/* Interrupt Status Register */
+#define OBOE_ISR       (0x0c+(self->base))
+#define OBOE_ISR_TXDONE        0x80
+#define OBOE_ISR_RXDONE        0x40
+#define OBOE_ISR_20    0x20
+#define OBOE_ISR_10    0x10
+#define OBOE_ISR_8     0x08         /*This is collision or parity or something */
+#define OBOE_ISR_4     0x08
+#define OBOE_ISR_2     0x08
+#define OBOE_ISR_1     0x08
+
+/*Dunno */
+#define OBOE_REG_D     (0x0d+(self->base))
+
+/*Register Lock Register */
+#define OBOE_LOCK      ((self->base)+0x0e)
+
+
+
+/*Speed control registers */
+#define OBOE_PMDL      (0x10+(self->base))
+#define OBOE_PMDL_SIR  0x18
+#define OBOE_PMDL_MIR  0xa0
+#define OBOE_PMDL_FIR  0x40
+
+#define OBOE_SMDL      (0x18+(self->base))
+#define OBOE_SMDL_SIR  0x20
+#define OBOE_SMDL_MIR  0x01
+#define OBOE_SMDL_FIR  0x0f
+
+#define OBOE_UDIV      (0x19+(self->base))
+
+/*Dunno */
+#define OBOE_REG_11    (0x11+(self->base))
+
+/*Chip Reset Register */
+#define OBOE_RST       (0x15+(self->base))
+#define OBOE_RST_WRAP  0x8
+
+/*Dunno */
+#define OBOE_REG_1A    (0x1a+(self->base))
+#define OBOE_REG_1B    (0x1b+(self->base))
+
+/* The PCI ID of the OBOE chip */
+#ifndef PCI_DEVICE_ID_FIR701
+#define PCI_DEVICE_ID_FIR701   0x0701
+#endif
+
+typedef unsigned int dword;
+typedef unsigned short int word;
+typedef unsigned char byte;
+typedef dword Paddr;
+
+struct OboeTask
+  {
+    __u16 len;
+    __u8 unused;
+    __u8 control;
+    __u32 buffer;
+  };
+
+#define OBOE_NTASKS 64
+
+struct OboeTaskFile
+  {
+    struct OboeTask recv[OBOE_NTASKS];
+    struct OboeTask xmit[OBOE_NTASKS];
+  };
+
+#define OBOE_TASK_BUF_LEN (sizeof(struct OboeTaskFile) << 1)
+
+/*These set the number of slots in use */
+#define TX_SLOTS       4
+#define RX_SLOTS       4
+
+/* You need also to change this, toshiba uses 4,8 and 4,4 */
+/* It makes no difference if you are only going to use ONETASK mode */
+/* remember each buffer use XX_BUF_SZ more _PHYSICAL_ memory */
+#define OBOE_NTR_VAL   (OBOE_NTR_XMIT4 | OBOE_NTR_RECV4)
+
+struct toshoboe_cb
+  {
+    struct irda_device idev;    /*IRDA device */
+    struct pci_dev *pdev;       /*PCI device */
+    int base;                   /*IO base */
+    int txpending;              /*how many tx's are pending */
+    int txs, rxs;               /*Which slots are we at  */
+    void *taskfilebuf;          /*The unaligned taskfile buffer */
+    struct OboeTaskFile *taskfile;  /*The taskfile   */
+    void *xmit_bufs[TX_SLOTS];  /*The buffers   */
+    void *recv_bufs[RX_SLOTS];
+  };
+
+
+#endif
+
+
index 3e3200b2de3fc847a482836fcfb61f344267a34d..d86456ada55291df7b2b867ffe3c3644f0073242 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Paul VanderSpek
  * Created at:    Thu Nov 19 13:55:34 1998
- * Modified at:   Thu Dec 10 14:06:18 1998
+ * Modified at:   Mon May  3 12:07:25 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
 #define IRM_CR_IRX_MSL 0x40
 #define IRM_CR_AF_MNT   0x80 /* Automatic format */
 
+/* For storing entries in the status FIFO */
+struct st_fifo_entry {
+       int status;
+       int len;
+};
+
+struct st_fifo {
+       struct st_fifo_entry entries[10];
+       int head;
+       int tail;
+       int len;
+};
+
+/* Private data for each instance */
+struct w83977af_ir {
+       struct st_fifo st_fifo;
+
+       int tx_buff_offsets[10]; /* Offsets between frames in tx_buff */
+       int tx_len;          /* Number of frames in tx_buff */
+
+       struct irda_device idev;
+};
+
 static inline void switch_bank( int iobase, int set)
 {
        outb( set, iobase+SSR);
index ca21ebec51234808ab4cfa4f4db81920973a852a..fa7ceb25c2216abca70a7c5188b4407a3fde9528 100644 (file)
@@ -1,15 +1,16 @@
 /*********************************************************************
  *                
  * Filename:      wrapper.h
- * Version:       1.0
- * Description:   IrDA Wrapper layer
+ * Version:       1.2
+ * Description:   IrDA SIR async wrapper layer
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Fri Jan 29 10:15:46 1999
+ * Modified at:   Mon May  3 09:02:36 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
+ *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
 #define STA BOF  /* Start flag */
 #define STO EOF  /* End flag */
 
-#define IR_TRANS 0x20    /* Asynchronous transparency modifier */       
+#define IRDA_TRANS 0x20    /* Asynchronous transparency modifier */       
 
+/* States for receving a frame in async mode */
 enum {
-       OUTSIDE_FRAME = 1
+       OUTSIDE_FRAME, 
        BEGIN_FRAME, 
        LINK_ESCAPE, 
        INSIDE_FRAME
 };
 
 /* Proto definitions */
-int  async_wrap_skb( struct sk_buff *skb, __u8 *tx_buff, int buffsize);
-void async_unwrap_char( struct irda_device *, __u8 byte);
+int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize);
+inline void async_unwrap_char(struct irda_device *idev, __u8 byte);
 
 #endif
index 0e1ea2586c2d3a923b6c7165eec0b676f26ae4e5..ac12d2acafe3b4600bb61bd3d032e4fdd39ab83f 100644 (file)
@@ -1,7 +1,7 @@
 #
 # DECnet configuration
 #
-bool 'DECnet: SIOCFIGCONF support' CONFIG_DECNET_SIOCGIFCONF 
+bool 'DECnet: SIOCGIFCONF support' CONFIG_DECNET_SIOCGIFCONF 
 bool 'DECnet: router support (VERY VERY EXPERIMENTAL)' CONFIG_DECNET_ROUTER
 bool 'DECnet: raw socket support' CONFIG_DECNET_RAW
 #bool 'DECnet: MOP support' CONFIG_DECNET_MOP
index 512dd2994157cf26f404ad61feaedf335f375425..9d355f7526088f686f7c9961e9c29dea2b06e912 100644 (file)
@@ -1503,7 +1503,7 @@ _dn_getsockopt(struct socket *sock, int level,int optname, char *optval,int *opt
                        break;
 
                case DSO_ACCEPTMODE:
-                       if (put_user(optval, &mode))
+                       if (put_user(mode, optval))
                                return -EFAULT;
                        break;
 
index 9d0fd175589a743c55a8bc01ae625a83920fb047..b8660044f95db4a11a3189537b8e698ce523bab1 100644 (file)
@@ -269,7 +269,7 @@ static void dn_dev_sysctl_register(struct device *dev, struct dn_dev_parms *parm
        memcpy(t, &dn_dev_sysctl, sizeof(*t));
 
        for(i = 0; i < (sizeof(t->dn_dev_vars)/sizeof(t->dn_dev_vars[0]) - 1); i++) {
-               int offset = (int)t->dn_dev_vars[i].data;
+               long offset = (long)t->dn_dev_vars[i].data;
                t->dn_dev_vars[i].data = ((char *)parms) + offset;
                t->dn_dev_vars[i].de = NULL;
        }
index cb9eb86fa645625baba2020306fc561f6e28926d..6d10df045ab1cafaf5ab75c7ab737606c51b48c8 100644 (file)
@@ -592,17 +592,21 @@ int dn_nsp_rx(struct sk_buff *skb)
         */
        if ((sk = dn_find_by_skb(skb)) != NULL) {
                struct dn_scp *scp = &sk->protinfo.dn;
+               int ret;
                /* printk(KERN_DEBUG "dn_nsp_rx: Found a socket\n"); */
 
                /* Reset backoff */
                scp->nsp_rxtshift = 0;
 
-               if (!atomic_read(&sk->sock_readers))
-                       return dn_nsp_backlog_rcv(sk, skb);
+               bh_lock_sock(sk);
+               ret = 0;
+               if (sk->lock.users == 0)
+                       ret = dn_nsp_backlog_rcv(sk, skb);
+               else
+                       sk_add_backlog(sk, skb);
+               bh_unlock_sock(sk);
 
-               __skb_queue_tail(&sk->back_log, skb);
-
-               goto out;
+               return ret;
        }
        return 1;
 
@@ -622,8 +626,6 @@ int dn_nsp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
        struct dn_scp *scp = &sk->protinfo.dn;
        struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;
 
-       lock_sock(sk); /* SMP locking */
-
        /*
         * Control packet.
         */
@@ -696,8 +698,6 @@ free_out:
                }
        }
 
-       release_sock(sk);
-
        return 0;
 }
 
index 4f12e6dd0dd7b52e39b1ab7a2e66e4e20f0e280e..8cfeaee705287a65d9ebbee6550e3db4eb021da0 100644 (file)
@@ -58,10 +58,12 @@ static void dn_slow_timer(unsigned long arg)
        struct sock *sk = (struct sock *)arg;
        struct dn_scp *scp = &sk->protinfo.dn;
 
-       if (atomic_read(&sk->sock_readers)) {
+       bh_lock_sock(sk);
+
+       if (sk->lock.users != 0) {
                sk->timer.expires = jiffies + HZ / 10;
                add_timer(&sk->timer);
-               return;
+               goto out;
        }
 
        /*
@@ -78,7 +80,7 @@ static void dn_slow_timer(unsigned long arg)
                        scp->persist = 0;
 
                        if (scp->persist_fxn(sk))
-                               return;
+                               goto out;
                } else {
                        scp->persist -= SLOW_INTERVAL;
                }
@@ -103,6 +105,8 @@ static void dn_slow_timer(unsigned long arg)
        sk->timer.expires = jiffies + SLOW_INTERVAL;
 
        add_timer(&sk->timer);
+out:
+       bh_unlock_sock(sk);
 }
 
 static void dn_fast_timer(unsigned long arg)
@@ -110,16 +114,19 @@ static void dn_fast_timer(unsigned long arg)
        struct sock *sk = (struct sock *)arg;
        struct dn_scp *scp = &sk->protinfo.dn;
 
-       if (atomic_read(&sk->sock_readers)) {
+       bh_lock_sock(sk);
+       if (sk->lock.users != 0) {
                scp->delack_timer.expires = jiffies + HZ / 20;
                add_timer(&scp->delack_timer);
-               return;
+               goto out;
        }
 
        scp->delack_pending = 0;
 
        if (scp->delack_fxn)
                scp->delack_fxn(sk);
+out:
+       bh_unlock_sock(sk);
 }
 
 void dn_start_fast_timer(struct sock *sk)
index 7f83c5a81bb5969cfec6fca1e441e71ae36048fc..717e01345a2106bc2e8aba807203c0c75b327f57 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun May 31 10:12:43 1998
- * Modified at:   Thu Apr 22 12:08:04 1999
+ * Modified at:   Tue May 11 12:42:26 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       af_netroom.c, af_ax25.c, af_rose.c, af_x25.c etc.
  * 
@@ -30,6 +30,7 @@
 #include <linux/if_arp.h>
 #include <linux/net.h>
 #include <linux/irda.h>
+#include <linux/poll.h>
 
 #include <asm/uaccess.h>
 
@@ -46,11 +47,12 @@ extern void irda_cleanup(void);
 extern int  irlap_driver_rcv(struct sk_buff *, struct device *, 
                             struct packet_type *);
 
-static struct proto_ops irda_proto_ops;
+static struct proto_ops irda_stream_ops;
+static struct proto_ops irda_dgram_ops;
 static hashbin_t *cachelog = NULL;
 static DECLARE_WAIT_QUEUE_HEAD(discovery_wait); /* Wait for discovery */
 
-#define IRDA_MAX_HEADER (TTP_HEADER+LMP_HEADER+LAP_HEADER)
+#define IRDA_MAX_HEADER (TTP_MAX_HEADER)
 
 /*
  * Function irda_data_indication (instance, sap, skb)
@@ -121,7 +123,8 @@ static void irda_disconnect_indication(void *instance, void *sap,
  */
 static void irda_connect_confirm(void *instance, void *sap, 
                                 struct qos_info *qos,
-                                __u32 max_sdu_size, struct sk_buff *skb)
+                                __u32 max_sdu_size, __u8 max_header_size, 
+                                struct sk_buff *skb)
 {
        struct irda_sock *self;
        struct sock *sk;
@@ -130,13 +133,28 @@ static void irda_connect_confirm(void *instance, void *sap,
 
        self = (struct irda_sock *) instance;
 
+       /* How much header space do we need to reserve */
+       self->max_header_size = max_header_size;
+
+       /* IrTTP max SDU size in transmit direction */
        self->max_sdu_size_tx = max_sdu_size;
+
+       /* Find out what the largest chunk of data that we can transmit is */
+       if (max_sdu_size == SAR_DISABLE)
+               self->max_data_size = qos->data_size.value - max_header_size;
+       else
+               self->max_data_size = max_sdu_size;
+
+       DEBUG(0, __FUNCTION__ "(), max_data_size=%d\n", self->max_data_size);
+
        memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
 
        sk = self->sk;
        if (sk == NULL)
                return;
 
+       skb_queue_tail(&sk->receive_queue, skb);
+
        /* We are now connected! */
        sk->state = TCP_ESTABLISHED;
        sk->state_change(sk);
@@ -150,7 +168,7 @@ static void irda_connect_confirm(void *instance, void *sap,
  */
 static void irda_connect_indication(void *instance, void *sap, 
                                    struct qos_info *qos, __u32 max_sdu_size,
-                                   struct sk_buff *skb)
+                                   __u8 max_header_size, struct sk_buff *skb)
 {
        struct irda_sock *self;
        struct sock *sk;
@@ -158,8 +176,21 @@ static void irda_connect_indication(void *instance, void *sap,
        DEBUG(1, __FUNCTION__ "()\n");
 
        self = (struct irda_sock *) instance;
-       
-       self->max_sdu_size_tx = max_sdu_size;
+
+       /* How much header space do we need to reserve */
+       self->max_header_size = max_header_size;
+
+       /* IrTTP max SDU size in transmit direction */
+       self->max_sdu_size_tx = max_sdu_size;   
+
+       /* Find out what the largest chunk of data that we can transmit is */
+       if (max_sdu_size == SAR_DISABLE)
+               self->max_data_size = qos->data_size.value - max_header_size;
+       else
+               self->max_data_size = max_sdu_size;
+
+       DEBUG(0, __FUNCTION__ "(), max_data_size=%d\n", self->max_data_size);
+
        memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
 
        sk = self->sk;
@@ -187,12 +218,12 @@ void irda_connect_response(struct irda_sock *self)
 
        skb = dev_alloc_skb(64);
        if (skb == NULL) {
-               DEBUG( 0, __FUNCTION__ "() Could not allocate sk_buff!\n");
+               DEBUG(0, __FUNCTION__ "() Unable to allocate sk_buff!\n");
                return;
        }
 
        /* Reserve space for MUX_CONTROL and LAP header */
-       skb_reserve(skb, TTP_HEADER+LMP_CONTROL_HEADER+LAP_HEADER);
+       skb_reserve(skb, IRDA_MAX_HEADER);
 
        irttp_connect_response(self->tsap, self->max_sdu_size_rx, skb);
 }
@@ -514,10 +545,13 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags)
        new->stsap_sel = new->tsap->stsap_sel;
        new->dtsap_sel = new->tsap->dtsap_sel;
        new->saddr = irttp_get_saddr(new->tsap);
-       new->saddr = irttp_get_saddr(new->tsap);
+       new->daddr = irttp_get_daddr(new->tsap);
 
        new->max_sdu_size_tx = self->max_sdu_size_tx;
        new->max_sdu_size_rx = self->max_sdu_size_rx;
+       new->max_data_size   = self->max_data_size;
+       new->max_header_size = self->max_header_size;
+
        memcpy(&new->qos_tx, &self->qos_tx, sizeof(struct qos_info));
 
        /* Clean up the original one to keep it in listen state */
@@ -669,7 +703,7 @@ static int irda_create(struct socket *sock, int protocol)
 
        sock_init_data(sock, sk);
 
-       sock->ops    = &irda_proto_ops;
+       sock->ops    = &irda_stream_ops;
        sk->protocol = protocol;
 
        /* Register as a client with IrLMP */
@@ -786,12 +820,20 @@ static int irda_sendmsg(struct socket *sock, struct msghdr *msg, int len,
                        return -ENOTCONN;
        }
 
-       skb = sock_alloc_send_skb(sk, len + IRDA_MAX_HEADER, 0, 
+       /* Check that we don't send out to big frames */
+       if (len > self->max_data_size) {
+               DEBUG(0, __FUNCTION__ "(), Warning to much data! "
+                     "Chopping frame from %d to %d bytes!\n", len, 
+                     self->max_data_size);
+               len = self->max_data_size;
+       }
+
+       skb = sock_alloc_send_skb(sk, len + self->max_header_size, 0, 
                                  msg->msg_flags & MSG_DONTWAIT, &err);
        if (!skb)
                return -ENOBUFS;
 
-       skb_reserve(skb, IRDA_MAX_HEADER);
+       skb_reserve(skb, self->max_header_size);
        
        DEBUG(4, __FUNCTION__ "(), appending user data\n");
        asmptr = skb->h.raw = skb_put(skb, len);
@@ -815,8 +857,8 @@ static int irda_sendmsg(struct socket *sock, struct msghdr *msg, int len,
  *    Try to receive message and copy it to user
  *
  */
-static int irda_recvmsg(struct socket *sock, struct msghdr *msg, int size,
-                       int flags, struct scm_cookie *scm)
+static int irda_recvmsg_dgram(struct socket *sock, struct msghdr *msg, 
+                             int size, int flags, struct scm_cookie *scm)
 {
        struct irda_sock *self;
        struct sock *sk = sock->sk;
@@ -861,6 +903,161 @@ static int irda_recvmsg(struct socket *sock, struct msghdr *msg, int size,
        return copied;
 }
 
+/*
+ * Function irda_data_wait (sk)
+ *
+ *    Sleep until data has arrive. But check for races..
+ *
+ */
+static void irda_data_wait(struct sock *sk)
+{
+       if (!skb_peek(&sk->receive_queue)) {
+               sk->socket->flags |= SO_WAITDATA;
+               interruptible_sleep_on(sk->sleep);
+               sk->socket->flags &= ~SO_WAITDATA;
+       }
+}
+
+/*
+ * Function irda_recvmsg_stream (sock, msg, size, flags, scm)
+ *
+ *    
+ *
+ */
+static int irda_recvmsg_stream(struct socket *sock, struct msghdr *msg, 
+                              int size, int flags, struct scm_cookie *scm)
+{
+       struct irda_sock *self;
+       struct sock *sk = sock->sk;
+       int noblock = flags & MSG_DONTWAIT;
+       int copied = 0;
+       int target = 1;
+
+       DEBUG(3, __FUNCTION__ "()\n");
+
+       self = sk->protinfo.irda;
+       ASSERT(self != NULL, return -1;);
+
+       if (sock->flags & SO_ACCEPTCON) 
+               return(-EINVAL);
+
+       if (flags & MSG_OOB)
+               return -EOPNOTSUPP;
+
+       if (flags & MSG_WAITALL)
+               target = size;
+               
+               
+       msg->msg_namelen = 0;
+
+       /* Lock the socket to prevent queue disordering
+        * while sleeps in memcpy_tomsg
+        */
+/*     down(&self->readsem); */
+
+       do {
+               int chunk;
+               struct sk_buff *skb;
+
+               skb=skb_dequeue(&sk->receive_queue);
+               if (skb==NULL) {
+                       if (copied >= target)
+                               break;
+                       
+                       /*
+                        *      POSIX 1003.1g mandates this order.
+                        */
+                       
+                       if (sk->err) {
+                               /* up(&self->readsem); */
+                               return sock_error(sk);
+                       }
+
+                       if (sk->shutdown & RCV_SHUTDOWN)
+                               break;
+
+               /*      up(&self->readsem); */
+
+                       if (noblock)
+                               return -EAGAIN;
+                       irda_data_wait(sk);
+                       if (signal_pending(current))
+                               return -ERESTARTSYS;
+               /*      down(&self->readsem); */
+                       continue;
+               }
+
+               /* Never glue messages from different writers */
+/*             if (check_creds && */
+/*                 memcmp(UNIXCREDS(skb), &scm->creds, sizeof(scm->creds)) != 0) */
+/*             { */
+/*                     skb_queue_head(&sk->receive_queue, skb); */
+/*                     break; */
+/*             } */
+
+               chunk = min(skb->len, size);
+               if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {
+                       skb_queue_head(&sk->receive_queue, skb);
+                       if (copied == 0)
+                               copied = -EFAULT;
+                       break;
+               }
+               copied += chunk;
+               size -= chunk;
+
+               /* Copy credentials */
+/*             scm->creds = *UNIXCREDS(skb); */
+/*             check_creds = 1; */
+
+               /* Mark read part of skb as used */
+               if (!(flags & MSG_PEEK)) {
+                       skb_pull(skb, chunk);
+
+/*                     if (UNIXCB(skb).fp) */
+/*                             unix_detach_fds(scm, skb); */
+
+                       /* put the skb back if we didn't use it up.. */
+                       if (skb->len) {
+                               DEBUG(1, __FUNCTION__ "(), back on q!\n");
+                               skb_queue_head(&sk->receive_queue, skb);
+                               break;
+                       }
+
+                       kfree_skb(skb);
+                       
+/*                     if (scm->fp) */
+/*                             break; */
+               } else {
+                       DEBUG(0, __FUNCTION__ "() questionable!?\n");
+                       /* It is questionable, see note in unix_dgram_recvmsg. */
+/*                     if (UNIXCB(skb).fp) */
+/*                             scm->fp = scm_fp_dup(UNIXCB(skb).fp); */
+
+                       /* put message back and return */
+                       skb_queue_head(&sk->receive_queue, skb);
+                       break;
+               }
+       } while (size);
+
+       /*
+        *  Check if we have previously stopped IrTTP and we know
+        *  have more free space in our rx_queue. If so tell IrTTP
+        *  to start delivering frames again before our rx_queue gets
+        *  empty
+        */
+       if (self->rx_flow == FLOW_STOP) {
+               if ((atomic_read(&sk->rmem_alloc) << 2) <= sk->rcvbuf) {
+                       DEBUG(2, __FUNCTION__ "(), Starting IrTTP\n");
+                       self->rx_flow = FLOW_START;
+                       irttp_flow_request(self->tsap, FLOW_START);
+               }
+       }
+
+       /* up(&self->readsem); */
+
+       return copied;
+}
+
 /*
  * Function irda_shutdown (sk, how)
  *
@@ -875,19 +1072,45 @@ static int irda_shutdown( struct socket *sk, int how)
         return -EOPNOTSUPP;
 }
 
-
 /*
  * Function irda_poll (file, sock, wait)
  *
  *    
  *
  */
-unsigned int irda_poll(struct file *file, struct socket *sock, 
-                      struct poll_table_struct *wait)
+static unsigned int irda_poll(struct file * file, struct socket *sock, 
+                             poll_table *wait)
 {
-       DEBUG(0, __FUNCTION__ "()\n");
+       struct sock *sk = sock->sk;
+       unsigned int mask;
 
-       return 0;
+       DEBUG(1, __FUNCTION__ "()\n");
+
+       poll_wait(file, sk->sleep, wait);
+       mask = 0;
+
+       /* exceptional events? */
+       if (sk->err)
+               mask |= POLLERR;
+       if (sk->shutdown & RCV_SHUTDOWN)
+               mask |= POLLHUP;
+
+       /* readable? */
+       if (!skb_queue_empty(&sk->receive_queue))
+               mask |= POLLIN | POLLRDNORM;
+
+       /* Connection-based need to check for termination and startup */
+       if (sk->type == SOCK_STREAM && sk->state==TCP_CLOSE)
+               mask |= POLLHUP;
+
+       /*
+        * we set writable also when the other side has shut down the
+        * connection. This prevents stuck sockets.
+        */
+       if (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= MIN_WRITE_SPACE)
+                       mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+
+       return mask;
 }
 
 /*
@@ -947,6 +1170,7 @@ static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                return -EINVAL;
                
        default:
+               DEBUG(0, __FUNCTION__ "(), doing device ioctl!\n");
                return dev_ioctl(cmd, (void *) arg);
        }
 
@@ -1082,13 +1306,7 @@ static int irda_getsockopt(struct socket *sock, int level, int optname,
                        return -EFAULT;
                break;
        case IRTTP_MAX_SDU_SIZE:
-               if (self->max_sdu_size_tx != SAR_DISABLE)
-                       val = self->max_sdu_size_tx;
-               else
-                       /* SAR is disabled, so use the IrLAP data size
-                        * instead */
-                       val = self->qos_tx.data_size.value - IRDA_MAX_HEADER;
-
+               val = self->max_data_size;
                DEBUG(0, __FUNCTION__ "(), getting max_sdu_size = %d\n", val);
                len = sizeof(int);
                if (put_user(len, optlen))
@@ -1110,7 +1328,7 @@ static struct net_proto_family irda_family_ops =
        irda_create
 };
 
-static struct proto_ops irda_proto_ops = {
+static struct proto_ops irda_stream_ops = {
        PF_IRDA,
        
        sock_no_dup,
@@ -1128,7 +1346,28 @@ static struct proto_ops irda_proto_ops = {
        irda_getsockopt,
        sock_no_fcntl,
        irda_sendmsg,
-       irda_recvmsg
+       irda_recvmsg_stream
+};
+
+static struct proto_ops irda_dgram_ops = {
+       PF_IRDA,
+       
+       sock_no_dup,
+       irda_release,
+       irda_bind,
+       irda_connect,
+       sock_no_socketpair,
+       irda_accept,
+       irda_getname,
+       datagram_poll,
+       irda_ioctl,
+       irda_listen,
+       irda_shutdown,
+       irda_setsockopt,
+       irda_getsockopt,
+       sock_no_fcntl,
+       irda_sendmsg,
+       irda_recvmsg_dgram
 };
 
 /*
@@ -1215,7 +1454,7 @@ void irda_proto_cleanup(void)
        irda_packet_type.type = htons(ETH_P_IRDA);
         dev_remove_pack(&irda_packet_type);
 
-        unregister_netdevice_notifier( &irda_dev_notifier);
+        unregister_netdevice_notifier(&irda_dev_notifier);
        
        sock_unregister(PF_IRDA);
        irda_cleanup();
index 9a6f3021fa0595aa12877a9114123eb95cc78e18..b3019d5c209573896a71dfec11d9738651e3c6a5 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Sat Dec 12 09:56:35 1998
+ * Modified at:   Sun May  2 20:28:08 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       ppp.c by Michael Callahan <callahan@maths.ox.ac.uk>
  *                Al Longyear <longyear@netcom.com>
@@ -59,7 +59,7 @@ __u16 const irda_crc16_table[256] =
 
 unsigned short crc_calc( __u16 fcs, __u8 const *buf, size_t len) 
 {
-    while ( len--)
-               fcs = IR_FCS(fcs, *buf++);
-    return fcs;
+       while (len--)
+                fcs = irda_fcs(fcs, *buf++);
+       return fcs;
 }
index 22def3a1e89cf10f781dca998435988ce0e7de04..41fc4d20a5e80ef3b674c96de4a5fd41e38f1a97 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Apr  6 15:33:50 1999
- * Modified at:   Sun Apr 11 00:41:58 1999
+ * Modified at:   Sun May  9 22:40:43 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
 /*
  * Function irlmp_add_discovery (cachelog, discovery)
  *
- *    
- *
+ *    Add a new discovery to the cachelog, and remove any old discoveries
+ *    from the same device
  */
-void irlmp_add_discovery(hashbin_t *cachelog, discovery_t *discovery)
+void irlmp_add_discovery(hashbin_t *cachelog, discovery_t *new)
 {
-       discovery_t *old;
+       discovery_t *discovery, *node;
+       unsigned long flags;
 
-       DEBUG(4, __FUNCTION__ "()\n");
+       spin_lock_irqsave(&irlmp->lock, flags);
+
+       /* 
+        * Remove all discoveries of devices that has previously been 
+        * discovered on the same link with the same name (info), or the 
+        * same daddr. We do this since some devices (mostly PDAs) change
+        * their device address between every discovery.
+        */
+       discovery = (discovery_t *) hashbin_get_first(cachelog);
+       while (discovery != NULL ) {
+                       node = discovery;
+
+                       /* Be sure to stay one item ahead */
+                       discovery = (discovery_t *) hashbin_get_next(cachelog);
+                       
+                       if ((node->daddr == new->daddr) || 
+                           (strcmp(node->info, new->info) == 0))
+                       {
+                               /* This discovery is a previous discovery 
+                                * from the same device, so just remove it
+                                */
+                               hashbin_remove(cachelog, node->daddr, NULL);
+                               kfree(node);
+                       }
+               }
 
-       /* Check if we have discovered this device before */
-       old = hashbin_remove(cachelog, discovery->daddr, NULL);
-       if (old)
-               kfree(old);
 
        /* Insert the new and updated version */
-       hashbin_insert(cachelog, (QUEUE *) discovery, discovery->daddr, NULL);
+       hashbin_insert(cachelog, (QUEUE *) new, new->daddr, NULL);
+
+       spin_unlock_irqrestore(&irlmp->lock, flags);
 }
 
 /*
  * Function irlmp_add_discovery_log (cachelog, log)
  *
- *    
+ *    Merge a disovery log into the cachlog.
  *
  */
 void irlmp_add_discovery_log(hashbin_t *cachelog, hashbin_t *log)
index bc8758e1eff540c2808615890bcc9cf7ad9a5257..97fc3cf279d266bd4d47d0e903ca3e9eaa4b33d3 100644 (file)
@@ -8,7 +8,7 @@
  * Author:        Takahide Higuchi <thiguchi@pluto.dti.ne.jp>
  * Source:        irlpt_event.c
  *
- *     Copyright (c) 1998, Takahide Higuchi, <thiguchi@pluto.dti.ne.jp>,
+ *     Copyright (c) 1998-1999, Takahide Higuchi, <thiguchi@pluto.dti.ne.jp>,
  *     All Rights Reserved.
  *
  *     This program is free software; you can redistribute it and/or
 static char *revision_date = "Sun Apr 18 00:40:19 1999";
 
 
-static void ircomm_state_idle( struct ircomm_cb *self, IRCOMM_EVENT event, 
-                              struct sk_buff *skb );
-
-static void ircomm_state_discoverywait( struct ircomm_cb *self, IRCOMM_EVENT event, 
+static void ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event, 
+                             struct sk_buff *skb );
+static void ircomm_state_discoverywait(struct ircomm_cb *self, 
+                                      IRCOMM_EVENT event, 
+                                      struct sk_buff *skb );
+static void ircomm_state_queryparamwait(struct ircomm_cb *self, 
+                                       IRCOMM_EVENT event, 
                                        struct sk_buff *skb );
-
-static void ircomm_state_queryparamwait( struct ircomm_cb *self, IRCOMM_EVENT event, 
-                                        struct sk_buff *skb );
-
-static void ircomm_state_querylsapwait( struct ircomm_cb *self, IRCOMM_EVENT event, 
-                                       struct sk_buff *skb );
-
+static void ircomm_state_querylsapwait(struct ircomm_cb *self, 
+                                      IRCOMM_EVENT event, 
+                                      struct sk_buff *skb );
 static void ircomm_state_waiti( struct ircomm_cb *self, IRCOMM_EVENT event, 
                                struct sk_buff *skb );
 static void ircomm_state_waitr( struct ircomm_cb *self, IRCOMM_EVENT event, 
@@ -207,7 +206,7 @@ __initfunc(int ircomm_init(void))
                ircomm[i]->ack_char = 0x06;  
 
                ircomm[i]->max_txbuff_size = COMM_DEFAULT_DATA_SIZE;   /* 64 */
-               ircomm[i]->maxsdusize = SAR_DISABLE;  
+               ircomm[i]->max_sdu_size = SAR_DISABLE;  
                ircomm[i]->ctrl_skb = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE);
                if (ircomm[i]->ctrl_skb == NULL){
                        DEBUG(0,"ircomm:init_module:alloc_skb failed!\n");
@@ -226,7 +225,6 @@ __initfunc(int ircomm_init(void))
        create_proc_entry("ircomm", 0, proc_irda)->get_info = ircomm_proc_read;
 #endif /* CONFIG_PROC_FS */
 
-
        discovering_instance = NULL;
        return 0;
 }
@@ -275,51 +273,53 @@ void ircomm_cleanup(void)
 static int ircomm_accept_data_indication(void *instance, void *sap, 
                                         struct sk_buff *skb)
 {
-       
-       struct ircomm_cb *self = (struct ircomm_cb *)instance;
+       struct ircomm_cb *self = (struct ircomm_cb *) instance;
 
-       ASSERT( self != NULL, return -1;);
-       ASSERT( self->magic == IRCOMM_MAGIC, return -1;);
-       ASSERT( skb != NULL, return -1;);
+       ASSERT(self != NULL, return -1;);
+       ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
+       ASSERT(skb != NULL, return -1;);
        
        DEBUG(4,__FUNCTION__"():\n");
-       ircomm_do_event( self, TTP_DATA_INDICATION, skb);
+       ircomm_do_event(self, TTP_DATA_INDICATION, skb);
        self->rx_packets++;
        
        return 0;
 }
 
 static void ircomm_accept_connect_confirm(void *instance, void *sap,
-                                  struct qos_info *qos, 
-                                  __u32 maxsdusize, struct sk_buff *skb)
+                                         struct qos_info *qos, 
+                                         __u32 max_sdu_size, 
+                                         __u8 max_header_size,
+                                         struct sk_buff *skb)
 {
+       struct ircomm_cb *self = (struct ircomm_cb *) instance;
 
-       struct ircomm_cb *self = (struct ircomm_cb *)instance;
-
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == IRCOMM_MAGIC, return;);
-       ASSERT( skb != NULL, return;);
-       ASSERT( qos != NULL, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == IRCOMM_MAGIC, return;);
+       ASSERT(skb != NULL, return;);
+       ASSERT(qos != NULL, return;);
 
        DEBUG(0,__FUNCTION__"(): got connected!\n");
 
-       if(maxsdusize == SAR_DISABLE)
-               self->max_txbuff_size = qos->data_size.value
+       if (max_sdu_size == SAR_DISABLE)
+               self->max_txbuff_size = qos->data_size.value - max_header_size;
        else {
-               ASSERT(maxsdusize >= COMM_DEFAULT_DATA_SIZE, return;);
-               self->max_txbuff_size = maxsdusize; /* use fragmentation */
+               ASSERT(max_sdu_size >= COMM_DEFAULT_DATA_SIZE, return;);
+               self->max_txbuff_size = max_sdu_size; /* use fragmentation */
        }
 
        self->qos = qos;
-       self->null_modem_mode = 0;              /* disable null modem emulation */
+       self->max_header_size = max_header_size;
+       self->null_modem_mode = 0;         /* disable null modem emulation */
 
-       ircomm_do_event( self, TTP_CONNECT_CONFIRM, skb);
+       ircomm_do_event(self, TTP_CONNECT_CONFIRM, skb);
 }
 
 static void ircomm_accept_connect_indication(void *instance, void *sap,
-                                     struct qos_info *qos,
-                                     __u32 maxsdusize,
-                                     struct sk_buff *skb )
+                                            struct qos_info *qos,
+                                            __u32 max_sdu_size,
+                                            __u8 max_header_size,
+                                            struct sk_buff *skb)
 {
        struct ircomm_cb *self = (struct ircomm_cb *)instance;
 
@@ -330,12 +330,14 @@ static void ircomm_accept_connect_indication(void *instance, void *sap,
 
        DEBUG(0,__FUNCTION__"()\n");
 
-       if(maxsdusize == SAR_DISABLE)
-               self->max_txbuff_size = qos->data_size.value;
+       if (max_sdu_size == SAR_DISABLE)
+               self->max_txbuff_size = qos->data_size.value - max_header_size;
        else
-               self->max_txbuff_size = maxsdusize;
+               self->max_txbuff_size = max_sdu_size;
 
        self->qos = qos;
+       self->max_header_size = max_header_size;
+
        ircomm_do_event( self, TTP_CONNECT_INDICATION, skb);
 
        /* stop connecting */
@@ -556,7 +558,7 @@ static void issue_connect_request(struct ircomm_cb *self,
 
                irttp_connect_request(self->tsap, self->dlsap, 
                                      self->saddr, self->daddr, 
-                                     NULL, self->maxsdusize, userdata); 
+                                     NULL, self->max_sdu_size, userdata); 
                break;
 
        default:
@@ -588,9 +590,9 @@ static void connect_indication(struct ircomm_cb *self, struct qos_info *qos,
 /*     if( !ircomm_parse_controlchannel( self, data)) */
 /*             self->servicetype = DEFAULT;     TODOD:fix this! TH */
 
-       if(self->notify.connect_indication)
+       if (self->notify.connect_indication)
                self->notify.connect_indication(self->notify.instance, self, 
-                                               qos, 0, skb);
+                                               qos, 0, 0, skb);
 }
     
 #if 0
@@ -602,28 +604,26 @@ static void connect_indication_three_wire_raw(void)
 #endif 
 
 
-static void connect_confirmation(struct ircomm_cb *self, struct sk_buff *skb)
+static void connect_confirm(struct ircomm_cb *self, struct sk_buff *skb)
 {
        DEBUG(4 ,__FUNCTION__"()\n");
 
        /* give a connect_confirm to the client */
        if( self->notify.connect_confirm )
                self->notify.connect_confirm(self->notify.instance,
-                                            self, NULL, SAR_DISABLE, skb);
+                                            self, NULL, SAR_DISABLE, 0, skb);
 }
 
 static void issue_connect_response(struct ircomm_cb *self,
                                   struct sk_buff *skb)
 {
-
        DEBUG(0,__FUNCTION__"()\n");
        
        if( self->servicetype == THREE_WIRE_RAW){
                DEBUG(0,__FUNCTION__"():THREE_WIRE_RAW is not implemented yet\n");
                /* irlmp_connect_rsp(); */
-       } else {
-               irttp_connect_response(self->tsap, self->maxsdusize, skb);
-       }
+       } else
+               irttp_connect_response(self->tsap, self->max_sdu_size, skb);
 }
 
 static void issue_disconnect_request(struct ircomm_cb *self,
@@ -642,30 +642,29 @@ static void issue_data_request(struct ircomm_cb *self,
 {
        int err;
 
-       if(self->servicetype == THREE_WIRE_RAW){
+       if (self->servicetype == THREE_WIRE_RAW){
                /* irlmp_data_request(self->lmhandle,userdata); */
                DEBUG(0,__FUNCTION__"():not implemented!");
                return;
        }
 
        DEBUG(4,__FUNCTION__"():sending frame\n");
-       err = irttp_data_request(self->tsap , userdata  );
-       if(err){
+       err = irttp_data_request(self->tsap, userdata);
+       if (err){
                printk(KERN_ERR __FUNCTION__":ttp_data_request failed\n");
-               if(userdata)
+               if (userdata)
                        dev_kfree_skb( userdata);
        }
        self->tx_packets++;
 }
 
 static void issue_control_request(struct ircomm_cb *self,
-                                 struct sk_buff *userdata )
+                                 struct sk_buff *userdata)
 {
        int err;
 
        DEBUG(4,__FUNCTION__"()\n"); 
-       if(self->servicetype == THREE_WIRE_RAW)
-       {
+       if (self->servicetype == THREE_WIRE_RAW) {
                DEBUG(0,__FUNCTION__"():THREE_WIRE_RAW is not implemented\n");
                
        }
@@ -676,7 +675,7 @@ static void issue_control_request(struct ircomm_cb *self,
                {
                        printk( __FUNCTION__"():ttp_data_request failed\n");
                        if(userdata)
-                               dev_kfree_skb( userdata);
+                               dev_kfree_skb(userdata);
                }
                else
                        self->tx_controls++;
@@ -701,7 +700,7 @@ static void process_data(struct ircomm_cb *self, struct sk_buff *skb )
 
        /* ircomm_parse_control(self, skb, CONTROL_CHANNEL); */
 
-       if(self->notify.data_indication && skb->len)
+       if (self->notify.data_indication && skb->len)
                self->notify.data_indication(self->notify.instance, self,
                                             skb);
 }
@@ -728,7 +727,7 @@ static void ircomm_do_event( struct ircomm_cb *self, IRCOMM_EVENT event,
        
        DEBUG( 4, __FUNCTION__": STATE = %s, EVENT = %s\n",
               ircommstate[self->state], ircommevent[event]);
-       (*state[ self->state ]) ( self, event, skb);
+       (*state[self->state])(self, event, skb);
 }
 
 static void ircomm_next_state( struct ircomm_cb *self, IRCOMM_STATE state) 
@@ -747,7 +746,7 @@ static void ircomm_next_state( struct ircomm_cb *self, IRCOMM_STATE state)
 static void ircomm_state_idle( struct ircomm_cb *self, IRCOMM_EVENT event, 
                               struct sk_buff *skb )
 {
-       switch(event){
+       switch (event){
        case IRCOMM_CONNECT_REQUEST:
 
                /* ircomm_next_state(self, COMM_WAITI); */
@@ -779,7 +778,8 @@ static void ircomm_state_idle( struct ircomm_cb *self, IRCOMM_EVENT event,
 /*
  * ircomm_state_discoverywait
  */
-static void ircomm_state_discoverywait(struct ircomm_cb *self, IRCOMM_EVENT event, 
+static void ircomm_state_discoverywait(struct ircomm_cb *self, 
+                                      IRCOMM_EVENT event, 
                                       struct sk_buff *skb )
 {
        switch(event){
@@ -817,11 +817,11 @@ static void ircomm_state_discoverywait(struct ircomm_cb *self, IRCOMM_EVENT even
  * ircomm_state_queryparamwait
  */
 
-static void ircomm_state_queryparamwait(struct ircomm_cb *self, IRCOMM_EVENT event, 
-                                       struct sk_buff *skb )
+static void ircomm_state_queryparamwait(struct ircomm_cb *self, 
+                                       IRCOMM_EVENT event, 
+                                       struct sk_buff *skb)
 {
-       switch(event){
-
+       switch (event) {
        case TTP_CONNECT_INDICATION:
 
                ircomm_next_state(self, COMM_WAITR);
@@ -855,10 +855,11 @@ static void ircomm_state_queryparamwait(struct ircomm_cb *self, IRCOMM_EVENT eve
  * ircomm_state_querylsapwait
  */
 
-static void ircomm_state_querylsapwait(struct ircomm_cb *self, IRCOMM_EVENT event, 
+static void ircomm_state_querylsapwait(struct ircomm_cb *self, 
+                                      IRCOMM_EVENT event, 
                                       struct sk_buff *skb )
 {
-       switch(event){
+       switch (event) {
 
        case TTP_CONNECT_INDICATION:
 
@@ -898,10 +899,10 @@ static void ircomm_state_querylsapwait(struct ircomm_cb *self, IRCOMM_EVENT even
 static void ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event, 
                          struct sk_buff *skb )
 {
-       switch(event){
+       switch (event) {
        case TTP_CONNECT_CONFIRM:
                ircomm_next_state(self, COMM_CONN);
-               connect_confirmation( self, skb );
+               connect_confirm(self, skb );
                break;
        case TTP_DISCONNECT_INDICATION:
                ircomm_next_state(self, COMM_IDLE);
@@ -921,21 +922,18 @@ static void ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event,
        }
 }
 
-
-
 /*
  * ircomm_state_waitr
  */
 static void ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event, 
-                         struct sk_buff *skb ) 
+                              struct sk_buff *skb ) 
 {
-       
-       switch(event){
+       switch (event) {
        case IRCOMM_CONNECT_RESPONSE:
 
                /* issue_connect_response */
                
-               if(self->servicetype==THREE_WIRE_RAW){
+               if (self->servicetype==THREE_WIRE_RAW) {
                        DEBUG(0,__FUNCTION__"():3WIRE_RAW is not implemented\n");
                        /* irlmp_connect_response(Vpeersap,
                         *                         ACCEPT,null);
@@ -987,7 +985,7 @@ static void ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
 static void ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event, 
                              struct sk_buff *skb )
 {
-       switch(event){
+       switch (event) {
        case TTP_DATA_INDICATION:
                process_data(self, skb);
                break;
@@ -1033,8 +1031,6 @@ static void ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event,
        }
 }
 
-
-
 /*
  *  ----------------------------------------------------------------------
  *  IrCOMM service interfaces and supporting functions
@@ -1042,12 +1038,12 @@ static void ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event,
  *  ----------------------------------------------------------------------
  */
 
-/* 
- * start_discovering()
+/*
+ * Function start_discovering (self)
+ *
+ *    Start discovering and enter DISCOVERY_WAIT state
  *
- * start discovering and enter DISCOVERY_WAIT state
  */
-
 static void start_discovering(struct ircomm_cb *self)
 {
        __u16  hints; 
@@ -1092,19 +1088,26 @@ static void start_discovering(struct ircomm_cb *self)
 /*
  * queryias_done(self)
  *
- * called when discovery process got wrong results, completed, or terminated.
+ * 
  */
 
+/*
+ * Function queryias_done (self)
+ *
+ *    Called when discovery process got wrong results, completed, or
+ *    terminated.
+ * 
+ */
 static void queryias_done(struct ircomm_cb *self)
 {
        DEBUG(0, __FUNCTION__"():\n");
-       if(self->queryias_lock){
+       if (self->queryias_lock){
                self->queryias_lock = 0;
                discovering_instance = NULL;
                MOD_DEC_USE_COUNT;
                irlmp_unregister_client(self->ckey);
        }
-       if(ircomm_cs != 1)
+       if (ircomm_cs != 1)
                irlmp_unregister_service(self->skey);
        return;
 }
@@ -1120,7 +1123,6 @@ static void query_parameters(struct ircomm_cb *self)
                                       ircomm_getvalue_confirm, self );
 }
 
-
 static void query_lsapsel(struct ircomm_cb * self)
 {
        DEBUG(0, __FUNCTION__"():querying IAS: Lsapsel...\n");
@@ -1135,13 +1137,13 @@ static void query_lsapsel(struct ircomm_cb * self)
        }
 }
 
-/* 
- * ircomm_connect_request()
- * Impl. of this function is differ from one of the reference.
- * This functin does discovery as well as sending connect request
+/*
+ * Function ircomm_connect_request (self, servicetype)
+ *
+ *    Impl. of this function is differ from one of the reference. This
+ *    function does discovery as well as sending connect request
+ * 
  */
-
-
 void ircomm_connect_request(struct ircomm_cb *self, __u8 servicetype)
 {
        /*
@@ -1158,12 +1160,12 @@ void ircomm_connect_request(struct ircomm_cb *self, __u8 servicetype)
        self->servicetype= servicetype;
        /* ircomm_control_request(self, SERVICETYPE); */ /*servictype*/
 
-       self->maxsdusize = SAR_DISABLE;
-       ircomm_do_event( self, IRCOMM_CONNECT_REQUEST, NULL);
+       self->max_sdu_size = SAR_DISABLE;
+       ircomm_do_event(self, IRCOMM_CONNECT_REQUEST, NULL);
 }
 
 void ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata,
-                            __u32 maxsdusize)
+                            __u32 max_sdu_size)
 {
 
        ASSERT( self != NULL, return;);
@@ -1177,10 +1179,11 @@ void ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata,
         * and send it with connect_response
         */
 
-       if(!userdata){
+       if (!userdata){
                /* FIXME: check for errors and initialize? DB */
                userdata = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE);
-               ASSERT(userdata != NULL, return;);
+               if (userdata == NULL)
+                       return;
 
                skb_reserve(userdata,COMM_HEADER_SIZE);
        }
@@ -1188,9 +1191,10 @@ void ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata,
        /* enable null-modem emulation (i.e. server mode )*/
        self->null_modem_mode = 1;
 
-       self->maxsdusize = maxsdusize;
-       if(maxsdusize != SAR_DISABLE)
-               self->max_txbuff_size = maxsdusize;
+       self->max_sdu_size = max_sdu_size;
+       if (max_sdu_size != SAR_DISABLE)
+               self->max_txbuff_size = max_sdu_size;
+
        ircomm_do_event(self, IRCOMM_CONNECT_RESPONSE, userdata);
 }      
 
@@ -1341,14 +1345,13 @@ static void append_tuple(struct ircomm_cb *self, __u8 instruction, __u8 pl ,
        self->control_ch_pending = 1;
 }
 
-
-
 /*
- * ircomm_control_request();
- * this function is exported as a request to send some control-channel tuples
- * to peer device
+ * Function ircomm_control_request (self, instruction)
+ *
+ *    This function is exported as a request to send some control-channel
+ *    tuples * to peer device
+ * 
  */
-
 void ircomm_control_request(struct ircomm_cb *self,  __u8 instruction)
 {
 
index 9cc8719f81cc7ea0d6fb8dee69a4ba8ac368e923..fcc0eb2bedd6d07083a4ce45636624d12ba9a63f 100644 (file)
@@ -8,7 +8,7 @@
  * Source:        serial.c by Linus Torvalds
  *                isdn_tty.c by Fritz Elfert
  *
- *     Copyright (c) 1998, Takahide Higuchi, <thiguchi@pluto.dti.ne.jp>,
+ *     Copyright (c) 1998-1999, Takahide Higuchi, <thiguchi@pluto.dti.ne.jp>,
  *     All Rights Reserved.
  *
  *     This program is free software; you can redistribute it and/or
@@ -341,15 +341,15 @@ static void irvtd_send_data_request(struct irvtd_cb *driver)
  ***********************************************************************
  */
 
-
 /*
  * Function irvtd_connect_confirm (instance, sap, qos, max_sdu_size, skb)
  *
- *    ircomm_connect_request which we have send have succeed!
+ *    ircomm_connect_request which we have send, has succeeded!
  *
  */
 void irvtd_connect_confirm(void *instance, void *sap, struct qos_info *qos,
-                          __u32 max_sdu_size, struct sk_buff *skb)
+                          __u32 max_sdu_size, __u8 max_header_size, 
+                          struct sk_buff *skb)
 {
        struct irvtd_cb *driver = (struct irvtd_cb *)instance;
        ASSERT(driver != NULL, return;);
@@ -364,7 +364,7 @@ void irvtd_connect_confirm(void *instance, void *sap, struct qos_info *qos,
        /*
         * sending initial control parameters here
         */
-       if(driver->comm->servicetype == THREE_WIRE_RAW)
+       if (driver->comm->servicetype ==        THREE_WIRE_RAW)
                return;                /* do nothing */
 
        driver->comm->dte |= (MCR_DTR | MCR_RTS | DELTA_DTR | DELTA_RTS);
@@ -376,7 +376,7 @@ void irvtd_connect_confirm(void *instance, void *sap, struct qos_info *qos,
        ircomm_control_request(driver->comm, XON_XOFF_CHAR);
        /* ircomm_control_request(driver->comm, ENQ_ACK_CHAR); */
 
-       switch(driver->comm->servicetype){
+       switch (driver->comm->servicetype) {
        case CENTRONICS:
                break;
 
@@ -397,17 +397,18 @@ void irvtd_connect_confirm(void *instance, void *sap, struct qos_info *qos,
  *
  */
 void irvtd_connect_indication(void *instance, void *sap, struct qos_info *qos,
-                             __u32 max_sdu_size, struct sk_buff *skb)
+                             __u32 max_sdu_size, __u8 max_header_size, 
+                             struct sk_buff *skb)
 {
-
        struct irvtd_cb *driver = (struct irvtd_cb *)instance;
        struct ircomm_cb *comm = (struct ircomm_cb *)sap;
+
        ASSERT(driver != NULL, return;);
        ASSERT(driver->magic == IRVTD_MAGIC, return;);
        ASSERT(comm != NULL, return;);
        ASSERT(comm->magic == IRCOMM_MAGIC, return;);
 
-       DEBUG(4,"irvtd_connect_indication:sending connect_response...\n");
+       DEBUG(4, __FUNCTION__ "():sending connect_response...\n");
 
        ircomm_connect_response(comm, NULL, SAR_DISABLE );
 
@@ -416,7 +417,7 @@ void irvtd_connect_indication(void *instance, void *sap, struct qos_info *qos,
        /*
         * send initial control parameters
         */
-       if(driver->comm->servicetype == THREE_WIRE_RAW)
+       if (driver->comm->servicetype == THREE_WIRE_RAW)
                return;                /* do nothing */
 
        driver->comm->dte |= (MCR_DTR | MCR_RTS | DELTA_DTR | DELTA_RTS);
@@ -426,6 +427,7 @@ void irvtd_connect_indication(void *instance, void *sap, struct qos_info *qos,
                ircomm_control_request(driver->comm, DTELINE_STATE);
                break;
        default:
+               DEBUG(0, __FUNCTION__ "(), not implemented!\n");
        }
 
 
@@ -576,6 +578,7 @@ void irvtd_control_indication(void *instance, void *sap, IRCOMM_CMD cmd)
        case DATA_RATE:
        case XON_XOFF_CHAR:
        case DTELINE_STATE:
+       case ENQ_ACK_CHAR:      /* got this from win95 */
                /* (maybe) nothing to do  */
                break;
        default:
@@ -778,7 +781,7 @@ static int irvtd_startup(struct irvtd_cb *driver)
        skb_queue_head_init(&driver->rxbuff);
        driver->txbuff = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE); 
        if (!driver->txbuff){
-               DEBUG(0,__FUNCTION__"():alloc_skb failed!\n");
+               DEBUG(0,__FUNCTION__"()alloc_skb failed!\n");
                return -ENOMEM;
        }
        skb_reserve(driver->txbuff, COMM_HEADER_SIZE);
@@ -793,9 +796,8 @@ static int irvtd_startup(struct irvtd_cb *driver)
        irvtd_notify.instance = driver;
 
        driver->comm = ircomm_open_instance(irvtd_notify);
-       if(!driver->comm){
+       if (!driver->comm)
                return -ENODEV;
-       }
 
 
        /* 
index cf9e6ea3441d90b0aac6640e28816a5b82567b65..d6452769fa7b581c2e155b6ea2b40cf0602b7a7d 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Wed Sep  2 20:22:08 1998
- * Modified at:   Wed Apr 21 09:48:19 1999
+ * Modified at:   Mon May 10 23:02:47 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -31,6 +31,8 @@
 #include <linux/netdevice.h>
 #include <linux/init.h>
 #include <linux/tty.h>
+#include <linux/kmod.h>
+#include <linux/wireless.h>
 
 #include <asm/ioctls.h>
 #include <asm/segment.h>
@@ -53,7 +55,8 @@ extern int tekram_init(void);
 extern int actisys_init(void);
 extern int girbil_init(void);
 
-hashbin_t *irda_device = NULL;
+static hashbin_t *irda_device = NULL;
+static hashbin_t *dongles = NULL;
 
 /* Netdevice functions */
 static int irda_device_net_rebuild_header(struct sk_buff *skb);
@@ -61,9 +64,9 @@ static int irda_device_net_hard_header(struct sk_buff *skb,
                                       struct device *dev,
                                       unsigned short type, void *daddr, 
                                       void *saddr, unsigned len);
-static int irda_device_net_set_config( struct device *dev, struct ifmap *map);
-static int irda_device_net_change_mtu( struct device *dev, int new_mtu);
-
+static int irda_device_net_set_config(struct device *dev, struct ifmap *map);
+static int irda_device_net_change_mtu(struct device *dev, int new_mtu);
+static int irda_device_net_ioctl(struct device *dev, struct ifreq *rq,int cmd);
 #ifdef CONFIG_PROC_FS
 int irda_device_proc_read( char *buf, char **start, off_t offset, int len, 
                           int unused);
@@ -74,8 +77,15 @@ __initfunc(int irda_device_init( void))
 {
        /* Allocate master array */
        irda_device = hashbin_new( HB_LOCAL);
-       if ( irda_device == NULL) {
-               printk( KERN_WARNING "IrDA: Can't allocate irda_device hashbin!\n");
+       if (irda_device == NULL) {
+               WARNING("IrDA: Can't allocate irda_device hashbin!\n");
+               return -ENOMEM;
+       }
+
+       dongles = hashbin_new(HB_LOCAL);
+       if (dongles == NULL) {
+               printk(KERN_WARNING 
+                      "IrDA: Can't allocate dongles hashbin!\n");
                return -ENOMEM;
        }
 
@@ -113,6 +123,7 @@ void irda_device_cleanup(void)
 
        ASSERT(irda_device != NULL, return;);
 
+       hashbin_delete(dongles, NULL);
        hashbin_delete(irda_device, (FREE_FUNC) irda_device_close);
 }
 
@@ -238,7 +249,7 @@ void __irda_device_close(struct irda_device *self)
 /*
  * Function irda_device_close (self)
  *
- *    
+ *    Close the device
  *
  */
 void irda_device_close(struct irda_device *self)
@@ -248,6 +259,10 @@ void irda_device_close(struct irda_device *self)
        ASSERT(self != NULL, return;);
        ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
 
+       /* We are not using any dongle anymore! */
+       if (self->dongle)
+               self->dongle->close(self);
+
        /* Stop and remove instance of IrLAP */
        if (self->irlap)
                irlap_close(self->irlap);
@@ -298,15 +313,19 @@ static void __irda_device_change_speed(struct irda_device *self, int speed)
         */
        if (self->wait_until_sent) {
                self->wait_until_sent(self);
+               
+               if (self->dongle)
+                       self->dongle->change_speed(self, speed);
+               
                if (self->change_speed) {
                        self->change_speed(self, speed);
-
+                       
                        /* Update the QoS value only */
                        self->qos.baud_rate.value = speed;
                }
        } else {
-               printk(KERN_WARNING "wait_until_sent() "
-                      "has not implemented by the IrDA device driver!\n");
+               WARNING("IrDA: wait_until_sent() "
+                       "has not implemented by the IrDA device driver!\n");
        }
 }
 
@@ -386,6 +405,7 @@ int irda_device_setup(struct device *dev)
        dev->set_config      = irda_device_net_set_config;
        dev->change_mtu      = irda_device_net_change_mtu;
 /*     dev->hard_header     = irda_device_net_hard_header; */
+       dev->do_ioctl        = irda_device_net_ioctl;
         dev->hard_header_len = 0;
         dev->addr_len        = 0;
 
@@ -444,6 +464,125 @@ static int irda_device_net_change_mtu( struct device *dev, int new_mtu)
      return 0;  
 }
 
+static int irda_device_net_ioctl(struct device *dev, /* ioctl device */
+                                struct ifreq *rq,   /* Data passed */
+                                int    cmd)         /* Ioctl number */
+{
+       unsigned long flags;
+       int                     ret = 0;
+#ifdef WIRELESS_EXT
+       struct iwreq *wrq = (struct iwreq *) rq;
+#endif
+       struct irda_device *self;
+
+       DEBUG(4, __FUNCTION__ "()\n");
+
+       ASSERT(dev != NULL, return -1;);
+
+       self = (struct irda_device *) dev->priv;
+
+       ASSERT(self != NULL, return -1;);
+       ASSERT(self->magic == IRDA_DEVICE_MAGIC, return -1;);
+
+       DEBUG(0, "%s: ->irda_device_net_ioctl(cmd=0x%X)\n", dev->name, cmd);
+       
+       /* Disable interrupts & save flags */
+       save_flags(flags);
+       cli();
+       
+       /* Look what is the request */
+       switch (cmd) {
+#ifdef WIRELESS_EXT
+       case SIOCGIWNAME:
+               /* Get name */
+               strcpy(wrq->u.name, self->name);
+               break;
+       case SIOCSIWNWID:
+               /* Set domain */
+               if (wrq->u.nwid.on) {
+                       
+               } break;
+       case SIOCGIWNWID:
+               /* Read domain*/
+/*             wrq->u.nwid.nwid = domain; */
+/*             wrq->u.nwid.on = 1; */
+               break;
+       case SIOCGIWENCODE:
+               /* Get scramble key */
+               /*      wrq->u.encoding.code = scramble_key; */
+/*             wrq->u.encoding.method = 1; */
+               break;
+       case SIOCSIWENCODE:
+               /* Set  scramble key */
+               /* scramble_key = wrq->u.encoding.code; */
+               break;
+       case SIOCGIWRANGE:
+               /* Basic checking... */
+               if(wrq->u.data.pointer != (caddr_t) 0) {
+                       struct iw_range range;
+                       
+                       /* Verify the user buffer */
+                       ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
+                                         sizeof(struct iw_range));
+                       if(ret)
+                               break;
+                       
+                       /* Set the length (useless : its constant...) */
+                       wrq->u.data.length = sizeof(struct iw_range);
+                       
+                       /* Set information in the range struct */
+                       range.throughput = 1.6 * 1024 * 1024;   /* don't argue on this ! */
+                       range.min_nwid = 0x0000;
+                       range.max_nwid = 0x01FF;
+                       
+                       range.num_channels = range.num_frequency = 0;
+                       
+                       range.sensitivity = 0x3F;
+                       range.max_qual.qual = 255;
+                       range.max_qual.level = 255;
+                       range.max_qual.noise = 0;
+                       
+                       /* Copy structure to the user buffer */
+                       copy_to_user(wrq->u.data.pointer, &range,
+                                    sizeof(struct iw_range));
+               }
+               break;
+       case SIOCGIWPRIV:
+               /* Basic checking... */
+#if 0
+               if (wrq->u.data.pointer != (caddr_t) 0) {
+                       struct iw_priv_args     priv[] =
+                       {       /* cmd,         set_args,       get_args,       name */
+                               { SIOCGIPSNAP, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 0, 
+                                 sizeof(struct site_survey), 
+                                 "getsitesurvey" },
+                       };
+                       
+                       /* Verify the user buffer */
+                       ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer,
+                                         sizeof(priv));
+                       if (ret)
+                               break;
+                       
+                       /* Set the number of ioctl available */
+                       wrq->u.data.length = 1;
+                       
+                       /* Copy structure to the user buffer */
+                       copy_to_user(wrq->u.data.pointer, (u_char *) priv,
+                                    sizeof(priv));
+               }
+#endif 
+               break;
+#endif
+       default:
+               ret = -EOPNOTSUPP;
+       }
+       
+       restore_flags(flags);
+       
+       return ret;
+}
+
 /*
  * Function irda_device_transmit_finished (void)
  *
@@ -451,7 +590,7 @@ static int irda_device_net_change_mtu( struct device *dev, int new_mtu)
  *    device. Maybe we should use: q->q.qlen == 0.
  *
  */
-int irda_device_txqueue_empty( struct irda_device *self)
+int irda_device_txqueue_empty(struct irda_device *self)
 {
        ASSERT(self != NULL, return -1;);
        ASSERT(self->magic == IRDA_DEVICE_MAGIC, return -1;);   
@@ -462,6 +601,117 @@ int irda_device_txqueue_empty( struct irda_device *self)
        return TRUE;
 }
 
+/*
+ * Function irda_device_init_dongle (self, type)
+ *
+ *    Initialize attached dongle. Warning, must be called with a process
+ *    context!
+ */
+void irda_device_init_dongle(struct irda_device *self, int type)
+{
+       struct dongle_q *node;
+
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
+
+#ifdef CONFIG_KMOD
+       /* Try to load the module needed */
+       switch (type) {
+       case ESI_DONGLE:
+               MESSAGE("IrDA: Initializing ESI dongle!\n");
+               request_module("esi");
+               break;
+       case TEKRAM_DONGLE:
+               MESSAGE("IrDA: Initializing Tekram dongle!\n");
+               request_module("tekram");
+               break;
+       case ACTISYS_DONGLE:     /* FALLTHROUGH */
+       case ACTISYS_PLUS_DONGLE:
+               MESSAGE("IrDA: Initializing ACTiSYS dongle!\n");
+               request_module("actisys");
+               break;
+       case GIRBIL_DONGLE:
+               MESSAGE("IrDA: Initializing GIrBIL dongle!\n");
+               request_module("girbil");
+               break;
+       case LITELINK_DONGLE:
+               MESSAGE("IrDA: Initializing Litelink dongle!\n");
+               request_module("litelink");
+               break;
+       default:
+               ERROR("Unknown dongle type!\n");
+               return;
+       }
+#endif /* CONFIG_KMOD */
+
+       node = hashbin_find(dongles, type, NULL);
+       if (!node) {
+               ERROR("IrDA: Unable to find requested dongle\n");
+               return;
+       }
+
+       /* Set the dongle to be used by this driver */
+       self->dongle = node->dongle;
+
+       /* Now initialize the dongle!  */
+       node->dongle->open(self, type);
+       node->dongle->qos_init(self, &self->qos);
+       
+       /* Reset dongle */
+       node->dongle->reset(self, 0);
+
+       /* Set to default baudrate */
+       irda_device_change_speed(self, 9600);
+}
+
+/*
+ * Function irda_device_register_dongle (dongle)
+ *
+ *    
+ *
+ */
+int irda_device_register_dongle(struct dongle *dongle)
+{
+       struct dongle_q *new;
+       
+       /* Check if this dongle has been registred before */
+       if (hashbin_find(dongles, dongle->type, NULL)) {
+               MESSAGE(__FUNCTION__ "(), Dongle already registered\n");
+                return 0;
+        }
+       
+       /* Make new IrDA dongle */
+        new = (struct dongle_q *) kmalloc(sizeof(struct dongle_q), GFP_KERNEL);
+        if (new == NULL)
+                return -1;
+               
+       memset(new, 0, sizeof( struct dongle_q));
+        new->dongle = dongle;
+
+       /* Insert IrDA dongle into hashbin */
+       hashbin_insert(dongles, (QUEUE *) new, dongle->type, NULL);
+       
+        return 0;
+}
+
+/*
+ * Function irda_device_unregister_dongle (dongle)
+ *
+ *    
+ *
+ */
+void irda_device_unregister_dongle(struct dongle *dongle)
+{
+       struct dongle_q *node;
+
+       node = hashbin_remove(dongles, dongle->type, NULL);
+       if (!node) {
+               ERROR(__FUNCTION__ "(), dongle not found!\n");
+               return;
+       }
+       kfree(node);
+}
+
 /*
  * Function setup_dma (idev, buffer, count, mode)
  *
@@ -536,7 +786,7 @@ int irda_device_proc_read(char *buf, char **start, off_t offset, int len,
 
        self = (struct irda_device *) hashbin_get_first(irda_device);
        while ( self != NULL) {
-               len += sprintf(buf+len, "%s,", self->name);
+               len += sprintf(buf+len, "\n%s,", self->name);
                len += sprintf(buf+len, "\tbinding: %s\n", 
                               self->description);
                
index b87ccbd028143fb861c6c4a0e4d88461ce2f2f4d..f3b752eb05fda9319cc367db11910907ad027c3c 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Thu Aug 21 00:02:07 1997
- * Modified at:   Fri Apr 23 09:57:12 1999
+ * Modified at:   Sun May  9 15:59:05 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
  *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
@@ -62,12 +62,17 @@ static __u32 service_handle;
 extern char *lmp_reasons[];
 
 static struct iriap_cb *iriap_open( __u8 slsap, int mode);
-static void __iriap_close( struct iriap_cb *self);
+static void __iriap_close(struct iriap_cb *self);
 static void iriap_disconnect_indication(void *instance, void *sap, 
                                        LM_REASON reason, struct sk_buff *skb);
 static void iriap_connect_indication(void *instance, void *sap, 
                                     struct qos_info *qos, __u32 max_sdu_size,
+                                    __u8 max_header_size, 
                                     struct sk_buff *skb);
+static void iriap_connect_confirm(void *instance, void *sap, 
+                                 struct qos_info *qos, 
+                                 __u32 max_sdu_size, __u8 max_header_size,
+                                 struct sk_buff *skb);
 static int iriap_data_indication(void *instance, void *sap, 
                                 struct sk_buff *skb);
 
@@ -181,7 +186,7 @@ struct iriap_cb *iriap_open( __u8 slsap_sel, int mode)
        self->slsap_sel = slsap_sel;
        self->mode = mode;
 
-       init_timer( &self->watchdog_timer);
+       init_timer(&self->watchdog_timer);
 
        hashbin_insert( iriap, (QUEUE*) self, slsap_sel, NULL);
        
@@ -206,7 +211,7 @@ static void __iriap_close( struct iriap_cb *self)
        ASSERT( self != NULL, return;);
        ASSERT( self->magic == IAS_MAGIC, return;);
 
-       del_timer( &self->watchdog_timer);
+       del_timer(&self->watchdog_timer);
 
        self->magic = 0;
 
@@ -260,7 +265,7 @@ static void iriap_disconnect_indication( void *instance, void *sap,
 
        ASSERT( iriap != NULL, return;);
 
-       del_timer( &self->watchdog_timer);
+       del_timer(&self->watchdog_timer);
 
        if ( self->mode == IAS_CLIENT) {
                DEBUG( 4, __FUNCTION__ "(), disconnect as client\n");
@@ -284,9 +289,8 @@ static void iriap_disconnect_indication( void *instance, void *sap,
                                       NULL);
        }
 
-       if ( userdata) {
+       if (userdata)
                dev_kfree_skb( userdata);
-       }
 }
 
 /*
@@ -295,28 +299,28 @@ static void iriap_disconnect_indication( void *instance, void *sap,
  *    
  *
  */
-void iriap_disconnect_request( struct iriap_cb *self)
+void iriap_disconnect_request(struct iriap_cb *self)
 {
        struct sk_buff *skb;
 
-       DEBUG( 4, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
 
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == IAS_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == IAS_MAGIC, return;);
 
-       skb = dev_alloc_skb( 64);
+       skb = dev_alloc_skb(64);
        if (skb == NULL) {
-               DEBUG( 0, __FUNCTION__
-                      "(), Could not allocate an sk_buff of length %d\n", 64);
+               DEBUG(0, __FUNCTION__
+                     "(), Could not allocate an sk_buff of length %d\n", 64);
                return;
        }
 
        /* 
-        *  Reserve space for MUX and LAP header 
+        *  Reserve space for MUX control and LAP header 
         */
-       skb_reserve( skb, LMP_CONTROL_HEADER+LAP_HEADER);
+       skb_reserve(skb, LMP_MAX_HEADER);
 
-       irlmp_disconnect_request( self->lsap, skb);
+       irlmp_disconnect_request(self->lsap, skb);
 }
 
 void iriap_getinfobasedetails_request(void) 
@@ -381,7 +385,7 @@ void iriap_getvaluebyclass_request(char *name, char *attr,
        /* Give ourselves 10 secs to finish this operation */
        iriap_start_watchdog_timer(self, 10*HZ);
        
-       skb = dev_alloc_skb( 64);
+       skb = dev_alloc_skb(64);
        if (!skb)
                return;
 
@@ -389,7 +393,7 @@ void iriap_getvaluebyclass_request(char *name, char *attr,
        attr_len = strlen(attr);
 
        /* Reserve space for MUX and LAP header */
-       skb_reserve(skb, LMP_CONTROL_HEADER+LAP_HEADER);
+       skb_reserve(skb, self->max_header_size);
        skb_put(skb, 3+name_len+attr_len);
        frame = skb->data;
 
@@ -535,13 +539,13 @@ void iriap_getvaluebyclass_response(struct iriap_cb *self, __u16 obj_id,
         *  value. We add 9 bytes because of the 6 bytes for the frame and
         *  max 3 bytes for the value coding.
         */
-       skb = dev_alloc_skb(value->len + LMP_HEADER + LAP_HEADER + 9);
+       skb = dev_alloc_skb(value->len + self->max_header_size + 9);
        if (!skb)
                return;
 
        /* Reserve space for MUX and LAP header */
-       skb_reserve( skb, LMP_HEADER+LAP_HEADER);
-       skb_put( skb, 6);
+       skb_reserve(skb, self->max_header_size);
+       skb_put(skb, 6);
        
        fp = skb->data;
 
@@ -666,7 +670,7 @@ void iriap_getvaluebyclass_indication(struct iriap_cb *self,
 /*
  * Function iriap_send_ack (void)
  *
- *    
+ *    Currently not used
  *
  */
 void iriap_send_ack( struct iriap_cb *self) 
@@ -679,13 +683,13 @@ void iriap_send_ack( struct iriap_cb *self)
        ASSERT( self != NULL, return;);
        ASSERT( self->magic == IAS_MAGIC, return;);
 
-       skb = dev_alloc_skb( 64);
+       skb = dev_alloc_skb(64);
        if (!skb)
                return;
 
        /* Reserve space for MUX and LAP header */
-       skb_reserve( skb, 4);
-       skb_put( skb, 3);
+       skb_reserve(skb, self->max_header_size);
+       skb_put(skb, 1);
        frame = skb->data;
 
        /* Build frame */
@@ -698,8 +702,10 @@ void iriap_send_ack( struct iriap_cb *self)
  *    LSAP connection confirmed!
  *
  */
-void iriap_connect_confirm(void *instance, void *sap, struct qos_info *qos, 
-                          __u32 max_sdu_size, struct sk_buff *userdata)
+static void iriap_connect_confirm(void *instance, void *sap, 
+                                 struct qos_info *qos, 
+                                 __u32 max_sdu_size, __u8 header_size, 
+                                 struct sk_buff *userdata)
 {
        struct iriap_cb *self;
        
@@ -711,7 +717,7 @@ void iriap_connect_confirm(void *instance, void *sap, struct qos_info *qos,
        
        DEBUG(4, __FUNCTION__ "()\n");
        
-       /* del_timer( &self->watchdog_timer); */
+       del_timer(&self->watchdog_timer);
 
        iriap_do_client_event(self, IAP_LM_CONNECT_CONFIRM, userdata);
 }
@@ -724,19 +730,17 @@ void iriap_connect_confirm(void *instance, void *sap, struct qos_info *qos,
  */
 static void iriap_connect_indication(void *instance, void *sap, 
                                     struct qos_info *qos, __u32 max_sdu_size,
+                                    __u8 header_size, 
                                     struct sk_buff *userdata)
 {
        struct iriap_cb *self;
 
-       DEBUG( 4, __FUNCTION__ "()\n");
-
-       self = ( struct iriap_cb *) instance;
+       self = (struct iriap_cb *) instance;
 
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == IAS_MAGIC, return;);
-       ASSERT( self->mode == IAS_SERVER, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == IAS_MAGIC, return;);
 
-       iriap_do_server_event( self, IAP_LM_CONNECT_INDICATION, userdata);
+       iriap_do_server_event(self, IAP_LM_CONNECT_INDICATION, userdata);
 }
  
 /*
@@ -856,7 +860,7 @@ void iriap_call_indication( struct iriap_cb *self, struct sk_buff *skb)
        }
        opcode &= 0x7f; /* Mask away LST bit */
        
-       switchopcode) {
+       switch (opcode) {
        case GET_INFO_BASE:
                DEBUG( 0, "IrLMP GetInfoBaseDetails not implemented!\n");
                break;
index ccba78ecefc2d65d87640f1483324cc6066a730e..18a70fec3e6a1f546afaeb64a3337d0624ecca28 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Thu Aug 21 00:02:07 1997
- * Modified at:   Tue Jan 26 12:29:36 1999
+ * Modified at:   Sun May  9 11:01:47 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1997 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
+ *     Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -387,9 +387,9 @@ static void state_r_disconnect( struct iriap_cb *self, IRIAP_EVENT event,
                }
 
                /* Reserve space for MUX_CONTROL and LAP header */
-               skb_reserve( tx_skb, LMP_CONTROL_HEADER+LAP_HEADER);
+               skb_reserve(tx_skb, LMP_MAX_HEADER);
                
-               irlmp_connect_response( self->lsap, tx_skb);
+               irlmp_connect_response(self->lsap, tx_skb);
                /*LM_Idle_request(idle); */
                
                iriap_next_server_state( self, R_CALL);
index f2f8271cf5a0c465503251e08ccb0a4c391c940a..66b94eec8092e251ff0e68e52cb15bb77fd47624 100644 (file)
@@ -6,13 +6,14 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Thu Apr 22 23:03:55 1999
+ * Modified at:   Tue May 11 00:22:39 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
  *                slip.c by Laurence Culhane, <loz@holmes.demon.co.uk>
  *                          Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
+ *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -61,6 +62,7 @@ static int irlan_client_ctrl_data_indication(void *instance, void *sap,
 static void irlan_client_ctrl_connect_confirm(void *instance, void *sap, 
                                              struct qos_info *qos, 
                                              __u32 max_sdu_size,
+                                             __u8 max_header_size,
                                              struct sk_buff *);
 static void irlan_check_response_param(struct irlan_cb *self, char *param, 
                                       char *value, int val_len);
@@ -79,7 +81,7 @@ static void irlan_client_kick_timer_expired(unsigned long data)
         * indication it needs to make progress. If the client is still in 
         * IDLE state, we must kick it to, but only if the provider is not IDLE
         */
-       if ((self->access_type == ACCESS_PEER) && 
+       if ((self->provider.access_type == ACCESS_PEER) && 
            (self->client.state == IRLAN_IDLE) &&
            (self->provider.state != IRLAN_IDLE)) {
                irlan_client_wakeup(self, self->saddr, self->daddr);
@@ -105,23 +107,29 @@ void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr)
 {
        struct irmanager_event mgr_event;
 
-       DEBUG(0, __FUNCTION__ "()\n");
+       DEBUG(1, __FUNCTION__ "()\n");
 
        ASSERT(self != NULL, return;);
        ASSERT(self->magic == IRLAN_MAGIC, return;);
 
-       /* Check if we are already awake */
-       if (self->client.state != IRLAN_IDLE)
+       /* 
+        * Check if we are already awake, or if we are a provider in direct
+        * mode (in that case we must leave the client idle
+        */
+       if ((self->client.state != IRLAN_IDLE) || 
+           (self->provider.access_type == ACCESS_DIRECT))
                return;
 
        /* saddr may have changed! */
        self->saddr = saddr;
        
-       /* Check if network device is up */
+       /* Before we try to connect, we check if network device is up. If it
+        * is up, that means that the "user" really wants to connect. If not
+        * we notify the user about the possibility of an IrLAN connection
+        */
        if (self->dev.start) {
                /* Open TSAPs */
                irlan_client_open_ctrl_tsap(self);
-               irlan_provider_open_ctrl_tsap(self);
                irlan_open_data_tsap(self);
                
                irlan_do_client_event(self, IRLAN_DISCOVERY_INDICATION, NULL);
@@ -161,7 +169,7 @@ void irlan_client_discovery_indication(discovery_t *discovery)
        struct irlan_cb *self, *entry;
        __u32 saddr, daddr;
        
-       DEBUG(0, __FUNCTION__"()\n");
+       DEBUG(1, __FUNCTION__"()\n");
 
        ASSERT(irlan != NULL, return;);
        ASSERT(discovery != NULL, return;);
@@ -176,7 +184,8 @@ void irlan_client_discovery_indication(discovery_t *discovery)
        if (self) {
                ASSERT(self->magic == IRLAN_MAGIC, return;);
 
-               DEBUG(2, __FUNCTION__ "(), Found instance!\n");
+               DEBUG(1, __FUNCTION__ "(), Found instance (%08x)!\n",
+                     daddr);
                
                irlan_client_wakeup(self, saddr, daddr);
 
@@ -184,30 +193,13 @@ void irlan_client_discovery_indication(discovery_t *discovery)
        }
        
        /* 
-        * We have no instance for daddr, so try and find an unused one
+        * We have no instance for daddr, so start a new one
         */
-       self = hashbin_find(irlan, DEV_ADDR_ANY, NULL);
-       if (self) {
-               DEBUG(0, __FUNCTION__ "(), Found instance with DEV_ADDR_ANY!\n");
-               /*
-                * Rehash instance, now we have a client (daddr) to serve.
-                */
-               entry = hashbin_remove(irlan, self->daddr, NULL);
-               ASSERT(entry == self, return;);
-
-               self->daddr = daddr;
-               self->saddr = saddr;
+       DEBUG(1, __FUNCTION__ "(), starting new instance!\n");
+       self = irlan_open(saddr, daddr, TRUE);
 
-               DEBUG(0, __FUNCTION__ "(), daddr=%08x\n", self->daddr);
-               hashbin_insert(irlan, (QUEUE*) self, self->daddr, NULL);
-               
-               /* Check if network device has been registered */
-               if (!self->netdev_registered)
-                       irlan_register_netdev(self);
-               
-               /* Restart watchdog timer */
-               irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
-       }
+       /* Restart watchdog timer */
+       irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
 }
        
 /*
@@ -302,6 +294,7 @@ void irlan_client_open_ctrl_tsap(struct irlan_cb *self)
 static void irlan_client_ctrl_connect_confirm(void *instance, void *sap, 
                                              struct qos_info *qos, 
                                              __u32 max_sdu_size,
+                                             __u8 max_header_size,
                                              struct sk_buff *skb) 
 {
        struct irlan_cb *self;
@@ -313,6 +306,9 @@ static void irlan_client_ctrl_connect_confirm(void *instance, void *sap,
        ASSERT(self != NULL, return;);
        ASSERT(self->magic == IRLAN_MAGIC, return;);
 
+       self->client.max_sdu_size = max_sdu_size;
+       self->client.max_header_size = max_header_size;
+
        /* TODO: we could set the MTU depending on the max_sdu_size */
 
        irlan_do_client_event(self, IRLAN_CONNECT_COMPLETE, NULL);
@@ -339,7 +335,7 @@ void irlan_client_reconnect_data_channel(struct irlan_cb *self)
                return;
 
        /* Reserve space for TTP, LMP, and LAP header */
-       skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+       skb_reserve(skb, self->max_header_size);
        skb_put(skb, 2);
        
        frame = skb->data;
@@ -410,11 +406,11 @@ void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb)
        /* For all parameters */
        for (i=0; i<count;i++) {
                ret = irlan_extract_param(ptr, name, value, &val_len);
-               if (ret == -1) {
+               if (ret < 0) {
                        DEBUG(2, __FUNCTION__ "(), IrLAN, Error!\n");
                        break;
                }
-               ptr+=ret;
+               ptr += ret;
                irlan_check_response_param(self, name, value, val_len);
        }
        /* Cleanup */
@@ -423,9 +419,9 @@ void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb)
 }
 
 /*
- * Function check_param (param, value)
+ * Function irlan_check_response_param (self, param, value, val_len)
  *
- *    Check which parameter is received and update local variables
+ *     Check which parameter is received and update local variables
  *
  */
 static void irlan_check_response_param(struct irlan_cb *self, char *param, 
@@ -469,11 +465,11 @@ static void irlan_check_response_param(struct irlan_cb *self, char *param,
        }
        if (strcmp(param, "ACCESS_TYPE") == 0) {
                if (strcmp(value, "DIRECT") == 0)
-                       self->access_type = ACCESS_DIRECT;
+                       self->client.access_type = ACCESS_DIRECT;
                else if (strcmp(value, "PEER") == 0)
-                       self->access_type = ACCESS_PEER;
+                       self->client.access_type = ACCESS_PEER;
                else if (strcmp(value, "HOSTED") == 0)
-                       self->access_type = ACCESS_HOSTED;
+                       self->client.access_type = ACCESS_HOSTED;
                else {
                        DEBUG(2, __FUNCTION__ "(), unknown access type!\n");
                }
index 1544c093e14dc7560b55dc364f078092e94fc7b0..682cda8540e9e647bd362f74c06d53e43275a503 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Thu Apr 22 12:23:22 1999
+ * Modified at:   Thu May  6 13:42:38 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
  *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
@@ -97,7 +97,7 @@ static int irlan_client_state_idle(struct irlan_cb *self, IRLAN_EVENT event,
        ASSERT(self != NULL, return -1;);
        ASSERT(self->magic == IRLAN_MAGIC, return -1;);
        
-       switch(event) {
+       switch (event) {
        case IRLAN_DISCOVERY_INDICATION:
                /* Get some values from peer IAS */
                iriap_getvaluebyclass_request(
@@ -152,7 +152,7 @@ static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event,
                irlan_next_client_state(self, IRLAN_IDLE);
 
                /* Give the client a kick! */
-               if ((self->access_type == ACCESS_PEER) && 
+               if ((self->provider.access_type == ACCESS_PEER) && 
                    (self->provider.state != IRLAN_IDLE))
                        irlan_client_wakeup(self, self->saddr, self->daddr);
                break;
@@ -222,7 +222,7 @@ static int irlan_client_state_info(struct irlan_cb *self, IRLAN_EVENT event,
 
        ASSERT(self != NULL, return -1;);
        
-       switch(event) {
+       switch (event) {
        case IRLAN_DATA_INDICATION:
                ASSERT(skb != NULL, return -1;);
        
@@ -314,7 +314,7 @@ static int irlan_client_state_open(struct irlan_cb *self, IRLAN_EVENT event,
                ASSERT(self->dtsap_sel_data != 0, return -1;);
 
                /* Check which access type we are dealing with */
-               switch(self->access_type) {
+               switch (self->client.access_type) {
                case ACCESS_PEER:
                    if (self->provider.state == IRLAN_OPEN) {
                            
index 6a30574ca765951ffa3aa58d4079a02899a5f6b8..1284d561a7fa8ccef075b182fa998db85892acc3 100644 (file)
@@ -6,10 +6,11 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Thu Apr 22 23:13:47 1999
+ * Modified at:   Sun May  9 11:48:49 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1997 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
+ *     Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>, 
+ *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -93,19 +94,25 @@ static void __irlan_close(struct irlan_cb *self);
 static int __irlan_insert_param(struct sk_buff *skb, char *param, int type, 
                                __u8 value_byte, __u16 value_short, 
                                __u8 *value_array, __u16 value_len);
-static void irlan_close_tsaps(struct irlan_cb *self);
+void irlan_close_tsaps(struct irlan_cb *self);
 
 #ifdef CONFIG_PROC_FS
 static int irlan_proc_read(char *buf, char **start, off_t offset, int len, 
                           int unused);
 
 extern struct proc_dir_entry *proc_irda;
-#endif
+#endif /* CONFIG_PROC_FS */
 
+/*
+ * Function irlan_watchdog_timer_expired (data)
+ *
+ *    
+ *
+ */
 void irlan_watchdog_timer_expired(unsigned long data)
 {
        struct irmanager_event mgr_event;
-       struct irlan_cb *self, *entry;
+       struct irlan_cb *self;
        
        DEBUG(0, __FUNCTION__ "()\n");
 
@@ -116,6 +123,7 @@ void irlan_watchdog_timer_expired(unsigned long data)
 
        /* Check if device still configured */
        if (self->dev.start) {
+               DEBUG(0, __FUNCTION__ "(), notifying irmanager to stop irlan!\n");
                mgr_event.event = EVENT_IRLAN_STOP;
                sprintf(mgr_event.devname, "%s", self->ifname);
                irmanager_notify(&mgr_event);
@@ -128,22 +136,13 @@ void irlan_watchdog_timer_expired(unsigned long data)
                 */
                self->notify_irmanager = FALSE;
        } else {
-               DEBUG(0, __FUNCTION__ "(), recycling instance!\n");
+               DEBUG(0, __FUNCTION__ "(), closing instance!\n");
                if (self->netdev_registered) {
                        DEBUG(0, __FUNCTION__ "(), removing netdev!\n");
                        unregister_netdev(&self->dev);
                        self->netdev_registered = FALSE;
                }
-
-               /* Unbind from daddr */
-               entry = hashbin_remove(irlan, self->daddr, NULL);
-               ASSERT(entry == self, return;);
-
-               self->daddr = DEV_ADDR_ANY;
-               self->saddr = DEV_ADDR_ANY;
-
-               DEBUG(2, __FUNCTION__ "(), daddr=%08x\n", self->daddr);
-               hashbin_insert(irlan, (QUEUE*) self, self->daddr, NULL);
+               irlan_close(self);
        }
 }
 
@@ -195,12 +194,12 @@ __initfunc(int irlan_init(void))
        /* Register with IrLMP as a service */
        skey = irlmp_register_service(hints);
 
-       /* Start the first IrLAN instance */
+       /* Start the master IrLAN instance */
        new = irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY, FALSE);
 
-       irlan_open_data_tsap(new);
-       irlan_client_open_ctrl_tsap(new);
+       /* The master will only open its (listen) control TSAP */
        irlan_provider_open_ctrl_tsap(new);
+       new->master = TRUE;
 
        /* Do some fast discovery! */
        irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
@@ -293,7 +292,7 @@ struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr, int netdev)
        self->daddr = daddr;
 
        /* Provider access can only be PEER, DIRECT, or HOSTED */
-       self->access_type = access;
+       self->provider.access_type = access;
        self->media = MEDIA_802_3;
 
        self->notify_irmanager = TRUE;
@@ -359,8 +358,11 @@ void irlan_close(struct irlan_cb *self)
 
        /* Check if device is still configured */
        if (self->dev.start) {
-               DEBUG(2, __FUNCTION__ 
+               DEBUG(0, __FUNCTION__ 
                       "(), Device still configured, closing later!\n");
+
+               /* Give it a chance to reconnect */
+               irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
                return;
        }
        DEBUG(2, __FUNCTION__ "(), daddr=%08x\n", self->daddr);
@@ -371,8 +373,15 @@ void irlan_close(struct irlan_cb *self)
         __irlan_close(self);
 }
 
+/*
+ * Function irlan_connect_indication (instance, sap, qos, max_sdu_size, skb)
+ *
+ *    Here we receive the connect indication for the data channel
+ *
+ */
 void irlan_connect_indication(void *instance, void *sap, struct qos_info *qos,
-                             __u32 max_sdu_size, struct sk_buff *skb)
+                             __u32 max_sdu_size, __u8 max_header_size, 
+                             struct sk_buff *skb)
 {
        struct irlan_cb *self;
        struct tsap_cb *tsap;
@@ -386,13 +395,17 @@ void irlan_connect_indication(void *instance, void *sap, struct qos_info *qos,
        ASSERT(self->magic == IRLAN_MAGIC, return;);
        ASSERT(tsap == self->tsap_data,return;);
 
-       DEBUG(2, "IrLAN, We are now connected!\n");
+       self->max_sdu_size = max_sdu_size;
+       self->max_header_size = max_header_size;
+
+       DEBUG(0, "IrLAN, We are now connected!\n");
+
        del_timer(&self->watchdog_timer);
 
        irlan_do_provider_event(self, IRLAN_DATA_CONNECT_INDICATION, skb);
        irlan_do_client_event(self, IRLAN_DATA_CONNECT_INDICATION, skb);
 
-       if (self->access_type == ACCESS_PEER) {
+       if (self->provider.access_type == ACCESS_PEER) {
                /* 
                 * Data channel is open, so we are now allowed to
                 * configure the remote filter 
@@ -400,12 +413,13 @@ void irlan_connect_indication(void *instance, void *sap, struct qos_info *qos,
                irlan_get_unicast_addr(self);
                irlan_open_unicast_addr(self);
        }
-       /* Ready to transfer Ethernet frames */
+       /* Ready to transfer Ethernet frames (at last) */
        self->dev.tbusy = 0;
 }
 
 void irlan_connect_confirm(void *instance, void *sap, struct qos_info *qos, 
-                          __u32 max_sdu_size, struct sk_buff *skb) 
+                          __u32 max_sdu_size, __u8 max_header_size, 
+                          struct sk_buff *skb) 
 {
        struct irlan_cb *self;
 
@@ -416,6 +430,9 @@ void irlan_connect_confirm(void *instance, void *sap, struct qos_info *qos,
        ASSERT(self != NULL, return;);
        ASSERT(self->magic == IRLAN_MAGIC, return;);
 
+       self->max_sdu_size = max_sdu_size;
+       self->max_header_size = max_header_size;
+
        /* TODO: we could set the MTU depending on the max_sdu_size */
 
        DEBUG(2, "IrLAN, We are now connected!\n");
@@ -444,7 +461,7 @@ void irlan_disconnect_indication(void *instance, void *sap, LM_REASON reason,
        struct irlan_cb *self;
        struct tsap_cb *tsap;
 
-       DEBUG(2, __FUNCTION__ "(), reason=%d\n", reason);
+       DEBUG(0, __FUNCTION__ "(), reason=%d\n", reason);
        
        self = (struct irlan_cb *) instance;
        tsap = (struct tsap_cb *) sap;
@@ -460,7 +477,7 @@ void irlan_disconnect_indication(void *instance, void *sap, LM_REASON reason,
 
        switch(reason) {
        case LM_USER_REQUEST: /* User request */
-               //irlan_close(self);
+               irlan_close(self);
                break;
        case LM_LAP_DISCONNECT: /* Unexpected IrLAP disconnect */
                irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
@@ -490,7 +507,7 @@ void irlan_open_data_tsap(struct irlan_cb *self)
        struct notify_t notify;
        struct tsap_cb *tsap;
 
-       DEBUG(4, __FUNCTION__ "()\n");
+       DEBUG(0, __FUNCTION__ "()\n");
 
        ASSERT(self != NULL, return;);
        ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -500,7 +517,7 @@ void irlan_open_data_tsap(struct irlan_cb *self)
                return;
 
        irda_notify_init(&notify);
-
+       
        notify.data_indication       = irlan_eth_receive;
        notify.udata_indication      = irlan_eth_receive;
        notify.connect_indication    = irlan_connect_indication;
@@ -620,7 +637,7 @@ void irlan_get_provider_info(struct irlan_cb *self)
                return;
 
        /* Reserve space for TTP, LMP, and LAP header */
-       skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+       skb_reserve(skb, self->client.max_header_size);
        skb_put(skb, 2);
        
        frame = skb->data;
@@ -651,7 +668,7 @@ void irlan_open_data_channel(struct irlan_cb *self)
        if (!skb)
                return;
 
-       skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+       skb_reserve(skb, self->client.max_header_size);
        skb_put(skb, 2);
        
        frame = skb->data;
@@ -683,7 +700,7 @@ void irlan_close_data_channel(struct irlan_cb *self)
        if (!skb)
                return;
 
-       skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+       skb_reserve(skb, self->client.max_header_size);
        skb_put(skb, 2);
        
        frame = skb->data;
@@ -719,7 +736,7 @@ void irlan_open_unicast_addr(struct irlan_cb *self)
                return;
 
        /* Reserve space for TTP, LMP, and LAP header */
-       skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+       skb_reserve(skb, self->max_header_size);
        skb_put(skb, 2);
        
        frame = skb->data;
@@ -757,7 +774,7 @@ void irlan_set_broadcast_filter(struct irlan_cb *self, int status)
                return;
 
        /* Reserve space for TTP, LMP, and LAP header */
-       skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+       skb_reserve(skb, self->client.max_header_size);
        skb_put(skb, 2);
        
        frame = skb->data;
@@ -796,7 +813,7 @@ void irlan_set_multicast_filter(struct irlan_cb *self, int status)
                return;
        
        /* Reserve space for TTP, LMP, and LAP header */
-       skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+       skb_reserve(skb, self->client.max_header_size);
        skb_put(skb, 2);
        
        frame = skb->data;
@@ -836,7 +853,7 @@ void irlan_get_unicast_addr(struct irlan_cb *self)
                return;
 
        /* Reserve space for TTP, LMP, and LAP header */
-       skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+       skb_reserve(skb, self->client.max_header_size);
        skb_put(skb, 2);
        
        frame = skb->data;
@@ -871,7 +888,7 @@ void irlan_get_media_char(struct irlan_cb *self)
                return;
 
        /* Reserve space for TTP, LMP, and LAP header */
-       skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+       skb_reserve(skb, self->client.max_header_size);
        skb_put(skb, 2);
        
        frame = skb->data;
@@ -1033,7 +1050,7 @@ int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len)
        
        /* get parameter name */
        memcpy(name, buf+n, name_len);
-       name[ name_len] = '\0';
+       name[name_len] = '\0';
        n+=name_len;
        
        /*  
@@ -1051,7 +1068,7 @@ int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len)
 
        /* get parameter value */
        memcpy(value, buf+n, val_len);
-       value[ val_len] = '\0';
+       value[val_len] = '\0';
        n+=val_len;
        
        DEBUG(4, "Parameter: %s ", name); 
@@ -1085,31 +1102,35 @@ static int irlan_proc_read(char *buf, char **start, off_t offset, int len,
        while (self != NULL) {
                ASSERT(self->magic == IRLAN_MAGIC, return len;);
                
-               len += sprintf(buf+len, "ifname: %s,\n",
-                              self->ifname);
-               len += sprintf(buf+len, "client state: %s, ",
-                              irlan_state[ self->client.state]);
-               len += sprintf(buf+len, "provider state: %s,\n",
-                              irlan_state[ self->provider.state]);
-               len += sprintf(buf+len, "saddr: %#08x, ",
-                              self->saddr);
-               len += sprintf(buf+len, "daddr: %#08x\n",
-                              self->daddr);
-               len += sprintf(buf+len, "version: %d.%d,\n",
-                              self->version[1], self->version[0]);
-               len += sprintf(buf+len, "access type: %s\n", 
-                              irlan_access[ self->access_type]);
-               len += sprintf(buf+len, "media: %s\n", 
-                              irlan_media[ self->media]);
-
-               len += sprintf(buf+len, "local filter:\n");
-               len += sprintf(buf+len, "remote filter: ");
-               len += irlan_print_filter(self->client.filter_type, buf+len);
-
-               len += sprintf(buf+len, "tx busy: %s\n", self->dev.tbusy ? 
-                              "TRUE" : "FALSE");
-
-               len += sprintf(buf+len, "\n");
+               /* Don't display the master server */
+               if (self->master == 0) {
+                       len += sprintf(buf+len, "ifname: %s,\n",
+                                      self->ifname);
+                       len += sprintf(buf+len, "client state: %s, ",
+                                      irlan_state[ self->client.state]);
+                       len += sprintf(buf+len, "provider state: %s,\n",
+                                      irlan_state[ self->provider.state]);
+                       len += sprintf(buf+len, "saddr: %#08x, ",
+                                      self->saddr);
+                       len += sprintf(buf+len, "daddr: %#08x\n",
+                                      self->daddr);
+                       len += sprintf(buf+len, "version: %d.%d,\n",
+                                      self->version[1], self->version[0]);
+                       len += sprintf(buf+len, "access type: %s\n", 
+                                      irlan_access[self->client.access_type]);
+                       len += sprintf(buf+len, "media: %s\n", 
+                                      irlan_media[self->media]);
+                       
+                       len += sprintf(buf+len, "local filter:\n");
+                       len += sprintf(buf+len, "remote filter: ");
+                       len += irlan_print_filter(self->client.filter_type, 
+                                                 buf+len);
+                       
+                       len += sprintf(buf+len, "tx busy: %s\n", 
+                                      self->dev.tbusy ? "TRUE" : "FALSE");
+                       
+                       len += sprintf(buf+len, "\n");
+               }
 
                self = (struct irlan_cb *) hashbin_get_next(irlan);
        } 
index c1965a11714fdd69cecec8f6531634829a330f41..26b16a196dcd277e8390888c090d8528e630612b 100644 (file)
@@ -6,13 +6,13 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Thu Oct 15 08:37:58 1998
- * Modified at:   Thu Apr 22 14:26:39 1999
+ * Modified at:   Mon May 10 20:23:49 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
  *                slip.c by Laurence Culhane,   <loz@holmes.demon.co.uk>
  *                          Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  * 
- *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -29,6 +29,7 @@
 #include <linux/etherdevice.h>
 #include <linux/inetdevice.h>
 #include <linux/if_arp.h>
+#include <linux/random.h>
 #include <net/arp.h>
 
 #include <net/irda/irda.h>
@@ -67,19 +68,19 @@ int irlan_eth_init(struct device *dev)
        
        dev->tx_queue_len = TTP_MAX_QUEUE;
 
-#if 0
-       /*  
-        *  OK, since we are emulating an IrLAN sever we will have to give
-        *  ourself an ethernet address!
-        *  FIXME: this must be more dynamically
-        */
-       dev->dev_addr[0] = 0x40;
-       dev->dev_addr[1] = 0x00;
-       dev->dev_addr[2] = 0x00;
-       dev->dev_addr[3] = 0x00;
-       dev->dev_addr[4] = 0x23;
-       dev->dev_addr[5] = 0x45;
-#endif
+       if (self->provider.access_type == ACCESS_DIRECT) {
+               /*  
+                * Since we are emulating an IrLAN sever we will have to
+                * give ourself an ethernet address!  
+                */
+               dev->dev_addr[0] = 0x40;
+               dev->dev_addr[1] = 0x00;
+               dev->dev_addr[2] = 0x00;
+               dev->dev_addr[3] = 0x00;
+               get_random_bytes(dev->dev_addr+4, 1);
+               get_random_bytes(dev->dev_addr+5, 1);
+       }
+
        /* 
         * Network device has now been registered, so tell irmanager about
         * it, so it can be configured with network parameters
@@ -180,8 +181,6 @@ int irlan_eth_xmit(struct sk_buff *skb, struct device *dev)
 {
        struct irlan_cb *self;
 
-       DEBUG(4, __FUNCTION__ "()\n");
-       
        self = (struct irlan_cb *) dev->priv;
 
        ASSERT(self != NULL, return 0;);
@@ -202,19 +201,19 @@ int irlan_eth_xmit(struct sk_buff *skb, struct device *dev)
                dev->trans_start = jiffies;
        }
        
-       DEBUG(4, "Room left at head: %d\n", skb_headroom(skb));
-       DEBUG(4, "Room left at tail: %d\n", skb_tailroom(skb));
-       DEBUG(4, "Required room: %d\n", IRLAN_MAX_HEADER);
-       
-       /* skb headroom large enough to contain IR-headers? */
-       if ((skb_headroom(skb) < IRLAN_MAX_HEADER) || (skb_shared(skb))) {
+       /* skb headroom large enough to contain all IrDA-headers? */
+       if ((skb_headroom(skb) < self->max_header_size) || (skb_shared(skb))) {
                struct sk_buff *new_skb = 
-                       skb_realloc_headroom(skb, IRLAN_MAX_HEADER);
-               ASSERT(new_skb != NULL, return 0;);
-               ASSERT(skb_headroom(new_skb) >= IRLAN_MAX_HEADER, return 0;);
+                       skb_realloc_headroom(skb, self->max_header_size);
 
-               /*  Free original skb, and use the new one */
+               /*  We have to free the original skb anyway */
                dev_kfree_skb(skb);
+
+               /* Did the realloc succeed? */
+               if (new_skb == NULL)
+                       return 0;
+
+               /* Use the new skb instead */
                skb = new_skb;
        } 
 
@@ -222,31 +221,26 @@ int irlan_eth_xmit(struct sk_buff *skb, struct device *dev)
        self->stats.tx_packets++;
        self->stats.tx_bytes += skb->len; 
 
-       /*
-        *  Now queue the packet in the transport layer
-        *  FIXME: clean up the code below! DB
-        */
-       if (self->use_udata) {
+       /* Now queue the packet in the transport layer */
+       if (self->use_udata)
                irttp_udata_request(self->tsap_data, skb);
-               dev->tbusy = 0;
-       
-               return 0;
-       }
-
-       if (irttp_data_request(self->tsap_data, skb) == -1) {
-               /*  
-                *  IrTTPs tx queue is full, so we just have to drop the
-                *  frame! You might think that we should just return -1
-                *  and don't deallocate the frame, but that is dangerous
-                *  since it's possible that we have replaced the original
-                *  skb with a new one with larger headroom, and that would
-                *  really confuse do_dev_queue_xmit() in dev.c! I have
-                *  tried :-) DB
-                */
-               dev_kfree_skb(skb);
-               ++self->stats.tx_dropped;
+       else {
+               if (irttp_data_request(self->tsap_data, skb) < 0) {
+                       /*   
+                        * IrTTPs tx queue is full, so we just have to
+                        * drop the frame! You might think that we should
+                        * just return -1 and don't deallocate the frame,
+                        * but that is dangerous since it's possible that
+                        * we have replaced the original skb with a new
+                        * one with larger headroom, and that would really
+                        * confuse do_dev_queue_xmit() in dev.c! I have
+                        * tried :-) DB 
+                        */
+                       dev_kfree_skb(skb);
+                       ++self->stats.tx_dropped;
                
-               return 0;
+                       return 0;
+               }
        }
        dev->tbusy = 0; /* Finished! */
        
@@ -314,26 +308,16 @@ void irlan_eth_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
        
        switch (flow) {
        case FLOW_STOP:
-               DEBUG(4, "IrLAN, stopping Ethernet layer\n");
-
                dev->tbusy = 1;
                break;
        case FLOW_START:
-               /* 
-                *  Tell upper layers that its time to transmit frames again
-                */
-               DEBUG(4, "IrLAN, starting Ethernet layer\n");
-
+       default:
+               /* Tell upper layers that its time to transmit frames again */
                dev->tbusy = 0;
 
-               /* 
-                *  Ready to receive more frames, so schedule the network
-                *  layer
-                */
+               /* Schedule network layer */
                mark_bh(NET_BH);                
                break;
-       default:
-               DEBUG(0, __FUNCTION__ "(), Unknown flow command!\n");
        }
 }
 
@@ -373,7 +357,7 @@ void irlan_etc_send_gratuitous_arp(struct device *dev)
        in_dev = dev->ip_ptr;
        arp_send(ARPOP_REQUEST, ETH_P_ARP, 
                 in_dev->ifa_list->ifa_address,
-                &dev, 
+                dev, 
                 in_dev->ifa_list->ifa_address,
                 NULL, dev->dev_addr, NULL);
 }
index d54e7cc122c06ff4e7e41d53d5c18d002d6bdf67..93d7c4efe10d6a6d024dd1298cb54585a92d1a08 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Oct 20 09:10:16 1998
- * Modified at:   Wed Feb  3 21:42:27 1999
+ * Modified at:   Sun May  9 21:17:44 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -38,22 +38,22 @@ char *irlan_state[] = {
        "IRLAN_SYNC",
 };
 
-void irlan_next_client_state( struct irlan_cb *self, IRLAN_STATE state) 
+void irlan_next_client_state(struct irlan_cb *self, IRLAN_STATE state) 
 {
        DEBUG(2, __FUNCTION__"(), %s\n", irlan_state[state]);
 
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == IRLAN_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == IRLAN_MAGIC, return;);
 
        self->client.state = state;
 }
 
-void irlan_next_provider_state( struct irlan_cb *self, IRLAN_STATE state) 
+void irlan_next_provider_state(struct irlan_cb *self, IRLAN_STATE state) 
 {
        DEBUG(2, __FUNCTION__"(), %s\n", irlan_state[state]);
 
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == IRLAN_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == IRLAN_MAGIC, return;);
 
        self->provider.state = state;
 }
index c4c1079dde7b327e48863ad72159faec4c9d9bb6..4f199e4ee74fc477dfe66c2bcdd9e6a862eaaf2b 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Fri Jan 29 11:16:38 1999
- * Modified at:   Thu Feb 25 15:10:54 1999
+ * Modified at:   Sat May  8 15:25:23 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -41,29 +41,29 @@ void handle_filter_request(struct irlan_cb *self, struct sk_buff *skb)
            (self->provider.filter_operation == DYNAMIC))
        {
                DEBUG(0, "Giving peer a dynamic Ethernet address\n");
-
                self->provider.mac_address[0] = 0x40;
                self->provider.mac_address[1] = 0x00;
                self->provider.mac_address[2] = 0x00;
                self->provider.mac_address[3] = 0x00;
                
                /* Use arbitration value to generate MAC address */
-               if (self->access_type == ACCESS_PEER) {
+               if (self->provider.access_type == ACCESS_PEER) {
                        self->provider.mac_address[4] = 
                                self->provider.send_arb_val & 0xff;
                        self->provider.mac_address[5] = 
                                (self->provider.send_arb_val >> 8) & 0xff;;
                } else {
                        /* Just generate something for now */
-                       self->provider.mac_address[4] = jiffies & 0xff;
-                       self->provider.mac_address[5] = (jiffies >> 8) & 0xff;
+                       get_random_bytes(self->provider.mac_address+4, 1);
+                       get_random_bytes(self->provider.mac_address+5, 1);
                }
 
                skb->data[0] = 0x00; /* Success */
                skb->data[1] = 0x03;
                irlan_insert_string_param(skb, "FILTER_MODE", "NONE");
                irlan_insert_short_param(skb, "MAX_ENTRY", 0x0001);
-               irlan_insert_array_param(skb, "FILTER_ENTRY", self->provider.mac_address, 6);
+               irlan_insert_array_param(skb, "FILTER_ENTRY", 
+                                        self->provider.mac_address, 6);
                return;
        }
        
@@ -138,8 +138,7 @@ void handle_filter_request(struct irlan_cb *self, struct sk_buff *skb)
  *    Check parameters in request from peer device
  *
  */
-void irlan_check_command_param(struct irlan_cb *self, char *param, 
-                              char *value)
+void irlan_check_command_param(struct irlan_cb *self, char *param, char *value)
 {
        __u8 *bytes;
 
@@ -210,6 +209,12 @@ void irlan_check_command_param(struct irlan_cb *self, char *param,
        }
 }
 
+/*
+ * Function irlan_print_filter (filter_type, buf)
+ *
+ *    Print status of filter. Used by /proc file system
+ *
+ */
 int irlan_print_filter(int filter_type, char *buf)
 {
        int len = 0;
index 8e2c3c25ab89ceb8c094387f843e6ed6528a3088..9471418724948b0d99b8d5730bcdef684e35944f 100644 (file)
@@ -6,13 +6,14 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Thu Apr 22 14:28:52 1999
+ * Modified at:   Sun May  9 12:22:56 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
  *                slip.c by Laurence Culhane,   <loz@holmes.demon.co.uk>
  *                          Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
+ *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -31,6 +32,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
+#include <linux/random.h>
 
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <net/irda/irlan_filter.h>
 #include <net/irda/irlan_client.h>
 
+static void irlan_provider_connect_indication(void *instance, void *sap, 
+                                             struct qos_info *qos, 
+                                             __u32 max_sdu_size,
+                                             __u8 max_header_size,
+                                             struct sk_buff *skb);
+
 /*
  * Function irlan_provider_control_data_indication (handle, skb)
  *
  *    This function gets the data that is received on the control channel
  *
  */
-int irlan_provider_data_indication(void *instance, void *sap, 
-                                  struct sk_buff *skb) 
+static int irlan_provider_data_indication(void *instance, void *sap, 
+                                         struct sk_buff *skb) 
 {
        struct irlan_cb *self;
        __u8 code;
@@ -111,14 +119,17 @@ int irlan_provider_data_indication(void *instance, void *sap,
  *    Got connection from peer IrLAN layer
  *
  */
-void irlan_provider_connect_indication(void *instance, void *sap, 
-                                      struct qos_info *qos,
-                                      __u32 max_sdu_size, struct sk_buff *skb)
+static void irlan_provider_connect_indication(void *instance, void *sap, 
+                                             struct qos_info *qos,
+                                             __u32 max_sdu_size, 
+                                             __u8 max_header_size,
+                                              struct sk_buff *skb)
 {
-       struct irlan_cb *self, *entry, *new;
+       struct irlan_cb *self, *new;
        struct tsap_cb *tsap;
+       __u32 saddr, daddr;
 
-       DEBUG(2, __FUNCTION__ "()\n");
+       DEBUG(0, __FUNCTION__ "()\n");
        
        self = (struct irlan_cb *) instance;
        tsap = (struct tsap_cb *) sap;
@@ -126,34 +137,69 @@ void irlan_provider_connect_indication(void *instance, void *sap,
        ASSERT(self != NULL, return;);
        ASSERT(self->magic == IRLAN_MAGIC, return;);
        
+       self->provider.max_sdu_size = max_sdu_size;
+       self->provider.max_header_size = max_header_size;
+
        ASSERT(tsap == self->provider.tsap_ctrl,return;);
        ASSERT(self->provider.state == IRLAN_IDLE, return;);
 
-       /* Check if this provider is currently unused */
-       if (self->daddr == DEV_ADDR_ANY) {
-               /*
-                * Rehash instance, now we have a client (daddr) to serve.
-                */
-               entry = hashbin_remove(irlan, self->daddr, NULL);
-               ASSERT( entry == self, return;);
-               
-               self->daddr = irttp_get_daddr(tsap);
-               DEBUG(2, __FUNCTION__ "(), daddr=%08x\n", self->daddr);
-               hashbin_insert(irlan, (QUEUE*) self, self->daddr, NULL);
+       daddr = irttp_get_daddr(tsap);
+       saddr = irttp_get_saddr(tsap);
+
+       /* Check if we already dealing with this client or peer */
+       new = (struct irlan_cb *) hashbin_find(irlan, daddr, NULL);
+       if (new) {
+               ASSERT(new->magic == IRLAN_MAGIC, return;);
+               DEBUG(0, __FUNCTION__ "(), found instance!\n");
+
+               /* Update saddr, since client may have moved to a new link */
+               new->saddr = saddr;
+               DEBUG(2, __FUNCTION__ "(), saddr=%08x\n", new->saddr);
+
+               /* Make sure that any old provider control TSAP is removed */
+               if ((new != self) && new->provider.tsap_ctrl) {
+                       irttp_disconnect_request(new->provider.tsap_ctrl, 
+                                                NULL, P_NORMAL);
+                       irttp_close_tsap(new->provider.tsap_ctrl);
+                       new->provider.tsap_ctrl = NULL;
+               }
        } else {
-               /*
-                * If we already have the daddr set, this means that the
-                * client must already have started (peer mode). We must
-                * make sure that this connection attempt is from the same
-                * device as the client is dealing with!  
+               /* This must be the master instance, so start a new instance */
+               DEBUG(0, __FUNCTION__ "(), starting new provider!\n");
+
+               new = irlan_open(saddr, daddr, TRUE); 
+       }
+
+       /*  
+        * Check if the connection came in on the master server, or the
+        * slave server. If it came on the slave, then everything is
+        * really, OK (reconnect), if not we need to dup the connection and
+        * hand it over to the slave.  
+        */
+       if (new != self) {
+                               
+               /* Now attach up the new "socket" */
+               new->provider.tsap_ctrl = irttp_dup(self->provider.tsap_ctrl, 
+                                                   new);
+               if (!new->provider.tsap_ctrl) {
+                       DEBUG(0, __FUNCTION__ "(), dup failed!\n");
+                       return;
+               }
+               
+               /* new->stsap_sel = new->tsap->stsap_sel; */
+               new->dtsap_sel_ctrl = new->provider.tsap_ctrl->dtsap_sel;
+
+               /* Clean up the original one to keep it in listen state */
+               self->provider.tsap_ctrl->dtsap_sel = LSAP_ANY;
+               self->provider.tsap_ctrl->lsap->dlsap_sel = LSAP_ANY;
+               self->provider.tsap_ctrl->lsap->lsap_state = LSAP_DISCONNECTED;
+               
+               /* 
+                * Use the new instance from here instead of the master
+                * struct! 
                 */
-               ASSERT(self->daddr == irttp_get_daddr(tsap), return;);
+               self = new;
        }
-       
-       /* Update saddr, since client may have moved to a new link */
-       self->saddr = irttp_get_saddr(tsap);
-       DEBUG(2, __FUNCTION__ "(), saddr=%08x\n", self->saddr);
-       
        /* Check if network device has been registered */
        if (!self->netdev_registered)
                irlan_register_netdev(self);
@@ -165,9 +211,10 @@ void irlan_provider_connect_indication(void *instance, void *sap,
         * indication it needs to make progress. If the client is still in 
         * IDLE state, we must kick it to 
         */
-       if ((self->access_type == ACCESS_PEER) && 
-           (self->client.state == IRLAN_IDLE))
+       if ((self->provider.access_type == ACCESS_PEER) && 
+           (self->client.state == IRLAN_IDLE)) {
                irlan_client_wakeup(self, self->saddr, self->daddr);
+       }
 }
 
 /*
@@ -225,6 +272,9 @@ int irlan_parse_open_data_cmd(struct irlan_cb *self, struct sk_buff *skb)
        
        ret = irlan_provider_parse_command(self, CMD_OPEN_DATA_CHANNEL, skb);
 
+       /* Open data channel */
+       irlan_open_data_tsap(self);
+
        return ret;
 }
 
@@ -314,7 +364,7 @@ void irlan_provider_send_reply(struct irlan_cb *self, int command,
                return;
 
        /* Reserve space for TTP, LMP, and LAP header */
-       skb_reserve(skb, TTP_HEADER+LMP_HEADER+LAP_HEADER);
+       skb_reserve(skb, self->provider.max_header_size);
        skb_put(skb, 2);
        
        switch (command) {
@@ -334,6 +384,7 @@ void irlan_provider_send_reply(struct irlan_cb *self, int command,
                }
                irlan_insert_short_param(skb, "IRLAN_VER", 0x0101);
                break;
+
        case CMD_GET_MEDIA_CHAR:
                skb->data[0] = 0x00; /* Success */
                skb->data[1] = 0x05; /* 5 parameters */
@@ -341,7 +392,7 @@ void irlan_provider_send_reply(struct irlan_cb *self, int command,
                irlan_insert_string_param(skb, "FILTER_TYPE", "BROADCAST");
                irlan_insert_string_param(skb, "FILTER_TYPE", "MULTICAST");
 
-               switch(self->access_type) {
+               switch (self->provider.access_type) {
                case ACCESS_DIRECT:
                        irlan_insert_string_param(skb, "ACCESS_TYPE", "DIRECT");
                        break;
index 6bdf503f1075a2e3d8060bdae14a4d619f7da597..29e660fa72dc3e8f58d0f058e8beba2c07a85ec0 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Thu Apr 22 10:46:28 1999
+ * Modified at:   Fri May  7 10:53:58 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -108,7 +108,7 @@ static int irlan_provider_state_info(struct irlan_cb *self, IRLAN_EVENT event,
        switch(event) {
        case IRLAN_GET_INFO_CMD:
                /* Be sure to use 802.3 in case of peer mode */
-               if (self->access_type == ACCESS_PEER) {
+               if (self->provider.access_type == ACCESS_PEER) {
                        self->media = MEDIA_802_3;
                        
                        /* Check if client has started yet */
@@ -129,7 +129,7 @@ static int irlan_provider_state_info(struct irlan_cb *self, IRLAN_EVENT event,
                break;          
        case IRLAN_OPEN_DATA_CMD:
                ret = irlan_parse_open_data_cmd(self, skb);
-               if (self->access_type == ACCESS_PEER) {
+               if (self->provider.access_type == ACCESS_PEER) {
                        /* FIXME: make use of random functions! */
                        self->provider.send_arb_val = (jiffies & 0xffff);
                }
@@ -205,8 +205,6 @@ static int irlan_provider_state_open(struct irlan_cb *self, IRLAN_EVENT event,
 static int irlan_provider_state_data(struct irlan_cb *self, IRLAN_EVENT event, 
                                     struct sk_buff *skb) 
 {
-       struct irmanager_event mgr_event;
-
        DEBUG(4, __FUNCTION__ "()\n");
 
        ASSERT(self != NULL, return -1;);
@@ -220,10 +218,6 @@ static int irlan_provider_state_data(struct irlan_cb *self, IRLAN_EVENT event,
                break;
        case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */
        case IRLAN_LAP_DISCONNECT:
-               mgr_event.event = EVENT_IRLAN_STOP;
-               sprintf(mgr_event.devname, "%s", self->ifname);
-               irmanager_notify(&mgr_event);
-
                irlan_next_provider_state(self, IRLAN_IDLE);
                break;
        default:
index 9959b64bc14e7d4a445752652d130f9ea9839df0..57a6b420bebc4f7dfa6a241c6978cb95869cef65 100644 (file)
@@ -6,11 +6,11 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Fri Oct  9 09:18:07 1998
- * Modified at:   Mon Feb  8 01:23:52 1999
+ * Modified at:   Sun May  9 11:37:06 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       ppp.c, isdn_ppp.c
  * 
- *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -255,11 +255,11 @@ struct sk_buff *irlap_compress_frame( struct irlap_cb *self,
        }
 
        /* FIXME: Find out what is the max overhead (not 10) */
-       new_skb = dev_alloc_skb( skb->len+LAP_HEADER+10);
+       new_skb = dev_alloc_skb( skb->len+LAP_MAX_HEADER+10);
        if(!new_skb)
                return skb;
 
-       skb_reserve( new_skb, LAP_HEADER);
+       skb_reserve( new_skb, LAP_MAX_HEADER);
        skb_put( new_skb, skb->len+10);
        
        count = (self->compressor.cp->compress)( self->compressor.state, 
index a2fbadf65045d951b1c915e3d7d5bd70f8737b68..936401339cfd4c70d64ac429e3f278037136edd3 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Aug 16 00:59:29 1997
- * Modified at:   Fri Apr 23 11:55:12 1999
+ * Modified at:   Sun May  9 22:44:32 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>,
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
  *                        Thomas Davis <ratbert@radiks.net>
  *     All Rights Reserved.
  *     
@@ -274,22 +274,22 @@ void irlap_do_event( struct irlap_cb *self, IRLAP_EVENT event,
  *    Switches state and provides debug information
  *
  */
-void irlap_next_state( struct irlap_cb *self, IRLAP_STATE state) 
+void irlap_next_state(struct irlap_cb *self, IRLAP_STATE state) 
 {      
-       if ( !self || self->magic != LAP_MAGIC)
+       if (!self || self->magic != LAP_MAGIC)
                return;
        
-       DEBUG( 4, "next LAP state = %s\n", irlap_state[ state]);
+       DEBUG(4, "next LAP state = %s\n", irlap_state[ state]);
 
        self->state = state;
 
        /*
         *  If we are swithing away from a XMIT state then we are allowed to 
         *  transmit a maximum number of bytes again when we enter the XMIT 
-        *  state again. Since its possible to "switch" from XMIT to XMIT and
+        *  state again. Since its possible to "switch" from XMIT to XMIT,
         *  we cannot do this when swithing into the XMIT state :-)
         */
-       if (( state != LAP_XMIT_P) && ( state != LAP_XMIT_S))
+       if ((state != LAP_XMIT_P) && (state != LAP_XMIT_S))
                self->bytes_left = self->window_bytes;
 }
 
@@ -310,7 +310,7 @@ static int irlap_state_ndm( struct irlap_cb *self, IRLAP_EVENT event,
        ASSERT( self != NULL, return -1;);
        ASSERT( self->magic == LAP_MAGIC, return -1;);
 
-       switch( event) {
+       switch(event) {
        case CONNECT_REQUEST:
                ASSERT( self->irdev != NULL, return -1;);
 
@@ -393,7 +393,6 @@ static int irlap_state_ndm( struct irlap_cb *self, IRLAP_EVENT event,
                        irlap_start_query_timer( self, QUERY_TIMEOUT);
                        irlap_next_state( self, LAP_REPLY);
                }
-
                dev_kfree_skb(skb);
                break;
 
@@ -530,7 +529,7 @@ static int irlap_state_reply(struct irlap_cb *self, IRLAP_EVENT event,
                        irlap_send_discovery_xid_frame(self, info->S,
                                                       self->slot, FALSE,
                                                       discovery_rsp);
-
+                       
                        self->frame_sent = TRUE;
                        irlap_next_state(self, LAP_REPLY);
                }
@@ -568,27 +567,28 @@ static int irlap_state_conn(struct irlap_cb *self, IRLAP_EVENT event,
 
        switch (event) {
        case CONNECT_RESPONSE:
-               skb_pull( skb, 11);
+               /* skb_pull(skb, 11); */
+               skb_pull(skb, sizeof(struct snrm_frame));
 
-               ASSERT( self->irdev != NULL, return -1;);
-               irda_qos_negotiate( &self->qos_rx, &self->qos_tx, skb);
+               ASSERT(self->irdev != NULL, return -1;);
+               irda_qos_negotiate(&self->qos_rx, &self->qos_tx, skb);
 
                irlap_initiate_connection_state( self);
 
                /*
                 * We are allowed to send two frames!
                 */
-               irlap_send_ua_response_frame( self, &self->qos_rx);
-               irlap_send_ua_response_frame( self, &self->qos_rx);
+               irlap_send_ua_response_frame(self, &self->qos_rx);
+               irlap_send_ua_response_frame(self, &self->qos_rx);
                
-               irlap_apply_connection_parameters( self, &self->qos_tx);
+               irlap_apply_connection_parameters(self, &self->qos_tx);
 
                /*
                 *  The WD-timer could be set to the duration of the P-timer 
-                *  for this case, but it is recommomended to use twice the 
+                *  for this case, but it is recommended to use twice the 
                 *  value (note 3 IrLAP p. 60). 
                 */
-               irlap_start_wd_timer( self, self->wd_timeout);
+               irlap_start_wd_timer(self, self->wd_timeout);
                irlap_next_state( self, LAP_NRM_S);
                break;
 
@@ -669,28 +669,30 @@ static int irlap_state_setup( struct irlap_cb *self, IRLAP_EVENT event,
                 *  The device with the largest device address wins the battle
                 *  (both have sent a SNRM command!)
                 */
-               if ( info->daddr > self->saddr) {
-                       del_timer( &self->final_timer);
-                       irlap_initiate_connection_state( self);
+               if (info->daddr > self->saddr) {
+                       del_timer(&self->final_timer);
+                       irlap_initiate_connection_state(self);
 
-                       ASSERT( self->irdev != NULL, return -1;);
-                       irda_qos_negotiate( &self->qos_rx, &self->qos_tx, skb);
+                       ASSERT(self->irdev != NULL, return -1;);
+                       /* skb_pull(skb, 11); */
+                       skb_pull(skb, sizeof(struct snrm_frame));
+                       irda_qos_negotiate(&self->qos_rx, &self->qos_tx, skb);
                        
                        irlap_send_ua_response_frame(self, &self->qos_rx);
-                       irlap_apply_connection_parameters( self, &self->qos_tx);
-                       irlap_connect_confirm( self, skb);
+                       irlap_apply_connection_parameters(self, &self->qos_tx);
+                       irlap_connect_confirm(self, skb);
                        
                        /* 
                         *  The WD-timer could be set to the duration of the
-                        *  P-timer for this case, but it is recommomended
+                        *  P-timer for this case, but it is recommended
                         *  to use twice the value (note 3 IrLAP p. 60).  
                         */
-                       irlap_start_wd_timer( self, self->wd_timeout);
+                       irlap_start_wd_timer(self, self->wd_timeout);
                        
-                       irlap_next_state( self, LAP_NRM_S);
+                       irlap_next_state(self, LAP_NRM_S);
                } else {
                        /* We just ignore the other device! */
-                       irlap_next_state( self, LAP_SETUP);
+                       irlap_next_state(self, LAP_SETUP);
                }
                break;
        case RECV_UA_RSP:
@@ -702,9 +704,10 @@ static int irlap_state_setup( struct irlap_cb *self, IRLAP_EVENT event,
 
                /* Negotiate connection parameters */
                ASSERT( skb->len > 10, return -1;);
-               skb_pull( skb, 10);
+               /* skb_pull(skb, 10); */
+               skb_pull(skb, sizeof(struct ua_frame));
 
-               ASSERT( self->irdev != NULL, return -1;);
+               ASSERT(self->irdev != NULL, return -1;);
                irda_qos_negotiate( &self->qos_rx, &self->qos_tx, skb);
 
                irlap_apply_connection_parameters( self, &self->qos_tx); 
@@ -1570,7 +1573,7 @@ static int irlap_state_nrm_s( struct irlap_cb *self, IRLAP_EVENT event,
                        /* 
                         *  poll bit cleared?
                         */
-                       if ( !info->pf) {
+                       if (!info->pf) {
                                self->vr = (self->vr + 1) % 8;
                                
                                /* Update Nr received */
@@ -1600,27 +1603,32 @@ static int irlap_state_nrm_s( struct irlap_cb *self, IRLAP_EVENT event,
                                 *  also before changing to XMIT_S
                                 *  state. (note 1, IrLAP p. 82) 
                                 */
-                               irlap_wait_min_turn_around( self, &self->qos_tx);
-                               /*
-                                *  Any pending data requests?
+                               irlap_wait_min_turn_around(self, &self->qos_tx);
+
+                               /*  
+                                * Give higher layers a chance to
+                                * immediately reply with some data before
+                                * we decide if we should send a RR frame
+                                * or not
                                 */
-                               if (( skb_queue_len( &self->tx_list) > 0) && 
-                                   ( self->window > 0)) 
+                               irlap_data_indication(self, skb);
+
+                               /* Any pending data requests?  */
+                               if ((skb_queue_len(&self->tx_list) > 0) && 
+                                   (self->window > 0)) 
                                {
                                        self->ack_required = TRUE;
                                        
-                                       del_timer( &self->wd_timer);
+                                       del_timer(&self->wd_timer);
                                        
-                                       irlap_next_state( self, LAP_XMIT_S);
+                                       irlap_next_state(self, LAP_XMIT_S);
                                } else {
-                                       irlap_send_rr_frame( self, RSP_FRAME);
-                                       irlap_start_wd_timer( self, self->wd_timeout);
+                                       irlap_send_rr_frame(self, RSP_FRAME);
+                                       irlap_start_wd_timer(self, self->wd_timeout);
 
                                        /* Keep the state */
-                                       irlap_next_state( self, LAP_NRM_S);
+                                       irlap_next_state(self, LAP_NRM_S);
                                }
-                               irlap_data_indication( self, skb);
-
                                break;
                        }
                }
index cda78e7f1d536ffb9462de13a53ffbcad4c1fe66..8ffd26a6e051807f10ad8d906ceda709cf0edafe 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Aug 19 10:27:26 1997
- * Modified at:   Fri Apr 23 09:30:42 1999
+ * Modified at:   Sun May  9 22:55:11 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Resrved.
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, All Rights Resrved.
  *     
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -1056,8 +1056,8 @@ static inline void irlap_recv_i_frame(struct irlap_cb *self,
  *    Receive and parse an Unnumbered Information (UI) frame
  *
  */
-static void irlap_recv_ui_frame( struct irlap_cb *self, struct sk_buff *skb, 
-                                struct irlap_info *info)
+static void irlap_recv_ui_frame(struct irlap_cb *self, struct sk_buff *skb, 
+                               struct irlap_info *info)
 {
        __u8 *frame;
 
@@ -1254,7 +1254,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct device *dev,
                 *  Received S(upervisory) frame, check which frame type it is
                 *  only the first nibble is of interest
                 */
-               switch(control & 0x0f) {
+               switch (control & 0x0f) {
                case RR:
                        irlap_recv_rr_frame( self, skb, &info, command);
                        self->stats.rx_packets++;
@@ -1279,7 +1279,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct device *dev,
        /* 
         *  This must be a C(ontrol) frame 
         */
-       switch(control) {
+       switch (control) {
        case XID_RSP:
                irlap_recv_discovery_xid_rsp(self, skb, &info);
                break;
index d76661b6cf1ed47474f1364689ff40e2b094e187..f4d4608cb9dc9e6469ec8e9d74ca9c51d810bfcd 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Stable.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 17 20:54:32 1997
- * Modified at:   Fri Apr 23 09:13:24 1999
+ * Modified at:   Sun May  9 22:45:06 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
  *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
@@ -197,7 +197,7 @@ struct lsap_cb *irlmp_open_lsap(__u8 slsap_sel, struct notify_t *notify)
 }
 
 /*
- * Function irlmp_close_lsap (self)
+ * Function __irlmp_close_lsap (self)
  *
  *    Remove an instance of LSAP
  */
@@ -369,11 +369,11 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
                if (!skb)
                        return -ENOMEM;
 
-               skb_reserve(skb, LMP_CONTROL_HEADER+LAP_HEADER);
+               skb_reserve(skb, LMP_MAX_HEADER);
        } else
                skb = userdata;
        
-       /* Make room for MUX control header ( 3 bytes) */
+       /* Make room for MUX control header (3 bytes) */
        ASSERT(skb_headroom(skb) >= LMP_CONTROL_HEADER, return -1;);
        skb_push(skb, LMP_CONTROL_HEADER);
 
@@ -443,25 +443,36 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
 void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb) 
 {
        int max_seg_size;
-
-       DEBUG(3, __FUNCTION__ "()\n");
+       int lap_header_size;
+       int max_header_size;
        
        ASSERT(self != NULL, return;);
        ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
        ASSERT(skb != NULL, return;);
        ASSERT(self->lap != NULL, return;);
 
+       DEBUG(0, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", 
+             self->slsap_sel, self->dlsap_sel);
+
        self->qos = *self->lap->qos;
 
-       max_seg_size = self->lap->qos->data_size.value;
-       DEBUG(4, __FUNCTION__ "(), max_seg_size=%d\n", max_seg_size);
+       lap_header_size = irlap_get_header_size(self->lap->irlap);
+
+       max_seg_size = self->lap->qos->data_size.value-LMP_HEADER-
+               lap_header_size;
+       DEBUG(2, __FUNCTION__ "(), max_seg_size=%d\n", max_seg_size);
        
+       max_header_size = LMP_HEADER + lap_header_size;
+
+       DEBUG(2, __FUNCTION__ "(), max_header_size=%d\n", max_header_size);
+
        /* Hide LMP_CONTROL_HEADER header from layer above */
        skb_pull(skb, LMP_CONTROL_HEADER);
 
        if (self->notify.connect_indication)
                self->notify.connect_indication(self->notify.instance, self, 
-                                               &self->qos, max_seg_size, skb);
+                                               &self->qos, max_seg_size, 
+                                               max_header_size, skb);
 }
 
 /*
@@ -470,24 +481,22 @@ void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb)
  *    Service user is accepting connection
  *
  */
-void irlmp_connect_response( struct lsap_cb *self, struct sk_buff *userdata) 
+void irlmp_connect_response(struct lsap_cb *self, struct sk_buff *userdata) 
 {
-       DEBUG(3, __FUNCTION__ "()\n");
-       
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LMP_LSAP_MAGIC, return;);
-       ASSERT( userdata != NULL, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
+       ASSERT(userdata != NULL, return;);
 
        self->connected = TRUE;
 
-       DEBUG( 4, "irlmp_connect_response: slsap_sel=%02x, dlsap_sel=%02x\n", 
-              self->slsap_sel, self->dlsap_sel);
+       DEBUG(2, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n", 
+             self->slsap_sel, self->dlsap_sel);
 
        /* Make room for MUX control header ( 3 bytes) */
-       ASSERT( skb_headroom( userdata) >= LMP_CONTROL_HEADER, return;);
-       skb_push( userdata, LMP_CONTROL_HEADER);
+       ASSERT(skb_headroom(userdata) >= LMP_CONTROL_HEADER, return;);
+       skb_push(userdata, LMP_CONTROL_HEADER);
        
-       irlmp_do_lsap_event( self, LM_CONNECT_RESPONSE, userdata);
+       irlmp_do_lsap_event(self, LM_CONNECT_RESPONSE, userdata);
 }
 
 /*
@@ -498,25 +507,35 @@ void irlmp_connect_response( struct lsap_cb *self, struct sk_buff *userdata)
 void irlmp_connect_confirm(struct lsap_cb *self, struct sk_buff *skb) 
 {
        int max_seg_size;
+       int max_header_size;
+       int lap_header_size;
 
        DEBUG(3, __FUNCTION__ "()\n");
        
-       ASSERT( skb != NULL, return;);
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LMP_LSAP_MAGIC, return;);
+       ASSERT(skb != NULL, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
        
-       ASSERT( self->lap != NULL, return;);
+       ASSERT(self->lap != NULL, return;);
        self->qos = *self->lap->qos;
 
-       max_seg_size = self->qos.data_size.value;
-       DEBUG( 4, __FUNCTION__ "(), max_seg_size=%d\n", max_seg_size);
+       lap_header_size = irlap_get_header_size(self->lap->irlap);
+
+       max_seg_size = self->lap->qos->data_size.value-LMP_HEADER-
+               lap_header_size;
+       DEBUG(2, __FUNCTION__ "(), max_seg_size=%d\n", max_seg_size);
        
+       max_header_size = LMP_HEADER + lap_header_size;
+
+       DEBUG(2, __FUNCTION__ "(), max_header_size=%d\n", max_header_size);
+
        /* Hide LMP_CONTROL_HEADER header from layer above */
-       skb_pull( skb, LMP_CONTROL_HEADER);
+       skb_pull(skb, LMP_CONTROL_HEADER);
 
-       if ( self->notify.connect_confirm) {
-               self->notify.connect_confirm( self->notify.instance, self,
-                                             &self->qos, max_seg_size, skb);
+       if (self->notify.connect_confirm) {
+               self->notify.connect_confirm(self->notify.instance, self,
+                                            &self->qos, max_seg_size, 
+                                            max_header_size, skb);
        }
 }
 
@@ -620,8 +639,8 @@ void irlmp_disconnect_request(struct lsap_cb *self, struct sk_buff *userdata)
  *
  *    LSAP is being closed!
  */
-void irlmp_disconnect_indication( struct lsap_cb *self, LM_REASON reason, 
-                                 struct sk_buff *userdata) 
+void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason, 
+                                struct sk_buff *userdata) 
 {
        struct lsap_cb *lsap;
 
@@ -637,6 +656,10 @@ void irlmp_disconnect_indication( struct lsap_cb *self, LM_REASON reason,
        self->connected = FALSE;
        self->dlsap_sel = LSAP_ANY;
 
+#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
+       irlmp->cache.valid = FALSE;
+#endif
+
        /* 
         *  Remove association between this LSAP and the link it used 
         */
@@ -975,7 +998,7 @@ void irlmp_status_request(void)
        DEBUG( 1, "irlmp_status_request(), Not implemented\n");
 }
 
-void irlmp_status_indication( LINK_STATUS link, LOCK_STATUS lock) 
+void irlmp_status_indication(LINK_STATUS link, LOCK_STATUS lock) 
 {
        DEBUG( 4, "irlmp_status_indication(), Not implemented\n");
 }
@@ -1418,14 +1441,14 @@ __u32 irlmp_get_daddr(struct lsap_cb *self)
  *    Give some info to the /proc file system
  *
  */
-int irlmp_proc_read( char *buf, char **start, off_t offset, int len, 
-                    int unused)
+int irlmp_proc_read(char *buf, char **start, off_t offset, int len, 
+                   int unused)
 {
        struct lsap_cb *self;
        struct lap_cb *lap;
        unsigned long flags;
 
-       ASSERT( irlmp != NULL, return 0;);
+       ASSERT(irlmp != NULL, return 0;);
        
        save_flags( flags);
        cli();
@@ -1449,35 +1472,34 @@ int irlmp_proc_read( char *buf, char **start, off_t offset, int len,
        } 
 
        len += sprintf( buf+len, "\nRegistred Link Layers:\n");
-       lap = (struct lap_cb *) hashbin_get_first( irlmp->links);
-       while ( lap != NULL) {
-               ASSERT( lap->magic == LMP_LAP_MAGIC, return 0;);
 
-               len += sprintf( buf+len, "lap state: %s, ", 
-                               irlmp_state[ lap->lap_state]);
+       lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
+       while (lap != NULL) {
+               len += sprintf(buf+len, "lap state: %s, ", 
+                              irlmp_state[lap->lap_state]);
 
-               len += sprintf( buf+len, "saddr: %#08x, daddr: %#08x, ",
-                               lap->saddr, lap->daddr); 
-               len += sprintf( buf+len, "\n");
+               len += sprintf(buf+len, "saddr: %#08x, daddr: %#08x, ",
+                              lap->saddr, lap->daddr); 
+               len += sprintf(buf+len, "\n");
 
                len += sprintf( buf+len, "\nConnected LSAPs:\n");
                self = (struct lsap_cb *) hashbin_get_first( lap->lsaps);
-               while ( self != NULL) {
-                       ASSERT( self->magic == LMP_LSAP_MAGIC, return 0;);
-                       len += sprintf( buf+len, "lsap state: %s, ", 
-                                       irlsap_state[ self->lsap_state]);
-                       len += sprintf( buf+len, 
-                                       "slsap_sel: %#02x, dlsap_sel: %#02x, ",
-                                       self->slsap_sel, self->dlsap_sel);
-                       len += sprintf( buf+len, "(%s)", self->notify.name);
-                       len += sprintf( buf+len, "\n");
+               while (self != NULL) {
+                       ASSERT(self->magic == LMP_LSAP_MAGIC, return 0;);
+                       len += sprintf(buf+len, "lsap state: %s, ", 
+                                      irlsap_state[ self->lsap_state]);
+                       len += sprintf(buf+len, 
+                                      "slsap_sel: %#02x, dlsap_sel: %#02x, ",
+                                      self->slsap_sel, self->dlsap_sel);
+                       len += sprintf(buf+len, "(%s)", self->notify.name);
+                       len += sprintf(buf+len, "\n");
                        
-                       self = ( struct lsap_cb *) hashbin_get_next( 
+                       self = (struct lsap_cb *) hashbin_get_next( 
                                lap->lsaps);
                } 
+               len += sprintf(buf+len, "\n");
 
-               lap = ( struct lap_cb *) hashbin_get_next( 
-                       irlmp->links);
+               lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
        } 
 
        restore_flags( flags);
index bf1bab31ecf7a602c4c2faaf7aca624979247d42..ff396c4ff7bdcddd0adceab3ad84f4691793a1b3 100644 (file)
@@ -1,15 +1,15 @@
 /*********************************************************************
  *                
  * Filename:      irlmp_frame.c
- * Version:       0.8
+ * Version:       0.9
  * Description:   IrLMP frame implementation
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Aug 19 02:09:59 1997
- * Modified at:   Fri Apr 23 09:12:23 1999
+ * Modified at:   Sun May  9 21:00:05 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>
  *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
@@ -59,16 +59,16 @@ inline void irlmp_send_data_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap,
  *
  *    Send Link Control Frame to IrLAP
  */
-void irlmp_send_lcf_pdu( struct lap_cb *self, __u8 dlsap, __u8 slsap,
-                        __u8 opcode, struct sk_buff *skb) 
+void irlmp_send_lcf_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap,
+                       __u8 opcode, struct sk_buff *skb) 
 {
        __u8 *frame;
        
-       DEBUG( 4, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
        
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LMP_LAP_MAGIC, return;);
-       ASSERT( skb != NULL, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LMP_LAP_MAGIC, return;);
+       ASSERT(skb != NULL, return;);
        
        frame = skb->data;
        
@@ -82,8 +82,8 @@ void irlmp_send_lcf_pdu( struct lap_cb *self, __u8 dlsap, __u8 slsap,
        else
                frame[3] = 0x00; /* rsvd */
 
-       ASSERT( self->irlap != NULL, return;);
-       irlap_data_request( self->irlap, skb, TRUE);
+       ASSERT(self->irlap != NULL, return;);
+       irlap_data_request(self->irlap, skb, TRUE);
 }
 
 /*
@@ -112,7 +112,7 @@ void irlmp_link_data_indication(struct lap_cb *self, int reliable,
         */
        slsap_sel = fp[0] & LSAP_MASK; 
        dlsap_sel = fp[1];
-       
+
        /*
         *  Check if this is an incoming connection, since we must deal with
         *  it in a different way than other established connections.
@@ -224,11 +224,11 @@ void irlmp_link_disconnect_indication(struct lap_cb *lap,
  *    Incoming LAP connection!
  *
  */
-void irlmp_link_connect_indication( struct lap_cb *self, __u32 saddr, 
-                                   __u32 daddr, struct qos_info *qos,
-                                   struct sk_buff *skb) 
+void irlmp_link_connect_indication(struct lap_cb *self, __u32 saddr, 
+                                  __u32 daddr, struct qos_info *qos,
+                                  struct sk_buff *skb) 
 {
-       DEBUG( 4, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
 
        /* Copy QoS settings for this session */
        self->qos = qos;
@@ -237,7 +237,7 @@ void irlmp_link_connect_indication( struct lap_cb *self, __u32 saddr,
        self->daddr = daddr;
        ASSERT(self->saddr == saddr, return;);
 
-       irlmp_do_lap_event( self, LM_LAP_CONNECT_INDICATION, skb);
+       irlmp_do_lap_event(self, LM_LAP_CONNECT_INDICATION, skb);
 }
 
 /*
@@ -246,19 +246,19 @@ void irlmp_link_connect_indication( struct lap_cb *self, __u32 saddr,
  *    LAP connection confirmed!
  *
  */
-void irlmp_link_connect_confirm( struct lap_cb *self, struct qos_info *qos, 
-                                struct sk_buff *userdata)
+void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos, 
+                               struct sk_buff *userdata)
 {
-       DEBUG( 4, "irlmp_link_connect_confirm()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
 
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LMP_LAP_MAGIC, return;);
-       ASSERT( qos != NULL, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LMP_LAP_MAGIC, return;);
+       ASSERT(qos != NULL, return;);
 
        /* Copy QoS settings for this session */
        self->qos = qos;
 
-       irlmp_do_lap_event( self, LM_LAP_CONNECT_CONFIRM, NULL);
+       irlmp_do_lap_event(self, LM_LAP_CONNECT_CONFIRM, NULL);
 }
 
 /*
@@ -276,7 +276,9 @@ void irlmp_link_discovery_indication(struct lap_cb *self,
        irlmp_add_discovery(irlmp->cachelog, discovery);
 
        /* Just handle it the same way as a discovery confirm */
+#if 0
        irlmp_do_lap_event(self, LM_LAP_DISCOVERY_CONFIRM, NULL);
+#endif
 }
 
 /*
@@ -365,7 +367,7 @@ static struct lsap_cb *irlmp_find_lsap(struct lap_cb *self, __u8 dlsap_sel,
 #endif
                        return lsap;
                }
-               lsap = ( struct lsap_cb *) hashbin_get_next(queue);
+               lsap = (struct lsap_cb *) hashbin_get_next(queue);
        }
 
        /* Sorry not found! */
index a0fbe23d678986188405048e1e86c923caa74477..9e02465ccae90c50673d8afe241c1f0d9024c8a3 100644 (file)
@@ -51,10 +51,11 @@ static void irlpt_client_discovery_indication(discovery_t *);
 static void irlpt_client_connect_confirm(void *instance, void *sap, 
                                         struct qos_info *qos, 
                                         __u32 max_seg_size, 
+                                        __u8 max_header_size,
                                         struct sk_buff *skb);
-static void irlpt_client_disconnect_indication( void *instance, void *sap, 
-                                               LM_REASON reason,
-                                               struct sk_buff *userdata);
+static void irlpt_client_disconnect_indication(void *instance, void *sap, 
+                                              LM_REASON reason,
+                                              struct sk_buff *userdata);
 static void irlpt_client_expired(unsigned long data);
 
 #if 0
@@ -187,7 +188,7 @@ __initfunc(int irlpt_client_init(void))
 
 #ifdef CONFIG_PROC_FS
        create_proc_entry("irlpt_client", 0, proc_irda)->get_info
-                       = irlpt_client_proc_read;
+               = irlpt_client_proc_read;
 #endif /* CONFIG_PROC_FS */
 
        DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
@@ -215,7 +216,6 @@ static void irlpt_client_cleanup(void)
 #ifdef CONFIG_PROC_FS
        remove_proc_entry("irlpt_client", proc_irda);
 #endif
-
        DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
 }
 #endif /* MODULE */
@@ -403,9 +403,8 @@ static void irlpt_client_disconnect_indication( void *instance,
 
        irlpt_client_do_event( self, LMP_DISCONNECT, NULL, NULL);
 
-       if (skb) {
+       if (skb)
                dev_kfree_skb( skb);
-       }
 
        DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
 }
@@ -417,7 +416,8 @@ static void irlpt_client_disconnect_indication( void *instance,
  */
 static void irlpt_client_connect_confirm(void *instance, void *sap, 
                                         struct qos_info *qos, 
-                                        __u32 max_sdu_size,
+                                        __u32 max_seg_size,
+                                        __u8 max_header_size,
                                         struct sk_buff *skb)
 {
        struct irlpt_info info;
@@ -443,14 +443,14 @@ static void irlpt_client_connect_confirm(void *instance, void *sap,
        }
 #endif
 
-       self->irlap_data_size = (qos->data_size.value - IRLPT_MAX_HEADER);
+       self->max_data_size = max_seg_size;
+       self->max_header_size = max_header_size;
        self->connected = TRUE;
        
        irlpt_client_do_event( self, LMP_CONNECT, NULL, NULL);
 
-       if (skb) {
+       if (skb)
                dev_kfree_skb( skb);
-       }
 
        DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
 }
@@ -603,7 +603,7 @@ static void irlpt_client_expired(unsigned long data)
                        return;
                }
 
-               skb_reserve( skb, LMP_CONTROL_HEADER+LAP_HEADER);
+               skb_reserve(skb, LMP_MAX_HEADER);
                irlmp_disconnect_request(self->lsap, skb);
                DEBUG(irlpt_client_debug, __FUNCTION__
                      ": irlmp_close_slap(self->lsap)\n");
index 75598742aa88538a6de2d9f9d69363c1e2a55702..83a2e69915d5aaea3ecb356a6bb182aa69cf1b96 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Jan 12 11:06:00 1999
- * Modified at:   Tue Jan 26 12:02:31 1999
+ * Modified at:   Sun May  9 13:36:13 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998, Thomas Davis, <ratbert@radiks.net>
+ *     Copyright (c) 1998-1999, Thomas Davis, <ratbert@radiks.net>
  *     Copyright (c) 1998, Dag Brattli, <dagb@cs.uit.no>
  *     All Rights Reserved.
  *      
@@ -43,10 +43,10 @@ static int irlpt_client_state_query ( struct irlpt_cb *self,
                                      IRLPT_EVENT event,
                                      struct sk_buff *skb, 
                                      struct irlpt_info *info);
-static int irlpt_client_state_ready  ( struct irlpt_cb *self, 
-                                      IRLPT_EVENT event, 
-                                      struct sk_buff *skb, 
-                                      struct irlpt_info *info);
+static int irlpt_client_state_ready ( struct irlpt_cb *self, 
+                                     IRLPT_EVENT event, 
+                                     struct sk_buff *skb, 
+                                     struct irlpt_info *info);
 static int irlpt_client_state_waiti ( struct irlpt_cb *self, 
                                      IRLPT_EVENT event,
                                      struct sk_buff *skb, 
index b4512736a6da0fe07782b9f7547c1f3cddade6c4..c6401416bb38f25f2e33694b5202392f3d61e844 100644 (file)
@@ -251,18 +251,18 @@ ssize_t irlpt_write(struct file *file, const char *buffer,
        }
 
        DEBUG( irlpt_common_debug, __FUNCTION__ 
-              ": count = %d, irlap_data_size = %d, IRLPT_MAX_HEADER = %d\n",
-               count, self->irlap_data_size, IRLPT_MAX_HEADER);
+              ": count = %d, max_data_size = %d, IRLPT_MAX_HEADER = %d\n",
+               count, self->max_data_size, IRLPT_MAX_HEADER);
 
-       if (count > (self->irlap_data_size - IRLPT_MAX_HEADER)) {
-               count = (self->irlap_data_size - IRLPT_MAX_HEADER);
+       if (count > self->max_data_size) {
+               count = self->max_data_size;
                DEBUG(irlpt_common_debug, __FUNCTION__ 
                      ": setting count to %d\n", count);
        }
 
        DEBUG( irlpt_common_debug, __FUNCTION__ ": count = %d\n", count);
 
-       skb = dev_alloc_skb(count + IRLPT_MAX_HEADER);
+       skb = dev_alloc_skb(count + self->max_header_size);
        if ( skb == NULL) {
                printk( KERN_INFO 
                        __FUNCTION__ ": couldn't allocate skbuff!\n");
@@ -417,7 +417,7 @@ int irlpt_close(struct inode *inode,
                        return 0;
                }
 
-               skb_reserve( skb, LMP_CONTROL_HEADER+LAP_HEADER);
+               skb_reserve( skb, LMP_MAX_HEADER);
                irlmp_disconnect_request(self->lsap, skb);
                DEBUG(irlpt_common_debug, __FUNCTION__
                      ": irlmp_close_slap(self->lsap)\n");
index a1362d0dc600b6a556cbd5988d5fe3e66640810b..12e5867a54344b0a54183eefdd7665685b19b089 100644 (file)
@@ -51,15 +51,21 @@ int irlpt_server_init(void);
 static void irlpt_server_disconnect_indication(void *instance, void *sap, 
                                                LM_REASON reason,
                                                struct sk_buff *skb);
+
+#if 0
 static void irlpt_server_connect_confirm(void *instance, void *sap, 
                                         struct qos_info *qos,  
                                         __u32 max_seg_size,
+                                        __u8 max_header_size,
                                         struct sk_buff *skb);
 static void irlpt_server_connect_indication(void *instance, 
                                            void *sap, 
                                            struct qos_info *qos, 
                                            __u32 max_seg_size,
+                                           __u8 max_header_size,
                                            struct sk_buff *skb);
+#endif
+
 static int irlpt_server_data_indication(void *instance, void *sap, 
                                        struct sk_buff *skb);
 static void register_irlpt_server(void);
@@ -161,7 +167,6 @@ static int irlpt_server_proc_read(char *buf, char **start, off_t offset,
 }
 
 extern struct proc_dir_entry *proc_irda;
-
 #endif /* CONFIG_PROC_FS */
 
 /*
@@ -171,9 +176,9 @@ extern struct proc_dir_entry *proc_irda;
  *
  */
 
-/*int irlpt_init( struct device *dev) {*/
 __initfunc(int irlpt_server_init(void))
 {
+       struct irmanager_event mgr_event;
        __u16 hints;
 
        DEBUG( irlpt_server_debug, "--> " __FUNCTION__ "\n");
@@ -212,6 +217,10 @@ __initfunc(int irlpt_server_init(void))
                = irlpt_server_proc_read;
 #endif /* CONFIG_PROC_FS */
 
+       mgr_event.event = EVENT_IRLPT_START;
+        sprintf(mgr_event.devname, "%s", irlpt_server->ifname);
+        irmanager_notify(&mgr_event);
+
        DEBUG( irlpt_server_debug, __FUNCTION__ " -->\n");
 
        return 0;
@@ -225,6 +234,7 @@ __initfunc(int irlpt_server_init(void))
  */
 static void irlpt_server_cleanup(void)
 {
+       struct irmanager_event mgr_event;
        struct sk_buff *skb;
 
        DEBUG( irlpt_server_debug, "--> " __FUNCTION__ "\n");
@@ -245,6 +255,10 @@ static void irlpt_server_cleanup(void)
        remove_proc_entry("irlpt_server", proc_irda);
 #endif
 
+        mgr_event.event = EVENT_IRLPT_STOP;
+        sprintf( mgr_event.devname, "%s", irlpt_server->ifname);
+        irmanager_notify( &mgr_event);
        DEBUG( irlpt_server_debug, __FUNCTION__ " -->\n");
 }
 
@@ -304,6 +318,7 @@ static void irlpt_server_connect_confirm(void *instance,
                                         void *sap, 
                                         struct qos_info *qos,
                                         __u32 max_seg_size,
+                                        __u8 max_header_size,
                                         struct sk_buff *skb)
 {
        struct irlpt_cb *self;
@@ -314,6 +329,9 @@ static void irlpt_server_connect_confirm(void *instance,
        ASSERT( self != NULL, return;);
        ASSERT( self->magic == IRLPT_MAGIC, return;);
 
+       self->max_data_size = max_seg_size;
+       self->max_header_size = max_header_size;
+
        self->connected = TRUE;
 
        irlpt_server_do_event( self, LMP_CONNECT, NULL, NULL);
@@ -329,6 +347,7 @@ static void irlpt_server_connect_indication(void *instance,
                                            void *sap, 
                                            struct qos_info *qos, 
                                            __u32 max_seg_size,
+                                           __u8 max_header_size,
                                            struct sk_buff *skb)
 {
        struct irlpt_cb *self;
@@ -343,14 +362,16 @@ static void irlpt_server_connect_indication(void *instance,
        ASSERT( self != NULL, return;);
        ASSERT( self->magic == IRLPT_MAGIC, return;);
 
+       self->max_data_size = max_seg_size;
+       self->max_header_size = max_header_size;
+
        self->connected = IRLPT_CONNECTED;
        self->eof = FALSE;
 
        irlpt_server_do_event( self, LMP_CONNECT, NULL, &info);
 
-       if (skb) {
+       if (skb)
                dev_kfree_skb( skb);
-       }
 
        DEBUG( irlpt_server_debug, __FUNCTION__ " -->\n");
 }
index 88d61c2cd62bca7850d4e7be3a6e28f0078fc29f..445a645a052b71d850ec44ea0ac31f48764b3b0a 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Dec 15 13:55:39 1997
- * Modified at:   Mon Apr 12 11:31:01 1999
+ * Modified at:   Mon May 10 15:28:49 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1997 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1997, 1999 Dag Brattli, All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -110,6 +110,7 @@ EXPORT_SYMBOL(irttp_disconnect_request);
 EXPORT_SYMBOL(irttp_flow_request);
 EXPORT_SYMBOL(irttp_connect_request);
 EXPORT_SYMBOL(irttp_udata_request);
+EXPORT_SYMBOL(irttp_dup);
 
 /* Main IrDA module */
 #ifdef CONFIG_IRDA_DEBUG
@@ -151,6 +152,7 @@ EXPORT_SYMBOL(irlmp_connect_response);
 EXPORT_SYMBOL(irlmp_disconnect_request);
 EXPORT_SYMBOL(irlmp_get_daddr);
 EXPORT_SYMBOL(irlmp_get_saddr);
+EXPORT_SYMBOL(irlmp_dup);
 EXPORT_SYMBOL(lmp_reasons);
 
 /* Queue */
@@ -174,10 +176,15 @@ EXPORT_SYMBOL(irda_device_close);
 EXPORT_SYMBOL(irda_device_setup);
 EXPORT_SYMBOL(irda_device_set_media_busy);
 EXPORT_SYMBOL(irda_device_txqueue_empty);
+
+EXPORT_SYMBOL(irda_device_init_dongle);
+EXPORT_SYMBOL(irda_device_register_dongle);
+EXPORT_SYMBOL(irda_device_unregister_dongle);
+
 EXPORT_SYMBOL(async_wrap_skb);
 EXPORT_SYMBOL(async_unwrap_char);
 EXPORT_SYMBOL(irda_start_timer);
-EXPORT_SYMBOL(irda_get_mtt);
+/* EXPORT_SYMBOL(irda_get_mtt); */
 EXPORT_SYMBOL(setup_dma);
 
 #ifdef CONFIG_IRTTY
@@ -505,19 +512,28 @@ void irda_mod_dec_use_count(void)
 #endif
 }
 
-#ifdef MODULE
-#ifdef CONFIG_PROC_FS
+/*
+ * Function irda_proc_modcount (inode, fill)
+ *
+ *    Use by the proc file system functions to prevent the irda module
+ *    being removed while the use is standing in the net/irda directory
+ */
 void irda_proc_modcount(struct inode *inode, int fill)
 {
+#ifdef MODULE
+#ifdef CONFIG_PROC_FS
        if (fill)
                MOD_INC_USE_COUNT;
        else
                MOD_DEC_USE_COUNT;
-}
 #endif /* CONFIG_PROC_FS */
+#endif /* MODULE */
+}
+
+#ifdef MODULE
 
 MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
-MODULE_DESCRIPTION("The Linux IrDA protocol subsystem"); 
+MODULE_DESCRIPTION("The Linux IrDA Protocol Subsystem"); 
 MODULE_PARM(irda_debug, "1l");
 
 /*
index f3b710b95324e2955a35d5435b457c6fb5e14ca5..a04951694167e52d978dd26cc92999d5f53e1165 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Thomas Davis, <ratbert@radiks.net>
  * Created at:    Sat Feb 21 21:33:24 1998
- * Modified at:   Tue Apr  6 19:07:06 1999
+ * Modified at:   Fri May  7 08:06:49 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998, Thomas Davis, <ratbert@radiks.net>, 
+ *     Copyright (c) 1998-1999, Thomas Davis, <ratbert@radiks.net>, 
  *     All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
@@ -20,8 +20,6 @@
  *     I, Thomas Davis, provide no warranty for any of this software. 
  *     This material is provided "AS-IS" and at no charge. 
  *     
- *     Portions lifted from the linux/fs/procfs/ files.
- *
  ********************************************************************/
 
 #include <linux/miscdevice.h>
@@ -44,28 +42,27 @@ extern int irias_proc_read(char *buf, char **start, off_t offset, int len,
                           int unused);
 extern int discovery_proc_read(char *buf, char **start, off_t offset, int len, 
                               int unused);
+static int proc_discovery_read(char *buf, char **start, off_t offset, int len,
+                              int unused);
 
-enum irda_directory_inos {
-       PROC_IRDA_LAP = 1,
-       PROC_IRDA_LMP,
-       PROC_IRDA_TTP,
-       PROC_IRDA_LPT,
-       PROC_IRDA_COMM,
-       PROC_IRDA_IRDA_DEVICE,
-       PROC_IRDA_IRIAS
-};
+/* enum irda_directory_inos { */
+/*     PROC_IRDA_LAP = 1, */
+/*     PROC_IRDA_LMP, */
+/*     PROC_IRDA_TTP, */
+/*     PROC_IRDA_LPT, */
+/*     PROC_IRDA_COMM, */
+/*     PROC_IRDA_IRDA_DEVICE, */
+/*     PROC_IRDA_IRIAS */
+/* }; */
 
 struct irda_entry {
        char *name;
-       int (*fn)(char*,char**,off_t,int,int);
+       int (*fn)(char*, char**, off_t, int, int);
 };
 
 struct proc_dir_entry *proc_irda;
-
 static struct irda_entry dir[] = {
-#if 0 
-       {"lpt", irlpt_proc_read},
-#endif
        {"discovery",   discovery_proc_read},
        {"irda_device", irda_device_proc_read},
        {"irttp",       irttp_proc_read},
@@ -75,19 +72,22 @@ static struct irda_entry dir[] = {
 };
 
 #define IRDA_ENTRIES_NUM (sizeof(dir)/sizeof(dir[0]))
-
 /*
  * Function irda_proc_register (void)
  *
  *    Register irda entry in /proc file system
  *
  */
-void irda_proc_register(void) {
+void irda_proc_register(void) 
+{
        int i;
+
        proc_irda = create_proc_entry("net/irda", S_IFDIR, NULL);
 #ifdef MODULE
        proc_irda->fill_inode = &irda_proc_modcount;
 #endif /* MODULE */
+
        for (i=0;i<IRDA_ENTRIES_NUM;i++)
                create_proc_entry(dir[i].name,0,proc_irda)->get_info=dir[i].fn;
 }
@@ -98,9 +98,14 @@ void irda_proc_register(void) {
  *    Unregister irda entry in /proc file system
  *
  */
-void irda_proc_unregister(void) {
+void irda_proc_unregister(void) 
+{
        int i;
+
        for (i=0;i<IRDA_ENTRIES_NUM;i++)
                remove_proc_entry(dir[i].name, proc_irda);
+
        remove_proc_entry("net/irda", NULL);
 }
+
+
index 0b9a4f1893cff23505927f58ea842c17fe011604..e82c2edd3c768606209803e64faed85e37e82c11 100644 (file)
@@ -1,15 +1,15 @@
 /*********************************************************************
  *                
  * Filename:      irsysctl.c
- * Version:       
- * Description:   
+ * Version:       1.0
+ * Description:   Sysctl interface for IrDA
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun May 24 22:12:06 1998
- * Modified at:   Fri Apr 23 09:46:38 1999
+ * Modified at:   Thu May  6 21:32:46 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1997 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1997, 1999 Dag Brattli, All Rights Reserved.
  *      
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
index bf0624eee0f926cfa2dd0984b5a568225b82da50..23b2a256e94553d5a54b6e6444eb61ef8ccffca3 100644 (file)
@@ -6,10 +6,10 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:31 1997
- * Modified at:   Sat Apr 10 10:32:21 1999
+ * Modified at:   Mon May 10 17:12:53 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
  *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
@@ -48,8 +48,10 @@ static void irttp_disconnect_indication(void *instance, void *sap,
                                        struct sk_buff *);
 static void irttp_connect_indication(void *instance, void *sap, 
                                     struct qos_info *qos, __u32 max_sdu_size,
-                                    struct sk_buff *skb);
-
+                                    __u8 header_size, struct sk_buff *skb);
+static void irttp_connect_confirm(void *instance, void *sap, 
+                                 struct qos_info *qos, __u32 max_sdu_size, 
+                                 __u8 header_size, struct sk_buff *skb);
 static void irttp_run_tx_queue(struct tsap_cb *self);
 static void irttp_run_rx_queue(struct tsap_cb *self);
 
@@ -337,6 +339,7 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
        /* Queue frame, or queue frame segments */
        if ((self->tx_max_sdu_size == 0) || (skb->len < self->max_seg_size)) {
                /* Queue frame */
+               ASSERT(skb_headroom(skb) >= TTP_HEADER, return -1;);
                frame = skb_push(skb, TTP_HEADER);
                frame[0] = 0x00; /* Clear more bit */
                
@@ -360,8 +363,8 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
                self->tx_sdu_busy = TRUE;
                
                if (self->notify.flow_indication) {
-                       self->notify.flow_indication(
-                               self->notify.instance, self, FLOW_STOP);
+                       self->notify.flow_indication(self->notify.instance, 
+                                                    self, FLOW_STOP);
                }
        }
        
@@ -472,7 +475,7 @@ void irttp_give_credit(struct tsap_cb *self)
                return;
 
        /* Reserve space for LMP, and LAP header */
-       skb_reserve(tx_skb, LMP_HEADER+LAP_HEADER);
+       skb_reserve(tx_skb, self->max_header_size);
 
        /*
         *  Since we can transmit and receive frames concurrently, 
@@ -655,15 +658,14 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
                        return -ENOMEM;
                
                /* Reserve space for MUX_CONTROL and LAP header */
-               skb_reserve(skb, (TTP_HEADER+LMP_CONTROL_HEADER+LAP_HEADER));
+               skb_reserve(skb, TTP_MAX_HEADER);
        } else {
                skb = userdata;
                /*  
                 *  Check that the client has reserved enough space for 
                 *  headers
                 */
-               ASSERT(skb_headroom(userdata) >= 
-                      (TTP_HEADER+LMP_CONTROL_HEADER+LAP_HEADER), return -1;);
+               ASSERT(skb_headroom(userdata) >= TTP_MAX_HEADER, return -1;);
        }
 
        /* Initialize connection parameters */
@@ -691,12 +693,11 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
 
        /* SAR enabled? */
        if (max_sdu_size > 0) {
-               ASSERT(skb_headroom(skb) >= 
-                       (TTP_HEADER_WITH_SAR+LMP_CONTROL_HEADER+LAP_HEADER), 
-                       return -1;);
+               ASSERT(skb_headroom(skb) >= (TTP_MAX_HEADER + TTP_SAR_HEADER), 
+                      return -1;);
 
                /* Insert SAR parameters */
-               frame = skb_push(skb, TTP_HEADER_WITH_SAR);
+               frame = skb_push(skb, TTP_HEADER+TTP_SAR_HEADER);
                
                frame[0] = TTP_PARAMETERS | n; 
                frame[1] = 0x04; /* Length */
@@ -724,8 +725,10 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
  *    Sevice user confirms TSAP connection with peer. 
  *
  */
-void irttp_connect_confirm(void *instance, void *sap, struct qos_info *qos,
-                          __u32 max_seg_size, struct sk_buff *skb) 
+static void irttp_connect_confirm(void *instance, void *sap, 
+                                 struct qos_info *qos,
+                                 __u32 max_seg_size, __u8 max_header_size,
+                                 struct sk_buff *skb) 
 {
        struct tsap_cb *self;
        int parameters;
@@ -741,7 +744,8 @@ void irttp_connect_confirm(void *instance, void *sap, struct qos_info *qos,
        ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
        ASSERT(skb != NULL, return;);
 
-       self->max_seg_size = max_seg_size-LMP_HEADER-LAP_HEADER;
+       self->max_seg_size = max_seg_size;
+       self->max_header_size = max_header_size + TTP_HEADER;
 
        /*
         *  Check if we have got some QoS parameters back! This should be the
@@ -797,9 +801,9 @@ void irttp_connect_confirm(void *instance, void *sap, struct qos_info *qos,
        skb_pull(skb, TTP_HEADER);
 
        if (self->notify.connect_confirm) {
-               self->notify.connect_confirm(self->notify.instance, self, 
-                                            qos, self->tx_max_sdu_size, 
-                                            skb);
+               self->notify.connect_confirm(self->notify.instance, self, qos,
+                                            self->tx_max_sdu_size, 
+                                            self->max_header_size, skb);
        }
 }
 
@@ -809,8 +813,8 @@ void irttp_connect_confirm(void *instance, void *sap, struct qos_info *qos,
  *    Some other device is connecting to this TSAP
  *
  */
-void irttp_connect_indication(void *instance, void *sap, 
-                             struct qos_info *qos, __u32 max_seg_size, 
+void irttp_connect_indication(void *instance, void *sap, struct qos_info *qos,
+                             __u32 max_seg_size,  __u8 max_header_size, 
                              struct sk_buff *skb) 
 {
        struct tsap_cb *self;
@@ -828,7 +832,9 @@ void irttp_connect_indication(void *instance, void *sap,
 
        lsap = (struct lsap_cb *) sap;
 
-       self->max_seg_size = max_seg_size-LMP_HEADER-LAP_HEADER;
+       self->max_seg_size = max_seg_size;
+
+       self->max_header_size = max_header_size+TTP_HEADER;
 
        DEBUG(4, __FUNCTION__ "(), TSAP sel=%02x\n", self->stsap_sel);
 
@@ -850,7 +856,7 @@ void irttp_connect_indication(void *instance, void *sap,
 
                switch (pl) {
                case 1:
-                       self->tx_max_sdu_size = *(frame+4);
+                       self->tx_max_sdu_size = frame[4];
                        break;
                case 2:
                        self->tx_max_sdu_size = 
@@ -878,7 +884,7 @@ void irttp_connect_indication(void *instance, void *sap,
        if (self->notify.connect_indication) {
                self->notify.connect_indication(self->notify.instance, self, 
                                                qos, self->rx_max_sdu_size, 
-                                               skb);
+                                               self->max_header_size, skb);
        }
 }
 
@@ -909,15 +915,14 @@ void irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size,
                        return;
 
                /* Reserve space for MUX_CONTROL and LAP header */
-               skb_reserve(skb, (TTP_HEADER+LMP_CONTROL_HEADER+LAP_HEADER));
+               skb_reserve(skb, TTP_MAX_HEADER);
        } else {
                skb = userdata;
                /*  
                 *  Check that the client has reserved enough space for 
                 *  headers
                 */
-               ASSERT(skb_headroom(skb) >= 
-                       (TTP_HEADER+LMP_CONTROL_HEADER+LAP_HEADER), return;);
+               ASSERT(skb_headroom(skb) >= TTP_MAX_HEADER, return;);
        }
        
        self->avail_credit = 0;
@@ -939,12 +944,11 @@ void irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size,
 
        /* SAR enabled? */
        if (max_sdu_size > 0) {
-               ASSERT(skb_headroom(skb) >= 
-                      (TTP_HEADER_WITH_SAR+LMP_CONTROL_HEADER+LAP_HEADER), 
+               ASSERT(skb_headroom(skb) >= (TTP_MAX_HEADER+TTP_SAR_HEADER), 
                       return;);
                
                /* Insert TTP header with SAR parameters */
-               frame = skb_push(skb, TTP_HEADER_WITH_SAR);
+               frame = skb_push(skb, TTP_HEADER+TTP_SAR_HEADER);
                
                frame[0] = TTP_PARAMETERS | n;
                frame[1] = 0x04; /* Length */
@@ -1079,7 +1083,7 @@ void irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata,
                /* 
                 *  Reserve space for MUX and LAP header 
                 */
-               skb_reserve(skb, LMP_CONTROL_HEADER+LAP_HEADER);
+               skb_reserve(skb, TTP_MAX_HEADER);
                
                userdata = skb;
        }
@@ -1357,13 +1361,11 @@ static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb)
                }
                
                /* Make new segment */
-               frag = dev_alloc_skb(self->max_seg_size+
-                                     TTP_HEADER+LMP_HEADER+
-                                     LAP_HEADER);
+               frag = dev_alloc_skb(self->max_seg_size+self->max_header_size);
                if (!frag)
                        return;
 
-               skb_reserve(frag, LMP_HEADER+LAP_HEADER);
+               skb_reserve(frag, self->max_header_size);
 
                /*
                 *  Copy data from the original skb into this fragment. We
index 7b226dfa6481dad5710d39b39395ca62909d4968..82f7fc28a70d9a4ad9d4e2d07ae0f8adaa08619f 100644 (file)
@@ -6,10 +6,11 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Sep  9 00:00:26 1997
- * Modified at:   Mon Apr 12 11:49:24 1999
+ * Modified at:   Mon May  3 21:15:08 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
+ *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
  *     modify it under the terms of the GNU General Public License as 
@@ -52,10 +53,10 @@ int compression[] = { CI_BZIP2, CI_DEFLATE, CI_DEFLATE_DRAFT };
  *    Compute the intersection of the old QoS capabilites with new ones
  *
  */
-void irda_qos_compute_intersection( struct qos_info *qos, struct qos_info *new)
+void irda_qos_compute_intersection(struct qos_info *qos, struct qos_info *new)
 {
-       ASSERT( qos != NULL, return;);
-       ASSERT( new != NULL, return;);
+       ASSERT(qos != NULL, return;);
+       ASSERT(new != NULL, return;);
 
        /* Apply */
        qos->baud_rate.bits       &= new->baud_rate.bits;
index c4822e2c6e8655bb9531ff4066678bcc4130b921..b78368bc0e69c17d7da206ce9576c063fa75467f 100644 (file)
@@ -1,15 +1,15 @@
 /*********************************************************************
  *                
  * Filename:      wrapper.c
- * Version:       1.1
- * Description:   SIR wrapper layer
+ * Version:       1.2
+ * Description:   IrDA SIR async wrapper layer
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Wed Apr 21 12:45:55 1999
+ * Modified at:   Sun May  2 21:58:00 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
- *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
+ *     Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, 
  *     All Rights Reserved.
  *     
  *     This program is free software; you can redistribute it and/or 
 #include <net/irda/irlap_frame.h>
 #include <net/irda/irda_device.h>
 
-inline static int stuff_byte(__u8 byte, __u8 *buf);
+static inline int stuff_byte(__u8 byte, __u8 *buf);
+
+static void state_outside_frame(struct irda_device *idev, __u8 byte);
+static void state_begin_frame(struct irda_device *idev, __u8 byte);
+static void state_link_escape(struct irda_device *idev, __u8 byte);
+static void state_inside_frame(struct irda_device *idev, __u8 byte);
+
+static void (*state[])(struct irda_device *idev, __u8 byte) = 
+{ 
+       state_outside_frame,
+       state_begin_frame,
+       state_link_escape,
+       state_inside_frame,
+};
 
 /*
  * Function async_wrap (skb, *tx_buff)
@@ -52,8 +65,6 @@ int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize)
                __u8 bytes[2];
        } fcs;
 
-       ASSERT(skb != NULL, return 0;);
-
        /* Initialize variables */
        fcs.value = INIT_FCS;
        n = 0;
@@ -74,13 +85,9 @@ int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize)
        } else
                xbofs = ((struct irlap_skb_cb *)(skb->cb))->xbofs;
 
-#if 0
-       for (i=0; i<xbofs; i++)
-               tx_buff[n++] = XBOF;
-#else
        memset(tx_buff+n, XBOF, xbofs);
        n += xbofs;
-#endif
+
        /* Start of packet character BOF */
        tx_buff[n++] = BOF;
 
@@ -94,7 +101,7 @@ int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize)
                ASSERT(n < (buffsize-5), return n;);
 
                n += stuff_byte(skb->data[i], tx_buff+n);
-               fcs.value = IR_FCS(fcs.value, skb->data[i]);
+               fcs.value = irda_fcs(fcs.value, skb->data[i]);
        }
        
        /* Insert CRC in little endian format (LSB first) */
@@ -108,15 +115,6 @@ int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize)
 #endif
        tx_buff[n++] = EOF;
 
-#if 0
-       {
-               int i;
-               
-               for (i=0;i<n;i++)
-                       printk("%02x", tx_buff[i]);
-               printk("\n");
-       }
-#endif
        return n;
 }
 
@@ -154,140 +152,6 @@ static inline void async_bump(struct irda_device *idev, __u8 *buf, int len)
        idev->stats.rx_bytes += skb->len;       
 }
 
-/*
- * Function async_unwrap (skb)
- *
- *    Parse and de-stuff frame received from the IR-port
- *
- */
-void async_unwrap_char(struct irda_device *idev, __u8 byte) 
-{
-       /* State machine for receiving frames */           
-       switch (idev->rx_buff.state) {
-       case OUTSIDE_FRAME:
-               switch(byte) {
-               case BOF:
-                       idev->rx_buff.state = BEGIN_FRAME;
-                       idev->rx_buff.in_frame = TRUE;
-                       break;
-               case XBOF:
-                       /* idev->xbofs++; */
-                       break;
-               case EOF:
-                       irda_device_set_media_busy( idev, TRUE);
-                       break;
-               default:
-                       break;
-               }
-               break;
-       case BEGIN_FRAME:
-               switch (byte) {
-               case BOF:
-                       /* Continue */
-                       break;
-               case CE:
-                       /* Stuffed byte */
-                       idev->rx_buff.state = LINK_ESCAPE;
-                       break;
-               case EOF:
-                       /* Abort frame */
-                       idev->rx_buff.state = OUTSIDE_FRAME;
-
-                       idev->stats.rx_errors++;
-                       idev->stats.rx_frame_errors++;
-                       break;
-               default:
-                       /* Got first byte of frame */
-                       idev->rx_buff.data = idev->rx_buff.head;
-                       idev->rx_buff.len = 0;
-
-                       idev->rx_buff.data[idev->rx_buff.len++] = byte;
-                       
-                       idev->rx_buff.fcs = IR_FCS(INIT_FCS, byte);
-                       idev->rx_buff.state = INSIDE_FRAME;
-                       break;
-               }
-               break;
-       case LINK_ESCAPE:
-               switch (byte) {
-               case BOF:
-                       /* New frame? */
-                       idev->rx_buff.state = BEGIN_FRAME;
-                       irda_device_set_media_busy(idev, TRUE);
-                       break;
-               case CE:
-                       DEBUG(4, "WARNING: State not defined\n");
-                       break;
-               case EOF:
-                       /* Abort frame */
-                       idev->rx_buff.state = OUTSIDE_FRAME;
-                       break;
-               default:
-                       /* 
-                        *  Stuffed char, complement bit 5 of byte 
-                        *  following CE, IrLAP p.114 
-                        */
-                       byte ^= IR_TRANS;
-                       if (idev->rx_buff.len < idev->rx_buff.truesize)  {
-                               idev->rx_buff.data[idev->rx_buff.len++] = byte;
-                               idev->rx_buff.fcs = IR_FCS(idev->rx_buff.fcs,
-                                                          byte);
-                               idev->rx_buff.state = INSIDE_FRAME;
-                       } else {
-                               DEBUG(1, __FUNCTION__ 
-                                      "(), Rx buffer overflow, aborting\n");
-                               idev->rx_buff.state = OUTSIDE_FRAME;
-                       }
-                       break;
-               }
-               break;
-       case INSIDE_FRAME:
-               switch (byte) {
-               case BOF:
-                       /* New frame? */
-                       idev->rx_buff.state = BEGIN_FRAME;
-                       irda_device_set_media_busy(idev, TRUE);
-                       break;
-               case CE:
-                       /* Stuffed char */
-                       idev->rx_buff.state = LINK_ESCAPE;
-                       break;
-               case EOF:
-                       /* End of frame */
-                       idev->rx_buff.state = OUTSIDE_FRAME;
-                       idev->rx_buff.in_frame = FALSE;
-                       
-                       /* 
-                        *  Test FCS and deliver frame if it's good
-                        */                     
-                       if (idev->rx_buff.fcs == GOOD_FCS) {
-                               async_bump(idev, idev->rx_buff.data, 
-                                          idev->rx_buff.len);
-                       } else {
-                               /* Wrong CRC, discard frame!  */
-                               irda_device_set_media_busy(idev, TRUE); 
-
-                               idev->stats.rx_errors++;
-                               idev->stats.rx_crc_errors++;
-                       }                       
-                       break;
-               default:
-                       /* Next byte of frame */
-                       if (idev->rx_buff.len < idev->rx_buff.truesize)  {
-                               idev->rx_buff.data[idev->rx_buff.len++] = byte;
-                               idev->rx_buff.fcs = IR_FCS(idev->rx_buff.fcs,
-                                                          byte);
-                       } else {
-                               DEBUG(1, __FUNCTION__ 
-                                     "(), Rx buffer overflow, aborting\n");
-                               idev->rx_buff.state = OUTSIDE_FRAME;
-                       }
-                       break;
-               }
-               break;
-       }
-}
 /*
  * Function stuff_byte (byte, buf)
  *
@@ -295,7 +159,7 @@ void async_unwrap_char(struct irda_device *idev, __u8 byte)
  *    buf. The buffer must at all times be able to have two bytes inserted.
  * 
  */
-inline static int stuff_byte(__u8 byte, __u8 *buf) 
+static inline int stuff_byte(__u8 byte, __u8 *buf) 
 {
        switch (byte) {
        case BOF: /* FALLTHROUGH */
@@ -303,7 +167,7 @@ inline static int stuff_byte(__u8 byte, __u8 *buf)
        case CE:
                /* Insert transparently coded */
                buf[0] = CE;               /* Send link escape */
-               buf[1] = byte^IR_TRANS;    /* Complement bit 5 */
+               buf[1] = byte^IRDA_TRANS;    /* Complement bit 5 */
                return 2;
                /* break; */
        default:
@@ -313,7 +177,159 @@ inline static int stuff_byte(__u8 byte, __u8 *buf)
                /* break; */
        }
 }
+
+/*
+ * Function async_unwrap (skb)
+ *
+ *    Parse and de-stuff frame received from the IrDA-port
+ *
+ */
+inline void async_unwrap_char(struct irda_device *idev, __u8 byte)
+{
+       (*state[idev->rx_buff.state]) (idev, byte);
+}
         
+/*
+ * Function state_outside_frame (idev, byte)
+ *
+ *    
+ *
+ */
+static void state_outside_frame(struct irda_device *idev, __u8 byte)
+{
+       switch (byte) {
+       case BOF:
+               idev->rx_buff.state = BEGIN_FRAME;
+               idev->rx_buff.in_frame = TRUE;
+               break;
+       case XBOF:
+               /* idev->xbofs++; */
+               break;
+       case EOF:
+               irda_device_set_media_busy( idev, TRUE);
+               break;
+       default:
+               break;
+       }
+}
 
+/*
+ * Function state_begin_frame (idev, byte)
+ *
+ *    
+ *
+ */
+static void state_begin_frame(struct irda_device *idev, __u8 byte)
+{
+       switch (byte) {
+       case BOF:
+               /* Continue */
+               break;
+       case CE:
+               /* Stuffed byte */
+               idev->rx_buff.state = LINK_ESCAPE;
+               break;
+       case EOF:
+               /* Abort frame */
+               idev->rx_buff.state = OUTSIDE_FRAME;
+               
+               idev->stats.rx_errors++;
+               idev->stats.rx_frame_errors++;
+               break;
+       default:
+               /* Got first byte of frame */
+               idev->rx_buff.data = idev->rx_buff.head;
+               idev->rx_buff.len = 0;
+               
+               idev->rx_buff.data[idev->rx_buff.len++] = byte;
+               
+               idev->rx_buff.fcs = irda_fcs(INIT_FCS, byte);
+               idev->rx_buff.state = INSIDE_FRAME;
+               break;
+       }
+}
+
+/*
+ * Function state_link_escape (idev, byte)
+ *
+ *    
+ *
+ */
+static void state_link_escape(struct irda_device *idev, __u8 byte)
+{
+       switch (byte) {
+       case BOF: /* New frame? */
+               idev->rx_buff.state = BEGIN_FRAME;
+               irda_device_set_media_busy(idev, TRUE);
+               break;
+       case CE:
+               DEBUG(4, "WARNING: State not defined\n");
+               break;
+       case EOF: /* Abort frame */
+               idev->rx_buff.state = OUTSIDE_FRAME;
+               break;
+       default:
+               /* 
+                *  Stuffed char, complement bit 5 of byte 
+                *  following CE, IrLAP p.114 
+                */
+               byte ^= IRDA_TRANS;
+               if (idev->rx_buff.len < idev->rx_buff.truesize)  {
+                       idev->rx_buff.data[idev->rx_buff.len++] = byte;
+                       idev->rx_buff.fcs = irda_fcs(idev->rx_buff.fcs, byte);
+                       idev->rx_buff.state = INSIDE_FRAME;
+               } else {
+                       DEBUG(1, __FUNCTION__ 
+                             "(), Rx buffer overflow, aborting\n");
+                       idev->rx_buff.state = OUTSIDE_FRAME;
+               }
+               break;
+       }
+}
+
+/*
+ * Function state_inside_frame (idev, byte)
+ *
+ *    
+ *
+ */
+static void state_inside_frame(struct irda_device *idev, __u8 byte)
+{
+       switch (byte) {
+       case BOF: /* New frame? */
+               idev->rx_buff.state = BEGIN_FRAME;
+               irda_device_set_media_busy(idev, TRUE);
+               break;
+       case CE: /* Stuffed char */
+               idev->rx_buff.state = LINK_ESCAPE;
+               break;
+       case EOF: /* End of frame */
+               idev->rx_buff.state = OUTSIDE_FRAME;
+               idev->rx_buff.in_frame = FALSE;
+               
+               /* Test FCS and deliver frame if it's good */
+               if (idev->rx_buff.fcs == GOOD_FCS) {
+                       async_bump(idev, idev->rx_buff.data, 
+                                  idev->rx_buff.len);
+               } else {
+                       /* Wrong CRC, discard frame!  */
+                       irda_device_set_media_busy(idev, TRUE); 
+                       
+                       idev->stats.rx_errors++;
+                       idev->stats.rx_crc_errors++;
+               }                       
+               break;
+       default: /* Must be the next byte of the frame */
+               if (idev->rx_buff.len < idev->rx_buff.truesize)  {
+                       idev->rx_buff.data[idev->rx_buff.len++] = byte;
+                       idev->rx_buff.fcs = irda_fcs(idev->rx_buff.fcs, byte);
+               } else {
+                       DEBUG(1, __FUNCTION__ 
+                             "(), Rx buffer overflow, aborting\n");
+                       idev->rx_buff.state = OUTSIDE_FRAME;
+               }
+               break;
+       }
+}