- 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
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,
# 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
# 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
# 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
-/* $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
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 {
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
-/* $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)
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();
}
}
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
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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];
+/* $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 */
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
-/*
+/*
* 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
* 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 */
#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
*/
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
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)
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);
}
-/* 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
--- /dev/null
+#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
# 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
# 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
-/* $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)
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
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
-/*
- * 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."
#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 { \
_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
#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 { \
_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. */
#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 */
--- /dev/null
+/* 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 */
+/* $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;
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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];
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
-
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
+/* $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;
}
-/* $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
#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 *);
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)
}
freg = ((insn >> 25) & 0x1f);
switch ((type >> 4) & 0x3) {
- case 0: rd = (void *)(((long)¤t->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;
-/*
- * 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)
#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 */
#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)
-/*
- * 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)
-/*
- * 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)
--- /dev/null
+/* 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)
+
+/* 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; \
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; \
_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; \
\
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
*/
#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)); \
_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 \
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); \
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; \
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.
*/
_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 \
_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; \
} \
{ \
/* +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 */ \
\
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: \
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; \
\
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: \
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 \
{ \
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; \
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)
* 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 { \
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 \
{ \
{ \
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) \
\
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); \
\
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)); \
} \
-/*
- * 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)
#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 { \
_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
#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 { \
_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 */
-/* 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
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)
--- /dev/null
+/* $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
-/*
- * 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."
#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 { \
_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)
+/* 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. */
typedef USItype UHWtype;
#endif
+#ifndef umul_ppmm
+#include <stdlib/longlong.h>
+#endif
+
#endif
+++ /dev/null
-/* 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;
-}
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);
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 */
{ 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))
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),
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);
#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
#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
/*
* 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
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;
* 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>
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;
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;
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 --
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);
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
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
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
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:
/*********************************************************************
*
* 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};
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");
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;
}
* 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 */
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]);
}
/*
* 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;
}
* 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 */
*/
int init_module(void)
{
- actisys_init();
- return(0);
+ return actisys_init();
}
/*
/*********************************************************************
*
* 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,
__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;
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;
}
* 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)
* 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)
*
/*********************************************************************
*
* 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.
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;
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;
}
*/
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);
}
/*
*/
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);
}
/*
*/
int init_module(void)
{
- girbil_init();
- return(0);
+ return girbil_init();
}
/*
#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);
/* 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;
}
/*
* 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);
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)
*
*/
int init_module(void)
{
- if (irport_init() < 0) {
- cleanup_module();
- return 1;
- }
- return(0);
+ return irport_init();
}
#endif /* MODULE */
* 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);
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));
* function to hashbin_destroy().
*/
hashbin_delete(irtty, NULL);
- hashbin_delete(dongles, NULL);
}
#endif /* MODULE */
/* 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);
/* 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 */
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);
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)
*
break;
case IRTTY_IOCTDONGLE:
/* Initialize dongle */
- irtty_init_dongle(self, (int) arg);
+ irda_device_init_dongle(&self->idev, (int) arg);
break;
default:
return -ENOIOCTLCMD;
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
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 */
MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
MODULE_DESCRIPTION("IrDA TTY device driver");
+MODULE_PARM(qos_mtt_bits, "i");
+
/*
* Function init_module (void)
*
--- /dev/null
+/*********************************************************************
+ *
+ * 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
* 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
#define BROKEN_DONGLE_ID
static char *driver_name = "pc87108";
+static int qos_mtt_bits = 0x07; /* 1 ms or more */
#define CHIP_IO_EXTENT 8
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;
* 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");
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;
}
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 */
*
*
*/
-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;
/* 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) {
}
/* 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 {
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;
#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)
*
/*********************************************************************
*
* 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
__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");
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;
}
* 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);
}
/*
* 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);
--- /dev/null
+/*********************************************************************
+ *
+ * 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
* 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
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);
#ifdef MODULE
static int uircc_close(struct irda_device *idev)
{
+ struct uircc_cb *self;
int iobase;
int status;
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);
/* 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);
}
irda_device_close(idev);
+ kfree(self);
+
return 0;
}
#endif /* MODULE */
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);
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);
/*********************************************************************
*
* 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
********************************************************************/
#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 ()
*/
__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;
{
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 */
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;
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 */
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;
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;
}
*/
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();
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;
}
int version;
DEBUG( 0, __FUNCTION__ "()\n");
-
+#ifdef CONFIG_USE_W977_PNP
/* Enter PnP configuration mode */
w977_efm_enter();
/* 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);
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)) {
}
/* 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.
* 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);
* 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;
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");
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);
}
/*
* 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;
/* 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);
switch_bank(iobase, SET0);
outb(ICR_ETMRI, iobase+ICR);
} else {
+#endif
+ DEBUG(4,__FUNCTION__ "(%ld), mtt=%d\n", jiffies, mtt);
if (mtt)
udelay(mtt);
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,
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);
}
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 */
}
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);
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;);
*/
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
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;
}
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;
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 {
/* 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);
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);
do {
byte = inb(iobase+RBR);
async_unwrap_char(idev, byte);
-
} while (inb(iobase+USR) & USR_RDR); /* Data available */
}
{
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 */
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++;
new_icr |= ICR_ETBREI;
}
-
}
/* Check if transmission has completed */
if (isr & ISR_TXEMP_I) {
* 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 */
/* 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) {
}
/* 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 */
if (idev == NULL) {
printk(KERN_WARNING "%s: irq %d for unknown device.\n",
- driver_name, irq);
+ driver_name, irq);
return;
}
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);
static void w83977af_wait_until_sent(struct irda_device *idev)
{
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(6);
+ schedule_timeout(60*HZ/1000);
}
/*
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;
}
*
*
*/
-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! */
* 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;
iobase = idev->io.iobase;
if (request_irq(idev->io.irq, w83977af_interrupt, 0, idev->name,
- (void *) idev)) {
+ (void *) idev)) {
return -EAGAIN;
}
/*
/* 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;
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;
#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)
*
# 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
#
# 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)
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
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)
*
* 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;
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;
}
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 = {
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;
}
return 0;
}
-#if 0
+#ifdef MODULE
int init_module(void)
{
#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);
{
}
+#ifdef MODULE
+int init_module(void)
+{
+ return usb_audio_init();
+}
+
+void module_cleanup(void)
+{
+ usb_deregister(&usb_audio_driver);
+}
+
+#endif
#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>
return 0;
}
+#ifdef MODULE
+int init_module(void)
+{
+ return usb_cpia_init();
+}
+void module_cleanup(void)
+{
+}
+#endif
+
/*
* 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;
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
-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);
#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"
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
+
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/malloc.h>
+#include <linux/config.h>
+#include <linux/module.h>
#include <asm/spinlock.h>
/* this might need work */
mouse->present = 0;
+ printk("Mouse disconnected\n");
}
static struct usb_driver mouse_driver = {
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
*
* (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> ]
#include "usb.h"
#include "ohci-hcd.h"
-#include "inits.h"
-
-
#ifdef CONFIG_APM
#include <linux/apm_bios.h>
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);
}
{
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]) );)
/*
*
* 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]);
* 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 */
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 */
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);
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;
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) {
}
#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) */
{
return 0;
}
-
-
-
/*
* Increment the module usage count, start the control thread and
* return success.
}
#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
}
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
+
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;
#include <asm/system.h>
#include "ohci.h"
-#include "inits.h"
#ifdef CONFIG_APM
#include <linux/apm_bios.h>
#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
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);
* 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 */
* 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 */);
/*
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);
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?
{
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;
* 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);
/*
* 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;
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);
*/
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) {
return;
}
} while (++num < maxport);
- }
+
} /* ohci_root_hub_events() */
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;
{
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 */
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 */
/* 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 */
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;
}
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;
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)
/* 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
+
+
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 */
};
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;
{
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;
}
}
}
-
#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>
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);
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;
}
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);
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.. */
#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);
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);
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);
#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);
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 */
while (len > 0) {
/* Build the TD for control status */
int pktsze = len;
-
if (pktsze > maxsze)
pktsze = maxsze;
/* 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);
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);
/*
*
* 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);
* 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);
*/
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 {
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) {
*/
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;
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 */
}
#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
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");
* Ok, all systems are go..
*/
start_hc(uhci);
+ usb_register_bus(uhci->bus);
for(;;) {
siginfo_t info;
int unsigned long signr;
{
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);
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;
}
#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)
{
}
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
/* 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 */
};
--- /dev/null
+/*
+ * 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
+
+
#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.
*
* 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;
}
/*
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)
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 *);
};
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 */
};
* (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 */
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);
#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..
*/
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
* 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
* 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
#define DONGLE_H
#include <net/irda/qos.h>
-#include <net/irda/irda_device.h>
/* These are the currently known dongles */
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);
* 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
#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 */
#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,
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;
int pending_control_tuples;
int ignored_control_tuples;
-
-
__u8 pi ; /* instruction of control channel*/
__u8 port_type;
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);
* 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
__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 */
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);
* 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
*
********************************************************************/
#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 */
struct iobuff_t tx_buff;
struct iobuff_t rx_buff;
+ struct dongle *dongle; /* Dongle driver */
+
/* spinlock_t lock; */ /* For serializing operations */
/* Media busy stuff */
/* 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 */
};
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);
* 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;
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
* 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
CONFIRM_CALLBACK confirm;
void *priv;
+ __u8 max_header_size;
+
struct timer_list watchdog_timer;
};
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);
* 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
#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
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;
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
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;
};
* 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
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);
* 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 */
__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 */
__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 */
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
* 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
#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
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 */
* 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
* 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
#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
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 */
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 */
__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);
* 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
#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
+
+
+
+
+
--- /dev/null
+/*********************************************************************
+ *
+ * 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
+
+
* 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);
/*********************************************************************
*
* 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
#
# 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
break;
case DSO_ACCEPTMODE:
- if (put_user(optval, &mode))
+ if (put_user(mode, optval))
return -EFAULT;
break;
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;
}
*/
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;
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.
*/
}
}
- release_sock(sk);
-
return 0;
}
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;
}
/*
scp->persist = 0;
if (scp->persist_fxn(sk))
- return;
+ goto out;
} else {
scp->persist -= SLOW_INTERVAL;
}
sk->timer.expires = jiffies + SLOW_INTERVAL;
add_timer(&sk->timer);
+out:
+ bh_unlock_sock(sk);
}
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)
* 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.
*
#include <linux/if_arp.h>
#include <linux/net.h>
#include <linux/irda.h>
+#include <linux/poll.h>
#include <asm/uaccess.h>
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)
*/
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;
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);
*/
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;
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;
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);
}
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 */
sock_init_data(sock, sk);
- sock->ops = &irda_proto_ops;
+ sock->ops = &irda_stream_ops;
sk->protocol = protocol;
/* Register as a client with IrLMP */
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);
* 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;
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)
*
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;
}
/*
return -EINVAL;
default:
+ DEBUG(0, __FUNCTION__ "(), doing device ioctl!\n");
return dev_ioctl(cmd, (void *) arg);
}
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))
irda_create
};
-static struct proto_ops irda_proto_ops = {
+static struct proto_ops irda_stream_ops = {
PF_IRDA,
sock_no_dup,
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
};
/*
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();
* 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>
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;
}
* 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)
* 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,
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");
create_proc_entry("ircomm", 0, proc_irda)->get_info = ircomm_proc_read;
#endif /* CONFIG_PROC_FS */
-
discovering_instance = NULL;
return 0;
}
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;
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 */
irttp_connect_request(self->tsap, self->dlsap,
self->saddr, self->daddr,
- NULL, self->maxsdusize, userdata);
+ NULL, self->max_sdu_size, userdata);
break;
default:
/* 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
#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,
{
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");
}
{
printk( __FUNCTION__"():ttp_data_request failed\n");
if(userdata)
- dev_kfree_skb( userdata);
+ dev_kfree_skb(userdata);
}
else
self->tx_controls++;
/* 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);
}
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)
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); */
/*
* 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){
* 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);
* 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:
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);
}
}
-
-
/*
* 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);
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;
}
}
-
-
/*
* ----------------------------------------------------------------------
* IrCOMM service interfaces and supporting functions
* ----------------------------------------------------------------------
*/
-/*
- * 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;
/*
* 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;
}
ircomm_getvalue_confirm, self );
}
-
static void query_lsapsel(struct ircomm_cb * self)
{
DEBUG(0, __FUNCTION__"():querying IAS: Lsapsel...\n");
}
}
-/*
- * 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)
{
/*
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;);
* 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);
}
/* 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);
}
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)
{
* 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
***********************************************************************
*/
-
/*
* 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;);
/*
* 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);
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;
*
*/
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 );
/*
* 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);
ircomm_control_request(driver->comm, DTELINE_STATE);
break;
default:
+ DEBUG(0, __FUNCTION__ "(), not implemented!\n");
}
case DATA_RATE:
case XON_XOFF_CHAR:
case DTELINE_STATE:
+ case ENQ_ACK_CHAR: /* got this from win95 */
/* (maybe) nothing to do */
break;
default:
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);
irvtd_notify.instance = driver;
driver->comm = ircomm_open_instance(irvtd_notify);
- if(!driver->comm){
+ if (!driver->comm)
return -ENODEV;
- }
/*
* 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
#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>
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);
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);
{
/* 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;
}
ASSERT(irda_device != NULL, return;);
+ hashbin_delete(dongles, NULL);
hashbin_delete(irda_device, (FREE_FUNC) irda_device_close);
}
/*
* Function irda_device_close (self)
*
- *
+ * Close the device
*
*/
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);
*/
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");
}
}
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;
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)
*
* 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;);
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)
*
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);
* 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
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);
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);
ASSERT( self != NULL, return;);
ASSERT( self->magic == IAS_MAGIC, return;);
- del_timer( &self->watchdog_timer);
+ del_timer(&self->watchdog_timer);
self->magic = 0;
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");
NULL);
}
- if ( userdata) {
+ if (userdata)
dev_kfree_skb( userdata);
- }
}
/*
*
*
*/
-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)
/* 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;
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;
* 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;
/*
* Function iriap_send_ack (void)
*
- *
+ * Currently not used
*
*/
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 */
* 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;
DEBUG(4, __FUNCTION__ "()\n");
- /* del_timer( &self->watchdog_timer); */
+ del_timer(&self->watchdog_timer);
iriap_do_client_event(self, IAP_LM_CONNECT_CONFIRM, userdata);
}
*/
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);
}
/*
}
opcode &= 0x7f; /* Mask away LST bit */
- switch( opcode) {
+ switch (opcode) {
case GET_INFO_BASE:
DEBUG( 0, "IrLMP GetInfoBaseDetails not implemented!\n");
break;
* 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
}
/* 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);
* 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
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);
* 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);
{
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);
struct irlan_cb *self, *entry;
__u32 saddr, daddr;
- DEBUG(0, __FUNCTION__"()\n");
+ DEBUG(1, __FUNCTION__"()\n");
ASSERT(irlan != NULL, return;);
ASSERT(discovery != NULL, return;);
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);
}
/*
- * 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);
}
/*
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;
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);
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;
/* 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 */
}
/*
- * 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,
}
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");
}
* 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
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(
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;
ASSERT(self != NULL, return -1;);
- switch(event) {
+ switch (event) {
case IRLAN_DATA_INDICATION:
ASSERT(skb != NULL, return -1;);
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) {
* 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
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");
/* 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);
*/
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);
}
}
/* 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);
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;
/* 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);
__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;
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
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;
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");
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;
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);
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;);
return;
irda_notify_init(¬ify);
-
+
notify.data_indication = irlan_eth_receive;
notify.udata_indication = irlan_eth_receive;
notify.connect_indication = irlan_connect_indication;
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;
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;
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;
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;
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;
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;
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;
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;
/* get parameter name */
memcpy(name, buf+n, name_len);
- name[ name_len] = '\0';
+ name[name_len] = '\0';
n+=name_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);
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);
}
* 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
#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>
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
{
struct irlan_cb *self;
- DEBUG(4, __FUNCTION__ "()\n");
-
self = (struct irlan_cb *) dev->priv;
ASSERT(self != NULL, return 0;);
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;
}
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! */
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");
}
}
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);
}
* 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
"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;
}
* 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
(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;
}
* 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;
}
}
+/*
+ * 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;
* 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
#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;
* 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;
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);
* 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);
+ }
}
/*
ret = irlan_provider_parse_command(self, CMD_OPEN_DATA_CHANNEL, skb);
+ /* Open data channel */
+ irlan_open_data_tsap(self);
+
return ret;
}
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) {
}
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 */
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;
* 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
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 */
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);
}
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;);
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:
* 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
}
/* 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,
* 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.
*
* 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;
}
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;);
irlap_start_query_timer( self, QUERY_TIMEOUT);
irlap_next_state( self, LAP_REPLY);
}
-
dev_kfree_skb(skb);
break;
irlap_send_discovery_xid_frame(self, info->S,
self->slot, FALSE,
discovery_rsp);
-
+
self->frame_sent = TRUE;
irlap_next_state(self, LAP_REPLY);
}
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;
* 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:
/* 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);
/*
* poll bit cleared?
*/
- if ( !info->pf) {
+ if (!info->pf) {
self->vr = (self->vr + 1) % 8;
/* Update Nr received */
* 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;
}
}
* 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
* 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;
* 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++;
/*
* This must be a C(ontrol) frame
*/
- switch(control) {
+ switch (control) {
case XID_RSP:
irlap_recv_discovery_xid_rsp(self, skb, &info);
break;
* 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
}
/*
- * Function irlmp_close_lsap (self)
+ * Function __irlmp_close_lsap (self)
*
* Remove an instance of LSAP
*/
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);
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);
}
/*
* 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);
}
/*
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);
}
}
*
* 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;
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
*/
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");
}
* 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();
}
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);
/*********************************************************************
*
* 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
*
* 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;
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);
}
/*
*/
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.
* 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;
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);
}
/*
* 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);
}
/*
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
}
/*
#endif
return lsap;
}
- lsap = ( struct lsap_cb *) hashbin_get_next(queue);
+ lsap = (struct lsap_cb *) hashbin_get_next(queue);
}
/* Sorry not found! */
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
#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");
#ifdef CONFIG_PROC_FS
remove_proc_entry("irlpt_client", proc_irda);
#endif
-
DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
}
#endif /* MODULE */
irlpt_client_do_event( self, LMP_DISCONNECT, NULL, NULL);
- if (skb) {
+ if (skb)
dev_kfree_skb( skb);
- }
DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
}
*/
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;
}
#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");
}
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");
* 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.
*
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,
}
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");
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");
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);
}
extern struct proc_dir_entry *proc_irda;
-
#endif /* CONFIG_PROC_FS */
/*
*
*/
-/*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");
= 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;
*/
static void irlpt_server_cleanup(void)
{
+ struct irmanager_event mgr_event;
struct sk_buff *skb;
DEBUG( irlpt_server_debug, "--> " __FUNCTION__ "\n");
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");
}
void *sap,
struct qos_info *qos,
__u32 max_seg_size,
+ __u8 max_header_size,
struct sk_buff *skb)
{
struct irlpt_cb *self;
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);
void *sap,
struct qos_info *qos,
__u32 max_seg_size,
+ __u8 max_header_size,
struct sk_buff *skb)
{
struct irlpt_cb *self;
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");
}
* 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
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
EXPORT_SYMBOL(irlmp_disconnect_request);
EXPORT_SYMBOL(irlmp_get_daddr);
EXPORT_SYMBOL(irlmp_get_saddr);
+EXPORT_SYMBOL(irlmp_dup);
EXPORT_SYMBOL(lmp_reasons);
/* Queue */
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
#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");
/*
* 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
* 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>
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},
};
#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;
}
* 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);
}
+
+
/*********************************************************************
*
* 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
* 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
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);
/* 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 */
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);
}
}
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,
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 */
/* 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 */
* 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;
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
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);
}
}
* 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;
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);
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 =
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);
}
}
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;
/* 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 */
/*
* Reserve space for MUX and LAP header
*/
- skb_reserve(skb, LMP_CONTROL_HEADER+LAP_HEADER);
+ skb_reserve(skb, TTP_MAX_HEADER);
userdata = 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
* 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
* 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;
/*********************************************************************
*
* 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)
__u8 bytes[2];
} fcs;
- ASSERT(skb != NULL, return 0;);
-
/* Initialize variables */
fcs.value = INIT_FCS;
n = 0;
} 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;
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) */
#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;
}
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)
*
* 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 */
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:
/* 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;
+ }
+}