diff options
Diffstat (limited to 'setup/Linux')
52 files changed, 10912 insertions, 0 deletions
diff --git a/setup/Linux/arm/Makefile.osscore.arm b/setup/Linux/arm/Makefile.osscore.arm new file mode 100644 index 0000000..ffe2d3f --- /dev/null +++ b/setup/Linux/arm/Makefile.osscore.arm @@ -0,0 +1,17 @@ + +ifneq ($(KERNELRELEASE),) + + obj-m := osscore.o + +else + + PWD := $(shell pwd) +endif + +default: + @echo "static const char __oss_compile_vermagic[];" > ubuntu_version_hack.inc + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules + +clean: + rm -f *.o *.ko *.mod.c *.mod.o .*.cmd core core.* x y z + rm -rf .tmp_versions diff --git a/setup/Linux/arm/Makefile.tmpl.arm b/setup/Linux/arm/Makefile.tmpl.arm new file mode 100644 index 0000000..a8f0df2 --- /dev/null +++ b/setup/Linux/arm/Makefile.tmpl.arm @@ -0,0 +1,21 @@ +include /etc/oss.conf + +EXTRA_CFLAGS += -I${OSSLIBDIR}/include/internals -I${OSSLIBDIR}/include/sys + +ifneq ($(KERNELRELEASE),) + + obj-m := MODNAME.o + +else + + #KERNELDIR ?= /lib/modules/$(shell uname -r)/build + PWD := $(shell pwd) + +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules + +endif + +clean: + @rm -f *.o *.ko *.mod.c *.mod.o .*.cmd core core.* x y z + @rm -rf .tmp_versions diff --git a/setup/Linux/arm/bpabi.S b/setup/Linux/arm/bpabi.S new file mode 100644 index 0000000..1f08346 --- /dev/null +++ b/setup/Linux/arm/bpabi.S @@ -0,0 +1,119 @@ +/* Miscellaneous BPABI functions. + + Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc. + Contributed by CodeSourcery, LLC. + + This file 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, or (at your option) any + later version. + + In addition to the permissions in the GNU General Public License, the + Free Software Foundation gives you unlimited permission to link the + compiled version of this file into combinations with other programs, + and to distribute those combinations without any restriction coming + from the use of this file. (The General Public License restrictions + do apply in other respects; for example, they cover modification of + the file, and distribution when not linked into a combine + executable.) + + This file 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; see the file COPYING. If not, write to + the Free Software Foundation, 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +#ifdef __ARMEB__ +#define xxh r0 +#define xxl r1 +#define yyh r2 +#define yyl r3 +#else +#define xxh r1 +#define xxl r0 +#define yyh r3 +#define yyl r2 +#endif + +#ifdef L_aeabi_lcmp + +ARM_FUNC_START aeabi_lcmp + cmp xxh, yyh + do_it lt + movlt r0, #-1 + do_it gt + movgt r0, #1 + do_it ne + RETc(ne) + subs r0, xxl, yyl + do_it lo + movlo r0, #-1 + do_it hi + movhi r0, #1 + RET + FUNC_END aeabi_lcmp + +#endif /* L_aeabi_lcmp */ + +#ifdef L_aeabi_ulcmp + +ARM_FUNC_START aeabi_ulcmp + cmp xxh, yyh + do_it lo + movlo r0, #-1 + do_it hi + movhi r0, #1 + do_it ne + RETc(ne) + cmp xxl, yyl + do_it lo + movlo r0, #-1 + do_it hi + movhi r0, #1 + do_it eq + moveq r0, #0 + RET + FUNC_END aeabi_ulcmp + +#endif /* L_aeabi_ulcmp */ + +#ifdef L_aeabi_ldivmod + +ARM_FUNC_START aeabi_ldivmod + sub sp, sp, #8 +#if defined(__thumb2__) + mov ip, sp + push {ip, lr} +#else + do_push {sp, lr} +#endif + bl SYM(__gnu_ldivmod_helper) __PLT__ + ldr lr, [sp, #4] + add sp, sp, #8 + do_pop {r2, r3} + RET + +#endif /* L_aeabi_ldivmod */ + +#ifdef L_aeabi_uldivmod + +ARM_FUNC_START aeabi_uldivmod + sub sp, sp, #8 +#if defined(__thumb2__) + mov ip, sp + push {ip, lr} +#else + do_push {sp, lr} +#endif + bl SYM(__gnu_uldivmod_helper) __PLT__ + ldr lr, [sp, #4] + add sp, sp, #8 + do_pop {r2, r3} + RET + +#endif /* L_aeabi_divmod */ + diff --git a/setup/Linux/arm/bpabi.c b/setup/Linux/arm/bpabi.c new file mode 100644 index 0000000..7ff8e2a --- /dev/null +++ b/setup/Linux/arm/bpabi.c @@ -0,0 +1,375 @@ +/* Miscellaneous BPABI functions. + + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + Contributed by CodeSourcery, LLC. + + This file 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, or (at your option) any + later version. + + In addition to the permissions in the GNU General Public License, the + Free Software Foundation gives you unlimited permission to link the + compiled version of this file into combinations with other programs, + and to distribute those combinations without any restriction coming + from the use of this file. (The General Public License restrictions + do apply in other respects; for example, they cover modification of + the file, and distribution when not linked into a combine + executable.) + + This file 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; see the file COPYING. If not, write to + the Free Software Foundation, 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + +extern long long __divdi3 (long long, long long); +extern unsigned long long __udivdi3 (unsigned long long, + unsigned long long); +extern long long __gnu_ldivmod_helper (long long, long long, long long *); +extern unsigned long long __gnu_uldivmod_helper (unsigned long long, + unsigned long long, + unsigned long long *); +#define UQItype unsigned char +#define DWtype long long +#define UDItype unsigned long long +#define Wtype int +#define USItype unsigned int + +#include "longlong.h" + +const UQItype __clz_tab[256] = +{ + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 +}; + +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("adds %1, %4, %5\n\tadc %0, %2, %3" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "%r" ((USItype) (ah)), \ + "rI" ((USItype) (bh)), \ + "%r" ((USItype) (al)), \ + "rI" ((USItype) (bl)) __CLOBBER_CC) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subs %1, %4, %5\n\tsbc %0, %2, %3" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "r" ((USItype) (ah)), \ + "rI" ((USItype) (bh)), \ + "r" ((USItype) (al)), \ + "rI" ((USItype) (bl)) __CLOBBER_CC) +#define umul_ppmm(xh, xl, a, b) \ +{register USItype __t0, __t1, __t2; \ + __asm__ ("%@ Inlined umul_ppmm\n" \ + " mov %2, %5, lsr #16\n" \ + " mov %0, %6, lsr #16\n" \ + " bic %3, %5, %2, lsl #16\n" \ + " bic %4, %6, %0, lsl #16\n" \ + " mul %1, %3, %4\n" \ + " mul %4, %2, %4\n" \ + " mul %3, %0, %3\n" \ + " mul %0, %2, %0\n" \ + " adds %3, %4, %3\n" \ + " addcs %0, %0, #65536\n" \ + " adds %1, %1, %3, lsl #16\n" \ + " adc %0, %0, %3, lsr #16" \ + : "=&r" ((USItype) (xh)), \ + "=r" ((USItype) (xl)), \ + "=&r" (__t0), "=&r" (__t1), "=r" (__t2) \ + : "r" ((USItype) (a)), \ + "r" ((USItype) (b)) __CLOBBER_CC );} +#define UMUL_TIME 20 +#define UDIV_TIME 100 + +#if 1 /* Big endian */ + struct DWstruct {Wtype high, low;}; +#else + struct DWstruct {Wtype low, high;}; +#endif + +/* We need this union to unpack/pack DImode values, since we don't have + any arithmetic yet. Incoming DImode parameters are stored into the + `ll' field, and the unpacked result is read from the struct `s'. */ + +typedef union +{ + struct DWstruct s; + DWtype ll; +} DWunion; + +UDWtype +__udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp) +{ + const DWunion nn = {.ll = n}; + const DWunion dd = {.ll = d}; + DWunion rr; + UWtype d0, d1, n0, n1, n2; + UWtype q0, q1; + UWtype b, bm; + + d0 = dd.s.low; + d1 = dd.s.high; + n0 = nn.s.low; + n1 = nn.s.high; + +#if !UDIV_NEEDS_NORMALIZATION + if (d1 == 0) + { + 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. */ + } + + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = 0; + *rp = rr.ll; + } + } + +#else /* UDIV_NEEDS_NORMALIZATION */ + + if (d1 == 0) + { + 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 >> (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 W_TYPE_SIZE are undefined.) */ + + n1 -= d0; + q1 = 1; + } + else + { + /* Normalize. */ + + b = 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. */ + } + + if (rp != 0) + { + rr.s.low = n0 >> bm; + rr.s.high = 0; + *rp = rr.ll; + } + } +#endif /* UDIV_NEEDS_NORMALIZATION */ + + else + { + if (d1 > n1) + { + /* 00 = nn / DD */ + + q0 = 0; + q1 = 0; + + /* Remainder in n1n0. */ + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } + 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; + + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } + else + { + UWtype m1, m0; + /* Normalize. */ + + b = 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. */ + if (rp != 0) + { + sub_ddmmss (n1, n0, n1, n0, m1, m0); + rr.s.low = (n1 << b) | (n0 >> bm); + rr.s.high = n1 >> bm; + *rp = rr.ll; + } + } + } + } + + const DWunion ww = {{.low = q0, .high = q1}}; + return ww.ll; +} + +UDWtype +__udivdi3 (UDWtype n, UDWtype d) +{ + return __udivmoddi4 (n, d, (UDWtype *) 0); +} + +long long +__divdi3 (DWtype u, DWtype v) +{ + Wtype c = 0; + DWunion uu = {.ll = u}; + DWunion vv = {.ll = v}; + DWtype w; + + if (uu.s.high < 0) + c = ~c, + uu.ll = -uu.ll; + if (vv.s.high < 0) + c = ~c, + vv.ll = -vv.ll; + + w = __udivmoddi4 (uu.ll, vv.ll, (UDWtype *) 0); + if (c) + w = -w; + + return w; +} + +long long +__gnu_ldivmod_helper (long long a, + long long b, + long long *remainder) +{ + long long quotient; + + quotient = __divdi3 (a, b); + *remainder = a - b * quotient; + return quotient; +} + +unsigned long long +__gnu_uldivmod_helper (unsigned long long a, + unsigned long long b, + unsigned long long *remainder) +{ + unsigned long long quotient; + + quotient = __udivdi3 (a, b); + *remainder = a - b * quotient; + return quotient; +} diff --git a/setup/Linux/arm/bpabi.h b/setup/Linux/arm/bpabi.h new file mode 100644 index 0000000..a67f649 --- /dev/null +++ b/setup/Linux/arm/bpabi.h @@ -0,0 +1,125 @@ +/* Configuration file for ARM BPABI targets. + Copyright (C) 2004, 2005, 2007 + Free Software Foundation, Inc. + Contributed by CodeSourcery, LLC + + This file is part of GCC. + + GCC 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 3, or (at your + option) any later version. + + GCC 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 GCC; see the file COPYING3. If not see + <http://www.gnu.org/licenses/>. */ + +/* Use the AAPCS ABI by default. */ +#define ARM_DEFAULT_ABI ARM_ABI_AAPCS + +/* Assume that AAPCS ABIs should adhere to the full BPABI. */ +#define TARGET_BPABI (TARGET_AAPCS_BASED) + +/* BPABI targets use EABI frame unwinding tables. */ +#define TARGET_UNWIND_INFO 1 + +/* Section 4.1 of the AAPCS requires the use of VFP format. */ +#undef FPUTYPE_DEFAULT +#define FPUTYPE_DEFAULT FPUTYPE_VFP + +/* TARGET_BIG_ENDIAN_DEFAULT is set in + config.gcc for big endian configurations. */ +#if TARGET_BIG_ENDIAN_DEFAULT +#define TARGET_ENDIAN_DEFAULT MASK_BIG_END +#else +#define TARGET_ENDIAN_DEFAULT 0 +#endif + +/* EABI targets should enable interworking by default. */ +#undef TARGET_DEFAULT +#define TARGET_DEFAULT (MASK_INTERWORK | TARGET_ENDIAN_DEFAULT) + +/* The ARM BPABI functions return a boolean; they use no special + calling convention. */ +#define FLOAT_LIB_COMPARE_RETURNS_BOOL(MODE, COMPARISON) TARGET_BPABI + +/* The BPABI integer comparison routines return { -1, 0, 1 }. */ +#define TARGET_LIB_INT_CMP_BIASED !TARGET_BPABI + +/* Tell the assembler to build BPABI binaries. */ +#undef SUBTARGET_EXTRA_ASM_SPEC +#define SUBTARGET_EXTRA_ASM_SPEC "%{mabi=apcs-gnu|mabi=atpcs:-meabi=gnu;:-meabi=4}" + +/* The generic link spec in elf.h does not support shared libraries. */ +#undef LINK_SPEC +#define LINK_SPEC "%{mbig-endian:-EB} %{mlittle-endian:-EL} " \ + "%{static:-Bstatic} %{shared:-shared} %{symbolic:-Bsymbolic} " \ + "-X" + +#if defined (__thumb__) +#define RENAME_LIBRARY_SET ".thumb_set" +#else +#define RENAME_LIBRARY_SET ".set" +#endif + +/* Make __aeabi_AEABI_NAME an alias for __GCC_NAME. */ +#define RENAME_LIBRARY(GCC_NAME, AEABI_NAME) \ + __asm__ (".globl\t__aeabi_" #AEABI_NAME "\n" \ + RENAME_LIBRARY_SET "\t__aeabi_" #AEABI_NAME \ + ", __" #GCC_NAME "\n"); + +/* Give some libgcc functions an additional __aeabi name. */ +#ifdef L_muldi3 +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (muldi3, lmul) +#endif +#ifdef L_muldi3 +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (muldi3, lmul) +#endif +#ifdef L_fixdfdi +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixdfdi, d2lz) +#endif +#ifdef L_fixunsdfdi +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixunsdfdi, d2ulz) +#endif +#ifdef L_fixsfdi +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixsfdi, f2lz) +#endif +#ifdef L_fixunssfdi +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (fixunssfdi, f2ulz) +#endif +#ifdef L_floatdidf +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatdidf, l2d) +#endif +#ifdef L_floatdisf +#define DECLARE_LIBRARY_RENAMES RENAME_LIBRARY (floatdisf, l2f) +#endif + +/* The BPABI requires that we always use an out-of-line implementation + of RTTI comparison, even if the target supports weak symbols, + because the same object file might be used on a target that does + not support merging symbols across DLL boundaries. This macro is + broken out separately so that it can be used within + TARGET_OS_CPP_BUILTINS in configuration files for systems based on + the BPABI. */ +#define TARGET_BPABI_CPP_BUILTINS() \ + do \ + { \ + builtin_define ("__GXX_TYPEINFO_EQUALITY_INLINE=0"); \ + } \ + while (false) + +#undef TARGET_OS_CPP_BUILTINS +#define TARGET_OS_CPP_BUILTINS() \ + TARGET_BPABI_CPP_BUILTINS() + +/* The BPABI specifies the use of .{init,fini}_array. Therefore, we + do not want GCC to put anything into the .{init,fini} sections. */ +#undef INIT_SECTION_ASM_OP +#undef FINI_SECTION_ASM_OP +#define INIT_ARRAY_SECTION_ASM_OP ARM_EABI_CTORS_SECTION_OP +#define FINI_ARRAY_SECTION_ASM_OP ARM_EABI_DTORS_SECTION_OP diff --git a/setup/Linux/arm/lib1funcs.asm b/setup/Linux/arm/lib1funcs.asm new file mode 100644 index 0000000..e2c2201 --- /dev/null +++ b/setup/Linux/arm/lib1funcs.asm @@ -0,0 +1,1393 @@ +@ libgcc routines for ARM cpu. +@ Division routines, written by Richard Earnshaw, (rearnsha@armltd.co.uk) + +/* Copyright 1995, 1996, 1998, 1999, 2000, 2003, 2004, 2005, 2007 + Free Software Foundation, Inc. + +This file 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, or (at your option) any +later version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combine +executable.) + +This file 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; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* An executable stack is *not* required for these functions. */ +#if defined(__ELF__) && defined(__linux__) +.section .note.GNU-stack,"",%progbits +.previous +#endif + +/* ------------------------------------------------------------------------ */ + +/* We need to know what prefix to add to function names. */ + +#ifndef __USER_LABEL_PREFIX__ +#error __USER_LABEL_PREFIX__ not defined +#endif + +/* ANSI concatenation macros. */ + +#define CONCAT1(a, b) CONCAT2(a, b) +#define CONCAT2(a, b) a ## b + +/* Use the right prefix for global labels. */ + +#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x) + +#ifdef __ELF__ +#ifdef __thumb__ +#define __PLT__ /* Not supported in Thumb assembler (for now). */ +#elif defined __vxworks && !defined __PIC__ +#define __PLT__ /* Not supported by the kernel loader. */ +#else +#define __PLT__ (PLT) +#endif +#define TYPE(x) .type SYM(x),function +#define SIZE(x) .size SYM(x), . - SYM(x) +#define LSYM(x) .x +#else +#define __PLT__ +#define TYPE(x) +#define SIZE(x) +#define LSYM(x) x +#endif + +/* Function end macros. Variants for interworking. */ + +#if defined(__ARM_ARCH_2__) +# define __ARM_ARCH__ 2 +#endif + +#if defined(__ARM_ARCH_3__) +# define __ARM_ARCH__ 3 +#endif + +#if defined(__ARM_ARCH_3M__) || defined(__ARM_ARCH_4__) \ + || defined(__ARM_ARCH_4T__) +/* We use __ARM_ARCH__ set to 4 here, but in reality it's any processor with + long multiply instructions. That includes v3M. */ +# define __ARM_ARCH__ 4 +#endif + +#if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \ + || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \ + || defined(__ARM_ARCH_5TEJ__) +# define __ARM_ARCH__ 5 +#endif + +#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \ + || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \ + || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) +# define __ARM_ARCH__ 6 +#endif + +#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \ + || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) +# define __ARM_ARCH__ 7 +#endif + +#ifndef __ARM_ARCH__ +#error Unable to determine architecture. +#endif + +/* How to return from a function call depends on the architecture variant. */ + +#if (__ARM_ARCH__ > 4) || defined(__ARM_ARCH_4T__) + +# define RET bx lr +# define RETc(x) bx##x lr + +/* Special precautions for interworking on armv4t. */ +# if (__ARM_ARCH__ == 4) + +/* Always use bx, not ldr pc. */ +# if (defined(__thumb__) || defined(__THUMB_INTERWORK__)) +# define __INTERWORKING__ +# endif /* __THUMB__ || __THUMB_INTERWORK__ */ + +/* Include thumb stub before arm mode code. */ +# if defined(__thumb__) && !defined(__THUMB_INTERWORK__) +# define __INTERWORKING_STUBS__ +# endif /* __thumb__ && !__THUMB_INTERWORK__ */ + +#endif /* __ARM_ARCH == 4 */ + +#else + +# define RET mov pc, lr +# define RETc(x) mov##x pc, lr + +#endif + +.macro cfi_pop advance, reg, cfa_offset +#ifdef __ELF__ + .pushsection .debug_frame + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte \advance + .byte (0xc0 | \reg) /* DW_CFA_restore */ + .byte 0xe /* DW_CFA_def_cfa_offset */ + .uleb128 \cfa_offset + .popsection +#endif +.endm +.macro cfi_push advance, reg, offset, cfa_offset +#ifdef __ELF__ + .pushsection .debug_frame + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte \advance + .byte (0x80 | \reg) /* DW_CFA_offset */ + .uleb128 (\offset / -4) + .byte 0xe /* DW_CFA_def_cfa_offset */ + .uleb128 \cfa_offset + .popsection +#endif +.endm +.macro cfi_start start_label, end_label +#ifdef __ELF__ + .pushsection .debug_frame +LSYM(Lstart_frame): + .4byte LSYM(Lend_cie) - LSYM(Lstart_cie) @ Length of CIE +LSYM(Lstart_cie): + .4byte 0xffffffff @ CIE Identifier Tag + .byte 0x1 @ CIE Version + .ascii "\0" @ CIE Augmentation + .uleb128 0x1 @ CIE Code Alignment Factor + .sleb128 -4 @ CIE Data Alignment Factor + .byte 0xe @ CIE RA Column + .byte 0xc @ DW_CFA_def_cfa + .uleb128 0xd + .uleb128 0x0 + + .align 2 +LSYM(Lend_cie): + .4byte LSYM(Lend_fde)-LSYM(Lstart_fde) @ FDE Length +LSYM(Lstart_fde): + .4byte LSYM(Lstart_frame) @ FDE CIE offset + .4byte \start_label @ FDE initial location + .4byte \end_label-\start_label @ FDE address range + .popsection +#endif +.endm +.macro cfi_end end_label +#ifdef __ELF__ + .pushsection .debug_frame + .align 2 +LSYM(Lend_fde): + .popsection +\end_label: +#endif +.endm + +/* Don't pass dirn, it's there just to get token pasting right. */ + +.macro RETLDM regs=, cond=, unwind=, dirn=ia +#if defined (__INTERWORKING__) + .ifc "\regs","" + ldr\cond lr, [sp], #8 + .else +# if defined(__thumb2__) + pop\cond {\regs, lr} +# else + ldm\cond\dirn sp!, {\regs, lr} +# endif + .endif + .ifnc "\unwind", "" + /* Mark LR as restored. */ +97: cfi_pop 97b - \unwind, 0xe, 0x0 + .endif + bx\cond lr +#else + /* Caller is responsible for providing IT instruction. */ + .ifc "\regs","" + ldr\cond pc, [sp], #8 + .else +# if defined(__thumb2__) + pop\cond {\regs, pc} +# else + ldm\cond\dirn sp!, {\regs, pc} +# endif + .endif +#endif +.endm + +/* The Unified assembly syntax allows the same code to be assembled for both + ARM and Thumb-2. However this is only supported by recent gas, so define + a set of macros to allow ARM code on older assemblers. */ +#if defined(__thumb2__) +.macro do_it cond, suffix="" + it\suffix \cond +.endm +.macro shift1 op, arg0, arg1, arg2 + \op \arg0, \arg1, \arg2 +.endm +#define do_push push +#define do_pop pop +#define COND(op1, op2, cond) op1 ## op2 ## cond +/* Perform an arithmetic operation with a variable shift operand. This + requires two instructions and a scratch register on Thumb-2. */ +.macro shiftop name, dest, src1, src2, shiftop, shiftreg, tmp + \shiftop \tmp, \src2, \shiftreg + \name \dest, \src1, \tmp +.endm +#else +.macro do_it cond, suffix="" +.endm +.macro shift1 op, arg0, arg1, arg2 + mov \arg0, \arg1, \op \arg2 +.endm +#define do_push stmfd sp!, +#define do_pop ldmfd sp!, +#define COND(op1, op2, cond) op1 ## cond ## op2 +.macro shiftop name, dest, src1, src2, shiftop, shiftreg, tmp + \name \dest, \src1, \src2, \shiftop \shiftreg +.endm +#endif + +.macro ARM_LDIV0 name + str lr, [sp, #-8]! +98: cfi_push 98b - __\name, 0xe, -0x8, 0x8 + bl SYM (__div0) __PLT__ + mov r0, #0 @ About as wrong as it could be. + RETLDM unwind=98b +.endm + + +.macro THUMB_LDIV0 name + push { r1, lr } +98: cfi_push 98b - __\name, 0xe, -0x4, 0x8 + bl SYM (__div0) + mov r0, #0 @ About as wrong as it could be. +#if defined (__INTERWORKING__) + pop { r1, r2 } + bx r2 +#else + pop { r1, pc } +#endif +.endm + +.macro FUNC_END name + SIZE (__\name) +.endm + +.macro DIV_FUNC_END name + cfi_start __\name, LSYM(Lend_div0) +LSYM(Ldiv0): +#ifdef __thumb__ + THUMB_LDIV0 \name +#else + ARM_LDIV0 \name +#endif + cfi_end LSYM(Lend_div0) + FUNC_END \name +.endm + +.macro THUMB_FUNC_START name + .globl SYM (\name) + TYPE (\name) + .thumb_func +SYM (\name): +.endm + +/* Function start macros. Variants for ARM and Thumb. */ + +#ifdef __thumb__ +#define THUMB_FUNC .thumb_func +#define THUMB_CODE .force_thumb +# if defined(__thumb2__) +#define THUMB_SYNTAX .syntax divided +# else +#define THUMB_SYNTAX +# endif +#else +#define THUMB_FUNC +#define THUMB_CODE +#define THUMB_SYNTAX +#endif + +.macro FUNC_START name + .text + .globl SYM (__\name) + TYPE (__\name) + .align 0 + THUMB_CODE + THUMB_FUNC + THUMB_SYNTAX +SYM (__\name): +.endm + +/* Special function that will always be coded in ARM assembly, even if + in Thumb-only compilation. */ + +#if defined(__thumb2__) + +/* For Thumb-2 we build everything in thumb mode. */ +.macro ARM_FUNC_START name + FUNC_START \name + .syntax unified +.endm +#define EQUIV .thumb_set +.macro ARM_CALL name + bl __\name +.endm + +#elif defined(__INTERWORKING_STUBS__) + +.macro ARM_FUNC_START name + FUNC_START \name + bx pc + nop + .arm +/* A hook to tell gdb that we've switched to ARM mode. Also used to call + directly from other local arm routines. */ +_L__\name: +.endm +#define EQUIV .thumb_set +/* Branch directly to a function declared with ARM_FUNC_START. + Must be called in arm mode. */ +.macro ARM_CALL name + bl _L__\name +.endm + +#else /* !(__INTERWORKING_STUBS__ || __thumb2__) */ + +.macro ARM_FUNC_START name + .text + .globl SYM (__\name) + TYPE (__\name) + .align 0 + .arm +SYM (__\name): +.endm +#define EQUIV .set +.macro ARM_CALL name + bl __\name +.endm + +#endif + +.macro FUNC_ALIAS new old + .globl SYM (__\new) +#if defined (__thumb__) + .thumb_set SYM (__\new), SYM (__\old) +#else + .set SYM (__\new), SYM (__\old) +#endif +.endm + +.macro ARM_FUNC_ALIAS new old + .globl SYM (__\new) + EQUIV SYM (__\new), SYM (__\old) +#if defined(__INTERWORKING_STUBS__) + .set SYM (_L__\new), SYM (_L__\old) +#endif +.endm + +#ifdef __thumb__ +/* Register aliases. */ + +work .req r4 @ XXXX is this safe ? +dividend .req r0 +divisor .req r1 +overdone .req r2 +result .req r2 +curbit .req r3 +#endif +#if 0 +ip .req r12 +sp .req r13 +lr .req r14 +pc .req r15 +#endif + +/* ------------------------------------------------------------------------ */ +/* Bodies of the division and modulo routines. */ +/* ------------------------------------------------------------------------ */ +.macro ARM_DIV_BODY dividend, divisor, result, curbit + +#if __ARM_ARCH__ >= 5 && ! defined (__OPTIMIZE_SIZE__) + + clz \curbit, \dividend + clz \result, \divisor + sub \curbit, \result, \curbit + rsbs \curbit, \curbit, #31 + addne \curbit, \curbit, \curbit, lsl #1 + mov \result, #0 + addne pc, pc, \curbit, lsl #2 + nop + .set shift, 32 + .rept 32 + .set shift, shift - 1 + cmp \dividend, \divisor, lsl #shift + adc \result, \result, \result + subcs \dividend, \dividend, \divisor, lsl #shift + .endr + +#else /* __ARM_ARCH__ < 5 || defined (__OPTIMIZE_SIZE__) */ +#if __ARM_ARCH__ >= 5 + + clz \curbit, \divisor + clz \result, \dividend + sub \result, \curbit, \result + mov \curbit, #1 + mov \divisor, \divisor, lsl \result + mov \curbit, \curbit, lsl \result + mov \result, #0 + +#else /* __ARM_ARCH__ < 5 */ + + @ Initially shift the divisor left 3 bits if possible, + @ set curbit accordingly. This allows for curbit to be located + @ at the left end of each 4-bit nibbles in the division loop + @ to save one loop in most cases. + tst \divisor, #0xe0000000 + moveq \divisor, \divisor, lsl #3 + moveq \curbit, #8 + movne \curbit, #1 + + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. +1: cmp \divisor, #0x10000000 + cmplo \divisor, \dividend + movlo \divisor, \divisor, lsl #4 + movlo \curbit, \curbit, lsl #4 + blo 1b + + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. +1: cmp \divisor, #0x80000000 + cmplo \divisor, \dividend + movlo \divisor, \divisor, lsl #1 + movlo \curbit, \curbit, lsl #1 + blo 1b + + mov \result, #0 + +#endif /* __ARM_ARCH__ < 5 */ + + @ Division loop +1: cmp \dividend, \divisor + subhs \dividend, \dividend, \divisor + orrhs \result, \result, \curbit + cmp \dividend, \divisor, lsr #1 + subhs \dividend, \dividend, \divisor, lsr #1 + orrhs \result, \result, \curbit, lsr #1 + cmp \dividend, \divisor, lsr #2 + subhs \dividend, \dividend, \divisor, lsr #2 + orrhs \result, \result, \curbit, lsr #2 + cmp \dividend, \divisor, lsr #3 + subhs \dividend, \dividend, \divisor, lsr #3 + orrhs \result, \result, \curbit, lsr #3 + cmp \dividend, #0 @ Early termination? + movnes \curbit, \curbit, lsr #4 @ No, any more bits to do? + movne \divisor, \divisor, lsr #4 + bne 1b + +#endif /* __ARM_ARCH__ < 5 || defined (__OPTIMIZE_SIZE__) */ + +.endm +/* ------------------------------------------------------------------------ */ +.macro ARM_DIV2_ORDER divisor, order + +#if __ARM_ARCH__ >= 5 + + clz \order, \divisor + rsb \order, \order, #31 + +#else + + cmp \divisor, #(1 << 16) + movhs \divisor, \divisor, lsr #16 + movhs \order, #16 + movlo \order, #0 + + cmp \divisor, #(1 << 8) + movhs \divisor, \divisor, lsr #8 + addhs \order, \order, #8 + + cmp \divisor, #(1 << 4) + movhs \divisor, \divisor, lsr #4 + addhs \order, \order, #4 + + cmp \divisor, #(1 << 2) + addhi \order, \order, #3 + addls \order, \order, \divisor, lsr #1 + +#endif + +.endm +/* ------------------------------------------------------------------------ */ +.macro ARM_MOD_BODY dividend, divisor, order, spare + +#if __ARM_ARCH__ >= 5 && ! defined (__OPTIMIZE_SIZE__) + + clz \order, \divisor + clz \spare, \dividend + sub \order, \order, \spare + rsbs \order, \order, #31 + addne pc, pc, \order, lsl #3 + nop + .set shift, 32 + .rept 32 + .set shift, shift - 1 + cmp \dividend, \divisor, lsl #shift + subcs \dividend, \dividend, \divisor, lsl #shift + .endr + +#else /* __ARM_ARCH__ < 5 || defined (__OPTIMIZE_SIZE__) */ +#if __ARM_ARCH__ >= 5 + + clz \order, \divisor + clz \spare, \dividend + sub \order, \order, \spare + mov \divisor, \divisor, lsl \order + +#else /* __ARM_ARCH__ < 5 */ + + mov \order, #0 + + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. +1: cmp \divisor, #0x10000000 + cmplo \divisor, \dividend + movlo \divisor, \divisor, lsl #4 + addlo \order, \order, #4 + blo 1b + + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. +1: cmp \divisor, #0x80000000 + cmplo \divisor, \dividend + movlo \divisor, \divisor, lsl #1 + addlo \order, \order, #1 + blo 1b + +#endif /* __ARM_ARCH__ < 5 */ + + @ Perform all needed substractions to keep only the reminder. + @ Do comparisons in batch of 4 first. + subs \order, \order, #3 @ yes, 3 is intended here + blt 2f + +1: cmp \dividend, \divisor + subhs \dividend, \dividend, \divisor + cmp \dividend, \divisor, lsr #1 + subhs \dividend, \dividend, \divisor, lsr #1 + cmp \dividend, \divisor, lsr #2 + subhs \dividend, \dividend, \divisor, lsr #2 + cmp \dividend, \divisor, lsr #3 + subhs \dividend, \dividend, \divisor, lsr #3 + cmp \dividend, #1 + mov \divisor, \divisor, lsr #4 + subges \order, \order, #4 + bge 1b + + tst \order, #3 + teqne \dividend, #0 + beq 5f + + @ Either 1, 2 or 3 comparison/substractions are left. +2: cmn \order, #2 + blt 4f + beq 3f + cmp \dividend, \divisor + subhs \dividend, \dividend, \divisor + mov \divisor, \divisor, lsr #1 +3: cmp \dividend, \divisor + subhs \dividend, \dividend, \divisor + mov \divisor, \divisor, lsr #1 +4: cmp \dividend, \divisor + subhs \dividend, \dividend, \divisor +5: + +#endif /* __ARM_ARCH__ < 5 || defined (__OPTIMIZE_SIZE__) */ + +.endm +/* ------------------------------------------------------------------------ */ +.macro THUMB_DIV_MOD_BODY modulo + @ Load the constant 0x10000000 into our work register. + mov work, #1 + lsl work, #28 +LSYM(Loop1): + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. + cmp divisor, work + bhs LSYM(Lbignum) + cmp divisor, dividend + bhs LSYM(Lbignum) + lsl divisor, #4 + lsl curbit, #4 + b LSYM(Loop1) +LSYM(Lbignum): + @ Set work to 0x80000000 + lsl work, #3 +LSYM(Loop2): + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. + cmp divisor, work + bhs LSYM(Loop3) + cmp divisor, dividend + bhs LSYM(Loop3) + lsl divisor, #1 + lsl curbit, #1 + b LSYM(Loop2) +LSYM(Loop3): + @ Test for possible subtractions ... + .if \modulo + @ ... On the final pass, this may subtract too much from the dividend, + @ so keep track of which subtractions are done, we can fix them up + @ afterwards. + mov overdone, #0 + cmp dividend, divisor + blo LSYM(Lover1) + sub dividend, dividend, divisor +LSYM(Lover1): + lsr work, divisor, #1 + cmp dividend, work + blo LSYM(Lover2) + sub dividend, dividend, work + mov ip, curbit + mov work, #1 + ror curbit, work + orr overdone, curbit + mov curbit, ip +LSYM(Lover2): + lsr work, divisor, #2 + cmp dividend, work + blo LSYM(Lover3) + sub dividend, dividend, work + mov ip, curbit + mov work, #2 + ror curbit, work + orr overdone, curbit + mov curbit, ip +LSYM(Lover3): + lsr work, divisor, #3 + cmp dividend, work + blo LSYM(Lover4) + sub dividend, dividend, work + mov ip, curbit + mov work, #3 + ror curbit, work + orr overdone, curbit + mov curbit, ip +LSYM(Lover4): + mov ip, curbit + .else + @ ... and note which bits are done in the result. On the final pass, + @ this may subtract too much from the dividend, but the result will be ok, + @ since the "bit" will have been shifted out at the bottom. + cmp dividend, divisor + blo LSYM(Lover1) + sub dividend, dividend, divisor + orr result, result, curbit +LSYM(Lover1): + lsr work, divisor, #1 + cmp dividend, work + blo LSYM(Lover2) + sub dividend, dividend, work + lsr work, curbit, #1 + orr result, work +LSYM(Lover2): + lsr work, divisor, #2 + cmp dividend, work + blo LSYM(Lover3) + sub dividend, dividend, work + lsr work, curbit, #2 + orr result, work +LSYM(Lover3): + lsr work, divisor, #3 + cmp dividend, work + blo LSYM(Lover4) + sub dividend, dividend, work + lsr work, curbit, #3 + orr result, work +LSYM(Lover4): + .endif + + cmp dividend, #0 @ Early termination? + beq LSYM(Lover5) + lsr curbit, #4 @ No, any more bits to do? + beq LSYM(Lover5) + lsr divisor, #4 + b LSYM(Loop3) +LSYM(Lover5): + .if \modulo + @ Any subtractions that we should not have done will be recorded in + @ the top three bits of "overdone". Exactly which were not needed + @ are governed by the position of the bit, stored in ip. + mov work, #0xe + lsl work, #28 + and overdone, work + beq LSYM(Lgot_result) + + @ If we terminated early, because dividend became zero, then the + @ bit in ip will not be in the bottom nibble, and we should not + @ perform the additions below. We must test for this though + @ (rather relying upon the TSTs to prevent the additions) since + @ the bit in ip could be in the top two bits which might then match + @ with one of the smaller RORs. + mov curbit, ip + mov work, #0x7 + tst curbit, work + beq LSYM(Lgot_result) + + mov curbit, ip + mov work, #3 + ror curbit, work + tst overdone, curbit + beq LSYM(Lover6) + lsr work, divisor, #3 + add dividend, work +LSYM(Lover6): + mov curbit, ip + mov work, #2 + ror curbit, work + tst overdone, curbit + beq LSYM(Lover7) + lsr work, divisor, #2 + add dividend, work +LSYM(Lover7): + mov curbit, ip + mov work, #1 + ror curbit, work + tst overdone, curbit + beq LSYM(Lgot_result) + lsr work, divisor, #1 + add dividend, work + .endif +LSYM(Lgot_result): +.endm +/* ------------------------------------------------------------------------ */ +/* Start of the Real Functions */ +/* ------------------------------------------------------------------------ */ +#ifdef L_udivsi3 + + FUNC_START udivsi3 + FUNC_ALIAS aeabi_uidiv udivsi3 + +#ifdef __thumb__ + + cmp divisor, #0 + beq LSYM(Ldiv0) + mov curbit, #1 + mov result, #0 + + push { work } + cmp dividend, divisor + blo LSYM(Lgot_result) + + THUMB_DIV_MOD_BODY 0 + + mov r0, result + pop { work } + RET + +#else /* ARM version. */ + + subs r2, r1, #1 + RETc(eq) + bcc LSYM(Ldiv0) + cmp r0, r1 + bls 11f + tst r1, r2 + beq 12f + + ARM_DIV_BODY r0, r1, r2, r3 + + mov r0, r2 + RET + +11: moveq r0, #1 + movne r0, #0 + RET + +12: ARM_DIV2_ORDER r1, r2 + + mov r0, r0, lsr r2 + RET + +#endif /* ARM version */ + + DIV_FUNC_END udivsi3 + +FUNC_START aeabi_uidivmod +#ifdef __thumb__ + push {r0, r1, lr} + bl SYM(__udivsi3) + POP {r1, r2, r3} + mul r2, r0 + sub r1, r1, r2 + bx r3 +#else + stmfd sp!, { r0, r1, lr } + bl SYM(__udivsi3) + ldmfd sp!, { r1, r2, lr } + mul r3, r2, r0 + sub r1, r1, r3 + RET +#endif + FUNC_END aeabi_uidivmod + +#endif /* L_udivsi3 */ +/* ------------------------------------------------------------------------ */ +#ifdef L_umodsi3 + + FUNC_START umodsi3 + +#ifdef __thumb__ + + cmp divisor, #0 + beq LSYM(Ldiv0) + mov curbit, #1 + cmp dividend, divisor + bhs LSYM(Lover10) + RET + +LSYM(Lover10): + push { work } + + THUMB_DIV_MOD_BODY 1 + + pop { work } + RET + +#else /* ARM version. */ + + subs r2, r1, #1 @ compare divisor with 1 + bcc LSYM(Ldiv0) + cmpne r0, r1 @ compare dividend with divisor + moveq r0, #0 + tsthi r1, r2 @ see if divisor is power of 2 + andeq r0, r0, r2 + RETc(ls) + + ARM_MOD_BODY r0, r1, r2, r3 + + RET + +#endif /* ARM version. */ + + DIV_FUNC_END umodsi3 + +#endif /* L_umodsi3 */ +/* ------------------------------------------------------------------------ */ +#ifdef L_divsi3 + + FUNC_START divsi3 + FUNC_ALIAS aeabi_idiv divsi3 + +#ifdef __thumb__ + cmp divisor, #0 + beq LSYM(Ldiv0) + + push { work } + mov work, dividend + eor work, divisor @ Save the sign of the result. + mov ip, work + mov curbit, #1 + mov result, #0 + cmp divisor, #0 + bpl LSYM(Lover10) + neg divisor, divisor @ Loops below use unsigned. +LSYM(Lover10): + cmp dividend, #0 + bpl LSYM(Lover11) + neg dividend, dividend +LSYM(Lover11): + cmp dividend, divisor + blo LSYM(Lgot_result) + + THUMB_DIV_MOD_BODY 0 + + mov r0, result + mov work, ip + cmp work, #0 + bpl LSYM(Lover12) + neg r0, r0 +LSYM(Lover12): + pop { work } + RET + +#else /* ARM version. */ + + cmp r1, #0 + eor ip, r0, r1 @ save the sign of the result. + beq LSYM(Ldiv0) + rsbmi r1, r1, #0 @ loops below use unsigned. + subs r2, r1, #1 @ division by 1 or -1 ? + beq 10f + movs r3, r0 + rsbmi r3, r0, #0 @ positive dividend value + cmp r3, r1 + bls 11f + tst r1, r2 @ divisor is power of 2 ? + beq 12f + + ARM_DIV_BODY r3, r1, r0, r2 + + cmp ip, #0 + rsbmi r0, r0, #0 + RET + +10: teq ip, r0 @ same sign ? + rsbmi r0, r0, #0 + RET + +11: movlo r0, #0 + moveq r0, ip, asr #31 + orreq r0, r0, #1 + RET + +12: ARM_DIV2_ORDER r1, r2 + + cmp ip, #0 + mov r0, r3, lsr r2 + rsbmi r0, r0, #0 + RET + +#endif /* ARM version */ + + DIV_FUNC_END divsi3 + +FUNC_START aeabi_idivmod +#ifdef __thumb__ + push {r0, r1, lr} + bl SYM(__divsi3) + POP {r1, r2, r3} + mul r2, r0 + sub r1, r1, r2 + bx r3 +#else + stmfd sp!, { r0, r1, lr } + bl SYM(__divsi3) + ldmfd sp!, { r1, r2, lr } + mul r3, r2, r0 + sub r1, r1, r3 + RET +#endif + FUNC_END aeabi_idivmod + +#endif /* L_divsi3 */ +/* ------------------------------------------------------------------------ */ +#ifdef L_modsi3 + + FUNC_START modsi3 + +#ifdef __thumb__ + + mov curbit, #1 + cmp divisor, #0 + beq LSYM(Ldiv0) + bpl LSYM(Lover10) + neg divisor, divisor @ Loops below use unsigned. +LSYM(Lover10): + push { work } + @ Need to save the sign of the dividend, unfortunately, we need + @ work later on. Must do this after saving the original value of + @ the work register, because we will pop this value off first. + push { dividend } + cmp dividend, #0 + bpl LSYM(Lover11) + neg dividend, dividend +LSYM(Lover11): + cmp dividend, divisor + blo LSYM(Lgot_result) + + THUMB_DIV_MOD_BODY 1 + + pop { work } + cmp work, #0 + bpl LSYM(Lover12) + neg dividend, dividend +LSYM(Lover12): + pop { work } + RET + +#else /* ARM version. */ + + cmp r1, #0 + beq LSYM(Ldiv0) + rsbmi r1, r1, #0 @ loops below use unsigned. + movs ip, r0 @ preserve sign of dividend + rsbmi r0, r0, #0 @ if negative make positive + subs r2, r1, #1 @ compare divisor with 1 + cmpne r0, r1 @ compare dividend with divisor + moveq r0, #0 + tsthi r1, r2 @ see if divisor is power of 2 + andeq r0, r0, r2 + bls 10f + + ARM_MOD_BODY r0, r1, r2, r3 + +10: cmp ip, #0 + rsbmi r0, r0, #0 + RET + +#endif /* ARM version */ + + DIV_FUNC_END modsi3 + +#endif /* L_modsi3 */ +/* ------------------------------------------------------------------------ */ +#ifdef L_dvmd_tls + + FUNC_START div0 + FUNC_ALIAS aeabi_idiv0 div0 + FUNC_ALIAS aeabi_ldiv0 div0 + + RET + + FUNC_END aeabi_ldiv0 + FUNC_END aeabi_idiv0 + FUNC_END div0 + +#endif /* L_divmodsi_tools */ +/* ------------------------------------------------------------------------ */ +#ifdef L_dvmd_lnx +@ GNU/Linux division-by zero handler. Used in place of L_dvmd_tls + +/* Constant taken from <asm/signal.h>. */ +#define SIGFPE 8 + + ARM_FUNC_START div0 + + do_push {r1, lr} + mov r0, #SIGFPE + bl SYM(raise) __PLT__ + RETLDM r1 + + FUNC_END div0 + +#endif /* L_dvmd_lnx */ +/* ------------------------------------------------------------------------ */ +/* Dword shift operations. */ +/* All the following Dword shift variants rely on the fact that + shft xxx, Reg + is in fact done as + shft xxx, (Reg & 255) + so for Reg value in (32...63) and (-1...-31) we will get zero (in the + case of logical shifts) or the sign (for asr). */ + +#ifdef __ARMEB__ +#define al r1 +#define ah r0 +#else +#define al r0 +#define ah r1 +#endif + +/* Prevent __aeabi double-word shifts from being produced on SymbianOS. */ +#ifndef __symbian__ + +#ifdef L_lshrdi3 + + FUNC_START lshrdi3 + FUNC_ALIAS aeabi_llsr lshrdi3 + +#ifdef __thumb__ + lsr al, r2 + mov r3, ah + lsr ah, r2 + mov ip, r3 + sub r2, #32 + lsr r3, r2 + orr al, r3 + neg r2, r2 + mov r3, ip + lsl r3, r2 + orr al, r3 + RET +#else + subs r3, r2, #32 + rsb ip, r2, #32 + movmi al, al, lsr r2 + movpl al, ah, lsr r3 + orrmi al, al, ah, lsl ip + mov ah, ah, lsr r2 + RET +#endif + FUNC_END aeabi_llsr + FUNC_END lshrdi3 + +#endif + +#ifdef L_ashrdi3 + + FUNC_START ashrdi3 + FUNC_ALIAS aeabi_lasr ashrdi3 + +#ifdef __thumb__ + lsr al, r2 + mov r3, ah + asr ah, r2 + sub r2, #32 + @ If r2 is negative at this point the following step would OR + @ the sign bit into all of AL. That's not what we want... + bmi 1f + mov ip, r3 + asr r3, r2 + orr al, r3 + mov r3, ip +1: + neg r2, r2 + lsl r3, r2 + orr al, r3 + RET +#else + subs r3, r2, #32 + rsb ip, r2, #32 + movmi al, al, lsr r2 + movpl al, ah, asr r3 + orrmi al, al, ah, lsl ip + mov ah, ah, asr r2 + RET +#endif + + FUNC_END aeabi_lasr + FUNC_END ashrdi3 + +#endif + +#ifdef L_ashldi3 + + FUNC_START ashldi3 + FUNC_ALIAS aeabi_llsl ashldi3 + +#ifdef __thumb__ + lsl ah, r2 + mov r3, al + lsl al, r2 + mov ip, r3 + sub r2, #32 + lsl r3, r2 + orr ah, r3 + neg r2, r2 + mov r3, ip + lsr r3, r2 + orr ah, r3 + RET +#else + subs r3, r2, #32 + rsb ip, r2, #32 + movmi ah, ah, lsl r2 + movpl ah, al, lsl r3 + orrmi ah, ah, al, lsr ip + mov al, al, lsl r2 + RET +#endif + FUNC_END aeabi_llsl + FUNC_END ashldi3 + +#endif + +#endif /* __symbian__ */ + +/* ------------------------------------------------------------------------ */ +/* These next two sections are here despite the fact that they contain Thumb + assembler because their presence allows interworked code to be linked even + when the GCC library is this one. */ + +/* Do not build the interworking functions when the target architecture does + not support Thumb instructions. (This can be a multilib option). */ +#if defined __ARM_ARCH_4T__ || defined __ARM_ARCH_5T__\ + || defined __ARM_ARCH_5TE__ || defined __ARM_ARCH_5TEJ__ \ + || __ARM_ARCH__ >= 6 + +#if defined L_call_via_rX + +/* These labels & instructions are used by the Arm/Thumb interworking code. + The address of function to be called is loaded into a register and then + one of these labels is called via a BL instruction. This puts the + return address into the link register with the bottom bit set, and the + code here switches to the correct mode before executing the function. */ + + .text + .align 0 + .force_thumb + +.macro call_via register + THUMB_FUNC_START _call_via_\register + + bx \register + nop + + SIZE (_call_via_\register) +.endm + + call_via r0 + call_via r1 + call_via r2 + call_via r3 + call_via r4 + call_via r5 + call_via r6 + call_via r7 + call_via r8 + call_via r9 + call_via sl + call_via fp + call_via ip + call_via sp + call_via lr + +#endif /* L_call_via_rX */ + +/* Don't bother with the old interworking routines for Thumb-2. */ +/* ??? Maybe only omit these on v7m. */ +#ifndef __thumb2__ + +#if defined L_interwork_call_via_rX + +/* These labels & instructions are used by the Arm/Thumb interworking code, + when the target address is in an unknown instruction set. The address + of function to be called is loaded into a register and then one of these + labels is called via a BL instruction. This puts the return address + into the link register with the bottom bit set, and the code here + switches to the correct mode before executing the function. Unfortunately + the target code cannot be relied upon to return via a BX instruction, so + instead we have to store the resturn address on the stack and allow the + called function to return here instead. Upon return we recover the real + return address and use a BX to get back to Thumb mode. + + There are three variations of this code. The first, + _interwork_call_via_rN(), will push the return address onto the + stack and pop it in _arm_return(). It should only be used if all + arguments are passed in registers. + + The second, _interwork_r7_call_via_rN(), instead stores the return + address at [r7, #-4]. It is the caller's responsibility to ensure + that this address is valid and contains no useful data. + + The third, _interwork_r11_call_via_rN(), works in the same way but + uses r11 instead of r7. It is useful if the caller does not really + need a frame pointer. */ + + .text + .align 0 + + .code 32 + .globl _arm_return +LSYM(Lstart_arm_return): + cfi_start LSYM(Lstart_arm_return) LSYM(Lend_arm_return) + cfi_push 0, 0xe, -0x8, 0x8 + nop @ This nop is for the benefit of debuggers, so that + @ backtraces will use the correct unwind information. +_arm_return: + RETLDM unwind=LSYM(Lstart_arm_return) + cfi_end LSYM(Lend_arm_return) + + .globl _arm_return_r7 +_arm_return_r7: + ldr lr, [r7, #-4] + bx lr + + .globl _arm_return_r11 +_arm_return_r11: + ldr lr, [r11, #-4] + bx lr + +.macro interwork_with_frame frame, register, name, return + .code 16 + + THUMB_FUNC_START \name + + bx pc + nop + + .code 32 + tst \register, #1 + streq lr, [\frame, #-4] + adreq lr, _arm_return_\frame + bx \register + + SIZE (\name) +.endm + +.macro interwork register + .code 16 + + THUMB_FUNC_START _interwork_call_via_\register + + bx pc + nop + + .code 32 + .globl LSYM(Lchange_\register) +LSYM(Lchange_\register): + tst \register, #1 + streq lr, [sp, #-8]! + adreq lr, _arm_return + bx \register + + SIZE (_interwork_call_via_\register) + + interwork_with_frame r7,\register,_interwork_r7_call_via_\register + interwork_with_frame r11,\register,_interwork_r11_call_via_\register +.endm + + interwork r0 + interwork r1 + interwork r2 + interwork r3 + interwork r4 + interwork r5 + interwork r6 + interwork r7 + interwork r8 + interwork r9 + interwork sl + interwork fp + interwork ip + interwork sp + + /* The LR case has to be handled a little differently... */ + .code 16 + + THUMB_FUNC_START _interwork_call_via_lr + + bx pc + nop + + .code 32 + .globl .Lchange_lr +.Lchange_lr: + tst lr, #1 + stmeqdb r13!, {lr, pc} + mov ip, lr + adreq lr, _arm_return + bx ip + + SIZE (_interwork_call_via_lr) + +#endif /* L_interwork_call_via_rX */ +#endif /* !__thumb2__ */ +#endif /* Arch supports thumb. */ + +#ifndef __symbian__ +//#include "ieee754-df.S" +//#include "ieee754-sf.S" +#include "bpabi.S" +#endif /* __symbian__ */ diff --git a/setup/Linux/arm/longlong.h b/setup/Linux/arm/longlong.h new file mode 100644 index 0000000..a2f4e56 --- /dev/null +++ b/setup/Linux/arm/longlong.h @@ -0,0 +1,1465 @@ +/* longlong.h -- definitions for mixed size 32/64 bit arithmetic. + Copyright (C) 1991, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 + Free Software Foundation, Inc. + + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + In addition to the permissions in the GNU Lesser General Public + License, the Free Software Foundation gives you unlimited + permission to link the compiled version of this file into + combinations with other programs, and to distribute those + combinations without any restriction coming from the use of this + file. (The Lesser General Public License restrictions do apply in + other respects; for example, they cover modification of the file, + and distribution when not linked into a combine executable.) + + 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. */ + +/* You have to define the following before including this file: + + UWtype -- An unsigned type, default type for operations (typically a "word") + UHWtype -- An unsigned type, at least half the size of UWtype. + UDWtype -- An unsigned type, at least twice as large a UWtype + W_TYPE_SIZE -- size in bits of UWtype + + UQItype -- Unsigned 8 bit type. + SItype, USItype -- Signed and unsigned 32 bit types. + DItype, UDItype -- Signed and unsigned 64 bit types. + + On a 32 bit machine UWtype should typically be USItype; + on a 64 bit machine, UWtype should typically be UDItype. */ + +#define __BITS4 (W_TYPE_SIZE / 4) +#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2)) +#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1)) +#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2)) + +#ifndef W_TYPE_SIZE +#define W_TYPE_SIZE 32 +#define UWtype USItype +#define UHWtype USItype +#define UDWtype UDItype +#endif + +extern const UQItype __clz_tab[256]; + +/* Define auxiliary asm macros. + + 1) umul_ppmm(high_prod, low_prod, multiplier, multiplicand) multiplies two + UWtype integers MULTIPLIER and MULTIPLICAND, and generates a two UWtype + word product in HIGH_PROD and LOW_PROD. + + 2) __umulsidi3(a,b) multiplies two UWtype integers A and B, and returns a + UDWtype product. This is just a variant of umul_ppmm. + + 3) 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. + + 4) sdiv_qrnnd(quotient, remainder, high_numerator, low_numerator, + denominator). Like udiv_qrnnd but the numbers are signed. The quotient + is rounded towards 0. + + 5) count_leading_zeros(count, x) counts the number of zero-bits from the + msb to the first nonzero bit in the UWtype X. This is the number of + steps X needs to be shifted left to set the msb. Undefined for X == 0, + unless the symbol COUNT_LEADING_ZEROS_0 is defined to some value. + + 6) count_trailing_zeros(count, x) like count_leading_zeros, but counts + from the least significant end. + + 7) 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. + + 8) 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. + + If any of these macros are left undefined for a particular CPU, + C macros are used. */ + +/* The CPUs come in alphabetical order below. + + Please add support for more CPUs here, or improve the current support + for the CPUs below! + (E.g. WE32100, IBM360.) */ + +#if defined (__GNUC__) && !defined (NO_ASM) + +/* We sometimes need to clobber "cc" with gcc2, but that would not be + understood by gcc1. Use cpp to avoid major code duplication. */ +#if __GNUC__ < 2 +#define __CLOBBER_CC +#define __AND_CLOBBER_CC +#else /* __GNUC__ >= 2 */ +#define __CLOBBER_CC : "cc" +#define __AND_CLOBBER_CC , "cc" +#endif /* __GNUC__ < 2 */ + +#if defined (__alpha) && W_TYPE_SIZE == 64 +#define umul_ppmm(ph, pl, m0, m1) \ + do { \ + UDItype __m0 = (m0), __m1 = (m1); \ + (ph) = __builtin_alpha_umulh (__m0, __m1); \ + (pl) = __m0 * __m1; \ + } while (0) +#define UMUL_TIME 46 +#ifndef LONGLONG_STANDALONE +#define udiv_qrnnd(q, r, n1, n0, d) \ + do { UDItype __r; \ + (q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \ + (r) = __r; \ + } while (0) +extern UDItype __udiv_qrnnd (UDItype *, UDItype, UDItype, UDItype); +#define UDIV_TIME 220 +#endif /* LONGLONG_STANDALONE */ +#ifdef __alpha_cix__ +#define count_leading_zeros(COUNT,X) ((COUNT) = __builtin_clzl (X)) +#define count_trailing_zeros(COUNT,X) ((COUNT) = __builtin_ctzl (X)) +#define COUNT_LEADING_ZEROS_0 64 +#else +#define count_leading_zeros(COUNT,X) \ + do { \ + UDItype __xr = (X), __t, __a; \ + __t = __builtin_alpha_cmpbge (0, __xr); \ + __a = __clz_tab[__t ^ 0xff] - 1; \ + __t = __builtin_alpha_extbl (__xr, __a); \ + (COUNT) = 64 - (__clz_tab[__t] + __a*8); \ + } while (0) +#define count_trailing_zeros(COUNT,X) \ + do { \ + UDItype __xr = (X), __t, __a; \ + __t = __builtin_alpha_cmpbge (0, __xr); \ + __t = ~__t & -~__t; \ + __a = ((__t & 0xCC) != 0) * 2; \ + __a += ((__t & 0xF0) != 0) * 4; \ + __a += ((__t & 0xAA) != 0); \ + __t = __builtin_alpha_extbl (__xr, __a); \ + __a <<= 3; \ + __t &= -__t; \ + __a += ((__t & 0xCC) != 0) * 2; \ + __a += ((__t & 0xF0) != 0) * 4; \ + __a += ((__t & 0xAA) != 0); \ + (COUNT) = __a; \ + } while (0) +#endif /* __alpha_cix__ */ +#endif /* __alpha */ + +#if defined (__arc__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("add.f %1, %4, %5\n\tadc %0, %2, %3" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "%r" ((USItype) (ah)), \ + "rIJ" ((USItype) (bh)), \ + "%r" ((USItype) (al)), \ + "rIJ" ((USItype) (bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("sub.f %1, %4, %5\n\tsbc %0, %2, %3" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "r" ((USItype) (ah)), \ + "rIJ" ((USItype) (bh)), \ + "r" ((USItype) (al)), \ + "rIJ" ((USItype) (bl))) +/* Call libgcc routine. */ +#define umul_ppmm(w1, w0, u, v) \ +do { \ + DWunion __w; \ + __w.ll = __umulsidi3 (u, v); \ + w1 = __w.s.high; \ + w0 = __w.s.low; \ +} while (0) +#define __umulsidi3 __umulsidi3 +UDItype __umulsidi3 (USItype, USItype); +#endif + +#if defined (__arm__) && !defined (__thumb__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("adds %1, %4, %5\n\tadc %0, %2, %3" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "%r" ((USItype) (ah)), \ + "rI" ((USItype) (bh)), \ + "%r" ((USItype) (al)), \ + "rI" ((USItype) (bl)) __CLOBBER_CC) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subs %1, %4, %5\n\tsbc %0, %2, %3" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "r" ((USItype) (ah)), \ + "rI" ((USItype) (bh)), \ + "r" ((USItype) (al)), \ + "rI" ((USItype) (bl)) __CLOBBER_CC) +#define umul_ppmm(xh, xl, a, b) \ +{register USItype __t0, __t1, __t2; \ + __asm__ ("%@ Inlined umul_ppmm\n" \ + " mov %2, %5, lsr #16\n" \ + " mov %0, %6, lsr #16\n" \ + " bic %3, %5, %2, lsl #16\n" \ + " bic %4, %6, %0, lsl #16\n" \ + " mul %1, %3, %4\n" \ + " mul %4, %2, %4\n" \ + " mul %3, %0, %3\n" \ + " mul %0, %2, %0\n" \ + " adds %3, %4, %3\n" \ + " addcs %0, %0, #65536\n" \ + " adds %1, %1, %3, lsl #16\n" \ + " adc %0, %0, %3, lsr #16" \ + : "=&r" ((USItype) (xh)), \ + "=r" ((USItype) (xl)), \ + "=&r" (__t0), "=&r" (__t1), "=r" (__t2) \ + : "r" ((USItype) (a)), \ + "r" ((USItype) (b)) __CLOBBER_CC );} +#define UMUL_TIME 20 +#define UDIV_TIME 100 +#endif /* __arm__ */ + +#if defined (__CRIS__) && __CRIS_arch_version >= 3 +#define count_leading_zeros(COUNT, X) ((COUNT) = __builtin_clz (X)) +#if __CRIS_arch_version >= 8 +#define count_trailing_zeros(COUNT, X) ((COUNT) = __builtin_ctz (X)) +#endif +#endif /* __CRIS__ */ + +#if defined (__hppa) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("add %4,%5,%1\n\taddc %2,%3,%0" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "%rM" ((USItype) (ah)), \ + "rM" ((USItype) (bh)), \ + "%rM" ((USItype) (al)), \ + "rM" ((USItype) (bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("sub %4,%5,%1\n\tsubb %2,%3,%0" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "rM" ((USItype) (ah)), \ + "rM" ((USItype) (bh)), \ + "rM" ((USItype) (al)), \ + "rM" ((USItype) (bl))) +#if defined (_PA_RISC1_1) +#define umul_ppmm(w1, w0, u, v) \ + do { \ + union \ + { \ + UDItype __f; \ + struct {USItype __w1, __w0;} __w1w0; \ + } __t; \ + __asm__ ("xmpyu %1,%2,%0" \ + : "=x" (__t.__f) \ + : "x" ((USItype) (u)), \ + "x" ((USItype) (v))); \ + (w1) = __t.__w1w0.__w1; \ + (w0) = __t.__w1w0.__w0; \ + } while (0) +#define UMUL_TIME 8 +#else +#define UMUL_TIME 30 +#endif +#define UDIV_TIME 40 +#define count_leading_zeros(count, x) \ + do { \ + USItype __tmp; \ + __asm__ ( \ + "ldi 1,%0\n" \ +" extru,= %1,15,16,%%r0 ; Bits 31..16 zero?\n" \ +" extru,tr %1,15,16,%1 ; No. Shift down, skip add.\n"\ +" ldo 16(%0),%0 ; Yes. Perform add.\n" \ +" extru,= %1,23,8,%%r0 ; Bits 15..8 zero?\n" \ +" extru,tr %1,23,8,%1 ; No. Shift down, skip add.\n"\ +" ldo 8(%0),%0 ; Yes. Perform add.\n" \ +" extru,= %1,27,4,%%r0 ; Bits 7..4 zero?\n" \ +" extru,tr %1,27,4,%1 ; No. Shift down, skip add.\n"\ +" ldo 4(%0),%0 ; Yes. Perform add.\n" \ +" extru,= %1,29,2,%%r0 ; Bits 3..2 zero?\n" \ +" extru,tr %1,29,2,%1 ; No. Shift down, skip add.\n"\ +" ldo 2(%0),%0 ; Yes. Perform add.\n" \ +" extru %1,30,1,%1 ; Extract bit 1.\n" \ +" sub %0,%1,%0 ; Subtract it.\n" \ + : "=r" (count), "=r" (__tmp) : "1" (x)); \ + } while (0) +#endif + +#if (defined (__i370__) || defined (__s390__) || defined (__mvs__)) && W_TYPE_SIZE == 32 +#define smul_ppmm(xh, xl, m0, m1) \ + do { \ + union {DItype __ll; \ + struct {USItype __h, __l;} __i; \ + } __x; \ + __asm__ ("lr %N0,%1\n\tmr %0,%2" \ + : "=&r" (__x.__ll) \ + : "r" (m0), "r" (m1)); \ + (xh) = __x.__i.__h; (xl) = __x.__i.__l; \ + } while (0) +#define sdiv_qrnnd(q, r, n1, n0, d) \ + do { \ + union {DItype __ll; \ + struct {USItype __h, __l;} __i; \ + } __x; \ + __x.__i.__h = n1; __x.__i.__l = n0; \ + __asm__ ("dr %0,%2" \ + : "=r" (__x.__ll) \ + : "0" (__x.__ll), "r" (d)); \ + (q) = __x.__i.__l; (r) = __x.__i.__h; \ + } while (0) +#endif + +#if (defined (__i386__) || defined (__i486__)) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("add{l} {%5,%1|%1,%5}\n\tadc{l} {%3,%0|%0,%3}" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "%0" ((USItype) (ah)), \ + "g" ((USItype) (bh)), \ + "%1" ((USItype) (al)), \ + "g" ((USItype) (bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("sub{l} {%5,%1|%1,%5}\n\tsbb{l} {%3,%0|%0,%3}" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "0" ((USItype) (ah)), \ + "g" ((USItype) (bh)), \ + "1" ((USItype) (al)), \ + "g" ((USItype) (bl))) +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("mul{l} %3" \ + : "=a" ((USItype) (w0)), \ + "=d" ((USItype) (w1)) \ + : "%0" ((USItype) (u)), \ + "rm" ((USItype) (v))) +#define udiv_qrnnd(q, r, n1, n0, dv) \ + __asm__ ("div{l} %4" \ + : "=a" ((USItype) (q)), \ + "=d" ((USItype) (r)) \ + : "0" ((USItype) (n0)), \ + "1" ((USItype) (n1)), \ + "rm" ((USItype) (dv))) +#define count_leading_zeros(count, x) ((count) = __builtin_clz (x)) +#define count_trailing_zeros(count, x) ((count) = __builtin_ctz (x)) +#define UMUL_TIME 40 +#define UDIV_TIME 40 +#endif /* 80x86 */ + +#if (defined (__x86_64__) || defined (__i386__)) && W_TYPE_SIZE == 64 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("add{q} {%5,%1|%1,%5}\n\tadc{q} {%3,%0|%0,%3}" \ + : "=r" ((UDItype) (sh)), \ + "=&r" ((UDItype) (sl)) \ + : "%0" ((UDItype) (ah)), \ + "rme" ((UDItype) (bh)), \ + "%1" ((UDItype) (al)), \ + "rme" ((UDItype) (bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("sub{q} {%5,%1|%1,%5}\n\tsbb{q} {%3,%0|%0,%3}" \ + : "=r" ((UDItype) (sh)), \ + "=&r" ((UDItype) (sl)) \ + : "0" ((UDItype) (ah)), \ + "rme" ((UDItype) (bh)), \ + "1" ((UDItype) (al)), \ + "rme" ((UDItype) (bl))) +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("mul{q} %3" \ + : "=a" ((UDItype) (w0)), \ + "=d" ((UDItype) (w1)) \ + : "%0" ((UDItype) (u)), \ + "rm" ((UDItype) (v))) +#define udiv_qrnnd(q, r, n1, n0, dv) \ + __asm__ ("div{q} %4" \ + : "=a" ((UDItype) (q)), \ + "=d" ((UDItype) (r)) \ + : "0" ((UDItype) (n0)), \ + "1" ((UDItype) (n1)), \ + "rm" ((UDItype) (dv))) +#define count_leading_zeros(count, x) ((count) = __builtin_clzl (x)) +#define count_trailing_zeros(count, x) ((count) = __builtin_ctzl (x)) +#define UMUL_TIME 40 +#define UDIV_TIME 40 +#endif /* x86_64 */ + +#if defined (__i960__) && W_TYPE_SIZE == 32 +#define umul_ppmm(w1, w0, u, v) \ + ({union {UDItype __ll; \ + struct {USItype __l, __h;} __i; \ + } __xx; \ + __asm__ ("emul %2,%1,%0" \ + : "=d" (__xx.__ll) \ + : "%dI" ((USItype) (u)), \ + "dI" ((USItype) (v))); \ + (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;}) +#define __umulsidi3(u, v) \ + ({UDItype __w; \ + __asm__ ("emul %2,%1,%0" \ + : "=d" (__w) \ + : "%dI" ((USItype) (u)), \ + "dI" ((USItype) (v))); \ + __w; }) +#endif /* __i960__ */ + +#if defined (__M32R__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + /* The cmp clears the condition bit. */ \ + __asm__ ("cmp %0,%0\n\taddx %1,%5\n\taddx %0,%3" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "0" ((USItype) (ah)), \ + "r" ((USItype) (bh)), \ + "1" ((USItype) (al)), \ + "r" ((USItype) (bl)) \ + : "cbit") +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + /* The cmp clears the condition bit. */ \ + __asm__ ("cmp %0,%0\n\tsubx %1,%5\n\tsubx %0,%3" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "0" ((USItype) (ah)), \ + "r" ((USItype) (bh)), \ + "1" ((USItype) (al)), \ + "r" ((USItype) (bl)) \ + : "cbit") +#endif /* __M32R__ */ + +#if defined (__mc68000__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("add%.l %5,%1\n\taddx%.l %3,%0" \ + : "=d" ((USItype) (sh)), \ + "=&d" ((USItype) (sl)) \ + : "%0" ((USItype) (ah)), \ + "d" ((USItype) (bh)), \ + "%1" ((USItype) (al)), \ + "g" ((USItype) (bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("sub%.l %5,%1\n\tsubx%.l %3,%0" \ + : "=d" ((USItype) (sh)), \ + "=&d" ((USItype) (sl)) \ + : "0" ((USItype) (ah)), \ + "d" ((USItype) (bh)), \ + "1" ((USItype) (al)), \ + "g" ((USItype) (bl))) + +/* The '020, '030, '040, '060 and CPU32 have 32x32->64 and 64/32->32q-32r. */ +#if (defined (__mc68020__) && !defined (__mc68060__)) +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("mulu%.l %3,%1:%0" \ + : "=d" ((USItype) (w0)), \ + "=d" ((USItype) (w1)) \ + : "%0" ((USItype) (u)), \ + "dmi" ((USItype) (v))) +#define UMUL_TIME 45 +#define udiv_qrnnd(q, r, n1, n0, d) \ + __asm__ ("divu%.l %4,%1:%0" \ + : "=d" ((USItype) (q)), \ + "=d" ((USItype) (r)) \ + : "0" ((USItype) (n0)), \ + "1" ((USItype) (n1)), \ + "dmi" ((USItype) (d))) +#define UDIV_TIME 90 +#define sdiv_qrnnd(q, r, n1, n0, d) \ + __asm__ ("divs%.l %4,%1:%0" \ + : "=d" ((USItype) (q)), \ + "=d" ((USItype) (r)) \ + : "0" ((USItype) (n0)), \ + "1" ((USItype) (n1)), \ + "dmi" ((USItype) (d))) + +#elif defined (__mcoldfire__) /* not mc68020 */ + +#define umul_ppmm(xh, xl, a, b) \ + __asm__ ("| Inlined umul_ppmm\n" \ + " move%.l %2,%/d0\n" \ + " move%.l %3,%/d1\n" \ + " move%.l %/d0,%/d2\n" \ + " swap %/d0\n" \ + " move%.l %/d1,%/d3\n" \ + " swap %/d1\n" \ + " move%.w %/d2,%/d4\n" \ + " mulu %/d3,%/d4\n" \ + " mulu %/d1,%/d2\n" \ + " mulu %/d0,%/d3\n" \ + " mulu %/d0,%/d1\n" \ + " move%.l %/d4,%/d0\n" \ + " clr%.w %/d0\n" \ + " swap %/d0\n" \ + " add%.l %/d0,%/d2\n" \ + " add%.l %/d3,%/d2\n" \ + " jcc 1f\n" \ + " add%.l %#65536,%/d1\n" \ + "1: swap %/d2\n" \ + " moveq %#0,%/d0\n" \ + " move%.w %/d2,%/d0\n" \ + " move%.w %/d4,%/d2\n" \ + " move%.l %/d2,%1\n" \ + " add%.l %/d1,%/d0\n" \ + " move%.l %/d0,%0" \ + : "=g" ((USItype) (xh)), \ + "=g" ((USItype) (xl)) \ + : "g" ((USItype) (a)), \ + "g" ((USItype) (b)) \ + : "d0", "d1", "d2", "d3", "d4") +#define UMUL_TIME 100 +#define UDIV_TIME 400 +#else /* not ColdFire */ +/* %/ inserts REGISTER_PREFIX, %# inserts IMMEDIATE_PREFIX. */ +#define umul_ppmm(xh, xl, a, b) \ + __asm__ ("| Inlined umul_ppmm\n" \ + " move%.l %2,%/d0\n" \ + " move%.l %3,%/d1\n" \ + " move%.l %/d0,%/d2\n" \ + " swap %/d0\n" \ + " move%.l %/d1,%/d3\n" \ + " swap %/d1\n" \ + " move%.w %/d2,%/d4\n" \ + " mulu %/d3,%/d4\n" \ + " mulu %/d1,%/d2\n" \ + " mulu %/d0,%/d3\n" \ + " mulu %/d0,%/d1\n" \ + " move%.l %/d4,%/d0\n" \ + " eor%.w %/d0,%/d0\n" \ + " swap %/d0\n" \ + " add%.l %/d0,%/d2\n" \ + " add%.l %/d3,%/d2\n" \ + " jcc 1f\n" \ + " add%.l %#65536,%/d1\n" \ + "1: swap %/d2\n" \ + " moveq %#0,%/d0\n" \ + " move%.w %/d2,%/d0\n" \ + " move%.w %/d4,%/d2\n" \ + " move%.l %/d2,%1\n" \ + " add%.l %/d1,%/d0\n" \ + " move%.l %/d0,%0" \ + : "=g" ((USItype) (xh)), \ + "=g" ((USItype) (xl)) \ + : "g" ((USItype) (a)), \ + "g" ((USItype) (b)) \ + : "d0", "d1", "d2", "d3", "d4") +#define UMUL_TIME 100 +#define UDIV_TIME 400 + +#endif /* not mc68020 */ + +/* The '020, '030, '040 and '060 have bitfield insns. + cpu32 disguises as a 68020, but lacks them. */ +#if defined (__mc68020__) && !defined (__mcpu32__) +#define count_leading_zeros(count, x) \ + __asm__ ("bfffo %1{%b2:%b2},%0" \ + : "=d" ((USItype) (count)) \ + : "od" ((USItype) (x)), "n" (0)) +/* Some ColdFire architectures have a ff1 instruction supported via + __builtin_clz. */ +#elif defined (__mcfisaaplus__) || defined (__mcfisac__) +#define count_leading_zeros(count,x) ((count) = __builtin_clz (x)) +#define COUNT_LEADING_ZEROS_0 32 +#endif +#endif /* mc68000 */ + +#if defined (__m88000__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("addu.co %1,%r4,%r5\n\taddu.ci %0,%r2,%r3" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "%rJ" ((USItype) (ah)), \ + "rJ" ((USItype) (bh)), \ + "%rJ" ((USItype) (al)), \ + "rJ" ((USItype) (bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subu.co %1,%r4,%r5\n\tsubu.ci %0,%r2,%r3" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "rJ" ((USItype) (ah)), \ + "rJ" ((USItype) (bh)), \ + "rJ" ((USItype) (al)), \ + "rJ" ((USItype) (bl))) +#define count_leading_zeros(count, x) \ + do { \ + USItype __cbtmp; \ + __asm__ ("ff1 %0,%1" \ + : "=r" (__cbtmp) \ + : "r" ((USItype) (x))); \ + (count) = __cbtmp ^ 31; \ + } while (0) +#define COUNT_LEADING_ZEROS_0 63 /* sic */ +#if defined (__mc88110__) +#define umul_ppmm(wh, wl, u, v) \ + do { \ + union {UDItype __ll; \ + struct {USItype __h, __l;} __i; \ + } __xx; \ + __asm__ ("mulu.d %0,%1,%2" \ + : "=r" (__xx.__ll) \ + : "r" ((USItype) (u)), \ + "r" ((USItype) (v))); \ + (wh) = __xx.__i.__h; \ + (wl) = __xx.__i.__l; \ + } while (0) +#define udiv_qrnnd(q, r, n1, n0, d) \ + ({union {UDItype __ll; \ + struct {USItype __h, __l;} __i; \ + } __xx; \ + USItype __q; \ + __xx.__i.__h = (n1); __xx.__i.__l = (n0); \ + __asm__ ("divu.d %0,%1,%2" \ + : "=r" (__q) \ + : "r" (__xx.__ll), \ + "r" ((USItype) (d))); \ + (r) = (n0) - __q * (d); (q) = __q; }) +#define UMUL_TIME 5 +#define UDIV_TIME 25 +#else +#define UMUL_TIME 17 +#define UDIV_TIME 150 +#endif /* __mc88110__ */ +#endif /* __m88000__ */ + +#if defined (__mips__) && W_TYPE_SIZE == 32 +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("multu %2,%3" \ + : "=l" ((USItype) (w0)), \ + "=h" ((USItype) (w1)) \ + : "d" ((USItype) (u)), \ + "d" ((USItype) (v))) +#define UMUL_TIME 10 +#define UDIV_TIME 100 + +#if (__mips == 32 || __mips == 64) && ! __mips16 +#define count_leading_zeros(COUNT,X) ((COUNT) = __builtin_clz (X)) +#define COUNT_LEADING_ZEROS_0 32 +#endif +#endif /* __mips__ */ + +#if defined (__ns32000__) && W_TYPE_SIZE == 32 +#define umul_ppmm(w1, w0, u, v) \ + ({union {UDItype __ll; \ + struct {USItype __l, __h;} __i; \ + } __xx; \ + __asm__ ("meid %2,%0" \ + : "=g" (__xx.__ll) \ + : "%0" ((USItype) (u)), \ + "g" ((USItype) (v))); \ + (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;}) +#define __umulsidi3(u, v) \ + ({UDItype __w; \ + __asm__ ("meid %2,%0" \ + : "=g" (__w) \ + : "%0" ((USItype) (u)), \ + "g" ((USItype) (v))); \ + __w; }) +#define udiv_qrnnd(q, r, n1, n0, d) \ + ({union {UDItype __ll; \ + struct {USItype __l, __h;} __i; \ + } __xx; \ + __xx.__i.__h = (n1); __xx.__i.__l = (n0); \ + __asm__ ("deid %2,%0" \ + : "=g" (__xx.__ll) \ + : "0" (__xx.__ll), \ + "g" ((USItype) (d))); \ + (r) = __xx.__i.__l; (q) = __xx.__i.__h; }) +#define count_trailing_zeros(count,x) \ + do { \ + __asm__ ("ffsd %2,%0" \ + : "=r" ((USItype) (count)) \ + : "0" ((USItype) 0), \ + "r" ((USItype) (x))); \ + } while (0) +#endif /* __ns32000__ */ + +/* FIXME: We should test _IBMR2 here when we add assembly support for the + system vendor compilers. + FIXME: What's needed for gcc PowerPC VxWorks? __vxworks__ is not good + enough, since that hits ARM and m68k too. */ +#if (defined (_ARCH_PPC) /* AIX */ \ + || defined (_ARCH_PWR) /* AIX */ \ + || defined (_ARCH_COM) /* AIX */ \ + || defined (__powerpc__) /* gcc */ \ + || defined (__POWERPC__) /* BEOS */ \ + || defined (__ppc__) /* Darwin */ \ + || (defined (PPC) && ! defined (CPU_FAMILY)) /* gcc 2.7.x GNU&SysV */ \ + || (defined (PPC) && defined (CPU_FAMILY) /* VxWorks */ \ + && CPU_FAMILY == PPC) \ + ) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + do { \ + if (__builtin_constant_p (bh) && (bh) == 0) \ + __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ + else if (__builtin_constant_p (bh) && (bh) == ~(USItype) 0) \ + __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ + else \ + __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \ + : "=r" (sh), "=&r" (sl) \ + : "%r" (ah), "r" (bh), "%r" (al), "rI" (bl)); \ + } while (0) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + do { \ + if (__builtin_constant_p (ah) && (ah) == 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ + else if (__builtin_constant_p (ah) && (ah) == ~(USItype) 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ + else if (__builtin_constant_p (bh) && (bh) == 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ + else if (__builtin_constant_p (bh) && (bh) == ~(USItype) 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ + else \ + __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \ + : "=r" (sh), "=&r" (sl) \ + : "r" (ah), "r" (bh), "rI" (al), "r" (bl)); \ + } while (0) +#define count_leading_zeros(count, x) \ + __asm__ ("{cntlz|cntlzw} %0,%1" : "=r" (count) : "r" (x)) +#define COUNT_LEADING_ZEROS_0 32 +#if defined (_ARCH_PPC) || defined (__powerpc__) || defined (__POWERPC__) \ + || defined (__ppc__) \ + || (defined (PPC) && ! defined (CPU_FAMILY)) /* gcc 2.7.x GNU&SysV */ \ + || (defined (PPC) && defined (CPU_FAMILY) /* VxWorks */ \ + && CPU_FAMILY == PPC) +#define umul_ppmm(ph, pl, m0, m1) \ + do { \ + USItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("mulhwu %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \ + (pl) = __m0 * __m1; \ + } while (0) +#define UMUL_TIME 15 +#define smul_ppmm(ph, pl, m0, m1) \ + do { \ + SItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("mulhw %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \ + (pl) = __m0 * __m1; \ + } while (0) +#define SMUL_TIME 14 +#define UDIV_TIME 120 +#elif defined (_ARCH_PWR) +#define UMUL_TIME 8 +#define smul_ppmm(xh, xl, m0, m1) \ + __asm__ ("mul %0,%2,%3" : "=r" (xh), "=q" (xl) : "r" (m0), "r" (m1)) +#define SMUL_TIME 4 +#define sdiv_qrnnd(q, r, nh, nl, d) \ + __asm__ ("div %0,%2,%4" : "=r" (q), "=q" (r) : "r" (nh), "1" (nl), "r" (d)) +#define UDIV_TIME 100 +#endif +#endif /* 32-bit POWER architecture variants. */ + +/* We should test _IBMR2 here when we add assembly support for the system + vendor compilers. */ +#if (defined (_ARCH_PPC64) || defined (__powerpc64__)) && W_TYPE_SIZE == 64 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + do { \ + if (__builtin_constant_p (bh) && (bh) == 0) \ + __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ + else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0) \ + __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ + else \ + __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \ + : "=r" (sh), "=&r" (sl) \ + : "%r" (ah), "r" (bh), "%r" (al), "rI" (bl)); \ + } while (0) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + do { \ + if (__builtin_constant_p (ah) && (ah) == 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ + else if (__builtin_constant_p (ah) && (ah) == ~(UDItype) 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ + else if (__builtin_constant_p (bh) && (bh) == 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ + else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \ + : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ + else \ + __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \ + : "=r" (sh), "=&r" (sl) \ + : "r" (ah), "r" (bh), "rI" (al), "r" (bl)); \ + } while (0) +#define count_leading_zeros(count, x) \ + __asm__ ("cntlzd %0,%1" : "=r" (count) : "r" (x)) +#define COUNT_LEADING_ZEROS_0 64 +#define umul_ppmm(ph, pl, m0, m1) \ + do { \ + UDItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("mulhdu %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \ + (pl) = __m0 * __m1; \ + } while (0) +#define UMUL_TIME 15 +#define smul_ppmm(ph, pl, m0, m1) \ + do { \ + DItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("mulhd %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \ + (pl) = __m0 * __m1; \ + } while (0) +#define SMUL_TIME 14 /* ??? */ +#define UDIV_TIME 120 /* ??? */ +#endif /* 64-bit PowerPC. */ + +#if defined (__ibm032__) /* RT/ROMP */ && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("a %1,%5\n\tae %0,%3" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "%0" ((USItype) (ah)), \ + "r" ((USItype) (bh)), \ + "%1" ((USItype) (al)), \ + "r" ((USItype) (bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("s %1,%5\n\tse %0,%3" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "0" ((USItype) (ah)), \ + "r" ((USItype) (bh)), \ + "1" ((USItype) (al)), \ + "r" ((USItype) (bl))) +#define umul_ppmm(ph, pl, m0, m1) \ + do { \ + USItype __m0 = (m0), __m1 = (m1); \ + __asm__ ( \ + "s r2,r2\n" \ +" mts r10,%2\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" m r2,%3\n" \ +" cas %0,r2,r0\n" \ +" mfs r10,%1" \ + : "=r" ((USItype) (ph)), \ + "=r" ((USItype) (pl)) \ + : "%r" (__m0), \ + "r" (__m1) \ + : "r2"); \ + (ph) += ((((SItype) __m0 >> 31) & __m1) \ + + (((SItype) __m1 >> 31) & __m0)); \ + } while (0) +#define UMUL_TIME 20 +#define UDIV_TIME 200 +#define count_leading_zeros(count, x) \ + do { \ + if ((x) >= 0x10000) \ + __asm__ ("clz %0,%1" \ + : "=r" ((USItype) (count)) \ + : "r" ((USItype) (x) >> 16)); \ + else \ + { \ + __asm__ ("clz %0,%1" \ + : "=r" ((USItype) (count)) \ + : "r" ((USItype) (x))); \ + (count) += 16; \ + } \ + } while (0) +#endif + +#if defined(__sh__) && !__SHMEDIA__ && W_TYPE_SIZE == 32 +#ifndef __sh1__ +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ( \ + "dmulu.l %2,%3\n\tsts%M1 macl,%1\n\tsts%M0 mach,%0" \ + : "=r<" ((USItype)(w1)), \ + "=r<" ((USItype)(w0)) \ + : "r" ((USItype)(u)), \ + "r" ((USItype)(v)) \ + : "macl", "mach") +#define UMUL_TIME 5 +#endif + +/* This is the same algorithm as __udiv_qrnnd_c. */ +#define UDIV_NEEDS_NORMALIZATION 1 + +#define udiv_qrnnd(q, r, n1, n0, d) \ + do { \ + extern UWtype __udiv_qrnnd_16 (UWtype, UWtype) \ + __attribute__ ((visibility ("hidden"))); \ + /* r0: rn r1: qn */ /* r0: n1 r4: n0 r5: d r6: d1 */ /* r2: __m */ \ + __asm__ ( \ + "mov%M4 %4,r5\n" \ +" swap.w %3,r4\n" \ +" swap.w r5,r6\n" \ +" jsr @%5\n" \ +" shll16 r6\n" \ +" swap.w r4,r4\n" \ +" jsr @%5\n" \ +" swap.w r1,%0\n" \ +" or r1,%0" \ + : "=r" (q), "=&z" (r) \ + : "1" (n1), "r" (n0), "rm" (d), "r" (&__udiv_qrnnd_16) \ + : "r1", "r2", "r4", "r5", "r6", "pr"); \ + } while (0) + +#define UDIV_TIME 80 + +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("clrt;subc %5,%1; subc %4,%0" \ + : "=r" (sh), "=r" (sl) \ + : "0" (ah), "1" (al), "r" (bh), "r" (bl)) + +#endif /* __sh__ */ + +#if defined (__SH5__) && __SHMEDIA__ && W_TYPE_SIZE == 32 +#define __umulsidi3(u,v) ((UDItype)(USItype)u*(USItype)v) +#define count_leading_zeros(count, x) \ + do \ + { \ + UDItype x_ = (USItype)(x); \ + SItype c_; \ + \ + __asm__ ("nsb %1, %0" : "=r" (c_) : "r" (x_)); \ + (count) = c_ - 31; \ + } \ + while (0) +#define COUNT_LEADING_ZEROS_0 32 +#endif + +#if defined (__sparc__) && !defined (__arch64__) && !defined (__sparcv9) \ + && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("addcc %r4,%5,%1\n\taddx %r2,%3,%0" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "%rJ" ((USItype) (ah)), \ + "rI" ((USItype) (bh)), \ + "%rJ" ((USItype) (al)), \ + "rI" ((USItype) (bl)) \ + __CLOBBER_CC) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subcc %r4,%5,%1\n\tsubx %r2,%3,%0" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "rJ" ((USItype) (ah)), \ + "rI" ((USItype) (bh)), \ + "rJ" ((USItype) (al)), \ + "rI" ((USItype) (bl)) \ + __CLOBBER_CC) +#if defined (__sparc_v8__) +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("umul %2,%3,%1;rd %%y,%0" \ + : "=r" ((USItype) (w1)), \ + "=r" ((USItype) (w0)) \ + : "r" ((USItype) (u)), \ + "r" ((USItype) (v))) +#define udiv_qrnnd(__q, __r, __n1, __n0, __d) \ + __asm__ ("mov %2,%%y;nop;nop;nop;udiv %3,%4,%0;umul %0,%4,%1;sub %3,%1,%1"\ + : "=&r" ((USItype) (__q)), \ + "=&r" ((USItype) (__r)) \ + : "r" ((USItype) (__n1)), \ + "r" ((USItype) (__n0)), \ + "r" ((USItype) (__d))) +#else +#if defined (__sparclite__) +/* This has hardware multiply but not divide. It also has two additional + instructions scan (ffs from high bit) and divscc. */ +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("umul %2,%3,%1;rd %%y,%0" \ + : "=r" ((USItype) (w1)), \ + "=r" ((USItype) (w0)) \ + : "r" ((USItype) (u)), \ + "r" ((USItype) (v))) +#define udiv_qrnnd(q, r, n1, n0, d) \ + __asm__ ("! Inlined udiv_qrnnd\n" \ +" wr %%g0,%2,%%y ! Not a delayed write for sparclite\n" \ +" tst %%g0\n" \ +" divscc %3,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%%g1\n" \ +" divscc %%g1,%4,%0\n" \ +" rd %%y,%1\n" \ +" bl,a 1f\n" \ +" add %1,%4,%1\n" \ +"1: ! End of inline udiv_qrnnd" \ + : "=r" ((USItype) (q)), \ + "=r" ((USItype) (r)) \ + : "r" ((USItype) (n1)), \ + "r" ((USItype) (n0)), \ + "rI" ((USItype) (d)) \ + : "g1" __AND_CLOBBER_CC) +#define UDIV_TIME 37 +#define count_leading_zeros(count, x) \ + do { \ + __asm__ ("scan %1,1,%0" \ + : "=r" ((USItype) (count)) \ + : "r" ((USItype) (x))); \ + } while (0) +/* Early sparclites return 63 for an argument of 0, but they warn that future + implementations might change this. Therefore, leave COUNT_LEADING_ZEROS_0 + undefined. */ +#else +/* SPARC without integer multiplication and divide instructions. + (i.e. at least Sun4/20,40,60,65,75,110,260,280,330,360,380,470,490) */ +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("! Inlined umul_ppmm\n" \ +" wr %%g0,%2,%%y ! SPARC has 0-3 delay insn after a wr\n"\ +" sra %3,31,%%o5 ! Don't move this insn\n" \ +" and %2,%%o5,%%o5 ! Don't move this insn\n" \ +" andcc %%g0,0,%%g1 ! Don't move this insn\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,%3,%%g1\n" \ +" mulscc %%g1,0,%%g1\n" \ +" add %%g1,%%o5,%0\n" \ +" rd %%y,%1" \ + : "=r" ((USItype) (w1)), \ + "=r" ((USItype) (w0)) \ + : "%rI" ((USItype) (u)), \ + "r" ((USItype) (v)) \ + : "g1", "o5" __AND_CLOBBER_CC) +#define UMUL_TIME 39 /* 39 instructions */ +/* 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\n" \ +" mov 32,%%g1\n" \ +" subcc %1,%2,%%g0\n" \ +"1: bcs 5f\n" \ +" addxcc %0,%0,%0 ! shift n1n0 and a q-bit in lsb\n" \ +" sub %1,%2,%1 ! this kills msb of n\n" \ +" addx %1,%1,%1 ! so this can't give carry\n" \ +" subcc %%g1,1,%%g1\n" \ +"2: bne 1b\n" \ +" subcc %1,%2,%%g0\n" \ +" bcs 3f\n" \ +" addxcc %0,%0,%0 ! shift n1n0 and a q-bit in lsb\n" \ +" b 3f\n" \ +" sub %1,%2,%1 ! this kills msb of n\n" \ +"4: sub %1,%2,%1\n" \ +"5: addxcc %1,%1,%1\n" \ +" bcc 2b\n" \ +" subcc %%g1,1,%%g1\n" \ +"! Got carry from n. Subtract next step to cancel this carry.\n" \ +" bne 4b\n" \ +" addcc %0,%0,%0 ! shift n1n0 and a 0-bit in lsb\n" \ +" sub %1,%2,%1\n" \ +"3: xnor %0,0,%0\n" \ +" ! End of inline udiv_qrnnd" \ + : "=&r" ((USItype) (__q)), \ + "=&r" ((USItype) (__r)) \ + : "r" ((USItype) (__d)), \ + "1" ((USItype) (__n1)), \ + "0" ((USItype) (__n0)) : "g1" __AND_CLOBBER_CC) +#define UDIV_TIME (3+7*32) /* 7 instructions/iteration. 32 iterations. */ +#endif /* __sparclite__ */ +#endif /* __sparc_v8__ */ +#endif /* sparc32 */ + +#if ((defined (__sparc__) && defined (__arch64__)) || defined (__sparcv9)) \ + && W_TYPE_SIZE == 64 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("addcc %r4,%5,%1\n\t" \ + "add %r2,%3,%0\n\t" \ + "bcs,a,pn %%xcc, 1f\n\t" \ + "add %0, 1, %0\n" \ + "1:" \ + : "=r" ((UDItype)(sh)), \ + "=&r" ((UDItype)(sl)) \ + : "%rJ" ((UDItype)(ah)), \ + "rI" ((UDItype)(bh)), \ + "%rJ" ((UDItype)(al)), \ + "rI" ((UDItype)(bl)) \ + __CLOBBER_CC) + +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subcc %r4,%5,%1\n\t" \ + "sub %r2,%3,%0\n\t" \ + "bcs,a,pn %%xcc, 1f\n\t" \ + "sub %0, 1, %0\n\t" \ + "1:" \ + : "=r" ((UDItype)(sh)), \ + "=&r" ((UDItype)(sl)) \ + : "rJ" ((UDItype)(ah)), \ + "rI" ((UDItype)(bh)), \ + "rJ" ((UDItype)(al)), \ + "rI" ((UDItype)(bl)) \ + __CLOBBER_CC) + +#define umul_ppmm(wh, wl, u, v) \ + do { \ + UDItype tmp1, tmp2, tmp3, tmp4; \ + __asm__ __volatile__ ( \ + "srl %7,0,%3\n\t" \ + "mulx %3,%6,%1\n\t" \ + "srlx %6,32,%2\n\t" \ + "mulx %2,%3,%4\n\t" \ + "sllx %4,32,%5\n\t" \ + "srl %6,0,%3\n\t" \ + "sub %1,%5,%5\n\t" \ + "srlx %5,32,%5\n\t" \ + "addcc %4,%5,%4\n\t" \ + "srlx %7,32,%5\n\t" \ + "mulx %3,%5,%3\n\t" \ + "mulx %2,%5,%5\n\t" \ + "sethi %%hi(0x80000000),%2\n\t" \ + "addcc %4,%3,%4\n\t" \ + "srlx %4,32,%4\n\t" \ + "add %2,%2,%2\n\t" \ + "movcc %%xcc,%%g0,%2\n\t" \ + "addcc %5,%4,%5\n\t" \ + "sllx %3,32,%3\n\t" \ + "add %1,%3,%1\n\t" \ + "add %5,%2,%0" \ + : "=r" ((UDItype)(wh)), \ + "=&r" ((UDItype)(wl)), \ + "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3), "=&r" (tmp4) \ + : "r" ((UDItype)(u)), \ + "r" ((UDItype)(v)) \ + __CLOBBER_CC); \ + } while (0) +#define UMUL_TIME 96 +#define UDIV_TIME 230 +#endif /* sparc64 */ + +#if defined (__vax__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("addl2 %5,%1\n\tadwc %3,%0" \ + : "=g" ((USItype) (sh)), \ + "=&g" ((USItype) (sl)) \ + : "%0" ((USItype) (ah)), \ + "g" ((USItype) (bh)), \ + "%1" ((USItype) (al)), \ + "g" ((USItype) (bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subl2 %5,%1\n\tsbwc %3,%0" \ + : "=g" ((USItype) (sh)), \ + "=&g" ((USItype) (sl)) \ + : "0" ((USItype) (ah)), \ + "g" ((USItype) (bh)), \ + "1" ((USItype) (al)), \ + "g" ((USItype) (bl))) +#define umul_ppmm(xh, xl, m0, m1) \ + do { \ + union { \ + UDItype __ll; \ + struct {USItype __l, __h;} __i; \ + } __xx; \ + USItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("emul %1,%2,$0,%0" \ + : "=r" (__xx.__ll) \ + : "g" (__m0), \ + "g" (__m1)); \ + (xh) = __xx.__i.__h; \ + (xl) = __xx.__i.__l; \ + (xh) += ((((SItype) __m0 >> 31) & __m1) \ + + (((SItype) __m1 >> 31) & __m0)); \ + } while (0) +#define sdiv_qrnnd(q, r, n1, n0, d) \ + do { \ + union {DItype __ll; \ + struct {SItype __l, __h;} __i; \ + } __xx; \ + __xx.__i.__h = n1; __xx.__i.__l = n0; \ + __asm__ ("ediv %3,%2,%0,%1" \ + : "=g" (q), "=g" (r) \ + : "g" (__xx.__ll), "g" (d)); \ + } while (0) +#endif /* __vax__ */ + +#if defined (__xtensa__) && W_TYPE_SIZE == 32 +/* This code is not Xtensa-configuration-specific, so rely on the compiler + to expand builtin functions depending on what configuration features + are available. This avoids library calls when the operation can be + performed in-line. */ +#define umul_ppmm(w1, w0, u, v) \ + do { \ + DWunion __w; \ + __w.ll = __builtin_umulsidi3 (u, v); \ + w1 = __w.s.high; \ + w0 = __w.s.low; \ + } while (0) +#define __umulsidi3(u, v) __builtin_umulsidi3 (u, v) +#define count_leading_zeros(COUNT, X) ((COUNT) = __builtin_clz (X)) +#define count_trailing_zeros(COUNT, X) ((COUNT) = __builtin_ctz (X)) +#endif /* __xtensa__ */ + +#if defined (__z8000__) && W_TYPE_SIZE == 16 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("add %H1,%H5\n\tadc %H0,%H3" \ + : "=r" ((unsigned int)(sh)), \ + "=&r" ((unsigned int)(sl)) \ + : "%0" ((unsigned int)(ah)), \ + "r" ((unsigned int)(bh)), \ + "%1" ((unsigned int)(al)), \ + "rQR" ((unsigned int)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("sub %H1,%H5\n\tsbc %H0,%H3" \ + : "=r" ((unsigned int)(sh)), \ + "=&r" ((unsigned int)(sl)) \ + : "0" ((unsigned int)(ah)), \ + "r" ((unsigned int)(bh)), \ + "1" ((unsigned int)(al)), \ + "rQR" ((unsigned int)(bl))) +#define umul_ppmm(xh, xl, m0, m1) \ + do { \ + union {long int __ll; \ + struct {unsigned int __h, __l;} __i; \ + } __xx; \ + unsigned int __m0 = (m0), __m1 = (m1); \ + __asm__ ("mult %S0,%H3" \ + : "=r" (__xx.__i.__h), \ + "=r" (__xx.__i.__l) \ + : "%1" (__m0), \ + "rQR" (__m1)); \ + (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \ + (xh) += ((((signed int) __m0 >> 15) & __m1) \ + + (((signed int) __m1 >> 15) & __m0)); \ + } while (0) +#endif /* __z8000__ */ + +#endif /* __GNUC__ */ + +/* If this machine has no inline assembler, use C macros. */ + +#if !defined (add_ssaaaa) +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + do { \ + UWtype __x; \ + __x = (al) + (bl); \ + (sh) = (ah) + (bh) + (__x < (al)); \ + (sl) = __x; \ + } while (0) +#endif + +#if !defined (sub_ddmmss) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + do { \ + UWtype __x; \ + __x = (al) - (bl); \ + (sh) = (ah) - (bh) - (__x > (al)); \ + (sl) = __x; \ + } while (0) +#endif + +/* If we lack umul_ppmm but have smul_ppmm, define umul_ppmm in terms of + smul_ppmm. */ +#if !defined (umul_ppmm) && defined (smul_ppmm) +#define umul_ppmm(w1, w0, u, v) \ + do { \ + UWtype __w1; \ + UWtype __xm0 = (u), __xm1 = (v); \ + smul_ppmm (__w1, w0, __xm0, __xm1); \ + (w1) = __w1 + (-(__xm0 >> (W_TYPE_SIZE - 1)) & __xm1) \ + + (-(__xm1 >> (W_TYPE_SIZE - 1)) & __xm0); \ + } while (0) +#endif + +/* If we still don't have umul_ppmm, define it using plain C. */ +#if !defined (umul_ppmm) +#define umul_ppmm(w1, w0, u, v) \ + do { \ + UWtype __x0, __x1, __x2, __x3; \ + UHWtype __ul, __vl, __uh, __vh; \ + \ + __ul = __ll_lowpart (u); \ + __uh = __ll_highpart (u); \ + __vl = __ll_lowpart (v); \ + __vh = __ll_highpart (v); \ + \ + __x0 = (UWtype) __ul * __vl; \ + __x1 = (UWtype) __ul * __vh; \ + __x2 = (UWtype) __uh * __vl; \ + __x3 = (UWtype) __uh * __vh; \ + \ + __x1 += __ll_highpart (__x0);/* this can't give carry */ \ + __x1 += __x2; /* but this indeed can */ \ + if (__x1 < __x2) /* did we get it? */ \ + __x3 += __ll_B; /* yes, add it in the proper pos. */ \ + \ + (w1) = __x3 + __ll_highpart (__x1); \ + (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0); \ + } while (0) +#endif + +#if !defined (__umulsidi3) +#define __umulsidi3(u, v) \ + ({DWunion __w; \ + umul_ppmm (__w.s.high, __w.s.low, u, v); \ + __w.ll; }) +#endif + +/* Define this unconditionally, so it can be used for debugging. */ +#define __udiv_qrnnd_c(q, r, n1, n0, d) \ + do { \ + UWtype __d1, __d0, __q1, __q0; \ + UWtype __r1, __r0, __m; \ + __d1 = __ll_highpart (d); \ + __d0 = __ll_lowpart (d); \ + \ + __r1 = (n1) % __d1; \ + __q1 = (n1) / __d1; \ + __m = (UWtype) __q1 * __d0; \ + __r1 = __r1 * __ll_B | __ll_highpart (n0); \ + 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 * __ll_B | __ll_lowpart (n0); \ + if (__r0 < __m) \ + { \ + __q0--, __r0 += (d); \ + if (__r0 >= (d)) \ + if (__r0 < __m) \ + __q0--, __r0 += (d); \ + } \ + __r0 -= __m; \ + \ + (q) = (UWtype) __q1 * __ll_B | __q0; \ + (r) = __r0; \ + } while (0) + +/* If the processor has no udiv_qrnnd but sdiv_qrnnd, go through + __udiv_w_sdiv (defined in libgcc or elsewhere). */ +#if !defined (udiv_qrnnd) && defined (sdiv_qrnnd) +#define udiv_qrnnd(q, r, nh, nl, d) \ + do { \ + USItype __r; \ + (q) = __udiv_w_sdiv (&__r, nh, nl, d); \ + (r) = __r; \ + } while (0) +#endif + +/* If udiv_qrnnd was not defined for this processor, use __udiv_qrnnd_c. */ +#if !defined (udiv_qrnnd) +#define UDIV_NEEDS_NORMALIZATION 1 +#define udiv_qrnnd __udiv_qrnnd_c +#endif + +#if !defined (count_leading_zeros) +#define count_leading_zeros(count, x) \ + do { \ + UWtype __xr = (x); \ + UWtype __a; \ + \ + if (W_TYPE_SIZE <= 32) \ + { \ + __a = __xr < ((UWtype)1<<2*__BITS4) \ + ? (__xr < ((UWtype)1<<__BITS4) ? 0 : __BITS4) \ + : (__xr < ((UWtype)1<<3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \ + } \ + else \ + { \ + for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8) \ + if (((__xr >> __a) & 0xff) != 0) \ + break; \ + } \ + \ + (count) = W_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \ + } while (0) +#define COUNT_LEADING_ZEROS_0 W_TYPE_SIZE +#endif + +#if !defined (count_trailing_zeros) +/* Define count_trailing_zeros using count_leading_zeros. The latter might be + defined in asm, but if it is not, the C version above is good enough. */ +#define count_trailing_zeros(count, x) \ + do { \ + UWtype __ctz_x = (x); \ + UWtype __ctz_c; \ + count_leading_zeros (__ctz_c, __ctz_x & -__ctz_x); \ + (count) = W_TYPE_SIZE - 1 - __ctz_c; \ + } while (0) +#endif + +#ifndef UDIV_NEEDS_NORMALIZATION +#define UDIV_NEEDS_NORMALIZATION 0 +#endif diff --git a/setup/Linux/build.sh b/setup/Linux/build.sh new file mode 100644 index 0000000..e889bfe --- /dev/null +++ b/setup/Linux/build.sh @@ -0,0 +1,240 @@ +#!/bin/sh + +. ./.directories + +if gawk '' >/dev/null +then + TXT2MAN=$SRCDIR/setup/txt2man +else + echo "No gawk found. Using lesser replacement" >&2 + cc -o txt2man origdir/setup/txt2man.c + TXT2MAN=./txt2man +fi + +[ -z "$LD" ] && LD=ld + +rm -rf prototype + +mkdir prototype +mkdir prototype/etc +echo "OSSLIBDIR=$OSSLIBDIR" > prototype/etc/oss.conf +mkdir prototype/usr +mkdir prototype/usr/bin +mkdir prototype/usr/share +mkdir prototype/usr/share/man +mkdir prototype/usr/share/man/man1 +mkdir prototype/usr/share/man/man7 +mkdir prototype/usr/share/man/man8 +mkdir prototype/usr/sbin +mkdir -p prototype/$OSSLIBDIR +mkdir prototype/$OSSLIBDIR/etc +mkdir prototype/$OSSLIBDIR/save +mkdir prototype/$OSSLIBDIR/conf.tmpl +mkdir prototype/$OSSLIBDIR/lib +mkdir prototype/$OSSLIBDIR/modules.regparm +mkdir prototype/$OSSLIBDIR/modules.noregparm +mkdir prototype/$OSSLIBDIR/objects.regparm +mkdir prototype/$OSSLIBDIR/objects.noregparm +mkdir prototype/$OSSLIBDIR/include +mkdir prototype/$OSSLIBDIR/include/sys +mkdir prototype/$OSSLIBDIR/include/internals +mkdir prototype/$OSSLIBDIR/build + +chmod 700 prototype/$OSSLIBDIR/modules.* +chmod 700 prototype/$OSSLIBDIR/objects.* +chmod 700 prototype/$OSSLIBDIR/build +chmod 700 prototype/$OSSLIBDIR/save + +if test -f regparm && test "`cat regparm` " = "1 " +then + MODULES=modules.regparm + OBJECTS=objects.regparm +else + MODULES=modules.noregparm + OBJECTS=objects.noregparm +fi + +cp .version prototype/$OSSLIBDIR/version.dat + +if test "`uname -m` " != "arm " +then + if ! test -f regparm + then + echo Error: ./regparm is missing + exit 1 + fi + cp regparm prototype/$OSSLIBDIR/build +fi + +# Regenerating the config file templates +rm -f /tmp/confgen +if ! cc -o /tmp/confgen ./setup/Linux/confgen.c +then + echo Building confgen failed + exit 1 +fi + +if ! /tmp/confgen prototype/$OSSLIBDIR/conf.tmpl $OSSLIBDIR/conf kernel/drv/* kernel/nonfree/drv/* +then + echo Running confgen failed + exit 1 +fi + +rm -f /tmp/confgen + +cp $SRCDIR/include/*.h prototype/$OSSLIBDIR/include/sys/ +cp $SRCDIR/kernel/framework/include/midiparser.h prototype/$OSSLIBDIR/include/ +cp -f $SRCDIR/kernel/OS/Linux/wrapper/wrap.h prototype/$OSSLIBDIR/build/ +cp -f $SRCDIR/kernel/framework/include/udi.h prototype/$OSSLIBDIR/build/ +cp -a $SRCDIR/kernel/framework/include/*_core.h kernel/framework/include/local_config.h prototype/$OSSLIBDIR/include/internals +cp $SRCDIR/kernel/framework/include/ossddk/*.h prototype/$OSSLIBDIR/include/internals +cp kernel/framework/include/timestamp.h prototype/$OSSLIBDIR/include/internals +cp kernel/framework/include/ossddk/oss_limits.h prototype/$OSSLIBDIR/include/internals + +cat > prototype/$OSSLIBDIR/include/internals/WARNING.txt << EOF +Caution: All header files included in this directory are there only because + some parts of OSS may need to be re-compiled. It is not safe to use + these files for any purposes because they will change between OSS + versions/builds. +EOF + +(cd target/bin; rm -f ossrecord; ln -s ossplay ossrecord) +cp -f target/build/* prototype/$OSSLIBDIR/build/ +cp -f target/bin/* prototype/usr/bin +cp -f target/sbin/* prototype/usr/sbin + +cp -a $SRCDIR/setup/Linux/oss/* prototype/$OSSLIBDIR/ +cp -a $SRCDIR/setup/Linux/sbin prototype/usr/ +chmod +x prototype/$OSSLIBDIR/scripts/* + +if ! $LD -r -o prototype/$OSSLIBDIR/$OBJECTS/osscore.o target/objects/*.o +then + echo Linking osscore failed! + exit 1 +fi + +rm -f devlist.txt devices.list + +for n in `find kernel/ -name .devices` +do + cat $n >> devices.list +done + +for n in target/modules/*.o +do + N=`basename $n .o` + $LD -r -o prototype/$OSSLIBDIR/$MODULES/$N.o $n + echo Check devices for $N + grep "^$N[ ]" ./devices.list >> devlist.txt + + rm -f /tmp/ossman.txt + + if test -f $SRCDIR/kernel/drv/$N/$N.man + then + sed "s:CONFIGFILEPATH:$OSSLIBDIR/conf:g" < $SRCDIR/kernel/drv/$N/$N.man > /tmp/ossman.txt + $TXT2MAN -t "$CMD" -v "OSS Devices" -s 7 /tmp/ossman.txt | gzip -9 > prototype/usr/share/man/man7/$N.7.gz + else + if test -f $SRCDIR/kernel/nonfree/drv/$N/$N.man + then + sed "s:CONFIGFILEPATH:$OSSLIBDIR/conf:g" < $SRCDIR/kernel/nonfree/drv/$N/$N.man > /tmp/ossman.txt + $TXT2MAN -t "$CMD" -v "OSS Devices" -s 7 $SRCDIR/kernel/nonfree/drv/$N/$N.man | gzip -9 > prototype/usr/share/man/man7/$N.7.gz + fi + fi +done + +sed "s:CONFIGFILEPATH:$OSSLIBDIR/conf:g" < $SRCDIR/kernel/drv/osscore/osscore.man > /tmp/ossman.txt +$TXT2MAN -t "osscore" -v "OSS Devices" -s 7 /tmp/ossman.txt | gzip -9 > prototype/usr/share/man/man7/osscore.7.gz +rm -f /tmp/ossman.txt + +# Link the optional NOREGPARM modules +if test -d noregparm +then + $LD -r -o prototype/$OSSLIBDIR/objects.noregparm/osscore.o noregparm/target/objects/*.o + + for n in noregparm/target/modules/*.o + do + N=`basename $n .o` + $LD -r -o prototype/$OSSLIBDIR/modules.noregparm/$N.o $n + done +fi + +for n in $SRCDIR/misc/man7/*.man +do + N=`basename $n .man` + + $TXT2MAN -t "$CMD" -v "OSS Devices" -s 7 $n | gzip -9 > prototype/usr/share/man/man7/$N.7.gz +done + +for n in $SRCDIR/misc/man1m/*.man +do + N=`basename $n .man` + $TXT2MAN -t "$CMD" -v "OSS System Administration Commands" -s 1 $n | gzip -9 > prototype/usr/share/man/man1/$N.1.gz +done + +if ! cp lib/libOSSlib/libOSSlib.so lib/libsalsa/.libs/libsalsa.so.2.0.0 prototype/$OSSLIBDIR/lib +then + echo Warning: No libsalsa library compiled +fi + +cp target/lib/* prototype/$OSSLIBDIR/lib + +cp devlist.txt prototype/$OSSLIBDIR/etc/devices.list + +if test -d kernel/nonfree +then + cp devlist.txt $SRCDIR/devlists/Linux +fi + +# Generate Man pages for commands +for i in target/bin/* +do +CMD=`basename $i` +$TXT2MAN -t "$CMD" -v "OSS User Commands" -s 1 cmd/$CMD/$CMD.man | gzip -9 > prototype/usr/share/man/man1/$CMD.1.gz +echo done $CMD +done + +for i in target/sbin/* +do + CMD=`basename $i` + if test -f cmd/$CMD/$CMD.man + then + $TXT2MAN -t "$CMD" -v "OSS System Administration Commands" -s 8 cmd/$CMD/$CMD.man | gzip -9 > prototype/usr/share/man/man8/$CMD.8.gz + echo done $CMD + fi +done + +$TXT2MAN -t "ossdetect" -v "User Commands" -s 8 os_cmd/Linux/ossdetect/ossdetect.man | gzip -9 > prototype/usr/share/man/man8/ossdetect.8.gz +echo done ossdetect + +cp -f $SRCDIR/oss/lib/flashsupport.c prototype/$OSSLIBDIR/lib + +# Licensing stuff +if test -f 4front-private/osslic.c +then + cc -o prototype/usr/sbin/osslic -Isetup -Ikernel/nonfree/include -Ikernel/framework/include -Iinclude -Ikernel/OS/Linux -I$SRCDIR $SRCDIR/4front-private/osslic.c + strip prototype/usr/sbin/osslic + + BITS=3 # Default to 32 bit ELF format + if test "`uname -m` " = "x86_64 " + then + BITS=6 # Use 64 bit ELF format + fi + prototype/usr/sbin/osslic -q -u -$BITS./prototype/$OSSLIBDIR/objects.regparm/osscore.o + prototype/usr/sbin/osslic -q -u -$BITS./prototype/$OSSLIBDIR/objects.noregparm/osscore.o + +fi + +if test -f 4front-private/ossupdate.c +then + #ossupdate + cc -I. 4front-private/ossupdate.c -s -o prototype/usr/sbin/ossupdate +fi + +sh $SRCDIR/setup/build_common.sh $SRCDIR $OSSLIBDIR + +chmod 700 prototype/usr/sbin/* +chmod 755 prototype/usr/bin/* + +(cd prototype;ls usr/sbin/* usr/bin/* etc/* usr/share/man/man*/*) > prototype/$OSSLIBDIR/sysfiles.list + +exit 0 diff --git a/setup/Linux/build_arm.sh b/setup/Linux/build_arm.sh new file mode 100644 index 0000000..7031ec5 --- /dev/null +++ b/setup/Linux/build_arm.sh @@ -0,0 +1,96 @@ +#!/bin/sh + +# build script for ARM Linux (Nokia's Maemo plattform) + +. ./.directories + +KERNELDIR=~/maemo_kernel/kernel-source-diablo-2.6.21/kernel-source + +rm -rf prototype + +mkdir prototype +mkdir prototype/etc +echo "OSSLIBDIR=$OSSLIBDIR" > prototype/etc/oss.conf +mkdir prototype/usr +mkdir prototype/usr/bin +mkdir prototype/usr/sbin +mkdir -p prototype/$OSSLIBDIR +mkdir prototype/$OSSLIBDIR/etc +mkdir prototype/$OSSLIBDIR/conf.tmpl +mkdir prototype/$OSSLIBDIR/lib +mkdir prototype/$OSSLIBDIR/modules + +cp target/bin/* prototype/usr/bin +cp target/sbin/* prototype/usr/sbin +cp target/lib/* prototype/$OSSLIBDIR/lib + +# Compile the 64 bit div/mod functions required by gcc +rm -f bpabi.s bpabi_s.o bpabi_c.o bpabi.o +cc -c origdir/setup/Linux/arm/bpabi.c -o bpabi_c.o + +for n in L_udivsi3 L_idivsi3 L_divsi3 L_aeabi_ldivmod L_aeabi_uldivmod L_dvmd_lnx +do +# Strip position independent code (PLT) from the asm sources before compile +cpp -static -D$n origdir/setup/Linux/arm/lib1funcs.asm | sed 's/..PLT.//g' > $n.s +as -o $n.o $n.s +done + +ld -r -o bpabi.o L*.o bpabi_c.o +rm -f L*.s L*.o bpabi_c.o + +#build osscore + +rm -rf tmp_build +mkdir tmp_build + +cp origdir/setup/Linux/arm/Makefile.osscore.arm tmp_build/Makefile +cp origdir/setup/Linux/oss/build/osscore.c tmp_build/osscore.c + +cp ./kernel/framework/include/*.h tmp_build/ +cp ./kernel/OS/Linux/wrapper/wrap.h tmp_build/ +cp ./setup/Linux/oss/build/ossdip.h tmp_build/ +cp ./include/soundcard.h tmp_build/ +cp ./kernel/framework/include/ossddk/oss_exports.h tmp_build/ + +if ! (cd tmp_build && make KERNELDIR=$KERNELDIR) > build.log 2>&1 +then + cat build.log + echo + echo Building osscore module failed + exit 1 +fi + +ld -r tmp_build/osscore.ko target/objects/*.o -o prototype/usr/lib/oss/modules/osscore.ko + +if test -f tmp_build/Module.symvers +then + #Take generated symbol information and add it to module.inc + echo "static const struct modversion_info ____versions[]" > tmp_build/osscore_symbols.inc + echo " __attribute__((used))" >> tmp_build/osscore_symbols.inc + echo "__attribute__((section(\"__versions\"))) = {" >> tmp_build/osscore_symbols.inc + sed -e "s:^:{:" -e "s:\t:, \":" -e "s:\t\(.\)*:\"},:" < tmp_build/Module.symvers >> tmp_build/osscore_symbols.inc + echo "};" >> tmp_build/osscore_symbols.inc +else + echo > tmp_build/osscore_symbols.inc +fi + +cp origdir/setup/Linux/oss/build/*.inc tmp_build/ + +for n in target/modules/*.o +do + N=`basename $n .o` + + cp target/build/$N.c tmp_build/$N.c + + sed "s/MODNAME/$N/" < origdir/setup/Linux/arm/Makefile.tmpl.arm > tmp_build/Makefile + if ! (cd tmp_build && make KERNELDIR=$KERNELDIR) > build.log 2>&1 + then + cat build.log + echo + echo Building $N module failed + exit 1 + fi + ld -r tmp_build/$N.ko bpabi.o target/modules/$N.o -o prototype/usr/lib/oss/modules/$N.ko +done + +exit 0 diff --git a/setup/Linux/confgen.c b/setup/Linux/confgen.c new file mode 100644 index 0000000..53662f2 --- /dev/null +++ b/setup/Linux/confgen.c @@ -0,0 +1,188 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <libgen.h> +#include <sys/stat.h> + +char *targetdir = ""; +char *confpath = ""; + +static int +copy_parms (FILE * f, FILE * conf) +{ + char line[1024], *s; + char var[256] = "", comment[64 * 1024] = ""; + int i; + int ok = 0; + + while (fgets (line, sizeof (line), f) != NULL) + { + for (i = 0; i < strlen (line); i++) + if (line[i] == '\n') + line[i] = 0; + + s = line; + + while (*s == ' ' || *s == '\t') + s++; + if (strncmp (s, "int ", 4) == 0) + { + if (*var != 0) + { + fprintf (conf, "%s\n", comment); + if (*var != 0) + fprintf (conf, "#%s\n#\n", var); + *var = 0; + *comment = 0; + } + s += 4; + + for (i = 0; i < strlen (line); i++) + if (line[i] == ';') + line[i] = 0; + ok = 1; + strcpy (var, s); + continue; + } + + + s = line; + + while (*s == ' ' || *s == '\t' || *s == '/' || *s == '*') + s++; + + if (*comment != 0) + strcat (comment, "\n"); + strcat (comment, "# "); + strcat (comment, s); + } + + if (*var != 0) + { + fprintf (conf, "%s\n", comment); + fprintf (conf, "#%s\n", var); + } + + return ok; +} + +static void +scan_dir (const char *srcdir, const char *modnam) +{ + char confname[256], tmp[256], line[1024]; + char module[256], *p; + FILE *conf; + FILE *f; + int i; + struct stat st; + + int check_platform = 0; + int platform_ok = 0; + int ok = 0; + + strcpy (module, modnam); + p = module; + while (*p) + { + if (*p == '.') + *p = 0; + else + p++; + } + + if (stat (srcdir, &st) == -1) + return; + + if (!S_ISDIR (st.st_mode)) /* Not a directory? */ + return; + + sprintf (tmp, "%s/.nomake", srcdir); + if (stat (tmp, &st) != -1) /* File exists */ + return; /* Skip this one */ + + sprintf (tmp, "%s/.config", srcdir); + if ((f = fopen (tmp, "r")) != NULL) + { + while (fgets (line, sizeof (line), f) != NULL) + { + char *s; + for (i = 0; i < strlen (line); i++) + if (line[i] == '\n') + line[i] = 0; + + s = line; + while (*s && *s != '=') + s++; + if (*s == '=') + *s++ = 0; + + if (strcmp (line, "OS") == 0 || strcmp (line, "targetos") == 0) + { + check_platform = 1; + if (strcmp (s, "Linux") == 0) + platform_ok = 1; + continue; + } + } + fclose (f); + } + + if (check_platform && !platform_ok && strcmp (modnam, "osscore")) + { + return; + } +#if 0 + /* copy the man pages */ + sprintf (syscmd, "sed 's:CONFIGFILEPATH:%s:g' < %s/%s.man > /tmp/ossman.man", + confpath, srcdir, module); + printf ("%s\n", syscmd); + unlink ("/tmp/ossman.man"); + system (syscmd); + + sprintf (syscmd, + "./origdir/setup/txt2man -t \"%s\" -v \"Devices\" -s 7 /tmp/ossman.man > prototype/usr/man/man7/%s.7", + module, module); + printf ("%s\n", syscmd); + system (syscmd); +#endif + + sprintf (confname, "%s/%s.conf", targetdir, module); + sprintf (tmp, "%s/.params", srcdir); + if ((f = fopen (tmp, "r")) != NULL) + { + if ((conf = fopen (confname, "w")) == NULL) + { + perror (confname); + exit (-1); + } + fprintf (conf, "# Open Sound System configuration file\n"); + fprintf (conf, + "# Remove the '#' in front of the option(s) you like to set.\n#\n"); + ok = copy_parms (f, conf); + fclose (f); +// fprintf(conf, "#\n"); + fclose (conf); + if (!ok) + unlink (confname); + } +} + +int +main (int argc, char *argv[]) +{ + int i; + + if (argc < 3) + exit (-1); + + targetdir = argv[1]; + confpath = argv[2]; + + for (i = 3; i < argc; i++) + { + scan_dir (argv[i], basename (argv[i])); + } + + exit (0); +} diff --git a/setup/Linux/copyright b/setup/Linux/copyright new file mode 100644 index 0000000..3ec1b2e --- /dev/null +++ b/setup/Linux/copyright @@ -0,0 +1,25 @@ +Upstream sources are at: + http://www.opensound.com + +Authors: + 4Front Technologies ( http://www.4front-tech.com ) + +Copyright: + Copyright (C) 2006-2008 Hannu Savolainen and Dev Mazumdar. + 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; version 2 dated June, 1991. + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +On Debian GNU/Linux systems, the complete text of the GNU General +Public License can be found in `/usr/share/common-licenses/GPL'. diff --git a/setup/Linux/installoss.sh b/setup/Linux/installoss.sh new file mode 100644 index 0000000..5109fca --- /dev/null +++ b/setup/Linux/installoss.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +if test "$USER " != "root " +then + echo "You must be super-user or logged in as root to install OSS" + exit 1 +fi + +if test "$1 " != " " +then + OSSLIBDIR="$1" +else + OSSLIBDIR="/usr/lib/oss" +fi + +echo "Installing Open Sound System `cat "./$OSSLIBDIR/version.dat"`...." +echo "Copying files from ./etc and ./usr into /..." +tar -cpf - etc usr |(cd /; tar -xpf -) +echo "Running /usr/lib/oss/build/install script...." +if ! sh "/$OSSLIBDIR/build/install.sh" +then + echo + echo "ERROR: install.sh script failed" + exit 0 +fi +echo "OSS installation complete..." +echo +echo "Run /usr/sbin/soundon to start the drivers" +echo "Run /usr/bin/osstest to test the audio" +echo "Run /usr/bin/ossinfo to display status" diff --git a/setup/Linux/linsetup.sh b/setup/Linux/linsetup.sh new file mode 100644 index 0000000..dc34289 --- /dev/null +++ b/setup/Linux/linsetup.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +if test "$CONFIGURE " != "YES " +then + echo + echo Error: Wrong usage + echo + echo You must run `dirname $0`/configure instead of $0 + exit 1 +fi + +if test "`ls .` " != " " +then + echo Error: Current directory must be empty + exit 1 +fi + +if test "`uname -m` " = "arm " +then +# ARM doesn't have regparm support + + echo Setting up for ARM architecture + sh $SRCDIR/setup/setupdir.sh + exit 0 +fi + +# Setup directory for REGPARM + +unset NO_REGPARM +export USE_REGPARM=1 + +echo Setting up full REGPARM compiling environment + +echo "SUBDIRS+=noregparm" > .makefile +sh $SRCDIR/setup/setupdir.sh + +# Setup for NOREGPARM + +mkdir noregparm + +unset USE_REGPARM +export NO_REGPARM=1 + +echo > .nocopy +echo Setting up kernel-only NOREGPARM compiling environment +(cd noregparm;sh $SRCDIR/setup/setupdir.sh -K) +rm -f .nocopy + +# Make sure both versions share the same timestamp.h file. +cp -f kernel/framework/include/timestamp.h noregparm/kernel/framework/include/timestamp.h + +exit 0 diff --git a/setup/Linux/make.local b/setup/Linux/make.local new file mode 100644 index 0000000..ad9ac7f --- /dev/null +++ b/setup/Linux/make.local @@ -0,0 +1,21 @@ +build: kernel/framework/include/buildid.h all + sh build.sh + +copy: build + #rm -f ${OSSLIBDIR}/modules/*.o + (cd prototype; find -L . -type d | xargs -i{} mkdir -p ${DESTDIR}/{}) + (cd prototype; find -L . -type f | xargs -i{} cp {} ${DESTDIR}/{}) + +package: build + sh setup/Linux/mkpkg.sh + +tarball: build + sh setup/Linux/mktarball.sh + +deb: build + sh setup/Linux/mkdeb.sh + +install: copy + cd ${OSSLIBDIR}/build && sh install.sh + sync + soundoff && sync && soundon && echo "OSS has started OK" diff --git a/setup/Linux/md5.sh b/setup/Linux/md5.sh new file mode 100644 index 0000000..533c12e --- /dev/null +++ b/setup/Linux/md5.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +i=$2 +i=${i#.} + +# Create the MD5 sums file using the program we have found earlier +case "$1" in + MD5SUM) + md5sum ".$i" + ;; + MD5) + x=`md5 ".$i" | awk "{ for (y=1;y<=NF;y++) if ((length(\\$y) == 32) && (\\$y !~ /[\/]/)) {print \\$y; break} }"`; echo "$x $i" + ;; + DIGEST) + x=`digest -a md5 ".$i"`; echo "$x $i" + ;; + OPENSSL) + x=`openssl md5 $i | awk "{ for (y=1;y<=NF;y++) if ((length(\\$y) == 32) && (\\$y !~ /[\/]/)) {print \\$y; break} }"`; echo "$x $i" + ;; +esac diff --git a/setup/Linux/menu.ex b/setup/Linux/menu.ex new file mode 100644 index 0000000..854671b --- /dev/null +++ b/setup/Linux/menu.ex @@ -0,0 +1,4 @@ +?package(oss-linux):needs="X11" \ + section="Apps/Sound" \ + title="ossxmix" \ + command="/usr/bin/ossxmix" diff --git a/setup/Linux/mkdeb.sh b/setup/Linux/mkdeb.sh new file mode 100644 index 0000000..8330ae2 --- /dev/null +++ b/setup/Linux/mkdeb.sh @@ -0,0 +1,95 @@ +#!/bin/sh + +. ./.directories + +VERSION=`sh showversion.sh` +VERSION=${VERSION#v} +RELEASE=`cat buildid.dat` +OSSNAME="oss-linux" + +# Chosing the right architecture +if test `uname -m` = "x86_64"; then ARCH=amd64 +else ARCH=`uname -m|sed 's/^i[3-9]86/i386/'` +fi + +DEBNAME=${OSSNAME}-${VERSION}-${RELEASE}_${ARCH} + +# Checking for known MD5 hashing programs +if type md5sum > /dev/null 2>&1; then MD5=MD5SUM +elif type openssl > /dev/null 2>&1; then MD5=OPENSSL +elif type md5 > /dev/null 2>&1; then MD5=MD5 +elif type digest > /dev/null 2>&1; then MD5=DIGEST +else echo "There has been no MD5 creation utily found. deb archive creation will be aborted." && exit 1 +fi + +echo building $DEBNAME.deb + + +mkdir control 2>/dev/null +echo "2.0" > debian-binary +cat > control/control << END +Package: $OSSNAME +Version: ${VERSION}-${RELEASE} +Section: sound +Priority: optional +Architecture: $ARCH +Installed-Size: `du -ks prototype | awk '{print $1}'` +Build-Depends: build-essential sed gawk libtool libgtk2.0-dev +Depends: binutils, gcc, libc6, libgtk2.0-0, sed (>= 1.0.0) +Conflicts: libflashsupport +Provides: oss +Suggests: libsdl1.2debian-oss | libsdl1.2debian-all, libesd0, libwine-oss, libsox-fmt-oss, mpg123, gstreamer0.10-plugins-bad (>= 0.10.7), libasound2-plugins +Maintainer: 4Front Technologies <support@opensound.com> +Description: Open Sound System (http://www.opensound.com) + OSS provides libraries and necessary drivers for practically all sound + cards on the market including PnP and many PCI ones which enable you + to play sound files, compose music, use MIDI (only included in the + testing releases) and adjust your sound card using various user space + programs. +END + +# Copying the menu and copyright file to the right place, taking care that the md5sums generation will take place AFTER this step +mkdir -p prototype/usr/share/menu prototype/usr/share/doc/oss-linux +cp setup/Linux/menu.ex prototype/usr/share/menu/ossxmix +cp setup/Linux/copyright prototype/usr/share/doc/oss-linux/ + + +# Create the MD5 sums file using the program we have found earlier +(cd prototype; find . -type f -exec sh ../setup/Linux/md5.sh "$MD5" "{}" \; > ../control/md5sums) + +(cd prototype; find . -type f -print | sed 's/^.//g' | egrep "^/etc/" > ../control/conffiles) + + +# Removing older builds +rm -rf /tmp/prototype $DEBNAME.deb + + +cp -pRf prototype /tmp +cp setup/Linux/preinst setup/Linux/postinst setup/Linux/prerm setup/Linux/postrm control/ +if test -e prototype/$OSSLIBDIR/lib/libsalsa.so* +then + cp setup/Linux/shlibs control/ +fi + + +# Correcting file and directory permissions required by lintian +chmod 0755 control/control + +# Building control and data archives +(cd control; tar c * | gzip -9 > ../control.tar.gz) +(cd /tmp/prototype; tar c ./* | gzip -9 > data.tar.gz) +mv /tmp/prototype/data.tar.gz . + + +# Creating the actual archive +ar r $DEBNAME.deb debian-binary control.tar.gz data.tar.gz + + +# Cleanup +rm -rf /tmp/prototype control control.tar.gz data.tar.gz debian-binary + + +if test -f 4front-private/export_package.sh +then + sh 4front-private/export_package.sh $OSSNAME*.deb . `sh showversion.sh` /tmp `uname -i`-26 +fi diff --git a/setup/Linux/mkpkg.sh b/setup/Linux/mkpkg.sh new file mode 100644 index 0000000..4ccfe90 --- /dev/null +++ b/setup/Linux/mkpkg.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +. ./.directories + +VERSION=`sh showversion.sh` +RELEASE=`cat buildid.dat` +ARCH=`uname -i` +OSSNAME=oss-linux + +RPMNAME=$OSSNAME-$VERSION +PKGNAME=$OSSNAME-$VERSION-$RELEASE.$ARCH +echo building $RPMNAME.rpm + +rm -rf spec $RPMNAME +mkdir $RPMNAME +echo "Version: " $VERSION > spec +echo "Release: " $RELEASE >> spec +echo "Name: " $OSSNAME >> spec +cat setup/Linux/spec.tmpl | sed "s:OSSLIBDIR:\"$OSSLIBDIR\":g" >> spec +echo "%files" >> spec +(cd prototype; find . -type f -print | sed 's/^.//g' > /tmp/filelist) +cat /tmp/filelist >> spec +rm -rf /tmp/prototype +cp -af prototype /tmp +tar zcvf /tmp/oss $RPMNAME +rpmbuild -bb --define "_sourcedir /tmp" --define "_rpmdir ./" --define '_build_name_fmt %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm' spec +# Cleanup +rm -rf /tmp/oss /tmp/filelist $RPMNAME spec + +if test -f 4front-private/export_package.sh +then + sh 4front-private/export_package.sh $PKGNAME.rpm . `sh showversion.sh` /tmp `uname -i`-26 +fi diff --git a/setup/Linux/mktarball.sh b/setup/Linux/mktarball.sh new file mode 100644 index 0000000..4610a4b --- /dev/null +++ b/setup/Linux/mktarball.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +. ./.directories + +VERSION=`sh showversion.sh` +RELEASE=`cat buildid.dat` +OSSNAME=oss-linux +PKGNAME=$OSSNAME-$VERSION-$RELEASE-`uname -m` + +echo building $PKGNAME.tar.bz2 +#cp ./setup/Linux/installoss.sh prototype +cp ./setup/Linux/removeoss.sh prototype/$OSSLIBDIR/scripts +(cd prototype; find . -type f -print) > prototype/$OSSLIBDIR/MANIFEST +(cd prototype; tar cfj /tmp/$PKGNAME.tar.bz2 . ) +mv /tmp/$PKGNAME.tar.bz2 . + +if test -f 4front-private/export_package.sh +then + sh 4front-private/export_package.sh $PKGNAME.tar.bz2 . `sh showversion.sh` /tmp `uname -m`-26 +fi + +exit 0 diff --git a/setup/Linux/oss/build/Makefile.osscore b/setup/Linux/oss/build/Makefile.osscore new file mode 100644 index 0000000..30d0287 --- /dev/null +++ b/setup/Linux/oss/build/Makefile.osscore @@ -0,0 +1,32 @@ +include /etc/oss.conf + +EXTRA_CFLAGS += -I${OSSLIBDIR}/include/internals -I${OSSLIBDIR}/include/sys + +ifneq ($(KERNELRELEASE),) + + obj-m := osscore.o + +else + + KERNELDIR ?= /lib/modules/$(shell uname -r)/build + PWD := $(shell pwd) +endif + +default: + @echo "static const char __oss_compile_vermagic[]" > ubuntu_version_hack.inc +#The kernel build system saves kernel version (obtained via "utsrelease.h") +#used during compile in a "vermagic" symbol. soundon compares this with +#current version of running kernel to know when to relink modules. +#Some Ubuntu kernels have 'uname -r' output different from "utsrelease.h" +#contents, so we save the previous uname as a fallback check. +# https://bugs.launchpad.net/ubuntu/+source/linux/+bug/247055 + @echo "__attribute__((used))" >> ubuntu_version_hack.inc + @echo "__attribute__((section(\".modinfo\")))" >> ubuntu_version_hack.inc + @echo "= \"$(shell /usr/sbin/ossvermagic -z -s)\";" >> ubuntu_version_hack.inc + + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules + @rm -f ubuntu_version_hack.inc + +clean: + rm -f *.o *.ko *.mod.c *.mod.o .*.cmd core core.* x y z ubuntu_version_hack.inc + rm -rf .tmp_versions diff --git a/setup/Linux/oss/build/Makefile.tmpl b/setup/Linux/oss/build/Makefile.tmpl new file mode 100644 index 0000000..fd331c1 --- /dev/null +++ b/setup/Linux/oss/build/Makefile.tmpl @@ -0,0 +1,21 @@ +include /etc/oss.conf + +EXTRA_CFLAGS += -I${OSSLIBDIR}/include/internals -I${OSSLIBDIR}/include/sys + +ifneq ($(KERNELRELEASE),) + + obj-m := MODNAME.o + +else + + KERNELDIR ?= /lib/modules/$(shell uname -r)/build + PWD := $(shell pwd) + +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules + +endif + +clean: + @rm -f *.o *.ko *.mod.c *.mod.o .*.cmd core core.* x y z + @rm -rf .tmp_versions diff --git a/setup/Linux/oss/build/install.sh b/setup/Linux/oss/build/install.sh new file mode 100644 index 0000000..13fdbc2 --- /dev/null +++ b/setup/Linux/oss/build/install.sh @@ -0,0 +1,347 @@ +#!/bin/sh +if test -f /etc/oss.conf +then + . /etc/oss.conf +else + OSSLIBDIR=/usr/lib/oss + echo "OSSLIBDIR=/usr/lib/oss" > /etc/oss.conf +fi + +[ -z "$LD" ] && LD=ld + +cd $OSSLIBDIR/build + +rm -f $OSSLIBDIR/.cuckoo_installed + +# Check if we should use REGPARM or non-REGPARM modules +if /usr/sbin/ossvermagic -r || /sbin/modinfo ext3|grep -q REGPARM +then + REGPARM=REGPARM + rm -rf $OSSLIBDIR/objects + ln -s $OSSLIBDIR/objects.regparm $OSSLIBDIR/objects + rm -rf $OSSLIBDIR/modules + ln -s $OSSLIBDIR/modules.regparm $OSSLIBDIR/modules +else + REGPARM=NOREGPARM + rm -rf $OSSLIBDIR/objects + ln -s $OSSLIBDIR/objects.noregparm $OSSLIBDIR/objects + rm -rf $OSSLIBDIR/modules + ln -s $OSSLIBDIR/modules.noregparm $OSSLIBDIR/modules +fi + +UNAME=`uname -r` + +if test -f /lib/modules/$UNAME/kernel/oss/vmix.ko || test -f /lib/modules/$UNAME/kernel/oss/ich.ko +then +# Older versions of OSS modules exist under /lib/modules. This indicates that +# previous version of OSS has not been properly uninstalled. Run osdetect +# again to fix rthe situation + + /usr/sbin/soundoff > /dev/null 2>&1 + /usr/sbin/ossdetect +fi + +# Remove previous OSS modules from the system +rm -rf /lib/modules/$UNAME/kernel/oss + +if test -f /usr/lib/oss/build/ich.c +then + # Older v4.0 modules found. Remove them + (cd /usr/lib/oss/build ; rm -f ali5455.c allegro.c als300.c als4000.c apci97.c atiaudio.c audigyls.c audioloop.c audiopci.c cmi8788.c cmpci.c cs4280.c cs4281.c digi32.c digi96.c emu10k1x.c envy24.c envy24ht.c fm801.c geode.c hdaudio.c hdsp.c ich.c imux.c maestro.c neomagic.c ossusb.c riptide.c s3vibes.c sblive.c sbxfi.c softoss.c solo.c sonorus.c trident.c via8233.c via97.c vmix.c vortex.c ymf7xx.c) + echo + echo + echo Error: Older OSS version seems to be installed in your system. + echo Please remove previous /usr/lib/oss directory and the install OSS v4.x again. + soundoff + exit 127 +fi + +if ! test -f $OSSLIBDIR/objects/osscore.o +then + echo Error: OSS core module for $REGPARM kernel is not available in $OSSLIBDIR/objects + exit 1 +fi + +echo +echo OSS build environment set up for $REGPARM kernels + +KERNELDIR=/lib/modules/$UNAME/build +UBUNTUPACKAGES="" + +OK=1 +echo + +if test "`which gcc 2>/dev/null` " = " " +then + echo " gcc" + UBUNTUPACKAGES="$UBUNTUPACKAGES gcc" + OK=0 +fi + +if test "`which make 2>/dev/null` " = " " +then + echo " make" + UBUNTUPACKAGES="$UBUNTUPACKAGES make" + OK=0 +fi + +if test "`which ld 2>/dev/null` " = " " +then + echo " binutils" + UBUNTUPACKAGES="$UBUNTUPACKAGES binutils" + OK=0 +fi + +if ! test -f /usr/include/stdio.h +then + echo " C library headers (glibc-devel or build-essential)" + OK=0 + UBUNTUPACKAGES="$UBUNTUPACKAGES build-essentials" +fi + +if test "$OK " = "0 " +then + echo + echo 'Error: The above Linux package(s) seem to be missing from your system.' + echo ' Please install them and then try to install OSS again.' + echo + echo Please refer to the documentation of your Linux distribution if you + echo have problems with installing the packages. + echo + + if grep -q Ubuntu /etc/issue # Ubuntu? + then + echo You can use the following commands to download and install all + echo required packages: + echo + + for n in $UBUNTUPACKAGES + do + echo " apt-get install $n" + done + + exit 1 + fi + + exit 1 +fi + + +if ! test -f $KERNELDIR/Makefile && ! test -f /lib/modules/$UNAME/sources/Makefile +then + echo + echo 'Warning: Cannot locate the Linux kernel development package for' + echo ' Linux kernel version ' $UNAME + echo ' Please install the kernel development package if linking the' + echo ' OSS modules fails.' + echo + echo The kernel development package may be called kernel-devel, kernel-smp-devel, + echo kernel-sources, kernel-headers or something like that. Please refer + echo to the documentation of your Linux distribution if there are any + echo difficulties in installing the kernel/driver development environment. + echo + + if grep -q 'Fedora Core release' /etc/issue + then + if uname -v|grep -q SMP + then + echo Assuming that you are using Fedora Core 5 or later + echo "the right kernel source package (RPM) is probably called" + echo kernel-smp-devel. + else + echo Assuming that you are using Fedora Core 5 or later + echo "the right kernel source package (RPM) is probably called" + echo kernel-devel. + fi + else + echo For your Linux distribution the right kernel source package + echo might be kernel-source. + fi + echo + + if grep -q Ubuntu /etc/issue || grep -q Debian /etc/issue # Ubuntu or Debian? + then + echo Under Ubuntu you may need to prepare the kernel environment + echo after downloading the kernel sources using + echo + echo " sudo apt-get install linux-headers-$UNAME" + echo " cd /usr/src/linux-headers-$UNAME/" +# echo " sudo make prepare" +# echo " sudo make prepare scripts" + echo + fi +fi + +if ! test -d /lib/modules/$UNAME +then + echo Error: Kernel directory /lib/modules/$UNAME does not exist + exit 1 +fi + +cp -f ../objects/osscore.o osscore_mainline.o + +rm -f Makefile +ln -s Makefile.osscore Makefile + +echo Building module osscore + +if ! make KERNELDIR=$KERNELDIR> build.list 2>&1 +then + echo Failed to compile OSS + cat build.list + exit 2 +fi + +if ! test -d /lib/modules/$UNAME/kernel/oss +then + mkdir /lib/modules/$UNAME/kernel/oss +fi + +if ! test -d /lib/modules/$UNAME/kernel/oss +then + echo OSS module directory /lib/modules/$UNAME/kernel/oss does not exist. + exit 3 +fi + +if ! $LD -r osscore.ko osscore_mainline.o -o /lib/modules/$UNAME/kernel/oss/osscore.ko +then + echo Linking the osscore module failed + exit 5 +fi + +if test -f Module.symvers +then + #Take generated symbol information and add it to module.inc + echo "static const struct modversion_info ____versions[]" > osscore_symbols.inc + echo " __attribute__((used))" >> osscore_symbols.inc + echo "__attribute__((section(\"__versions\"))) = {" >> osscore_symbols.inc + sed -e "s:^:{:" -e "s:\t:, \":" -e "s:\t\(.\)*:\"},:" < Module.symvers >> osscore_symbols.inc + echo "};" >> osscore_symbols.inc +else + echo > osscore_symbols.inc +fi + +#depmod -a + +for n in ../modules/*.o +do + N=`basename $n .o` + echo Building module $N + + rm -f $N_mainline.o Makefile + + sed "s/MODNAME/$N/" < Makefile.tmpl > Makefile + ln -s $n $N_mainline.o + + if ! make KERNELDIR=$KERNELDIR > build.list 2>&1 + then + echo Compiling module $N failed + cat build.list + exit 4 + fi + + if ! $LD -r $N.ko $N_mainline.o -o /lib/modules/$UNAME/kernel/oss/$N.ko + then + echo Linking $N module failed + exit 6 + fi + + rm -f $N_mainline.o + make clean +done + +rm -f Makefile + +echo "depmod -a" +depmod -a + +# Copy config files for any new driver modules + +if ! test -d $OSSLIBDIR/conf +then + mkdir $OSSLIBDIR/conf +fi + +if test -d $OSSLIBDIR/conf.tmpl +then + for n in $OSSLIBDIR/conf.tmpl/*.conf + do + N=`basename $n` + + if ! test -f $OSSLIBDIR/conf/$N + then + cp -f $n $OSSLIBDIR/conf/ + fi + done + rm -rf $OSSLIBDIR/conf.tmpl +fi + +if ! test -f $OSSLIBDIR/etc/installed_drivers +then + echo "-----------------------------" + /usr/sbin/ossdetect -v + echo "-----------------------------" + echo +fi + +if ! test -d /etc/init.d +then + mkdir /etc/init.d +fi + +rm -f /etc/init.d/oss /etc/rc.d/rc3.d/S89oss /etc/rc3.d/S89oss +cp -f $OSSLIBDIR/etc/S89oss /etc/init.d/oss + +chmod 744 /etc/init.d/oss + +if test -x /sbin/chkconfig +then + /sbin/chkconfig oss on > /dev/null 2>&1 +else + if test -x /usr/sbin/update-rc.d + then + /usr/sbin/update-rc.d oss defaults > /dev/null 2>&1 + else + if test -d etc/rc.d/rc3.d + then + rm -f /etc/rc.d/rc3.d/S89oss + ln -s /etc/init.d/oss /etc/rc.d/rc3.d/S89oss + else + if test -d /etc/rc3.d + then + rm -f /etc/rc3.d/S89oss + ln -s /etc/init.d/oss /etc/rc3.d/S89oss + fi + fi + fi +fi + +# Install ALSA interface module (Cuckoo) +#(cd $OSSLIBDIR/cuckoo && make clean) > /dev/null 2>&1 +#if (cd $OSSLIBDIR/cuckoo && make install) > /var/log/cuckoo.log 2>&1 +#then +# touch $OSSLIBDIR/.cuckoo_installed +#fi +#(cd $OSSLIBDIR/cuckoo && make clean) > /dev/null 2>&1 + +# Remove bogus char major 14 device files left from earlier OSS versions. + +rm -f `ls -l -d /dev/*|grep ^c|grep ' 14, '|sed 's/.* //'` + +# Recompile libflashsupport.so if possible. Otherwise use the precompiled +# version. +(cd $OSSLIBDIR/lib;cc -m64 -shared -fPIC -O2 -Wall -Werror flashsupport.c -o $OSSLIBDIR/lib/libflashsupport_64.so) > /dev/null 2>&1 +(cd $OSSLIBDIR/lib;cc -m32 -shared -fPIC -O2 -Wall -Werror flashsupport.c -o $OSSLIBDIR/lib/libflashsupport_32.so) > /dev/null 2>&1 + +if test ! -f $OSSLIBDIR/etc/userdefs +then + echo "autosave_mixer yes" > $OSSLIBDIR/etc/userdefs +fi + +# Hal 0.5.0+ hotplug +mkdir -p /usr/lib/hal/scripts +ln -sf $OSSLIBDIR/scripts/oss_usb-create-devices /usr/lib/hal/scripts/ +mkdir -p /usr/share/hal/fdi/policy/20thirdparty/ +ln -sf $OSSLIBDIR/scripts/90-oss_usb-create-device.fdi /usr/share/hal/fdi/policy/20thirdparty/ + +exit 0 diff --git a/setup/Linux/oss/build/module.inc b/setup/Linux/oss/build/module.inc new file mode 100644 index 0000000..4e34003 --- /dev/null +++ b/setup/Linux/oss/build/module.inc @@ -0,0 +1,245 @@ +/* + * Purpose: Template for OSS modules under Linux + * + * This file is included by the low level driver modules when they are + * compiled in the target system. In this way this file can be modified + * for non-standard kernels by the customer. Compiling in the target is + * necessary because the driver/module framework of Linux cannot support + * binary drivers. Another reason is that the kbuild mechanism used to build + * kernel modules under Linux is not compatible with the way how the source + * code of OSS is organized. + */ +/* + * Copyright (C) 4Front Technologies 2005-2007. Released under GPL2 license. + */ +#define strcpy dummy_strcpy +#include <linux/version.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include "timestamp.h" +#include "oss_exports.h" +#include "wrap.h" +#include "ossddk.h" +#include "ossdip.h" +#undef strcpy +#define strcpy oss_strcpy +#undef strlen +#define strlen oss_strlen + +static int module_major = 0; +static int instance = 0; + +MODULE_LICENSE ("GPL v2"); +MODULE_DESCRIPTION ("Open Sound System '" DRIVER_PURPOSE "' driver module"); +MODULE_AUTHOR ("4Front Technologies (support@opensound.com)"); + +extern int DRIVER_ATTACH (oss_device_t * osdev); +extern int DRIVER_DETACH (oss_device_t * osdev); + +#if DRIVER_TYPE==DRV_PCI +#define DRIVER_TYPE_OK + +#include "pci_wrapper.inc" + +// MODULE_DEVICE_TABLE(pci, id_table); +static struct pci_driver osspci_driver = { + .name = DRIVER_NICK, + .id_table = id_table, + .probe = osspci_probe, + .remove = osspci_remove +}; + +static int __init +pcidrv_init (void) +{ + int err; + + if ((err = pci_register_driver (&osspci_driver)) < 0) + return err; + oss_register_module (THIS_MODULE); + return 0; +} + +static void __exit +pcidrv_exit (void) +{ + if (module_major > 0) + { + oss_unregister_chrdev (module_major, DRIVER_NICK); + } + pci_unregister_driver (&osspci_driver); + oss_unregister_module (THIS_MODULE); +} + +module_init (pcidrv_init); +module_exit (pcidrv_exit); +#endif /* PCI driver */ + +#if DRIVER_TYPE==DRV_VIRTUAL || DRIVER_TYPE==DRV_VMIX +#define DRIVER_TYPE_OK +static oss_device_t *osdev = NULL; + +static int +virtualdrv_init (void) +{ + static int instance = 0, maj; + + if ((osdev = + osdev_create (NULL, DRIVER_TYPE, instance++, DRIVER_NICK, + NULL)) == NULL) + { + return -ENOMEM; + } + osdev_set_owner (osdev, THIS_MODULE); + maj = oss_request_major (osdev, 0, DRIVER_NICK); + osdev_set_major (osdev, maj); + if (!DRIVER_ATTACH (osdev)) + return -EIO; + oss_register_module (THIS_MODULE); + oss_audio_delayed_attach (); + return 0; +} + +static void +virtualdrv_exit (void) +{ + + if (!DRIVER_DETACH (osdev)) + printk (KERN_ALERT DRIVER_NICK ": Unloading busy device\n"); + osdev_delete (osdev); + oss_unregister_module (THIS_MODULE); +} + +module_init (virtualdrv_init); +module_exit (virtualdrv_exit); +#endif /* Virtual driver */ + +#if DRIVER_TYPE==DRV_USB +#define DRIVER_TYPE_OK +oss_device_t *osdev = NULL; +static int usb_major = 0; + +#include "usb_wrapper.inc" + +static int +usbdrv_init (void) +{ + int res; + + if (udi_usb_installed) + return 0; + if ((osdev = + osdev_create (NULL, DRV_VIRTUAL, instance++, DRIVER_NICK, + NULL)) == NULL) + { + return -ENOMEM; + } + osdev_set_owner (osdev, THIS_MODULE); + usb_major = oss_request_major (osdev, 0, DRIVER_NICK); + if (usb_major < 0) + { + oss_cmn_err (CE_WARN, "Failed to allocate USB major (%d)\n", usb_major); + return -EIO; + } + osdev_set_major (osdev, usb_major); + oss_register_device (osdev, "USB audio core services"); + if (!DRIVER_ATTACH (osdev)) + return -EIO; + oss_register_module (THIS_MODULE); + oss_audio_delayed_attach (); + + udi_usb_installed = 1; + + if ((res = usb_register (&oss_usb)) < 0) + { + printk ("oss: usb_register failed, err=%d\n", res); + drv = NULL; + return -ENXIO; + } + return 0; +} + +static void +usbdrv_exit (void) +{ + if (!udi_usb_installed) + return; + if (!DRIVER_DETACH (osdev)) + printk (KERN_ALERT DRIVER_NICK ": Unloading busy device\n"); + usb_deregister (&oss_usb); + udi_usb_installed = 0; + known_devices = NULL; + osdev_delete (osdev); + osdev = NULL; + oss_unregister_module (THIS_MODULE); +} + +module_init (usbdrv_init); +module_exit (usbdrv_exit); +#endif /* USB driver */ + +#ifndef DRIVER_TYPE_OK +#error Unrecognized driver type +#endif + +char * +strcpy (char *s1, const char *s2) +{ + char *s = s1; + + while (*s2) + *s1++ = *s2++; + *s1 = 0; + return s; +} + +void +oss_cmn_err (int level, const char *s, ...) +{ + char tmp[1024], *a[6]; + va_list ap; + int i, n = 0; + + va_start (ap, s); + + for (i = 0; i < strlen (s); i++) + if (s[i] == '%') + n++; + + for (i = 0; i < n && i < 6; i++) + { + a[i] = va_arg (ap, char *); + } + + for (i = n; i < 6; i++) + a[i] = NULL; + + if (level == CE_CONT) + { + sprintf (tmp, s, a[0], a[1], a[2], a[3], a[4], a[5], NULL, + NULL, NULL, NULL); + printk ("%s", tmp); + } + else + { + strcpy (tmp, DRIVER_NICK ": "); + + sprintf (tmp + strlen (tmp), s, a[0], a[1], a[2], a[3], a[4], a[5], + NULL, NULL, NULL, NULL); + if (level == CE_PANIC) + panic (tmp); + printk (KERN_ALERT "%s", tmp); + } +#if 0 + /* This may cause a crash under SMP */ + if (sound_started) + store_msg (tmp); +#endif + + va_end (ap); +} + +#include "osscore_symbols.inc" diff --git a/setup/Linux/oss/build/osscore.c b/setup/Linux/oss/build/osscore.c new file mode 100644 index 0000000..1a029b4 --- /dev/null +++ b/setup/Linux/oss/build/osscore.c @@ -0,0 +1,2214 @@ +/* + * Purpose: Linux kernel version specific wrapper routines. + * + * This file will be shipped in source format and compiled in the target + * (customer) system. In this way minor changes between Linux versions + * can be fixed by the customer. + */ + +/* + * Copyright (C) 4Front Technologies 2005-2009. Released under GPL2 license. + */ +//#include <linux/config.h> +typedef int *ioctl_arg; +#include <linux/init.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <stdarg.h> +#include <linux/vmalloc.h> +#include "timestamp.h" +#include "local_config.h" +#include "oss_exports.h" +#include "wrap.h" +#include "ossdip.h" +#include <linux/version.h> +#include <linux/fs.h> +#include <linux/poll.h> +#include <linux/time.h> +#include <linux/proc_fs.h> +#include <linux/spinlock.h> +#include <linux/pci.h> +#include <linux/irq.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#undef strlen +#undef strcpy +#define strlen oss_strlen +#define strcpy oss_strcpy + +typedef struct _smap_t dmap_t; + +#include "soundcard.h" +#include "audio_core.h" +#include "mixer_core.h" +#include "ubuntu_version_hack.inc" + +MODULE_LICENSE ("GPL v2"); +MODULE_DESCRIPTION ("Open Sound System core services"); +MODULE_AUTHOR ("4Front Technologies (support@opensound.com)"); + +struct _oss_mutex_t +{ + /* Caution! This definition must match cuckoo.h */ + spinlock_t lock; + int filler; /* Make sure this structure doesn't become zero length */ +}; + +static oss_device_t *core_osdev = NULL; +/* + * Minor device list + */ +#define MAX_MINOR 256 +typedef struct +{ + int major, minor; + char name[32]; +} oss_minor_t; + +static oss_minor_t minors[MAX_MINOR]; +static int nminors = 0; + +/* + * Sleep flags. Make sure these definitions match oss_config.h. + */ +#define WK_NONE 0x00 +#define WK_WAKEUP 0x01 +#define WK_TIMEOUT 0x02 +#define WK_SIGNAL 0x04 +#define WK_SLEEP 0x08 +#define WK_SELECT 0x10 + +time_t +oss_get_time (void) +{ +#if 1 + return get_seconds (); +#else + return xtime.tv_sec; +#endif +} + +void *oss_memset (void *t, int val, size_t l); + +void * +oss_kmem_alloc (size_t size) +{ + void *ptr; + if ((ptr = vmalloc (size)) == NULL) + { + oss_cmn_err (CE_WARN, "vmalloc(%d) failed\n", size); + return NULL; + } + memset (ptr, 0, size); + return ptr; +} + +void +oss_kmem_free (void *addr) +{ + vfree (addr); +} + +/* oss_pmalloc() moved to os_linux.c */ + +extern oss_native_word +oss_virt_to_bus (void *addr) +{ + return virt_to_bus (addr); +} + +void * +oss_memcpy (void *t_, const void *f_, size_t l) +{ + unsigned char *t = t_; + unsigned const char *f = f_; + int i; + + for (i = 0; i < l; i++) + *t++ = *f++; + + return t; +} + +void * +oss_memset (void *t, int val, size_t l) +{ + char *c = t; + while (l-- > 0) + *c++ = val; + + return t; +} + +int +oss_strcmp (const char *s1, const char *s2) +{ + while (*s1 && *s2) + { + if (*s1 != *s2) + return *s1 - *s2; + s1++; + s2++; + } + + return *s1 - *s2; +} + +int +oss_strncmp (const char *s1, const char *s2, size_t len) +{ + while (*s1 && *s2 && len--) + { + if (*s1 != *s2) + return *s1 - *s2; + s1++; + s2++; + } + + return *s1 - *s2; +} + +char * +oss_strcpy (char *s1, const char *s2) +{ + char *s = s1; + + while (*s2) + *s1++ = *s2++; + *s1 = '\0'; + return s; +} + +size_t +oss_strlen (const char *s) +{ + int i; + + for (i = 0; s[i]; i++); + + return i; +} + +char * +oss_strncpy (char *s1, const char *s2, size_t l) +{ + char *s = s1; + int n = 0; + + while (*s2) + { + if (n++ >= l) + return s; + + *s1++ = *s2++; + } + *s1 = '\0'; + return s; +} + +int oss_hz = HZ; +extern int max_intrate; +extern int detect_trace; +extern int src_quality; +extern int flat_device_model; +extern int vmix_disabled; +extern int vmix_no_autoattach; +extern int vmix_loopdevs; +extern int ac97_amplifier; +extern int ac97_recselect; +extern int cooked_enable; +extern int dma_buffsize; +extern int excl_policy; +extern int mixer_muted; + +module_param (oss_hz, int, S_IRUGO); +module_param (max_intrate, int, S_IRUGO); +module_param (detect_trace, int, S_IRUGO); +module_param (src_quality, int, S_IRUGO); +module_param (flat_device_model, int, S_IRUGO); +module_param (vmix_disabled, int, S_IRUGO); +module_param (vmix_no_autoattach, int, S_IRUGO); +module_param (vmix_loopdevs, int, S_IRUGO); +module_param (ac97_amplifier, int, S_IRUGO); +module_param (ac97_recselect, int, S_IRUGO); +module_param (cooked_enable, int, S_IRUGO); +module_param (dma_buffsize, int, S_IRUGO); +module_param (excl_policy, int, S_IRUGO); +module_param (mixer_muted, int, S_IRUGO); + +static struct proc_dir_entry *oss_proc_root = NULL; +static struct proc_dir_entry *oss_proc_devfiles = NULL; + +static ssize_t +oss_read_devfiles (struct file *file, char __user * buf, size_t count, + loff_t * ppos) +{ + static char tmp[8192]; + char *s; + static int eof = 0; + int i; + + if (eof) + { + eof = 0; + return 0; + } + + *tmp = 0; + s = tmp; + + for (i = 0; i < nminors; i++) + { + if (strlen (tmp) > sizeof (tmp) - 20) + { + printk (KERN_ALERT "osscore: Procfs buffer too small\n"); + return -ENOMEM; + } + + s += sprintf (s, "%s %d %d\n", + minors[i].name, minors[i].major, minors[i].minor); + } + + if (copy_to_user (buf, (void *) tmp, strlen (tmp))) + return -EFAULT; + + eof = 1; + return strlen (tmp); +} + +static struct file_operations oss_proc_operations = { + .read = oss_read_devfiles, +}; + +static void +init_proc_fs (void) +{ + if ((oss_proc_root = + create_proc_entry ("opensound", 0700 | S_IFDIR, NULL)) == NULL) + { + oss_cmn_err (CE_CONT, "Cannot create /proc/opensound\n"); + return; + } + + if ((oss_proc_devfiles = + create_proc_entry ("devfiles", 0600, oss_proc_root)) == NULL) + { + oss_cmn_err (CE_CONT, "Cannot create /proc/opensound/devfiles\n"); + return; + } + + oss_proc_devfiles->proc_fops = &oss_proc_operations; +} + +static void +uninit_proc_fs (void) +{ + if (oss_proc_root) + { + if (oss_proc_devfiles) + remove_proc_entry ("devfiles", oss_proc_root); + remove_proc_entry ("opensound", NULL); + } +} + +static int +osscore_init (void) +{ + if ((core_osdev = + osdev_create (NULL, DRV_UNKNOWN, 0, "osscore", NULL)) == NULL) + { + oss_cmn_err (CE_WARN, "Failed to allocate OSDEV structure\n"); + return -ENOMEM; + } + + osdev_set_owner (core_osdev, THIS_MODULE); + + init_proc_fs (); + + return oss_init_osscore (core_osdev); +} + +static void +osscore_exit (void) +{ + uninit_proc_fs (); + oss_uninit_osscore (core_osdev); +} + +void +oss_udelay (unsigned long d) +{ + udelay (d); +} + +oss_mutex_t +oss_mutex_init (void) +{ + oss_mutex_t mutex; + + if ((mutex = vmalloc (sizeof (*mutex))) == NULL) + { + oss_cmn_err (CE_WARN, "vmalloc(%d) failed (mutex)\n", sizeof (*mutex)); + return NULL; + } + + spin_lock_init (&(mutex->lock)); + + return mutex; +} + +void +oss_mutex_cleanup (oss_mutex_t mutex) +{ + vfree (mutex); +} + +void +oss_spin_lock_irqsave (oss_mutex_t mutex, oss_native_word * flags) +{ + unsigned long flag; + if (mutex == NULL) + return; + spin_lock_irqsave (&mutex->lock, flag); + *flags = flag; +} + +void +oss_spin_unlock_irqrestore (oss_mutex_t mutex, oss_native_word flags) +{ + if (mutex == NULL) + return; + spin_unlock_irqrestore (&mutex->lock, flags); +} + +void +oss_spin_lock (oss_mutex_t mutex) +{ + if (mutex == NULL) + return; + spin_lock (&mutex->lock); +} + +void +oss_spin_unlock (oss_mutex_t mutex) +{ + if (mutex == NULL) + return; + spin_unlock (&mutex->lock); +} + +void * +oss_map_pci_mem (oss_device_t * osdev, int size, unsigned long offset) +{ +#ifdef __arm__ + return (void*)offset; +#else + return ioremap (offset, size); +#endif +} + +void +oss_unmap_pci_mem (void *addr) +{ +#ifndef __arm__ + iounmap (addr); +#endif +} + +unsigned long long +oss_get_jiffies (void) +{ + return jiffies_64; +} + +char * +oss_get_procname (void) +{ + return current->comm; +} + +int +oss_get_pid (void) +{ + return current->pid; +} + +int +oss_get_uid (void) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) + return current->cred->uid; +#else + return current->uid; +#endif +} + +typedef struct tmout_desc +{ + volatile int active; + int timestamp; + void (*func) (void *); + void *arg; + + struct timer_list timer; +} tmout_desc_t; + +static volatile int next_id = 0; +#define MAX_TMOUTS 128 + +tmout_desc_t tmouts[MAX_TMOUTS] = { {0} }; + +int timeout_random = 0x12123400; + +void +oss_timer_callback (unsigned long id) +{ + tmout_desc_t *tmout; + int ix; + void *arg; + + timeout_random++; + + ix = id & 0xff; + if (ix < 0 || ix >= MAX_TMOUTS) + return; + tmout = &tmouts[ix]; + + if (tmout->timestamp != id) /* Expired timer */ + return; + + if (!tmout->active) + return; + + arg = tmout->arg; + tmout->active = 0; + tmout->timestamp = 0; + + tmout->func (arg); +} + +timeout_id_t +oss_timeout (void (*func) (void *), void *arg, unsigned long long ticks) +{ + tmout_desc_t *tmout = NULL; + int id, n; + + timeout_random++; + + n = 0; + id = -1; + + while (id == -1 && n < MAX_TMOUTS) + { + if (!tmouts[next_id].active) + { + tmouts[next_id].active = 1; + id = next_id++; + tmout = &tmouts[id]; + break; + } + + next_id = (next_id + 1) % MAX_TMOUTS; + } + + if (id == -1) /* No timer slots available */ + { + oss_cmn_err (CE_WARN, "Timeout table full\n"); + return 0; + } + + tmout->func = func; + tmout->arg = arg; + tmout->timestamp = id | (timeout_random & ~0xff); + + init_timer (&tmout->timer); + tmout->timer.expires = jiffies + ticks; + tmout->timer.data = id | (timeout_random & ~0xff); + tmout->timer.function = oss_timer_callback; + add_timer (&tmout->timer); + + return id | (timeout_random & ~0xff); +} + +void +oss_untimeout (timeout_id_t id) +{ + tmout_desc_t *tmout; + int ix; + + ix = id & 0xff; + if (ix < 0 || ix >= MAX_TMOUTS) + return; + + timeout_random++; + tmout = &tmouts[ix]; + + if (tmout->timestamp != id) /* Expired timer */ + return; + if (tmout->active) + del_timer (&tmout->timer); + tmout->active = 0; + tmout->timestamp = 0; +} + +int +oss_uiomove (void *addr, size_t nbytes, enum uio_rw rwflag, uio_t * uio) +{ +/* + * NOTE! Returns 0 upon success and EFAULT on failure (instead of -EFAULT + * (for Solaris/BSD compatibilityi)). + */ + + int c; + char *address = addr; + + if (rwflag != uio->rw) + { + oss_cmn_err (CE_WARN, "uiomove: Bad direction\n"); + return EFAULT; + } + + if (uio->resid < nbytes) + { + oss_cmn_err (CE_WARN, "uiomove: Bad count %d (%d)\n", nbytes, + uio->resid); + return EFAULT; + } + + if (uio->kernel_space) + return EFAULT; + + switch (rwflag) + { + case UIO_READ: + c = nbytes; + if (c > 10) + c = 0; + + if ((c = copy_to_user (uio->ptr, address, nbytes) != 0)) + { + uio->resid -= nbytes; + oss_cmn_err (CE_CONT, "copy_to_user(%d) failed (%d)\n", nbytes, c); + return EFAULT; + } + break; + + case UIO_WRITE: + if (copy_from_user (address, uio->ptr, nbytes) != 0) + { + oss_cmn_err (CE_CONT, "copy_from_user failed\n"); + uio->resid -= nbytes; + return EFAULT; + } + break; + } + + uio->resid -= nbytes; + uio->ptr += nbytes; + + return 0; +} + +int +oss_create_uio (uio_t * uio, char *buf, size_t count, uio_rw_t rw, + int is_kernel) +{ + memset (uio, 0, sizeof (*uio)); + + if (is_kernel) + { + oss_cmn_err (CE_CONT, + "oss_create_uio: Kernel space buffers not supported\n"); + return -EIO; + } + + uio->ptr = buf; + uio->resid = count; + uio->kernel_space = is_kernel; + uio->rw = rw; + + return 0; +} + +void +oss_cmn_err (int level, const char *s, ...) +{ + char tmp[1024], *a[6]; + va_list ap; + int i, n = 0; + + va_start (ap, s); + + for (i = 0; i < strlen (s); i++) + if (s[i] == '%') + n++; + + for (i = 0; i < n && i < 6; i++) + a[i] = va_arg (ap, char *); + + for (i = n; i < 6; i++) + a[i] = NULL; + + if (level == CE_CONT) + { + sprintf (tmp, s, a[0], a[1], a[2], a[3], a[4], a[5], NULL, + NULL, NULL, NULL); + printk ("%s", tmp); + } + else + { + strcpy (tmp, "osscore: "); + sprintf (tmp + strlen (tmp), s, a[0], a[1], a[2], a[3], a[4], a[5], + NULL, NULL, NULL, NULL); + if (level == CE_PANIC) + panic (tmp); + + printk (KERN_ALERT "%s", tmp); + } +#if 0 + /* This may cause a crash under SMP */ + if (sound_started) + store_msg (tmp); +#endif + + va_end (ap); +} + +/* + * Sleep/wakeup + */ + +struct oss_wait_queue +{ + volatile int flags; + wait_queue_head_t wq; +}; + +struct oss_wait_queue * +oss_create_wait_queue (oss_device_t * osdev, const char *name) +{ + struct oss_wait_queue *wq; + + if ((wq = vmalloc (sizeof (*wq))) == NULL) + { + oss_cmn_err (CE_WARN, "vmalloc(%d) failed (wq)\n", sizeof (*wq)); + return NULL; + } + init_waitqueue_head (&wq->wq); + + return wq; +} + +void +oss_reset_wait_queue (struct oss_wait_queue *wq) +{ + wq->flags = 0; +} + +void +oss_remove_wait_queue (struct oss_wait_queue *wq) +{ + vfree (wq); +} + +int +oss_sleep (struct oss_wait_queue *wq, oss_mutex_t * mutex, int ticks, + oss_native_word * flags, unsigned int *status) +{ + int result = 0; + *status = 0; + + if (wq == NULL) + return 0; + + wq->flags = 0; + oss_spin_unlock_irqrestore (*mutex, *flags); + + if (ticks <= 0) + result = wait_event_interruptible (wq->wq, (wq->flags & WK_WAKEUP)); + else + result = + wait_event_interruptible_timeout (wq->wq, (wq->flags & WK_WAKEUP), + ticks); + + oss_spin_lock_irqsave (*mutex, flags); + + if (result < 0) /* Signal received */ + { + *status |= WK_SIGNAL; + return 1; + } + + if (!(wq->flags & WK_WAKEUP)) /* Timeout */ + { + return 0; + } + + return 1; +} + +int +oss_register_poll (struct oss_wait_queue *wq, oss_mutex_t * mutex, + oss_native_word * flags, oss_poll_event_t * ev) +{ + oss_spin_unlock_irqrestore (*mutex, *flags); + poll_wait ((struct file *) ev->file, &wq->wq, + (struct poll_table_struct *) ev->wait); + oss_spin_lock_irqsave (*mutex, flags); + return 0; +} + +void +oss_wakeup (struct oss_wait_queue *wq, oss_mutex_t * mutex, + oss_native_word * flags, short events) +{ + if (wq == NULL) + return; + + wq->flags |= WK_WAKEUP; + oss_spin_unlock_irqrestore (*mutex, *flags); + wake_up (&wq->wq); + oss_spin_lock_irqsave (*mutex, flags); +} + +void +oss_reserve_pages (oss_native_word start_addr, oss_native_word end_addr) +{ + struct page *page, *lastpage; + + lastpage = virt_to_page (end_addr); + + for (page = virt_to_page (start_addr); page <= lastpage; page++) + set_bit (PG_reserved, &page->flags); +} + +void +oss_unreserve_pages (oss_native_word start_addr, oss_native_word end_addr) +{ + struct page *page, *lastpage; + + lastpage = virt_to_page (end_addr); + + for (page = virt_to_page (start_addr); page <= lastpage; page++) + clear_bit (PG_reserved, &page->flags); +} + +void * +oss_contig_malloc (oss_device_t * osdev, int buffsize, oss_uint64_t memlimit, + oss_native_word * phaddr) +{ + char *start_addr, *end_addr; + int sz, size; + int flags = 0; + + *phaddr = 0; + +#ifdef GFP_DMA32 + if (memlimit < 0x0000000100000000LL) + flags |= GFP_DMA32; +#endif + + if (memlimit < 0x00000000ffffffffLL) + flags |= GFP_DMA; + + start_addr = NULL; + + for (sz = 0, size = PAGE_SIZE; size < buffsize; sz++, size <<= 1); + + if (buffsize != (PAGE_SIZE * (1 << sz))) + { +#if 0 + printk + ("Contig_malloc: Invalid size %d != %ld\n", buffsize, + PAGE_SIZE * (1 << sz)); +#endif + } + + start_addr = (char *) __get_free_pages (GFP_KERNEL | flags, sz); + + if (start_addr == NULL) + { + cmn_err (CE_NOTE, "Failed to allocate memory buffer of %d bytes\n", + buffsize); + return NULL; + } + else + { + /* make some checks */ + end_addr = start_addr + buffsize - 1; + + oss_reserve_pages ((oss_native_word) start_addr, + (oss_native_word) end_addr); + } + + *phaddr = virt_to_bus (start_addr); + return start_addr; +} + +void +oss_contig_free (oss_device_t * osdev, void *p, int buffsize) +{ + int sz, size; + caddr_t start_addr, end_addr; + + if (p == NULL) + return; + + for (sz = 0, size = PAGE_SIZE; size < buffsize; sz++, size <<= 1); + + start_addr = p; + end_addr = p + buffsize - 1; + + oss_unreserve_pages ((oss_native_word) start_addr, + (oss_native_word) end_addr); + free_pages ((unsigned long) p, sz); +} + +/* + * These typedefs must match definition of struct file_operations. + * (See notes in routine oss_register_chrdev). + */ +typedef ssize_t (*read_t) (struct file *, char *, size_t, loff_t *); +typedef ssize_t (*write_t) (struct file *, const char *, size_t, loff_t *); +typedef unsigned int (*poll_t) (struct file *, poll_table *); +typedef poll_table select_table; + +typedef int (*readdir_t) (struct inode *, struct file *, void *, filldir_t); +typedef int (*ioctl_t) (struct inode *, struct file *, unsigned int, + unsigned long); +typedef long (*new_ioctl_t) (struct file *, unsigned int, unsigned long); +typedef int (*mmap_t) (struct file *, struct vm_area_struct *); +typedef int (*open_t) (struct inode *, struct file *); + +typedef int (*release_t) (struct inode *, struct file *); +typedef int (*fasync_t) (int, struct file *, int); +typedef int (*fsync_t) (struct inode *, struct file *); + +static loff_t +oss_no_llseek (struct file *file, loff_t offset, int orig) +{ + return -EINVAL; +} + +static int +oss_no_fsync (struct file *f, struct dentry *d, int datasync) +{ + return -EINVAL; +} + +static int +oss_no_fasync (int x, struct file *f, int m) +{ + return -EINVAL; +} + +/* + * Wrappers for installing and uninstalling character and block devices. + * + * The oss_file_operation_handle structure differs from kernel's + * file_operations structure in parameters of the driver entry points. + * Kernel inode, file, wait_struct, vm_are_struct etc. typed arguments + * are replaced by wrapper handles. + */ + +static struct file_operations * +alloc_fop (oss_device_t * osdev, struct oss_file_operation_handle *op) +{ +/* + * This routine performs initialization of kernel file_operations structure + * from oss_file_operation_handle structure. Each procedure pointer is copied + * to a temporary variable before doing the actual assignment. This + * prevents unnecessary warnings while it still enables compatibility + * warnings. + * + * Any warning given by this routine may indicate that kernel fs + * call interface has changed significantly (added parameters to the routines). + * In this case definition routine in oss_file_operation_handle must be updated + * and WRAPPER_VERSION must be incremented. + */ + + struct file_operations *fop; + + poll_t tmp_poll = (poll_t) op->poll; + read_t tmp_read = (read_t) op->read; + write_t tmp_write = (write_t) op->write; + /* readdir_t tmp_readdir = (readdir_t)op->readdir; */ +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,35) + ioctl_t tmp_ioctl = (ioctl_t) op->ioctl; +#endif + mmap_t tmp_mmap = (mmap_t) op->mmap; + open_t tmp_open = (open_t) op->open; + release_t tmp_release = (release_t) op->release; + new_ioctl_t tmp_unlocked_ioctl = (new_ioctl_t) op->unlocked_ioctl; + new_ioctl_t tmp_compat_ioctl = (new_ioctl_t) op->compat_ioctl; + + fop = (struct file_operations *) + oss_kmem_alloc (sizeof (struct file_operations)); + + memset ((char *) fop, 0, sizeof (struct file_operations)); + +/* + * Now the assignment + */ + fop->llseek = oss_no_llseek; + fop->read = tmp_read; + fop->write = tmp_write; + fop->readdir = NULL; /* tmp_readdir; */ + fop->poll = tmp_poll; +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,35) + fop->ioctl = tmp_ioctl; +#endif + fop->mmap = tmp_mmap; + fop->open = tmp_open; + fop->release = tmp_release; + fop->fsync = oss_no_fsync; + fop->fasync = oss_no_fasync; + fop->lock = NULL; + fop->flush = NULL; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + fop->owner = osdev_get_owner (osdev); +#endif +#ifdef HAVE_UNLOCKED_IOCTL + fop->unlocked_ioctl = tmp_unlocked_ioctl; +#endif +#ifdef HAVE_COMPAT_IOCTL + fop->compat_ioctl = tmp_compat_ioctl; +#endif + + return fop; +} + +int +oss_register_chrdev (oss_device_t * osdev, unsigned int major, + const char *name, struct oss_file_operation_handle *op) +{ + int maj; + maj = register_chrdev (major, name, alloc_fop (osdev, op)); + + return maj; +} + +void +oss_register_minor (int major, int minor, char *name) +{ + if (nminors >= MAX_MINOR) + { + oss_cmn_err (CE_WARN, "Too many device files\n"); + return; + } + + minors[nminors].major = major; + minors[nminors].minor = minor; + strcpy (minors[nminors].name, name); + nminors++; +} + +int +oss_unregister_chrdev (unsigned int major, const char *name) +{ + unregister_chrdev (major, name); + return 0; +} + +int +oss_inode_get_minor (oss_inode_handle_t * inode) +{ + return MINOR (((struct inode *) inode)->i_rdev); +} + +int +oss_file_get_flags (oss_file_handle_t * file) +{ + return ((struct file *) file)->f_flags; +} + +void * +oss_file_get_private (oss_file_handle_t * file) +{ + return ((struct file *) file)->private_data; +} + +void +oss_file_set_private (oss_file_handle_t * file, void *v) +{ + ((struct file *) file)->private_data = v; +} + +int +oss_vma_get_flags (oss_vm_area_handle_t * vma) +{ + return ((struct vm_area_struct *) vma)->vm_flags; +} + +int +oss_do_mmap (oss_vm_area_handle_t * v, oss_native_word dmabuf_phys, + int bytes_in_use) +{ + struct vm_area_struct *vma = (struct vm_area_struct *) v; + int res, size; + + if (vma->vm_pgoff != 0) + { + oss_cmn_err (CE_WARN, "mmap() offset must be 0.\n"); + return -EINVAL; + } + + size = vma->vm_end - vma->vm_start; + + if (size != bytes_in_use) + { + oss_cmn_err (CE_WARN, "mmap() size = %ld. Should be %d\n", + size, bytes_in_use); + return -EBUSY; + } + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13) + res = io_remap_page_range (vma, vma->vm_start, + dmabuf_phys, size, vma->vm_page_prot); + +#else + res = io_remap_pfn_range (vma, vma->vm_start, + dmabuf_phys >> PAGE_SHIFT, + size, vma->vm_page_prot); +#endif + + if (res) + { + oss_cmn_err (CE_WARN, "io_remap_pfn_range returned %d\n", res); + return -EAGAIN; + } + + return 0; +} + +/* As a special exception, if you link this library with other files, + some of which are compiled with GCC, to produce an executable, + this library does not by itself cause the resulting executable + to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +typedef unsigned int UQItype __attribute__ ((mode (QI))); +typedef int SItype __attribute__ ((mode (SI))); +typedef unsigned int USItype __attribute__ ((mode (SI))); +typedef int DItype __attribute__ ((mode (DI))); +typedef unsigned int UDItype __attribute__ ((mode (DI))); + +typedef int word_type __attribute__ ((mode (__word__))); + +/* DIstructs are pairs of SItype values in the order determined by + little/big ENDIAN. */ + +#if defined(__i386__) || defined(__x86_64__) +struct DIstruct +{ + SItype low, high; +}; +#endif + + +#ifndef __arm__ +/* We need this union to unpack/pack DImode values, since we don't have + any arithmetic yet. Incoming DImode parameters are stored into the + `ll' field, and the unpacked result is read from the struct `s'. */ + +typedef union +{ + struct DIstruct s; + DItype ll; +} DIunion; + + +/* From gcc/longlong.h */ + +#ifndef SI_TYPE_SIZE +#define SI_TYPE_SIZE 32 +#endif + +#define __BITS4 (SI_TYPE_SIZE / 4) +#define __ll_B (1L << (SI_TYPE_SIZE / 2)) +#define __ll_lowpart(t) ((USItype) (t) % __ll_B) +#define __ll_highpart(t) ((USItype) (t) / __ll_B) + +#if defined(__i386__) || defined(__x86_64__) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subl %5,%1\n" \ + "sbbl %3,%0" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "0" ((USItype) (ah)), \ + "g" ((USItype) (bh)), \ + "1" ((USItype) (al)), \ + "g" ((USItype) (bl))) +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("mull %3" \ + : "=a" ((USItype) (w0)), \ + "=d" ((USItype) (w1)) \ + : "%0" ((USItype) (u)), \ + "rm" ((USItype) (v))) +#define udiv_qrnnd(q, r, n1, n0, d) \ + __asm__ ("divl %4" \ + : "=a" ((USItype) (q)), \ + "=d" ((USItype) (r)) \ + : "0" ((USItype) (n0)), \ + "1" ((USItype) (n1)), \ + "rm" ((USItype) (d))) +#define count_leading_zeros(count, x) \ + do { \ + USItype __cbtmp; \ + __asm__ ("bsrl %1,%0" \ + : "=r" (__cbtmp) : "rm" ((USItype) (x))); \ + (count) = __cbtmp ^ 31; \ + } while (0) +#endif /* __i386__ */ + +/* If this machine has no inline assembler, use C macros. */ + +/* Define this unconditionally, so it can be used for debugging. */ +#define __udiv_qrnnd_c(q, r, n1, n0, d) \ + do { \ + USItype __d1, __d0, __q1, __q0; \ + USItype __r1, __r0, __m; \ + __d1 = __ll_highpart (d); \ + __d0 = __ll_lowpart (d); \ + \ + __r1 = (n1) % __d1; \ + __q1 = (n1) / __d1; \ + __m = (USItype) __q1 * __d0; \ + __r1 = __r1 * __ll_B | __ll_highpart (n0); \ + 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 = (USItype) __q0 * __d0; \ + __r0 = __r0 * __ll_B | __ll_lowpart (n0); \ + if (__r0 < __m) \ + { \ + __q0--, __r0 += (d); \ + if (__r0 >= (d)) \ + if (__r0 < __m) \ + __q0--, __r0 += (d); \ + } \ + __r0 -= __m; \ + \ + (q) = (USItype) __q1 * __ll_B | __q0; \ + (r) = __r0; \ + } while (0) + +/* If udiv_qrnnd was not defined for this processor, use __udiv_qrnnd_c. */ +#if !defined (udiv_qrnnd) +#define UDIV_NEEDS_NORMALIZATION 1 +#define udiv_qrnnd __udiv_qrnnd_c +#endif + +/* End of gcc/longlong.h */ + + +static inline DItype +__negdi2 (DItype u) +{ + DIunion w; + DIunion uu; + + uu.ll = u; + + w.s.low = -uu.s.low; + w.s.high = -uu.s.high - ((USItype) w.s.low > 0); + + return w.ll; +} + +static inline UDItype +__udivmoddi4 (UDItype n, UDItype d, UDItype * rp) +{ + DIunion ww; + DIunion nn, dd; + DIunion rr; + USItype d0, d1, n0, n1, n2; + USItype q0, q1; + USItype b, bm; + + nn.ll = n; + dd.ll = d; + + d0 = dd.s.low; + d1 = dd.s.high; + n0 = nn.s.low; + n1 = nn.s.high; + +#ifndef UDIV_NEEDS_NORMALIZATION + if (d1 == 0) + { + 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. */ + } + + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = 0; + *rp = rr.ll; + } + } + +#else /* UDIV_NEEDS_NORMALIZATION */ + + if (d1 == 0) + { + 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 >> (SI_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 + { + /* Normalize. */ + + b = SI_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. */ + } + + if (rp != 0) + { + rr.s.low = n0 >> bm; + rr.s.high = 0; + *rp = rr.ll; + } + } +#endif /* UDIV_NEEDS_NORMALIZATION */ + + else + { + if (d1 > n1) + { + /* 00 = nn / DD */ + + q0 = 0; + q1 = 0; + + /* Remainder in n1n0. */ + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } + 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; + + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } + else + { + USItype m1, m0; + /* Normalize. */ + + b = SI_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. */ + if (rp != 0) + { + sub_ddmmss (n1, n0, n1, n0, m1, m0); + rr.s.low = (n1 << b) | (n0 >> bm); + rr.s.high = n1 >> bm; + *rp = rr.ll; + } + } + } + } + + ww.s.low = q0; + ww.s.high = q1; + return ww.ll; +} + +DItype +__divdi3 (DItype u, DItype v) +{ + word_type c = 0; + DIunion uu, vv; + DItype w; + + uu.ll = u; + vv.ll = v; + + if (uu.s.high < 0) + c = ~c, uu.ll = __negdi2 (uu.ll); + if (vv.s.high < 0) + c = ~c, vv.ll = __negdi2 (vv.ll); + + w = __udivmoddi4 (uu.ll, vv.ll, (UDItype *) 0); + if (c) + w = __negdi2 (w); + + return w; +} + + +DItype +__moddi3 (DItype u, DItype v) +{ + word_type c = 0; + DIunion uu, vv; + DItype w; + + uu.ll = u; + vv.ll = v; + + if (uu.s.high < 0) + c = ~c, uu.ll = __negdi2 (uu.ll); + if (vv.s.high < 0) + vv.ll = __negdi2 (vv.ll); + + (void) __udivmoddi4 (uu.ll, vv.ll, (UDItype *) & w); + if (c) + w = __negdi2 (w); + + return w; +} + + +UDItype +__umoddi3 (UDItype u, UDItype v) +{ + UDItype w; + + (void) __udivmoddi4 (u, v, (UDItype *) & w); + + return w; +} + + +UDItype +__udivdi3 (UDItype n, UDItype d) +{ + return __udivmoddi4 (n, d, (UDItype *) 0); +} +#endif + +#ifdef __arm__ +void +raise(void) +{ + oss_cmn_err (CE_PANIC, "raise() got called\n"); +} + +#endif + +dev_info_t * +oss_create_pcidip (struct pci_dev * pcidev) +{ + dev_info_t *dip; + + if ((dip = oss_pmalloc (sizeof (*dip))) == NULL) + return NULL; + + memset (dip, 0, sizeof (*dip)); + dip->pcidev = pcidev; + + return dip; +} + +int +osscore_pci_read_config_byte (dev_info_t * dip, unsigned int where, + unsigned char *val) +{ + return pci_read_config_byte (dip->pcidev, where, val); +} + +int +osscore_pci_read_config_irq (dev_info_t * dip, unsigned int where, + unsigned char *val) +{ + *val = dip->pcidev->irq; + return 0; // PCIBIOS_SUCCESSFUL +} + +int +osscore_pci_read_config_word (dev_info_t * dip, unsigned int where, + unsigned short *val) +{ + if (dip == NULL) + { + oss_cmn_err (CE_CONT, "osscore_pci_read_config_word: dip==NULL\n"); + return -1; + } + return pci_read_config_word (dip->pcidev, where, val); +} + +int +osscore_pci_read_config_dword (dev_info_t * dip, unsigned int where, + unsigned int *val) +{ + return pci_read_config_dword (dip->pcidev, where, val); +} + +int +osscore_pci_write_config_byte (dev_info_t * dip, unsigned int where, + unsigned char val) +{ + return pci_write_config_byte (dip->pcidev, where, val); +} + +int +osscore_pci_write_config_word (dev_info_t * dip, unsigned int where, + unsigned short val) +{ + return pci_write_config_word (dip->pcidev, where, val); +} + +int +osscore_pci_write_config_dword (dev_info_t * dip, unsigned int where, + unsigned int val) +{ + return pci_write_config_dword (dip->pcidev, where, val); +} + +int +osscore_pci_enable_msi (dev_info_t * dip) +{ + pci_enable_msi (dip->pcidev); + return (dip->pcidev->irq); +} + +/* These definitions must match with oss_config.h */ +typedef int (*oss_tophalf_handler_t) (struct _oss_device_t * osdev); +typedef void (*oss_bottomhalf_handler_t) (struct _oss_device_t * osdev); + +typedef struct +{ + int irq; + oss_device_t *osdev; + oss_tophalf_handler_t top; + oss_bottomhalf_handler_t bottom; +} osscore_intr_t; + +#define MAX_INTRS 32 + +static osscore_intr_t intrs[MAX_INTRS] = { {0} }; +static int nintrs = 0; + +static irqreturn_t +osscore_intr (int irq, void *arg) +{ + int serviced; + osscore_intr_t *intr = arg; + + if (intr->osdev == NULL || intr->top == NULL) /* Removed interrupt */ + return 0; + + serviced = intr->top (intr->osdev); + oss_inc_intrcount (intr->osdev, serviced); + if (serviced) + { + if (intr->bottom != NULL) + intr->bottom (intr->osdev); + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +extern int oss_pci_read_config_irq (oss_device_t * osdev, unsigned long where, + unsigned char *val); + +char * +oss_pci_read_devpath (dev_info_t * dip) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30) + return dev_name(&dip->pcidev->dev); +#else + return dip->pcidev->dev.bus_id; +#endif +} + +int +oss_register_interrupts (oss_device_t * osdev, int irqnum, + oss_tophalf_handler_t top, + oss_bottomhalf_handler_t bottom) +{ + + unsigned char pci_irq_line; + osscore_intr_t *intr; + char *name; + int err; + + if (nintrs >= MAX_INTRS) + { + oss_cmn_err (CE_CONT, + "oss_register_interrupts: Too many interrupt handlers\n"); + return -ENOMEM; + } + + intr = &intrs[nintrs]; + + if (oss_pci_read_config_irq (osdev, PCI_INTERRUPT_LINE, &pci_irq_line) > 0) + return -EIO; + + intr->irq = pci_irq_line; + intr->osdev = osdev; + intr->top = top; + intr->bottom = bottom; + + name = osdev_get_nick (osdev); +#ifndef IRQF_SHARED +#define IRQF_SHARED SA_SHIRQ +#endif + + if ((err = + request_irq (pci_irq_line, osscore_intr, IRQF_SHARED, name, intr)) < 0) + { + oss_cmn_err (CE_CONT, "request_irq(%d) failed, err=%d\n", pci_irq_line, + err); + return err; + } + + nintrs++; + + return 0; +} + +void +oss_unregister_interrupts (oss_device_t * osdev) +{ + int i; + + for (i = 0; i < nintrs; i++) + if (intrs[i].osdev == osdev) + { + free_irq (intrs[i].irq, &intrs[i]); + intrs[i].osdev = NULL; + intrs[i].top = NULL; + intrs[i].bottom = NULL; + } +} + +int +oss_copy_to_user (void *to, const void *from, unsigned long n) +{ + return copy_to_user (to, from, n); +} + +int +oss_copy_from_user (void *to, const void *from, unsigned long n) +{ + return copy_from_user (to, from, n); +} + +static int refcount = 0; + +typedef struct +{ + struct module *module; + int active; +} oss_module_t; + +#define OSS_MAX_MODULES 50 + +static oss_module_t oss_modules[OSS_MAX_MODULES]; +static int num_oss_modules = 0; + +void +oss_inc_refcounts (void) +{ + int i; + refcount++; + for (i = 0; i < num_oss_modules; i++) + if (oss_modules[i].active) + { + if (!try_module_get (oss_modules[i].module)) + oss_cmn_err (CE_WARN, "try_module_get() failed\n"); + } +} + +void +oss_dec_refcounts (void) +{ + int i; + refcount--; + for (i = 0; i < num_oss_modules; i++) + if (oss_modules[i].active) + { + module_put (oss_modules[i].module); + } +} + +void +oss_register_module (struct module *mod) +{ + int i, n = -1; + + for (i = 0; i < num_oss_modules; i++) + if (!oss_modules[i].active) + { + n = i; + break; + } + + if (n == -1) + { + if (num_oss_modules >= OSS_MAX_MODULES) + { + printk (KERN_ALERT "Too many OSS modules\n"); + return; + } + + n = num_oss_modules++; + } + + oss_modules[n].module = mod; + oss_modules[n].active = 1; +} + +void +oss_unregister_module (struct module *mod) +{ + int i; + + for (i = 0; i < num_oss_modules; i++) + if (oss_modules[i].active && oss_modules[i].module == mod) + { + oss_modules[i].active = 0; + oss_modules[i].module = NULL; + return; + } +} + +module_init (osscore_init); +module_exit (osscore_exit); + +#ifdef CONFIG_OSS_VMIX_FLOAT + +#define FP_SAVE(envbuf) asm ("fnsave %0":"=m" (*envbuf)); +#define FP_RESTORE(envbuf) asm ("frstor %0":"=m" (*envbuf)); + +/* SSE/SSE2 compatible macros */ +#define FX_SAVE(envbuf) asm ("fxsave %0":"=m" (*envbuf)); +#define FX_RESTORE(envbuf) asm ("fxrstor %0":"=m" (*envbuf)); + +static int old_arch = 0; /* No SSE/SSE2 instructions */ + +#if 0 +static inline unsigned long +read_cr0 (void) +{ + unsigned long cr0; + asm volatile ("movq %%cr0,%0":"=r" (cr0)); + return cr0; +} + +static inline void +write_cr0 (unsigned long val) +{ + asm volatile ("movq %0,%%cr0"::"r" (val)); +} + +static inline unsigned long +read_cr4 (void) +{ + unsigned long cr4; + asm volatile ("movq %%cr4,%0":"=r" (cr4)); + return cr4; +} + +static inline void +write_cr4 (unsigned long val) +{ + asm volatile ("movq %0,%%cr4"::"r" (val)); +} +#endif + +static inline unsigned long long +read_mxcsr (void) +{ + unsigned long long mxcsr; + asm volatile ("stmxcsr %0":"=m" (mxcsr)); + return mxcsr; +} + +static inline void +write_mxcsr (unsigned long long val) +{ + asm volatile ("ldmxcsr %0"::"m" (val)); +} + +int +oss_fp_check (void) +{ + int eax, ebx, ecx, edx; +#define FLAGS_ID (1<<21) + + oss_native_word flags_reg; + + local_save_flags (flags_reg); + flags_reg &= ~FLAGS_ID; + local_irq_restore (flags_reg); + + local_save_flags (flags_reg); + if (flags_reg & FLAGS_ID) + return 0; + + flags_reg |= FLAGS_ID; + local_irq_restore (flags_reg); + + local_save_flags (flags_reg); + if (!(flags_reg & FLAGS_ID)) + return 0; + +#define CPUID_FXSR (1<<24) +#define CPUID_SSE (1<<25) +#define CPUID_SSE2 (1<<26) + + cpuid (1, &eax, &ebx, &ecx, &edx); + + if (!(edx & CPUID_FXSR)) + return -1; + + /* + * Older machines require different FP handling than the latest ones. Use the SSE + * instruction set as an indicator. + */ + if (!(edx & CPUID_SSE)) + old_arch = 1; + + return 1; +} + +void +oss_fp_save (short *envbuf, unsigned int flags[]) +{ + flags[0] = read_cr0 (); + write_cr0 (flags[0] & ~0x0e); /* Clear CR0.TS/MP/EM */ + + if (old_arch) + { + FP_SAVE (envbuf); + } + else + { + flags[1] = read_cr4 (); + write_cr4 (flags[1] | 0x600); /* Set OSFXSR & OSXMMEXCEPT */ + FX_SAVE (envbuf); + asm ("fninit"); + asm ("fwait"); + write_mxcsr (0x1f80); + } + flags[2] = read_cr0 (); +} + +void +oss_fp_restore (short *envbuf, unsigned int flags[]) +{ + asm ("fwait"); + if (old_arch) + { + FP_RESTORE (envbuf); + } + else + { + FX_RESTORE (envbuf); + write_cr4 (flags[1]); /* Restore cr4 */ + } + write_cr0 (flags[0]); /* Restore cr0 */ +} +#endif + +#if 0 +void +__stack_chk_fail (void) +{ + panic ("__stack_chk_fail\n"); +} +#endif + +/* + * Exported symbols + */ + +#define EXPORT_FUNC(name) extern void name(void);EXPORT_SYMBOL(name); +#define EXPORT_DATA(name) extern int name;EXPORT_SYMBOL(name); + +/* EXPORT_SYMBOL (__stack_chk_fail); */ + +#ifdef CONFIG_OSS_VMIX_FLOAT +EXPORT_SYMBOL (oss_fp_check); +EXPORT_SYMBOL (oss_fp_save); +EXPORT_SYMBOL (oss_fp_restore); +#endif + +EXPORT_SYMBOL (oss_register_chrdev); +EXPORT_SYMBOL (oss_unregister_chrdev); +EXPORT_SYMBOL (oss_reserve_pages); +EXPORT_SYMBOL (oss_unreserve_pages); +EXPORT_FUNC (ac97_install); +EXPORT_FUNC (ac97_install_full); +EXPORT_FUNC (ac97_playrate); +EXPORT_FUNC (ac97_recrate); +EXPORT_FUNC (ac97_varrate); +EXPORT_FUNC (ac97_override_control); +EXPORT_FUNC (ac97_init_ext); +EXPORT_FUNC (ac97_mixer_set); +EXPORT_FUNC (ac97_spdif_setup); +EXPORT_FUNC (ac97_spdifout_ctl); +EXPORT_FUNC (ac97_remove_control); +EXPORT_SYMBOL (ac97_amplifier); +EXPORT_FUNC (ac97_disable_spdif); +EXPORT_FUNC (ac97_enable_spdif); +EXPORT_FUNC (ac97_mixext_ctl); +EXPORT_FUNC (ac97_spdifin_ctl); +EXPORT_FUNC (oss_pci_byteswap); +EXPORT_SYMBOL (mixer_ext_truncate); +EXPORT_SYMBOL (mixer_ext_rebuild_all); +EXPORT_FUNC (remux_install); +EXPORT_SYMBOL (oss_strlen); +EXPORT_SYMBOL (oss_strcmp); +EXPORT_FUNC (oss_install_mididev); +EXPORT_DATA (detect_trace); +EXPORT_SYMBOL (dmap_get_qhead); +EXPORT_SYMBOL (dmap_get_qtail); +EXPORT_FUNC (oss_alloc_dmabuf); +EXPORT_SYMBOL (oss_contig_free); +EXPORT_SYMBOL (oss_contig_malloc); +EXPORT_FUNC (oss_disable_device); +EXPORT_FUNC (oss_free_dmabuf); +EXPORT_SYMBOL (oss_map_pci_mem); +EXPORT_SYMBOL (oss_install_audiodev); +EXPORT_SYMBOL (oss_install_audiodev_with_devname); +EXPORT_FUNC (oss_audio_set_error); +EXPORT_SYMBOL (load_mixer_volumes); +EXPORT_SYMBOL (oss_unmap_pci_mem); +EXPORT_SYMBOL (oss_memset); +EXPORT_SYMBOL (oss_mutex_cleanup); +EXPORT_SYMBOL (oss_mutex_init); +EXPORT_SYMBOL (oss_register_device); +EXPORT_SYMBOL (oss_register_interrupts); +EXPORT_SYMBOL (oss_inc_intrcount); +EXPORT_SYMBOL (oss_spin_lock); +EXPORT_SYMBOL (oss_spin_lock_irqsave); +EXPORT_SYMBOL (oss_spin_unlock); +EXPORT_SYMBOL (oss_spin_unlock_irqrestore); +EXPORT_SYMBOL (oss_udelay); +EXPORT_FUNC (oss_unregister_device); +EXPORT_SYMBOL (oss_unregister_interrupts); +EXPORT_SYMBOL (oss_virt_to_bus); +EXPORT_FUNC (oss_pci_read_config_byte); +EXPORT_FUNC (oss_pci_read_config_word); +EXPORT_FUNC (oss_pci_read_config_dword); +EXPORT_FUNC (oss_pci_write_config_byte); +EXPORT_FUNC (oss_pci_write_config_word); +EXPORT_FUNC (oss_pci_write_config_dword); +EXPORT_FUNC (oss_pci_enable_msi); +EXPORT_SYMBOL (oss_pci_read_config_irq); +EXPORT_SYMBOL (oss_pci_read_devpath); +EXPORT_SYMBOL (oss_get_jiffies); +EXPORT_SYMBOL (mixer_find_ext); +EXPORT_SYMBOL (oss_install_mixer); +EXPORT_SYMBOL (oss_strcpy); +EXPORT_SYMBOL (oss_kmem_free); +#ifndef __arm__ +EXPORT_FUNC (uart401_init); +EXPORT_FUNC (uart401_disable); +EXPORT_FUNC (uart401_irq); +#endif +EXPORT_SYMBOL (mixer_ext_set_init_fn); +EXPORT_SYMBOL (mixer_ext_set_vmix_init_fn); +#ifdef CONFIG_OSS_VMIX +EXPORT_FUNC (vmix_attach_audiodev); +EXPORT_FUNC (vmix_detach_audiodev); +EXPORT_FUNC (vmix_change_devnames); +#endif +EXPORT_SYMBOL (mixer_ext_set_strings); +EXPORT_SYMBOL (mixer_ext_create_group); +EXPORT_SYMBOL (mixer_ext_create_group_flags); +EXPORT_SYMBOL (mixer_ext_create_control); +EXPORT_SYMBOL (oss_strncpy); +EXPORT_SYMBOL (oss_memcpy); +EXPORT_SYMBOL (oss_kmem_alloc); +EXPORT_DATA (oss_hz); +EXPORT_FUNC (oss_spdif_open); +EXPORT_FUNC (oss_spdif_ioctl); +EXPORT_FUNC (oss_spdif_install); +EXPORT_FUNC (oss_spdif_uninstall); +EXPORT_FUNC (oss_spdif_close); +EXPORT_FUNC (oss_spdif_mix_init); +EXPORT_FUNC (oss_spdif_setrate); +EXPORT_FUNC (create_new_card); +EXPORT_FUNC (oss_audio_ioctl); +EXPORT_FUNC (oss_audio_open_engine); +EXPORT_FUNC (oss_audio_release); +EXPORT_FUNC (oss_audio_set_rate); +EXPORT_SYMBOL (oss_uiomove); +EXPORT_SYMBOL (oss_get_pid); +EXPORT_SYMBOL (oss_get_uid); +EXPORT_SYMBOL (oss_get_procname); +EXPORT_SYMBOL (mix_cvt); +EXPORT_FUNC (oss_audio_set_format); +EXPORT_FUNC (oss_audio_set_channels); +EXPORT_FUNC (midiparser_create); +EXPORT_FUNC (midiparser_input); +EXPORT_FUNC (midiparser_unalloc); +EXPORT_FUNC (mixer_ext_create_device); +EXPORT_SYMBOL (mixer_ext_recrw); +EXPORT_SYMBOL (mixer_ext_rw); +EXPORT_SYMBOL (mixer_ext_set_enum); +EXPORT_SYMBOL (mixer_ext_set_description); +EXPORT_SYMBOL (osdev_create); +EXPORT_FUNC (osdev_clone); +EXPORT_SYMBOL (osdev_delete); +EXPORT_FUNC (oss_audio_chpoll); +EXPORT_FUNC (oss_audio_delayed_attach); +EXPORT_FUNC (oss_audio_read); +EXPORT_FUNC (oss_audio_write); +EXPORT_SYMBOL (oss_create_wait_queue); +EXPORT_SYMBOL (oss_remove_wait_queue); +EXPORT_SYMBOL (oss_reset_wait_queue); +EXPORT_SYMBOL (oss_sleep); +EXPORT_SYMBOL (oss_strncmp); +EXPORT_SYMBOL (oss_timeout); +EXPORT_SYMBOL (oss_untimeout); +EXPORT_SYMBOL (oss_wakeup); +#if 0 +EXPORT_FUNC (ossddk_ac97_install); +EXPORT_FUNC (ossddk_ac97_is_varrate); +EXPORT_FUNC (ossddk_ac97_remove); +EXPORT_FUNC (ossddk_ac97_set_ext_init); +EXPORT_FUNC (ossddk_ac97_set_playrate); +EXPORT_FUNC (ossddk_ac97_set_recrate); +EXPORT_FUNC (ossddk_adev_get_devc); +EXPORT_FUNC (ossddk_adev_get_dmapin); +EXPORT_FUNC (ossddk_adev_get_dmapout); +EXPORT_FUNC (ossddk_adev_get_flags); +EXPORT_FUNC (ossddk_adev_get_label); +EXPORT_FUNC (ossddk_adev_get_portc); +EXPORT_FUNC (ossddk_adev_get_portc_play); +EXPORT_FUNC (ossddk_adev_get_portc_record); +EXPORT_FUNC (ossddk_adev_get_songname); +EXPORT_FUNC (ossddk_adev_set_buflimits); +EXPORT_FUNC (ossddk_adev_set_caps); +EXPORT_FUNC (ossddk_adev_set_channels); +EXPORT_FUNC (ossddk_adev_set_devc); +EXPORT_FUNC (ossddk_adev_set_enable_flag); +EXPORT_FUNC (ossddk_adev_set_flags); +EXPORT_FUNC (ossddk_adev_set_formats); +EXPORT_FUNC (ossddk_adev_set_label); +EXPORT_FUNC (ossddk_adev_set_magic); +EXPORT_FUNC (ossddk_adev_set_mixer); +EXPORT_FUNC (ossddk_adev_set_portc); +EXPORT_FUNC (ossddk_adev_set_portc_play); +EXPORT_FUNC (ossddk_adev_set_portc_record); +EXPORT_FUNC (ossddk_adev_set_portnum); +EXPORT_FUNC (ossddk_adev_set_rates); +EXPORT_FUNC (ossddk_adev_set_ratesource); +EXPORT_FUNC (ossddk_adev_set_songname); +EXPORT_FUNC (ossddk_adev_set_unloaded_flag); +EXPORT_FUNC (ossddk_audio_inputintr); +EXPORT_FUNC (ossddk_audio_outputintr); +EXPORT_FUNC (ossddk_disable_device); +EXPORT_FUNC (ossddk_dmap_get_buffsize); +EXPORT_FUNC (ossddk_dmap_get_buffused); +EXPORT_FUNC (ossddk_dmap_get_dmabuf); +EXPORT_FUNC (ossddk_dmap_get_fragsize); +EXPORT_FUNC (ossddk_dmap_get_numfrags); +EXPORT_FUNC (ossddk_dmap_get_phys); +EXPORT_FUNC (ossddk_dmap_get_private); +EXPORT_FUNC (ossddk_dmap_get_qhead); +EXPORT_FUNC (ossddk_dmap_get_qtail); +EXPORT_FUNC (ossddk_dmap_set_buffsize); +EXPORT_FUNC (ossddk_dmap_set_callback); +EXPORT_FUNC (ossddk_dmap_set_dmabuf); +EXPORT_FUNC (ossddk_dmap_set_fragsize); +EXPORT_FUNC (ossddk_dmap_set_numfrags); +EXPORT_FUNC (ossddk_dmap_set_phys); +EXPORT_FUNC (ossddk_dmap_set_playerror); +EXPORT_FUNC (ossddk_dmap_set_private); +EXPORT_FUNC (ossddk_dmap_set_recerror); +EXPORT_FUNC (ossddk_install_audiodev); +EXPORT_FUNC (ossddk_install_mixer); +EXPORT_FUNC (ossddk_mixer_create_control); +EXPORT_FUNC (ossddk_mixer_create_group); +EXPORT_FUNC (ossddk_mixer_get_devc); +EXPORT_FUNC (ossddk_mixer_set_strings); +EXPORT_FUNC (ossddk_mixer_touch); +EXPORT_FUNC (ossddk_mixer_truncate); +EXPORT_FUNC (ossddk_osdev_get_devc); +EXPORT_FUNC (ossddk_register_device); +EXPORT_FUNC (ossddk_unregister_device); +#endif +EXPORT_SYMBOL (osdev_set_major); +EXPORT_SYMBOL (osdev_set_owner); +EXPORT_SYMBOL (osdev_get_owner); +EXPORT_SYMBOL (oss_create_pcidip); +EXPORT_SYMBOL (touch_mixer); +EXPORT_SYMBOL (oss_mixer_ext); +EXPORT_SYMBOL (oss_request_major); +EXPORT_SYMBOL (audio_engines); +EXPORT_DATA (midi_devs); +EXPORT_SYMBOL (mixer_devs); +EXPORT_SYMBOL (mixer_devs_p); +EXPORT_DATA (num_audio_engines); +EXPORT_DATA (num_mididevs); +EXPORT_SYMBOL (num_mixers); +EXPORT_DATA (oss_timing_mutex); +EXPORT_DATA (oss_num_cards); +EXPORT_FUNC (oss_do_timing); +EXPORT_FUNC (oss_do_timing2); +EXPORT_FUNC (oss_timing_enter); +EXPORT_FUNC (oss_timing_leave); +#ifndef __arm__ +EXPORT_SYMBOL (__udivdi3); +EXPORT_SYMBOL (__umoddi3); +EXPORT_SYMBOL (__divdi3); +#else +EXPORT_SYMBOL (raise); +#endif +EXPORT_SYMBOL (oss_copy_from_user); +EXPORT_SYMBOL (oss_copy_to_user); +EXPORT_SYMBOL (osdev_set_irqparms); +EXPORT_SYMBOL (osdev_get_irqparms); +EXPORT_SYMBOL (osdev_get_nick); +EXPORT_SYMBOL (osdev_get_instance); +EXPORT_SYMBOL (oss_inc_refcounts); +EXPORT_SYMBOL (oss_dec_refcounts); +EXPORT_SYMBOL (oss_register_module); +EXPORT_SYMBOL (oss_unregister_module); +EXPORT_SYMBOL (oss_audio_reset); +EXPORT_SYMBOL (oss_audio_start_syncgroup); +EXPORT_SYMBOL (oss_encode_enum); +EXPORT_SYMBOL (dmap_get_qlen); +EXPORT_SYMBOL (num_audio_devfiles); +EXPORT_SYMBOL (oss_audio_inc_byte_counter); +EXPORT_SYMBOL (oss_audio_register_client); +EXPORT_SYMBOL (audio_devfiles); +EXPORT_FUNC (oss_get_cardinfo); +EXPORT_SYMBOL (oss_pmalloc); +EXPORT_SYMBOL (oss_add_audio_devlist); +EXPORT_FUNC (oss_memblk_malloc); +EXPORT_FUNC (oss_memblk_free); +EXPORT_FUNC (oss_memblk_unalloc); +EXPORT_DATA (oss_global_memblk); +EXPORT_FUNC (oss_get_procinfo); +EXPORT_DATA (mixer_muted); + +#ifdef CONFIG_OSS_MIDI +EXPORT_FUNC (oss_midi_ioctl); +EXPORT_FUNC (oss_midi_copy_timer); +#endif diff --git a/setup/Linux/oss/build/ossdip.h b/setup/Linux/oss/build/ossdip.h new file mode 100644 index 0000000..811e70a --- /dev/null +++ b/setup/Linux/oss/build/ossdip.h @@ -0,0 +1,10 @@ +/* + * Purpose: Definition of the _dev_info_t structure for Linux + */ +#ifndef OSSDIP_H +#define OSSDIP_H +struct _dev_info_t +{ + struct pci_dev *pcidev; +}; +#endif diff --git a/setup/Linux/oss/build/pci_wrapper.inc b/setup/Linux/oss/build/pci_wrapper.inc new file mode 100644 index 0000000..e08ec3a --- /dev/null +++ b/setup/Linux/oss/build/pci_wrapper.inc @@ -0,0 +1,93 @@ +/* + * Purpose: PCI wrapper routines for Linux + * + * This source file contains probe and remove routines for PCI devices. + * This code will be compiled in the target system. + */ +/* + * Copyright (C) 4Front Technologies 2005-2007. Released under GPL2 license. + */ +typedef struct +{ + struct pci_dev *pcidev; + oss_device_t *osdev; +} dev_map_t; + +#define MAX_INSTANCE 10 +static dev_map_t dev_map[MAX_INSTANCE]; +static int n_devmap = 0; + +static int __devinit +osspci_probe (struct pci_dev *pcidev, const struct pci_device_id *pciid) +{ + oss_device_t *osdev; + dev_info_t *dip; + + if (n_devmap >= MAX_INSTANCE) + { + printk (KERN_ALERT "oss: Too many instances of " DRIVER_NICK); + return -ENOMEM; + } + + if ((dip = oss_create_pcidip (pcidev)) == NULL) + return -ENOMEM; + + if ((osdev = + osdev_create (dip, DRIVER_TYPE, instance++, DRIVER_NICK, + NULL)) == NULL) + { + return -ENOMEM; + } + + osdev_set_owner (osdev, THIS_MODULE); + + if (module_major == 0) + module_major = oss_request_major (osdev, 0, DRIVER_NICK); + if (module_major <= 0) + { + printk (KERN_ALERT "Failed to allocate major device for " DRIVER_NICK); + return -EIO; + + } + osdev_set_major (osdev, module_major); + + pci_enable_device (pcidev); + if (!DRIVER_ATTACH (osdev)) + { + pci_disable_device (pcidev); + return -EIO; + } + + dev_map[n_devmap].pcidev = pcidev; + dev_map[n_devmap++].osdev = osdev; + oss_audio_delayed_attach (); + + return 0; +} + +static void __devexit +osspci_remove (struct pci_dev *pcidev) +{ + int i; + oss_device_t *osdev; + + for (i = 0; i < n_devmap; i++) + if (dev_map[i].pcidev == pcidev) + { + osdev = dev_map[i].osdev; + if (!DRIVER_DETACH (osdev)) + printk (KERN_ALERT DRIVER_NICK ": Unloading busy device\n"); + pci_disable_device (dev_map[i].pcidev); + osdev_delete (osdev); + + return; + } + + printk (KERN_ALERT DRIVER_NICK ": Can't find the PCI device to detach\n"); +} + +void +oss_pcie_init (oss_device_t * osdev, int flags) +{ + /* TODO: Do we need to do something here? */ +} diff --git a/setup/Linux/oss/build/usb_wrapper.inc b/setup/Linux/oss/build/usb_wrapper.inc new file mode 100644 index 0000000..ee199a7 --- /dev/null +++ b/setup/Linux/oss/build/usb_wrapper.inc @@ -0,0 +1,730 @@ +/* + * Purpose: Low level USB wrapper routines for Linux (2.6.x and later) + * + * This file contains the Linux specific USB support routines defined in udi.h + */ +/* + * Copyright (C) 4Front Technologies 2005-2007. Released under GPL2 license. + */ +#include "udi.h" + +#undef IO_DEBUG +static const udi_usb_devinfo *known_devices = NULL; + +#define MAX_DEVICE_SLOTS 20 + +int udi_usb_trace = 0; + +static udi_usb_driver *drv = NULL; +extern void *oss_pmalloc (size_t sz); + +struct udi_usb_devc +{ + struct usb_device *usb_dev; + const struct usb_device_id *id; + const udi_usb_devinfo *udi_usb_dev; + char *devpath; + + int enabled; + + int vendor, product, class, subclass; + struct usb_interface *iface; + int iface_number; + char *dev_name; + char *altsetting_labels; + int default_altsetting; + unsigned int altsetting_mask; + udi_usb_driver *drv; + void *client_devc; + int num_altsettings; + int usb_version; + struct usb_host_interface *altsetting; + +}; + +struct _udi_endpoint_handle_t +{ + unsigned char desc[32]; +}; + +#define MAX_DEVC 32 + +static udi_usb_devc usb_devc_list[MAX_DEVC] = { {0} }; +static int ndevs = 0; + +udi_endpoint_handle_t * +udi_open_endpoint (udi_usb_devc * usbdev, void *ep_descr) +{ + return (udi_endpoint_handle_t *) ep_descr; +} + +void +udi_close_endpoint (udi_endpoint_handle_t * eph) +{ + // NOP +} + +int +udi_endpoint_get_num (udi_endpoint_handle_t * eph) +{ + return eph->desc[2] /* & 0x7f */; +} + +#if 1 +static void +dump_configs (struct usb_device *dev) +{ + int c; + + printk ("#configs %d\n", dev->descriptor.bNumConfigurations); + + for (c = 0; c < dev->descriptor.bNumConfigurations; c++) + { + int i, j, k; + struct usb_host_config *config = &dev->config[c]; + + printk ("\tConfig #%d - #interfaces=%d\n", c, + config->desc.bNumInterfaces); + + for (j = 0; j < config->desc.bNumInterfaces; j++) + { + struct usb_interface *ifp = config->interface[j]; + printk ("\t\tInterface #%d - altsettings=%d\n", j, + ifp->num_altsetting); + + for (k = 0; k < ifp->num_altsetting; k++) + { + struct usb_host_interface *alt = &ifp->altsetting[k]; + unsigned char *buf = alt->extra; + + printk ("\t\t\tAlt setting #%d:\n", k); + + for (i = 0; i < alt->extralen; i++) + { + if (!(i % 8)) + { + if (i) + printk ("\n"); + printk ("\t\t\t%04x: ", i); + } + printk ("%02x ", buf[i]); + } + + printk ("\n"); + } + } + } +} +#endif + +static int +udi_attach_usbdev (struct usb_device *dev, + oss_device_t * osdev, + char *devpath, + struct usb_interface *iface, + const struct usb_device_id *id, + const udi_usb_devinfo * udi_usb_dev) +{ + int cfg_num, ep; + + udi_usb_devc *devc = &usb_devc_list[ndevs]; + struct usb_host_interface *alts; + + if (ndevs >= MAX_DEVC) + { + printk ("OSS: Too many USB audio/midi devices\n"); + return -ENODEV; + } + + if (udi_usb_trace > 1) + printk ("OSS: Attaching USB device %x:%x/%d, class=%x:%x, name=%s\n", + dev->descriptor.idVendor, dev->descriptor.idProduct, + iface->altsetting[0].desc.bInterfaceNumber, + iface->altsetting[0].desc.bInterfaceClass, + iface->altsetting[0].desc.bInterfaceSubClass, udi_usb_dev->name); + + devc->usb_dev = dev; + devc->id = id; + devc->udi_usb_dev = udi_usb_dev; + + devc->vendor = dev->descriptor.idVendor; + devc->product = dev->descriptor.idProduct; + devc->usb_version = dev->descriptor.bcdUSB >> 8; + devc->class = iface->altsetting[0].desc.bInterfaceClass; + devc->subclass = iface->altsetting[0].desc.bInterfaceSubClass; + devc->iface_number = iface->altsetting[0].desc.bInterfaceNumber; + devc->iface = iface; + devc->dev_name = udi_usb_dev->name; + devc->devpath = devpath; + devc->num_altsettings = iface->num_altsetting; + devc->altsetting = iface->altsetting; + + alts = &iface->altsetting[devc->num_altsettings - 1]; + ep = 0; + + if (alts->desc.bNumEndpoints > 1) + ep = 1; + + if (udi_usb_trace > 2) + { + int i; + + for (i = 0; i < alts->desc.bNumEndpoints; i++) + { + printk ("Endpoint: %02x\n", + alts->endpoint[i].desc.bEndpointAddress); + } + } + + cfg_num = 0; + + devc->enabled = 1; + devc->drv = drv; + + if (udi_usb_trace > 2) + dump_configs (dev); + + if ((devc->client_devc = drv->attach (devc, osdev)) == NULL) + { + return -EIO; + } + + ndevs++; + + usb_set_intfdata (iface, devc); + return 0; +} + +static char *prev_devices[32] = { NULL }; +static int nprev_devices = 0; + +static int +udi_usb_probe (struct usb_interface *iface, const struct usb_device_id *id) +{ + int i; + static int ncalls = 0; + oss_device_t *osdev = NULL; + dev_info_t *dip = NULL; // TODO + + char nick[32]; + int inst = 0; + + struct usb_device *dev = interface_to_usbdev (iface); + + if (ncalls++ > 100) + return -EIO; + + sprintf (nick, "usb%04x%04x-", dev->descriptor.idVendor, + dev->descriptor.idProduct); + +/* + * Find out how many instances of this device (ID) are already attached. + */ + + for (i = 0; i < nprev_devices; i++) + { + if (strcmp (nick, prev_devices[i]) == 0) + { + inst++; + } + } + + prev_devices[nprev_devices] = oss_pmalloc (strlen (nick) + 1); + strcpy (prev_devices[nprev_devices], nick); + if (nprev_devices < 32) + nprev_devices++; + + if ((osdev = osdev_create (dip, DRV_USB, inst, nick, NULL)) == NULL) + { + return -ENOMEM; + } + osdev_set_owner (osdev, THIS_MODULE); + osdev_set_major (osdev, usb_major); + + i = 0; + if (udi_usb_trace > 1) + printk ("\n\nProbing dev=%s id=%x:%x/%d\n", dev->devpath, + dev->descriptor.idVendor, + dev->descriptor.idProduct, + iface->altsetting[0].desc.bInterfaceNumber); + + while (i >= 0 && known_devices[i].vendor >= 0) + { + if (dev->descriptor.idVendor == known_devices[i].vendor && + dev->descriptor.idProduct == known_devices[i].product) + { + int ret; + const udi_usb_devinfo *d = &known_devices[i]; + ret = udi_attach_usbdev (dev, osdev, dev->devpath, iface, id, d); + return ret; + } + else + i++; + } + +/* Try the "generic" device */ + { + int ret; + const udi_usb_devinfo *d = &known_devices[i]; + ret = udi_attach_usbdev (dev, osdev, dev->devpath, iface, id, d); + return ret; + } + + return -ENODEV; +} + +static void +udi_usb_disconnect (struct usb_interface *iface) +{ + udi_usb_devc *devc = usb_get_intfdata (iface); + //struct usb_device *dev = interface_to_usbdev (iface); + + if (devc == (udi_usb_devc *) - 1) + return; + + if (!devc->enabled) + return; + + if (udi_usb_trace > 0) + printk ("OSS: Disconnect USB device %x:%x %s\n", devc->vendor, + devc->product, devc->udi_usb_dev->name); + devc->drv->disconnect (devc->client_devc); + devc->enabled = 0; +} + +static struct usb_driver oss_usb = { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) +owner:THIS_MODULE, +#endif +name:"oss_usb", +probe:udi_usb_probe, +disconnect:udi_usb_disconnect, +id_table:udi_usb_table +}; + +static int udi_usb_installed = 0; + +int +udi_attach_usbdriver (oss_device_t * osdev, const udi_usb_devinfo * devlist, + udi_usb_driver * driver) +{ + drv = driver; + known_devices = devlist; + return 1; +} + +void +udi_unload_usbdriver (oss_device_t * osdev) +{ +} + +/* + * Device access routines + */ + +int +udi_usbdev_get_class (udi_usb_devc * usbdev) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + + return devc->class; +} + +int +udi_usbdev_get_subclass (udi_usb_devc * usbdev) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + + return devc->subclass; +} + +int +udi_usbdev_get_vendor (udi_usb_devc * usbdev) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + + return devc->vendor; +} + +int +udi_usbdev_get_product (udi_usb_devc * usbdev) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + + return devc->product; +} + +int +udi_usbdev_get_inum (udi_usb_devc * usbdev) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + + return devc->iface_number; +} + +int +udi_usbdev_set_interface (udi_usb_devc * usbdev, int inum, int altset) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + + return usb_set_interface (devc->usb_dev, inum, altset); +} + +unsigned char * +udi_usbdev_get_endpoint (udi_usb_devc * usbdev, int altsetting, int n, + int *len) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + int num_endpoints; + struct usb_device *dev; + struct usb_host_interface *alts; + struct usb_interface *iface; + + dev = devc->usb_dev; + iface = devc->iface; + + if (altsetting >= devc->num_altsettings) + return NULL; + + alts = &iface->altsetting[altsetting]; + + num_endpoints = alts->desc.bNumEndpoints; + + if (n >= num_endpoints) + return NULL; + + *len = alts->endpoint[n].desc.bLength; + return (unsigned char *) &alts->endpoint[n].desc; +} + +int +udi_usbdev_get_num_altsettings (udi_usb_devc * usbdev) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + + return devc->num_altsettings; +} + +int +udi_usbdev_get_usb_version (udi_usb_devc * usbdev) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + + return devc->usb_version; +} + +unsigned char * +udi_usbdev_get_altsetting (udi_usb_devc * usbdev, int n, int *size) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + struct usb_host_interface *alt; + + if (n < 0 || n >= devc->num_altsettings) + { + /* printk("udi usb: Bad altsetting %d (%d)\n", n, n >= devc->num_altsettings); */ + return NULL; + } + + alt = &devc->altsetting[n]; + + *size = alt->extralen; + return alt->extra; +} + +char * +udi_usbdev_get_name (udi_usb_devc * usbdev) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + + return devc->dev_name == NULL ? "Unknown" : devc->dev_name; +} + + +char * +udi_usbdev_get_altsetting_labels (udi_usb_devc * usbdev, int if_num, int *default_alt, unsigned int *mask) +{ + int i; + + *default_alt=1; + *mask=0xffffffff; + + if (usbdev->udi_usb_dev == NULL) /* No device definitions available */ + { + return NULL; + } + + for (i=0;usbdev->udi_usb_dev->altsettings[i].altsetting_labels!=NULL;i++) + if (i==if_num) + { + *default_alt = usbdev->udi_usb_dev->altsettings[i].default_altsetting; + *mask = usbdev->udi_usb_dev->altsettings[i].altsetting_mask; + if (*mask==0) + *mask=0xffffffff; + return usbdev->udi_usb_dev->altsettings[i].altsetting_labels; + } + + return NULL; /* Not found */ +} + +char * +udi_usbdev_get_string (udi_usb_devc * usbdev, int ix) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + static char str[100]; + int err; + + if (ix == 0) + return NULL; + + if ((err = usb_string (devc->usb_dev, ix, str, sizeof (str) - 1)) != 0) + { + return NULL; + } + + return str; +} + +char * +udi_usbdev_get_devpath (udi_usb_devc * usbdev) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + + return devc->devpath; +} + +int +udi_usb_snd_control_msg (udi_usb_devc * usbdev, unsigned int endpoint, + unsigned char rq, + unsigned char rqtype, + unsigned short value, + unsigned short index, + void *buf, int len, int timeout) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + int err; + + if (!devc->enabled) + return -EPIPE; + + if (timeout < 0) + timeout = 0; + +#ifdef IO_DEBUG + printk ("Snd %x (%x) rq=%x, rt=%x, v=%x, ix=%x, l=%d %02x %02x\n", + devc->usb_dev, + usb_sndctrlpipe (devc->usb_dev, endpoint), + rq, rqtype, value, index, len, b[0], b[1]); +#endif + err = usb_control_msg (devc->usb_dev, + usb_sndctrlpipe (devc->usb_dev, endpoint), + rq, rqtype, value, index, buf, len, timeout); +#ifdef IO_DEBUG + if (err < 0) + printk ("Usb write error %d\n", err); +#endif + + return err; +} + +int +udi_usb_rcv_control_msg (udi_usb_devc * usbdev, unsigned int endpoint, + unsigned char rq, + unsigned char rqtype, + unsigned short value, + unsigned short index, + void *buf, int len, int timeout) +{ + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + int err; + + if (!devc->enabled) + return -EPIPE; + + if (timeout < 0) + timeout = 0; + +#ifdef IO_DEBUG + printk ("Rcv %x (%x) rq=%x, rt=%x, v=%x, ix=%x, l=%d\n", + devc->usb_dev, + (unsigned int) usb_rcvctrlpipe (devc->usb_dev, endpoint), + rq, rqtype | USB_DIR_IN, value, index, len); +#endif + err = usb_control_msg (devc->usb_dev, + (unsigned int) usb_rcvctrlpipe (devc->usb_dev, + endpoint), rq, + rqtype | USB_DIR_IN, value, index, buf, len, + timeout); +#ifdef IO_DEBUG + if (err < 0) + printk ("Usb read error %d\n", err); + else + printk ("Got %02x %02x\n", b[0], b[1]); +#endif + + return err; +} + +/* Request stuff */ + +struct udi_usb_request +{ + struct urb *urb; + udi_usb_complete_func_t callback; + void *callback_arg; + int active; + void *data; +}; + +udi_usb_request_t + * udi_usb_alloc_request (udi_usb_devc * usbdev, udi_endpoint_handle_t * eph, + int nframes, int xfer_type) +{ + udi_usb_request_t *rq; + udi_usb_devc *devc = (udi_usb_devc *) usbdev; + + if ((rq = kmalloc (sizeof (*rq), GFP_KERNEL)) == NULL) + { + printk ("udi_usb_alloc_request: Out of memory\n"); + return NULL; + } + + memset (rq, 0, sizeof (*rq)); + + if ((rq->urb = usb_alloc_urb (nframes, 0)) == NULL) + { + kfree (rq); + printk ("udi_usb_alloc_request: Failed to allocate URB\n"); + return NULL; + } + + rq->urb->dev = devc->usb_dev; + rq->urb->number_of_packets = nframes; + rq->active = 0; + + return rq; +} + +void +udi_usb_free_request (udi_usb_request_t * request) +{ + if (request == NULL) + return; + + udi_usb_cancel_request (request); + + usb_free_urb (request->urb); + kfree (request); +} + +unsigned char * +udi_usb_request_actdata (udi_usb_request_t * request) +{ + return request->data; +} + +static void +complete_func (struct urb *urb) +{ + udi_usb_request_t *request = urb->context; + + request->active = 0; + request->callback (request, request->callback_arg); +} + +int +udi_usb_submit_request (udi_usb_request_t * request, + udi_usb_complete_func_t callback, void *callback_arg, + udi_endpoint_handle_t * eph, int xfer_type, + void *data, int data_len) +{ + struct urb *urb; + struct usb_device *d; + int i, err; + int endpoint = eph->desc[2] & 0x7f; + + if (request == NULL) + return -EINVAL; + + urb = request->urb; + d = urb->dev; + request->callback = callback; + request->callback_arg = callback_arg; + request->data = data; + urb->complete = (usb_complete_t) complete_func; + urb->context = request; + urb->transfer_buffer = data; + + for (i = 0; i < urb->number_of_packets; i++) + { + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].length = data_len; + urb->iso_frame_desc[i].offset = i * data_len; + } + + urb->transfer_buffer_length = urb->actual_length = data_len; + + switch (xfer_type) + { + case UDI_USBXFER_ISO_WRITE: + urb->pipe = usb_sndisocpipe (urb->dev, endpoint); + urb->transfer_flags = URB_ISO_ASAP; + urb->interval = 1; + break; + + case UDI_USBXFER_ISO_READ: + urb->pipe = usb_rcvisocpipe (urb->dev, endpoint); + urb->transfer_flags = URB_ISO_ASAP; + urb->interval = 1; + break; + + case UDI_USBXFER_BULK_READ: + usb_fill_bulk_urb (urb, d, usb_rcvbulkpipe (d, endpoint), + data, data_len, + (usb_complete_t) complete_func, request); + break; + + case UDI_USBXFER_INTR_READ: + usb_fill_int_urb (urb, d, usb_rcvintpipe (d, endpoint), + data, data_len, + (usb_complete_t) complete_func, request, 8); + break; + + case UDI_USBXFER_BULK_WRITE: + usb_fill_bulk_urb (urb, d, usb_sndbulkpipe (d, endpoint), + data, data_len, + (usb_complete_t) complete_func, request); + break; + + default: + printk ("udi usb: Bad xfer type %d\n", xfer_type); + return -EINVAL; + } + +#ifdef SLAB_ATOMIC + if ((err = usb_submit_urb (request->urb, SLAB_ATOMIC)) >= 0) + request->active = 1; +#else + /* + * Linux 2.6.20 and later don't have SLAB_ATOMIC + */ + if ((err = usb_submit_urb (request->urb, GFP_ATOMIC)) >= 0) + request->active = 1; +#endif + return err; +} + +int +udi_usb_request_actlen (udi_usb_request_t * request) +{ + return request->urb->actual_length; +} + +void +udi_usb_cancel_request (udi_usb_request_t * request) +{ + if (request == NULL || !request->active) + return; + + usb_kill_urb (request->urb); + +} diff --git a/setup/Linux/oss/cuckoo/Makefile b/setup/Linux/oss/cuckoo/Makefile new file mode 100644 index 0000000..da9013b --- /dev/null +++ b/setup/Linux/oss/cuckoo/Makefile @@ -0,0 +1,23 @@ +ccflags-y += -I/usr/lib/oss + +ifneq ($(KERNELRELEASE),) + + obj-m := cuckoo.o cuckoo_pcm.o cuckoo_mixer.o + +else + + KERNELDIR ?= /lib/modules/$(shell uname -r)/build + PWD := $(shell pwd) + +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules + +endif + +install: default + cp *.ko /lib/modules/`uname -r`/kernel/oss + depmod -a + +clean: + rm -f *.o *.ko *.mod.c *.mod.o .*.cmd core core.* x y z + rm -rf .tmp_versions Modules.symvers diff --git a/setup/Linux/oss/cuckoo/checksum.h b/setup/Linux/oss/cuckoo/checksum.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/setup/Linux/oss/cuckoo/checksum.h diff --git a/setup/Linux/oss/cuckoo/cuckoo.c b/setup/Linux/oss/cuckoo/cuckoo.c new file mode 100644 index 0000000..b7a04a6 --- /dev/null +++ b/setup/Linux/oss/cuckoo/cuckoo.c @@ -0,0 +1,251 @@ +/* + * This software module makes it possible to use Open Sound System for Linux + * (the _professional_ version) as a low level driver source for ALSA. + * + * Copyright (C) 2004-2009 Hannu Savolainen (hannu@opensound.com). + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License. + * + * This 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 + * Lesser General Public License for more details. + */ + +/* + * !!!!!!!!!!!!!!!!!!!! Important !!!!!!!!!!!!!!!!!! + * + * If this file doesn't compile, you must not try to resolve the problem + * without perfect understanding of internals of Linux kernel, ALSA and + * Open Sound System. + * + * Instead you need to check that you are using the version of this file + * that matches the versions of ALSA, OSS and Linux you are currently using. + */ + +#ifndef KBUILD_MODNAME +#define KBUILD_MODNAME cuckoo +#endif + +#include "cuckoo.h" + +#include "./checksum.h" + +#ifdef VERMAGIC_STRING +static const char vermagic[] = VERMAGIC_STRING; +#endif + +MODULE_AUTHOR ("Hannu Savolainen <hannu@opensound.com>"); +MODULE_LICENSE ("GPL v2"); +//MODULE_CLASSES("{sound}"); +MODULE_DESCRIPTION ("OSS low level driver interface for ALSA"); + +#define CUCKOO_MAXCARD SNDRV_CARDS +static int index[CUCKOO_MAXCARD] = SNDRV_DEFAULT_IDX; +static char *id[CUCKOO_MAXCARD] = SNDRV_DEFAULT_STR; +static int enable[CUCKOO_MAXCARD] = SNDRV_DEFAULT_ENABLE_PNP; + +static int +snd_cuckoo_free (cuckoo_t * chip) +{ + // TODO + return 0; +} + +static int +snd_cuckoo_dev_free (snd_device_t * device) +{ + cuckoo_t *cuckoo = (cuckoo_t *) device->device_data; + return snd_cuckoo_free (cuckoo); +} + +static int +snd_cuckoo_create (snd_card_t * card, int osscard, cuckoo_t ** rchip) +{ + cuckoo_t *chip; + int err; + + static snd_device_ops_t ops = { + .dev_free = snd_cuckoo_dev_free + }; + + *rchip = NULL; + + if ((chip = (cuckoo_t *) kmalloc (sizeof (cuckoo_t), GFP_KERNEL)) == NULL) + return -ENOMEM; + + chip->card = card; + chip->osscard = osscard; + chip->ncapture = chip->nplay = chip->npcm = 0; + + if ((err = snd_device_new (card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) + { + snd_cuckoo_free (chip); + return err; + } + + *rchip = chip; + return 0; +} + +static snd_card_t *cards[SNDRV_CARDS]; +static int ncards = 0; + +int +init_module (void) +{ + int err; + int dev, cardno; + char tmp[100]; + int pass; + +#if 0 + // TODO + if ((err = udi_connect (WRAPPER_VERSION)) < 0) + return err; + + if (strcmp (oss_checksum, cuckoo_checksum) != 0) + { + printk + ("cuckoo: Error OSS incompatibility problem. Please recompile.\n"); + return -EIO; + } +#endif + + for (pass = 0; pass < 2; pass++) + { + cardno = -1; + + for (dev = 0; dev < num_audio_engines; dev++) + { + adev_p adev = audio_engines[dev]; + cuckoo_t *chip; + snd_card_t *card = NULL; + + if (pass == 0) + { + // Ignore non-virtual devices + if (!(adev->flags & ADEV_VIRTUAL)) + continue; + } + else + { + // Ignore virtual devices + if ((adev->flags & ADEV_VIRTUAL)) + continue; + } + + if (adev->card_number < 0) + { + printk ("cuckoo: Ignored audio device %d - %s\n", dev, + adev->name); + continue; + } + + if (adev->card_number != cardno) + { + oss_card_info cd; + + cardno = adev->card_number; + + if (oss_get_cardinfo (cardno, &cd) < 0) + { + printk ("oss_get_cardinfo(%d) failed\n", cardno); + continue; + } + + // printk("Card %d: %s/%s\n", cardno, cd.shortname, cd.longname); + printk ("Card %d: %s/%s\n", cardno, cd.shortname, cd.longname); + + if (ncards >= CUCKOO_MAXCARD) + { + printk + ("Cuckoo: Too many audio devices (%d), only %d supported. by ALSA.\n", + num_audio_engines, CUCKOO_MAXCARD); + return -EIO; + } + + if (!enable[ncards]) + { + printk ("cuckoo: Device was not enabled (yet)\n"); + return -EIO; + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31) + if ((card = + snd_card_new (index[ncards], id[ncards], THIS_MODULE, + 0)) == NULL) +#else + if ( + snd_card_create (index[ncards], id[ncards], THIS_MODULE, + 0, &card) != 0) +#endif + { + printk ("cuckoo: Can't create a card instance\n"); + return -EIO; + } + + if ((err = snd_cuckoo_create (card, cardno, &chip)) < 0) + { + printk ("cuckoo: Couldn't create a chip instance (%d)\n", + err); + snd_card_free (card); + return err; + } + +#define oss_version_string "v4.x" // TODO + sprintf (tmp, "OSS %s", oss_version_string); + strlcpy (card->driver, tmp); + strlcpy (card->shortname, cd.shortname); + strlcpy (card->longname, cd.longname); + + if ((err = install_pcm_instances (chip, cardno)) < 0) + return err; + + if ((err = install_mixer_instances (chip, cardno)) < 0) + return err; + + // if ((err=install_midiport_instances(chip, cardno))<0) + // return err; + + if ((err = snd_card_register (card)) < 0) + { + printk ("cuckoo: Couldn't register card(%s) err=%d\n", + card->shortname, err); + continue; // TODO: Should handle this in more intelligent way + + snd_card_free (card); + return err; + } + + cards[ncards++] = card; + } + } + } + + return 0; +} + +void +cleanup_module (void) +{ + int i; + + for (i = 0; i < ncards; i++) + snd_card_free (cards[i]); +} + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,5)) +#undef unix +struct module __this_module + __attribute__ ((section (".gnu.linkonce.this_module"))) = +{ + .name = __stringify (KBUILD_MODNAME),.init = init_module, +#ifdef CONFIG_MODULE_UNLOAD + .exit = cleanup_module +#endif +}; +#endif diff --git a/setup/Linux/oss/cuckoo/cuckoo.h b/setup/Linux/oss/cuckoo/cuckoo.h new file mode 100644 index 0000000..3df2966 --- /dev/null +++ b/setup/Linux/oss/cuckoo/cuckoo.h @@ -0,0 +1,171 @@ +/* + * This software module makes it possible to use Open Ssund System for Linux + * (the _professional_ version) as a low level driver source for ALSA. + * + * Copyright (C) 2004-2006 Hannu Savolainen (hannu@voimakentta.net). + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License. + * + * This 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 + * Lesser General Public License for more details. + */ + +#define _KERNEL + +/* + * !!!!!!!!!!!!!!!!!!!! Important !!!!!!!!!!!!!!!!!! + * + * If this file doesn't compile, you must not try to resolve the problem + * without perfect understanding of internals of Linux kernel, ALSA and + * Open Sound System. + * + * Instead you need to check that you are using the version of this file + * that matches the versions of ALSA, OSS and Linux you are currently using. + */ + +#define _KERNEL +#include "../include/sys/soundcard.h" + +#include <linux/version.h> + +#define _LOOSE_KERNEL_NAMES + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,18) +#include <linux/config.h> +#else +#include <linux/autoconf.h> +#endif + +#if !defined(__SMP__) && defined(CONFIG_SMP) +#define __SMP__ +#endif +#include <linux/module.h> + +#include <stdarg.h> + +extern int oss_get_cardinfo (int cardnum, oss_card_info * ci); /* from oss_config.h */ + +#include <linux/param.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/signal.h> +#include <linux/fcntl.h> +#include <linux/sched.h> +#include <linux/timer.h> +#include <linux/tty.h> +#include <linux/mm.h> +#include <linux/ctype.h> +#include <linux/delay.h> +#include <linux/vmalloc.h> +#include <asm/processor.h> +#include <asm/io.h> +#include <linux/pci.h> +#include <linux/apm_bios.h> +#include <asm/segment.h> +#include <asm/uaccess.h> +#include <linux/poll.h> + +#include <asm/system.h> +#include <asm/dma.h> +#include <linux/wait.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/ioport.h> +//#include <asm/mach-default/irq_vectors.h> +#include <linux/interrupt.h> +#include <linux/pm.h> + +struct _oss_mutex_t +{ + /* Caution! This definition must match Linux/osscore.c */ + spinlock_t lock; +}; + +#define audio_devs dummy_audio_devs + +#include "../include/internals/oss_exports.h" +#include "../build/wrap.h" +#include "../include/internals/ossddk.h" + +typedef struct oss_wait_queue oss_wait_queue_t; /* This must match oss_config.h */ + +#include "../include/internals/ossddk.h" + +//#include <sound/driver.h> +#include <sound/core.h> +#include <sound/control.h> +#include <sound/pcm.h> + +#include "../build/osscore_symbols.inc" + +#define SNDRV_GET_ID +#include <sound/initval.h> + +typedef caddr_t ioctl_arg; +typedef char snd_rw_buf; + +typedef int sound_os_info; + +#define WR_BUF_CONST const + +#include "../include/internals/audio_core.h" +#include "../include/internals/mixer_core.h" + +typedef struct _snd_cuckoo cuckoo_t, chip_t; + +typedef struct +{ + adev_p adev; +} cuckoo_pcm_t; + +#define MAX_OSSPCM 24 // Max # of PCM devices/card instance + +#if 1 +// Older ALSA versions used to define these... +typedef struct snd_card snd_card_t; +typedef struct snd_pcm snd_pcm_t; +typedef struct snd_rawmidi snd_rawmidi_t; +typedef struct snd_rawmidi_substream snd_rawmidi_substream_t; +typedef struct snd_rawmidi_ops snd_rawmidi_ops_t; +typedef struct snd_kcontrol snd_kcontrol_t; +typedef struct snd_kcontrol_new snd_kcontrol_new_t; +typedef struct snd_ctl_elem_info snd_ctl_elem_info_t; +typedef struct snd_ctl_elem_value snd_ctl_elem_value_t; +typedef struct snd_pcm_substream snd_pcm_substream_t; +typedef struct snd_pcm_hardware snd_pcm_hardware_t; +typedef struct snd_pcm_runtime snd_pcm_runtime_t; +typedef struct snd_pcm_hw_params snd_pcm_hw_params_t; +typedef struct snd_pcm_ops snd_pcm_ops_t; +typedef struct snd_device snd_device_t; +typedef struct snd_device_ops snd_device_ops_t; +#endif + +struct _snd_cuckoo +{ + snd_card_t *card; + snd_pcm_t *pcm[MAX_OSSPCM]; + adev_p play_adev[MAX_OSSPCM], capture_adev[MAX_OSSPCM]; + int osscard; + int nplay, ncapture, npcm; +}; + +#define cuckoo_t_magic 0xaabbccdd +#define chip__tmagic cuckoo_t_magic + +//#define OPEN_READ PCM_ENABLE_INPUT +//#define OPEN_WRITE PCM_ENABLE_OUTPUT + +extern int install_mixer_instances (cuckoo_t * chip, int cardno); +extern int install_midiport_instances (cuckoo_t * chip, int cardno); +extern int install_pcm_instances (cuckoo_t * chip, int cardno); + +// Disable locking for now +#define udi_spin_lock_irqsave(a, b) *(b)=0 +#define udi_spin_unlock_irqrestore(a, b) + +#define strlcpy(a, b) {strncpy(a, b, sizeof(a)-1);a[sizeof(a)-1]=0;} diff --git a/setup/Linux/oss/cuckoo/cuckoo_midi.c b/setup/Linux/oss/cuckoo/cuckoo_midi.c new file mode 100644 index 0000000..949379b --- /dev/null +++ b/setup/Linux/oss/cuckoo/cuckoo_midi.c @@ -0,0 +1,310 @@ +/* + * This software module makes it possible to use Open Sound System for Linux + * (the _professional_ version) as a low level driver source for ALSA. + * + * Copyright (C) 2004 Hannu Savolainen (hannu@voimakentta.net). + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License. + * + * This 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 + * Lesser General Public License for more details. + */ + +/* + * !!!!!!!!!!!!!!!!!!!! Important !!!!!!!!!!!!!!!!!! + * + * If this file doesn't compile, you must not try to resolve the problem + * without perfect understanding of internals of Linux kernel, ALSA and + * Open Sound System. + * + * Instead you need to check that you are using the version of this file + * that matches the versions of ALSA, OSS and Linux you are currently using. + */ + +#include "cuckoo.h" +#include <sound/rawmidi.h> +#include <midi_core.h> + +static snd_rawmidi_t *rmidis[256] = { NULL }; + +static int +cuckoo_uart_input_open (snd_rawmidi_substream_t * substream) +{ +#if 0 + mpu401_t *mpu; + int err; + + mpu = + snd_magic_cast (mpu401_t, substream->rmidi->private_data, return -ENXIO); + if (mpu->open_input && (err = mpu->open_input (mpu)) < 0) + return err; + if (!test_bit (MPU401_MODE_BIT_OUTPUT, &mpu->mode)) + { + cuckoo_uart_cmd (mpu, MPU401_RESET, 1); + cuckoo_uart_cmd (mpu, MPU401_ENTER_UART, 1); + } + mpu->substream_input = substream; + atomic_set (&mpu->rx_loop, 1); + set_bit (MPU401_MODE_BIT_INPUT, &mpu->mode); +#endif + return 0; +} + +static int +cuckoo_uart_output_open (snd_rawmidi_substream_t * substream) +{ + int dev; + + dev = (int) substream->rmidi->private_data; + + printk ("Output open %d\n", dev); + + return -EIO; +#if 0 + mpu401_t *mpu; + int err; + if (mpu->open_output && (err = mpu->open_output (mpu)) < 0) + return err; + if (!test_bit (MPU401_MODE_BIT_INPUT, &mpu->mode)) + { + cuckoo_uart_cmd (mpu, MPU401_RESET, 1); + cuckoo_uart_cmd (mpu, MPU401_ENTER_UART, 1); + } + mpu->substream_output = substream; + atomic_set (&mpu->tx_loop, 1); + set_bit (MPU401_MODE_BIT_OUTPUT, &mpu->mode); +#endif + return 0; +} + +static int +cuckoo_uart_input_close (snd_rawmidi_substream_t * substream) +{ +#if 0 + mpu401_t *mpu; + + mpu = + snd_magic_cast (mpu401_t, substream->rmidi->private_data, return -ENXIO); + clear_bit (MPU401_MODE_BIT_INPUT, &mpu->mode); + mpu->substream_input = NULL; + if (!test_bit (MPU401_MODE_BIT_OUTPUT, &mpu->mode)) + cuckoo_uart_cmd (mpu, MPU401_RESET, 0); + if (mpu->close_input) + mpu->close_input (mpu); +#endif + return 0; +} + +static int +cuckoo_uart_output_close (snd_rawmidi_substream_t * substream) +{ +#if 0 + mpu401_t *mpu; + + mpu = + snd_magic_cast (mpu401_t, substream->rmidi->private_data, return -ENXIO); + clear_bit (MPU401_MODE_BIT_OUTPUT, &mpu->mode); + mpu->substream_output = NULL; + if (!test_bit (MPU401_MODE_BIT_INPUT, &mpu->mode)) + cuckoo_uart_cmd (mpu, MPU401_RESET, 0); + if (mpu->close_output) + mpu->close_output (mpu); +#endif + return 0; +} + +static void +cuckoo_uart_input_trigger (snd_rawmidi_substream_t * substream, int up) +{ +#if 0 + unsigned long flags; + mpu401_t *mpu; + int max = 64; + + mpu = snd_magic_cast (mpu401_t, substream->rmidi->private_data, return); + if (up) + { + if (!test_and_set_bit (MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) + { + /* first time - flush FIFO */ + while (max-- > 0) + mpu->read (mpu, MPU401D (mpu)); + if (mpu->irq < 0) + cuckoo_uart_add_timer (mpu, 1); + } + + /* read data in advance */ + /* prevent double enter via rawmidi->event callback */ + if (atomic_dec_and_test (&mpu->rx_loop)) + { + local_irq_save (flags); + if (spin_trylock (&mpu->input_lock)) + { + cuckoo_uart_input_read (mpu); + spin_unlock (&mpu->input_lock); + } + local_irq_restore (flags); + } + atomic_inc (&mpu->rx_loop); + } + else + { + if (mpu->irq < 0) + cuckoo_uart_remove_timer (mpu, 1); + clear_bit (MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode); + } +#endif +} + +#if 0 +static void +cuckoo_uart_input_read (void *mpu) +{ + int max = 128; + unsigned char byte; + + while (max-- > 0) + { + if (cuckoo_input_avail (mpu)) + { + byte = mpu->read (mpu, MPU401D (mpu)); + if (test_bit (MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) + snd_rawmidi_receive (mpu->substream_input, &byte, 1); + } + else + { + break; /* input not available */ + } + } +} +#endif + +#if 0 +static void +cuckoo_uart_output_write (void *mpu) +{ + unsigned char byte; + int max = 256, timeout; + + do + { + if (snd_rawmidi_transmit_peek (mpu->substream_output, &byte, 1) == 1) + { + for (timeout = 100; timeout > 0; timeout--) + { + if (cuckoo_output_ready (mpu)) + { + mpu->write (mpu, byte, MPU401D (mpu)); + snd_rawmidi_transmit_ack (mpu->substream_output, 1); + break; + } + } + if (timeout == 0) + break; /* Tx FIFO full - try again later */ + } + else + { + cuckoo_uart_remove_timer (mpu, 0); + break; /* no other data - leave the tx loop */ + } + } + while (--max > 0); +} +#endif + +static void +cuckoo_uart_output_trigger (snd_rawmidi_substream_t * substream, int up) +{ + int dev; + + dev = (int) substream->rmidi->private_data; + printk ("Output trigger %d\n", dev); +#if 0 + if (up) + { + set_bit (MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode); + + /* try to add the timer at each output trigger, + * since the output timer might have been removed in + * cuckoo_uart_output_write(). + */ + cuckoo_uart_add_timer (mpu, 0); + + /* output pending data */ + /* prevent double enter via rawmidi->event callback */ + if (atomic_dec_and_test (&mpu->tx_loop)) + { + local_irq_save (flags); + if (spin_trylock (&mpu->output_lock)) + { + cuckoo_uart_output_write (mpu); + spin_unlock (&mpu->output_lock); + } + local_irq_restore (flags); + } + atomic_inc (&mpu->tx_loop); + } + else + { + cuckoo_uart_remove_timer (mpu, 0); + clear_bit (MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode); + } +#endif +} + +static snd_rawmidi_ops_t cuckoo_uart_output = { + .open = cuckoo_uart_output_open, + .close = cuckoo_uart_output_close, + .trigger = cuckoo_uart_output_trigger, +}; + +static snd_rawmidi_ops_t cuckoo_uart_input = { + .open = cuckoo_uart_input_open, + .close = cuckoo_uart_input_close, + .trigger = cuckoo_uart_input_trigger, +}; + +extern mididev_p *midi_devs; + +int +install_midiport_instances (cuckoo_t * chip, int cardno) +{ + int dev, devix = 0; + + for (dev = 0; dev < num_mididevs; dev++) + if (midi_devs[dev]->card_number == cardno) + { + mididev_p mididev = midi_devs[dev]; + snd_rawmidi_t *rmidi; + int err; + +//printk("Midi device %s\n", mididev->info.name); + + if ((err = snd_rawmidi_new (chip->card, mididev->name, devix, + 1, 1, &rmidi)) < 0) + { + printk ("cuckoo: Failed to register rawmidi device, err=%d\n", + err); + return 0; + } + + rmidi->private_data = (void *) dev; + strcpy (rmidi->name, mididev->name); + rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | + SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; + snd_rawmidi_set_ops (rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, + &cuckoo_uart_output); + snd_rawmidi_set_ops (rmidi, SNDRV_RAWMIDI_STREAM_INPUT, + &cuckoo_uart_input); + + devix++; + rmidis[dev] = rmidi; + } // dev + + return 0; +} diff --git a/setup/Linux/oss/cuckoo/cuckoo_mixer.c b/setup/Linux/oss/cuckoo/cuckoo_mixer.c new file mode 100644 index 0000000..6d2bb6d --- /dev/null +++ b/setup/Linux/oss/cuckoo/cuckoo_mixer.c @@ -0,0 +1,389 @@ +/* + * This software module makes it possible to use Open Sound System for Linux + * (the _professional_ version) as a low level driver source for ALSA. + * + * Copyright (C) 2004 Hannu Savolainen (hannu@voimakentta.net). + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License. + * + * This 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 + * Lesser General Public License for more details. + */ + +/* + * !!!!!!!!!!!!!!!!!!!! Important !!!!!!!!!!!!!!!!!! + * + * If this file doesn't compile, you must not try to resolve the problem + * without perfect understanding of internals of Linux kernel, ALSA and + * Open Sound System. + * + * Instead you need to check that you are using the version of this file + * that matches the versions of ALSA, OSS and Linux you are currently using. + */ + +#include "cuckoo.h" + +MODULE_AUTHOR ("Hannu Savolainen <hannu@opensound.com>"); +MODULE_LICENSE ("GPL v2"); +MODULE_DESCRIPTION ("OSS mixer low level driver interface for ALSA"); + +typedef struct +{ + char *name, *data; +} enum_entry_t; + +#if 0 +static void +downshift (char *s) +{ + while (*s) + { + if (*s >= 'A' && *s <= 'Z') + *s += 32; + s++; + } +} +#endif + +static int +get_mixer_info (snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo) +{ + oss_mixext ext; + int dev, ix; + + dev = ext.dev = kcontrol->private_value >> 16; + ix = ext.ctrl = kcontrol->private_value & 0xffff;; + + oss_mixer_ext (dev, OSS_DEV_MIXER, SNDCTL_MIX_EXTINFO, (caddr_t) & ext); + + switch (ext.type) + { + case MIXT_STEREOSLIDER: + case MIXT_STEREOVU: + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = ext.minvalue; + uinfo->value.integer.max = ext.maxvalue; + break; + + case MIXT_MONOSLIDER: + case MIXT_MONOVU: + case MIXT_SLIDER: + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = ext.minvalue; + uinfo->value.integer.max = ext.maxvalue; + break; + + case MIXT_ONOFF: + case MIXT_MUTE: + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + break; + + case MIXT_ENUM: + { + static const char *texts[] = { + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", + "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", + "30", "31", "32" + }; + oss_mixer_enuminfo enumdef; + uinfo->value.enumerated.items = ext.maxvalue; + + if (uinfo->value.enumerated.item < 0) + uinfo->value.enumerated.item = 0; + if (uinfo->value.enumerated.item >= ext.maxvalue) + uinfo->value.enumerated.item = ext.maxvalue - 1; + if (uinfo->value.enumerated.item > 31) + uinfo->value.enumerated.item = 31; + strcpy (uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + + enumdef.dev = ext.dev; + enumdef.ctrl = ext.ctrl; + if (oss_mixer_ext + (dev, OSS_DEV_MIXER, SNDCTL_MIX_ENUMINFO, + (caddr_t) & enumdef) >= 0) + { + char *text; + + text = + &enumdef.strings[enumdef. + strindex[uinfo->value.enumerated.item]]; + strcpy (uinfo->value.enumerated.name, text); + } + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = ext.maxvalue; + } + break; + + default: + printk ("cuckoo: mixer_info(%d/%d) - unknown type %d\n", dev, ix, + ext.type); + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = ext.minvalue; + uinfo->value.integer.max = ext.maxvalue; + return 0; + } + + return 0; +} + +static int +mixer_get (snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + oss_mixext ext; + oss_mixer_value val; + int dev, ix, err; + + dev = ext.dev = kcontrol->private_value >> 16; + ix = ext.ctrl = kcontrol->private_value & 0xffff;; + if ((err = + oss_mixer_ext (dev, OSS_DEV_MIXER, SNDCTL_MIX_EXTINFO, + (caddr_t) & ext)) < 0) + return err; + + val.dev = dev; + val.ctrl = ix; + val.timestamp = ext.timestamp; + if ((err = + oss_mixer_ext (dev, OSS_DEV_MIXER, SNDCTL_MIX_READ, + (caddr_t) & val)) < 0) + return err; + + switch (ext.type) + { + case MIXT_STEREOVU: + case MIXT_STEREOSLIDER: + ucontrol->value.integer.value[0] = val.value & 0xff; // Left + ucontrol->value.integer.value[1] = (val.value >> 8) & 0xff; // Right + break; + + case MIXT_MONOSLIDER: + case MIXT_MONOVU: + case MIXT_SLIDER: + ucontrol->value.integer.value[0] = val.value & 0xff; + break; + + case MIXT_ONOFF: + case MIXT_MUTE: + ucontrol->value.integer.value[0] = !!val.value; + break; + + case MIXT_ENUM: + ucontrol->value.integer.value[0] = val.value; + break; + + default: + printk ("cuckoo: mixer_get(%d/%d) - unknown type %d\n", dev, ix, + ext.type); + ucontrol->value.integer.value[0] = val.value & 0xff; + return 0; + } + + return 0; +} + +static int +mixer_put (snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + oss_mixext ext; + oss_mixer_value val; + int dev, ix, err; + + dev = ext.dev = kcontrol->private_value >> 16; + ix = ext.ctrl = kcontrol->private_value & 0xffff;; + if ((err = + oss_mixer_ext (dev, OSS_DEV_MIXER, SNDCTL_MIX_EXTINFO, + (caddr_t) & ext)) < 0) + return err; + + val.dev = dev; + val.ctrl = ix; + val.timestamp = ext.timestamp; + + switch (ext.type) + { + case MIXT_STEREOSLIDER: + val.value = ucontrol->value.integer.value[0] | // Left + ucontrol->value.integer.value[1] << 8; // Right + if ((err = + oss_mixer_ext (dev, OSS_DEV_MIXER, SNDCTL_MIX_WRITE, + (caddr_t) & val)) < 0) + return err; + break; + + case MIXT_MONOSLIDER: + case MIXT_SLIDER: + val.value = ucontrol->value.integer.value[0]; + if ((err = + oss_mixer_ext (dev, OSS_DEV_MIXER, SNDCTL_MIX_WRITE, + (caddr_t) & val)) < 0) + return err; + break; + + case MIXT_ONOFF: + case MIXT_MUTE: + val.value = !!ucontrol->value.integer.value[0]; + if ((err = + oss_mixer_ext (dev, OSS_DEV_MIXER, SNDCTL_MIX_WRITE, + (caddr_t) & val)) < 0) + return err; + break; + + case MIXT_ENUM: + val.value = ucontrol->value.integer.value[0]; + if ((err = + oss_mixer_ext (dev, OSS_DEV_MIXER, SNDCTL_MIX_WRITE, + (caddr_t) & val)) < 0) + return err; + break; + + case MIXT_MONOVU: + case MIXT_STEREOVU: + return -EPERM; + + default: + printk ("cuckoo: mixer_put(%d/%d) - unknown type %d\n", dev, ix, + ext.type); + val.value = ucontrol->value.integer.value[0]; + if ((err = + oss_mixer_ext (dev, OSS_DEV_MIXER, SNDCTL_MIX_WRITE, + (caddr_t) & val)) < 0) + return err; + } + + return 0; +} + +static void +add_control (cuckoo_t * chip, int dev, int ix, oss_mixext * ext, char *name) +{ + int i, ok, err = 0; + snd_kcontrol_new_t my_control; + +// Upshift the name if it's an single part one + + ok = 0; + for (i = 0; i < strlen (name); i++) + if (name[i] == '.') + ok = 1; + if (!ok) + for (i = 0; i < strlen (name); i++) + if (name[i] >= 'a' && name[i] <= 'z') + name[i] -= 32; + +// Add the control + + memset (&my_control, 0, sizeof (my_control)); + + my_control.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + my_control.name = name; + my_control.index = 0; + my_control.access = 0; + + if (ext->flags & MIXF_READABLE) + my_control.access |= SNDRV_CTL_ELEM_ACCESS_READ; + if (ext->flags & MIXF_WRITEABLE) + my_control.access |= SNDRV_CTL_ELEM_ACCESS_WRITE; + if ((ext->flags & 0x3) == MIXF_READABLE) /* Read only */ + my_control.access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE; + + my_control.private_value = (dev << 16) | ix; + my_control.info = get_mixer_info; + my_control.get = mixer_get; + my_control.put = mixer_put; + + switch (ext->type) + { + case MIXT_ENUM: + case MIXT_ONOFF: + case MIXT_MUTE: + case MIXT_STEREOSLIDER: + case MIXT_SLIDER: + case MIXT_MONOSLIDER: + case MIXT_MONOVU: + case MIXT_STEREOVU: + if ((err = + snd_ctl_add (chip->card, snd_ctl_new1 (&my_control, chip))) < 0) + { + printk ("cuckoo: snd_ctl_add(%s) failed, err=%d\n", ext->extname, + err); + return; + } + break; + } +} + +int +install_mixer_instances (cuckoo_t * chip, int cardno) +{ + int dev; + mixer_operations_t **cuckoo_mixer_devs = mixer_devs_p; + + for (dev = 0; dev < num_mixers; dev++) + if (cuckoo_mixer_devs[dev]->card_number == cardno) + { + int nrext, i, sz; + + touch_mixer (dev); + + nrext = dev; + oss_mixer_ext (dev, OSS_DEV_MIXER, SNDCTL_MIX_NREXT, + (ioctl_arg) & nrext); + + if (nrext == 0) + continue; + + sz = nrext * (sizeof (char *) + 32); // 32 characters / name (average) + + for (i = 0; i < nrext; i++) + { + oss_mixext ext; + int parent = 0; + oss_mixext_root *root = NULL; + + ext.dev = dev; + ext.ctrl = i; + oss_mixer_ext (dev, OSS_DEV_MIXER, SNDCTL_MIX_EXTINFO, + (caddr_t) & ext); + + switch (ext.type) + { + case MIXT_DEVROOT: + root = (oss_mixext_root *) & ext.data; + break; + + case MIXT_GROUP: + parent = ext.parent; + break; + + case MIXT_MARKER: + break; + + default: + add_control (chip, dev, i, &ext, ext.extname); + break; + } // Switch + + } // i + + + } // dev + + return 0; +} + +EXPORT_SYMBOL (install_mixer_instances); diff --git a/setup/Linux/oss/cuckoo/cuckoo_pcm.c b/setup/Linux/oss/cuckoo/cuckoo_pcm.c new file mode 100644 index 0000000..2ae08b5 --- /dev/null +++ b/setup/Linux/oss/cuckoo/cuckoo_pcm.c @@ -0,0 +1,810 @@ +/* + * This software module makes it possible to use Open Sound System for Linux + * (the _professional_ version) as a low level driver source for ALSA. + * + * Copyright (C) 2004 Hannu Savolainen (hannu@voimakentta.net). + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License. + * + * This 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 + * Lesser General Public License for more details. + */ + +/* + * !!!!!!!!!!!!!!!!!!!! Important !!!!!!!!!!!!!!!!!! + * + * If this file doesn't compile, you must not try to resolve the problem + * without perfect understanding of internals of Linux kernel, ALSA and + * Open Sound System. + * + * Instead you need to check that you are using the version of this file + * that matches the versions of ALSA, OSS and Linux you are currently using. + */ + +#include "cuckoo.h" + +MODULE_AUTHOR ("Hannu Savolainen <hannu@opensound.com>"); +MODULE_LICENSE ("GPL v2"); +MODULE_DESCRIPTION ("OSS PCM low level driver interface for ALSA"); + +static snd_pcm_substream_t *cuckoo_playsubstream[256] = { NULL }; +static snd_pcm_substream_t *cuckoo_capturesubstream[256] = { NULL }; + +static snd_pcm_hardware_t snd_cuckoo_playback = { + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START), + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, + .rate_min = 4000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = (64 * 1024), + .period_bytes_min = 64, + .period_bytes_max = (32 * 1024), + .periods_min = 2, + .periods_max = 1024, + .fifo_size = 0, +}; + +static snd_pcm_hardware_t snd_cuckoo_capture = { + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START), + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, + .rate_min = 4000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = (128 * 1024), + .period_bytes_min = 64, + .period_bytes_max = (64 * 1024), + .periods_min = 2, + .periods_max = 1024, + .fifo_size = 0, +}; + +static void +cuckoo_outputintr (int dev, int notify_only) +{ + snd_pcm_substream_t *substream; + adev_t *adev; + dmap_t *dmap; + oss_native_word flags; + + if (dev < 0 || dev > 255) + return; + + adev = audio_devfiles[dev]; + dmap = adev->dmap_out; + + dmap->fragment_counter = (dmap->fragment_counter + 1) % dmap->nfrags; + + substream = cuckoo_playsubstream[dev]; + if (substream == NULL) + return; + + udi_spin_lock_irqsave (&adev->mutex, &flags); + snd_pcm_period_elapsed (substream); + udi_spin_unlock_irqrestore (&adev->mutex, flags); +} + +static void +cuckoo_inputintr (int dev, int intr_flags) +{ + snd_pcm_substream_t *substream; + adev_t *adev; + dmap_t *dmap; + oss_native_word flags; + + if (dev < 0 || dev > 255) + return; + + adev = audio_devfiles[dev]; + dmap = adev->dmap_in; + + dmap->fragment_counter = (dmap->fragment_counter + 1) % dmap->nfrags; + + substream = cuckoo_capturesubstream[dev]; + if (substream == NULL) + return; + + udi_spin_lock_irqsave (&adev->mutex, &flags); + snd_pcm_period_elapsed (substream); + udi_spin_unlock_irqrestore (&adev->mutex, flags); +} + +static void +copy_hw_caps (snd_pcm_runtime_t * runtime, adev_t * adev, int dir) +{ + u64 fmts = 0; + int i; + unsigned int fmtmask; + + if (dir == OPEN_WRITE) + { + fmtmask = adev->oformat_mask; + } + else + { + fmtmask = adev->iformat_mask; + } + + for (i = 0; i < 32; i++) + switch (fmtmask & (1 << i)) + { + case AFMT_MU_LAW: + fmts |= SNDRV_PCM_FMTBIT_MU_LAW; + break; + case AFMT_A_LAW: + fmts |= SNDRV_PCM_FMTBIT_A_LAW; + break; + case AFMT_IMA_ADPCM: + fmts |= SNDRV_PCM_FMTBIT_IMA_ADPCM; + break; + case AFMT_U8: + fmts |= SNDRV_PCM_FMTBIT_U8; + break; + case AFMT_S8: + fmts |= SNDRV_PCM_FMTBIT_S8; + break; + case AFMT_S16_LE: + fmts |= SNDRV_PCM_FMTBIT_S16_LE; + break; + case AFMT_S16_BE: + fmts |= SNDRV_PCM_FMTBIT_S16_BE; + break; + case AFMT_S24_LE: + fmts |= SNDRV_PCM_FMTBIT_S24_LE; + break; + case AFMT_S24_BE: + fmts |= SNDRV_PCM_FMTBIT_S24_BE; + break; + case AFMT_S32_LE: + fmts |= SNDRV_PCM_FMTBIT_S32_LE; + break; + case AFMT_S32_BE: + fmts |= SNDRV_PCM_FMTBIT_S32_BE; + break; + case AFMT_MPEG: + fmts |= SNDRV_PCM_FMTBIT_MPEG; + break; + case AFMT_FLOAT: + fmts |= SNDRV_PCM_FMTBIT_FLOAT_LE; + break; + case AFMT_SPDIF_RAW: + fmts |= SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE; + break; + } + + runtime->hw.formats = fmts; + + if (adev->min_block > 0) + runtime->hw.period_bytes_min = adev->min_block; + if (adev->max_block > 0) + runtime->hw.period_bytes_max = adev->max_block; + + if (adev->flags & ADEV_NOMMAP) + runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID); + + if (adev->max_rate > adev->min_rate) + { + runtime->hw.rate_min = adev->min_rate; + runtime->hw.rate_max = adev->max_rate; + } + + if (!(adev->caps & DSP_CAP_FREERATE)) + runtime->hw.rates &= + ~(SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000); +} + +static int +snd_cuckoo_playback_open (snd_pcm_substream_t * substream) +{ + cuckoo_t *chip = snd_pcm_substream_chip (substream); + snd_pcm_runtime_t *runtime = substream->runtime; + int snum = substream->number; + int err; + adev_t *adev; + oss_native_word flags; + struct fileinfo tmp_finfo; + + if (snum < 0 || snum >= chip->npcm) + { + printk ("cuckoo: Playback open - bad substream index %d\n", snum); + return -EIO; + } + + adev = chip->play_adev[snum]; + printk ("cuckoo_playback_open(%d=%s)\n", adev->engine_num, adev->name); + + cuckoo_playsubstream[adev->engine_num] = substream; + + if (adev->dmap_out == NULL || adev->dmap_out->dmabuf == NULL) + { + printk ("cuckoo: dev %d - no buffer available\n", adev->engine_num); + return -ENOMEM; + } + + if (adev->open_mode != 0) + { + udi_spin_unlock_irqrestore (&adev->mutex, flags); + return -EBUSY; + } + + tmp_finfo.mode = OPEN_WRITE; + tmp_finfo.acc_flags = 0; + if ((err = + oss_audio_open_engine (adev->engine_num, OSS_DEV_DSP, + &tmp_finfo, 1, OF_SMALLBUF, + NULL)) < 0) + { + return err; + } + + udi_spin_lock_irqsave (&adev->mutex, &flags); + adev->open_mode = OPEN_WRITE; + runtime->hw = snd_cuckoo_playback; + copy_hw_caps (runtime, adev, OPEN_WRITE); + snd_pcm_set_sync (substream); + adev->pid = current->pid; + strncpy (adev->cmd, current->comm, sizeof (adev->cmd) - 1); + adev->cmd[sizeof (adev->cmd) - 1] = 0; + adev->outputintr = cuckoo_outputintr; + udi_spin_unlock_irqrestore (&adev->mutex, flags); + + return 0; +} + +static int +snd_cuckoo_capture_open (snd_pcm_substream_t * substream) +{ + cuckoo_t *chip = snd_pcm_substream_chip (substream); + snd_pcm_runtime_t *runtime = substream->runtime; + int snum = substream->number; + int err; + adev_t *adev; + oss_native_word flags; + struct fileinfo tmp_finfo; + + if (snum < 0 || snum >= chip->npcm) + { + printk ("cuckoo: Capture open - bad substream index %d\n", snum); + return -EIO; + } + + adev = chip->capture_adev[snum]; + + cuckoo_capturesubstream[adev->engine_num] = substream; + + if (adev->dmap_in == NULL || adev->dmap_in->dmabuf == NULL) + { + printk ("cuckoo: dev %d - no buffer available\n", adev->engine_num); + return -ENOMEM; + } + + if (adev->open_mode != 0) + { + udi_spin_unlock_irqrestore (&adev->mutex, flags); + return -EBUSY; + } + + tmp_finfo.mode = OPEN_READ; + tmp_finfo.acc_flags = 0; + if ((err = + oss_audio_open_engine (adev->engine_num, OSS_DEV_DSP, + &tmp_finfo, 1, OF_SMALLBUF, + NULL)) < 0) + { + return err; + } + + udi_spin_lock_irqsave (&adev->mutex, &flags); + adev->open_mode = OPEN_READ; + runtime->hw = snd_cuckoo_capture; + copy_hw_caps (runtime, adev, OPEN_READ); + snd_pcm_set_sync (substream); + adev->pid = current->pid; + strncpy (adev->cmd, current->comm, sizeof (adev->cmd) - 1); + adev->cmd[sizeof (adev->cmd) - 1] = 0; + adev->inputintr = cuckoo_inputintr; + udi_spin_unlock_irqrestore (&adev->mutex, flags); + + return 0; +} + +static int +snd_cuckoo_playback_close (snd_pcm_substream_t * substream) +{ + cuckoo_t *chip = snd_pcm_substream_chip (substream); + int snum = substream->number; + adev_t *adev; + oss_native_word flags; + struct fileinfo tmp_finfo; + + if (snum < 0 || snum >= chip->npcm) + return -ENXIO; + + adev = chip->play_adev[snum]; + + udi_spin_lock_irqsave (&adev->mutex, &flags); + cuckoo_playsubstream[adev->engine_num] = NULL; + udi_spin_unlock_irqrestore (&adev->mutex, flags); + + tmp_finfo.mode = OPEN_WRITE; + tmp_finfo.acc_flags = 0; + oss_audio_release (adev->engine_num, &tmp_finfo); + + return 0; +} + +static int +snd_cuckoo_capture_close (snd_pcm_substream_t * substream) +{ + cuckoo_t *chip = snd_pcm_substream_chip (substream); + int snum = substream->number; + adev_t *adev; + oss_native_word flags; + struct fileinfo tmp_finfo; + + if (snum < 0 || snum >= chip->npcm) + return -ENXIO; + + adev = chip->capture_adev[snum]; + + udi_spin_lock_irqsave (&adev->mutex, &flags); + cuckoo_capturesubstream[adev->engine_num] = NULL; + udi_spin_unlock_irqrestore (&adev->mutex, flags); + + tmp_finfo.mode = OPEN_READ; + tmp_finfo.acc_flags = 0; + oss_audio_release (adev->engine_num, &tmp_finfo); + + return 0; +} + +static int +snd_cuckoo_playback_hw_params (snd_pcm_substream_t * substream, + snd_pcm_hw_params_t * hw_params) +{ + cuckoo_t *chip = snd_pcm_substream_chip (substream); + snd_pcm_runtime_t *runtime = substream->runtime; + int snum = substream->number; + adev_t *adev; + dmap_t *dmap; + + if (snum < 0 || snum >= chip->npcm) + return -ENXIO; + + adev = chip->play_adev[snum]; + dmap = adev->dmap_out; + + if (dmap->dmabuf == NULL) + return -ENOMEM; + + runtime->dma_area = dmap->dmabuf; + runtime->dma_addr = dmap->dmabuf_phys; + runtime->dma_bytes = dmap->buffsize; + memset (dmap->dmabuf, 0, dmap->buffsize); + + return 0; +} + +static int +snd_cuckoo_capture_hw_params (snd_pcm_substream_t * substream, + snd_pcm_hw_params_t * hw_params) +{ + cuckoo_t *chip = snd_pcm_substream_chip (substream); + snd_pcm_runtime_t *runtime = substream->runtime; + int snum = substream->number; + adev_t *adev; + dmap_t *dmap; + + if (snum < 0 || snum >= chip->npcm) + return -ENXIO; + + adev = chip->capture_adev[snum]; + dmap = adev->dmap_in; + + if (dmap->dmabuf == NULL) + return -ENOMEM; + + runtime->dma_area = dmap->dmabuf; + runtime->dma_addr = dmap->dmabuf_phys; + runtime->dma_bytes = dmap->buffsize; + memset (dmap->dmabuf, 0, dmap->buffsize); + + return 0; +} + +static int +snd_cuckoo_hw_free (snd_pcm_substream_t * substream) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + + runtime->dma_area = NULL; + runtime->dma_addr = 0; + runtime->dma_bytes = 0; + + return 0; +} + +static int +snd_cuckoo_playback_prepare (snd_pcm_substream_t * substream) +{ + cuckoo_t *chip = snd_pcm_substream_chip (substream); + snd_pcm_runtime_t *runtime = substream->runtime; + int snum = substream->number, err; + adev_t *adev; + oss_native_word flags; + dmap_t *dmap; + + if (snum < 0 || snum >= chip->npcm) + return -ENXIO; + + adev = chip->play_adev[snum]; + dmap = adev->dmap_out; + + udi_spin_lock_irqsave (&adev->mutex, &flags); + + adev->d->adrv_set_format (adev->engine_num, + snd_pcm_format_width (runtime->format)); + runtime->channels = + adev->d->adrv_set_channels (adev->engine_num, runtime->channels); + runtime->rate = adev->d->adrv_set_rate (adev->engine_num, runtime->rate); + adev->user_parms.rate = adev->user_parms.rate = runtime->rate; + + dmap->bytes_in_use = snd_pcm_lib_buffer_bytes (substream); + dmap->fragment_size = snd_pcm_lib_period_bytes (substream); + +#if 1 + { + int f, s;; + + f = dmap->fragment_size / 4; + if (f < 128) + f = dmap->fragment_size / 2; + if (f < 128) + f = dmap->fragment_size; + + s = dmap->bytes_in_use; + while (s > f) + s /= 2; + + dmap->fragment_size = s; + } +#endif + + if (adev->max_block > 0 && dmap->fragment_size > adev->max_block) + dmap->fragment_size = adev->max_block; + if (adev->min_block > 0 && dmap->fragment_size < adev->min_block) + dmap->fragment_size = adev->min_block; + if (dmap->fragment_size < 8) + dmap->fragment_size = 8; + dmap->nfrags = dmap->bytes_in_use / dmap->fragment_size; + + err = + adev->d->adrv_prepare_for_output (adev->engine_num, dmap->fragment_size, + dmap->nfrags); + cuckoo_playsubstream[adev->engine_num] = substream; + udi_spin_unlock_irqrestore (&adev->mutex, flags); + return err; +} + +static int +snd_cuckoo_capture_prepare (snd_pcm_substream_t * substream) +{ + cuckoo_t *chip = snd_pcm_substream_chip (substream); + snd_pcm_runtime_t *runtime = substream->runtime; + int snum = substream->number, err; + adev_t *adev; + oss_native_word flags; + dmap_t *dmap; + + if (snum < 0 || snum >= chip->npcm) + return -ENXIO; + + adev = chip->capture_adev[snum]; + dmap = adev->dmap_in; + + udi_spin_lock_irqsave (&adev->mutex, &flags); + + adev->d->adrv_set_format (adev->engine_num, + snd_pcm_format_width (runtime->format)); + adev->d->adrv_set_channels (adev->engine_num, runtime->channels); + adev->d->adrv_set_rate (adev->engine_num, runtime->rate); + + dmap->bytes_in_use = snd_pcm_lib_buffer_bytes (substream); + dmap->fragment_size = snd_pcm_lib_period_bytes (substream); + +#if 1 + { + int f, s;; + + f = dmap->fragment_size / 4; + if (f < 128) + f = dmap->fragment_size / 2; + if (f < 128) + f = dmap->fragment_size; + + s = dmap->bytes_in_use; + while (s > f) + s /= 2; + + dmap->fragment_size = s; + } +#endif + + if (adev->max_block > 0 && dmap->fragment_size > adev->max_block) + dmap->fragment_size = adev->max_block; + if (adev->min_block > 0 && dmap->fragment_size < adev->min_block) + dmap->fragment_size = adev->min_block; + if (dmap->fragment_size < 8) + dmap->fragment_size = 8; + dmap->nfrags = dmap->bytes_in_use / dmap->fragment_size; + + err = + adev->d->adrv_prepare_for_input (adev->engine_num, dmap->fragment_size, + dmap->nfrags); + cuckoo_capturesubstream[adev->engine_num] = substream; + udi_spin_unlock_irqrestore (&adev->mutex, flags); + return err; +} + +static int +snd_cuckoo_playback_trigger (snd_pcm_substream_t * substream, int cmd) +{ + cuckoo_t *chip = snd_pcm_substream_chip (substream); + //snd_pcm_runtime_t *runtime = substream->runtime; + int snum = substream->number; + adev_t *adev; + oss_native_word flags; + dmap_t *dmap; + int err = 0; + + if (snum < 0 || snum >= chip->npcm) + return -ENXIO; + + adev = chip->play_adev[snum]; + dmap = adev->dmap_out; + + udi_spin_lock_irqsave (&adev->mutex, &flags); + + switch (cmd) + { + case SNDRV_PCM_TRIGGER_START: + adev->d->adrv_output_block (adev->engine_num, dmap->dmabuf_phys, + dmap->bytes_in_use, dmap->fragment_size, 0); + adev->d->adrv_trigger (adev->engine_num, PCM_ENABLE_OUTPUT); + break; + + case SNDRV_PCM_TRIGGER_STOP: + adev->d->adrv_trigger (adev->engine_num, 0); + break; + + default: + printk ("cuckoo: Bad trigger cmd %x\n", cmd); + err = -EIO; + goto fail; + } + +fail: + udi_spin_unlock_irqrestore (&adev->mutex, flags); + return err; +} + +static int +snd_cuckoo_capture_trigger (snd_pcm_substream_t * substream, int cmd) +{ + cuckoo_t *chip = snd_pcm_substream_chip (substream); + //snd_pcm_runtime_t *runtime = substream->runtime; + int snum = substream->number; + adev_t *adev; + oss_native_word flags; + dmap_t *dmap; + int err = 0; + + if (snum < 0 || snum >= chip->npcm) + return -ENXIO; + + adev = chip->capture_adev[snum]; + dmap = adev->dmap_in; + + udi_spin_lock_irqsave (&adev->mutex, &flags); + + switch (cmd) + { + case SNDRV_PCM_TRIGGER_START: + adev->d->adrv_start_input (adev->engine_num, dmap->dmabuf_phys, + dmap->bytes_in_use, dmap->fragment_size, 0); + adev->d->adrv_trigger (adev->engine_num, PCM_ENABLE_INPUT); + break; + + case SNDRV_PCM_TRIGGER_STOP: + adev->d->adrv_trigger (adev->engine_num, 0); + break; + + default: + printk ("cuckoo: Bad trigger cmd %x\n", cmd); + err = -EIO; + goto fail; + } + +fail: + udi_spin_unlock_irqrestore (&adev->mutex, flags); + return err; +} + +static snd_pcm_uframes_t +snd_cuckoo_playback_pointer (snd_pcm_substream_t * substream) +{ + cuckoo_t *chip = snd_pcm_substream_chip (substream); + //snd_pcm_runtime_t *runtime = substream->runtime; + int snum = substream->number; + adev_t *adev; + dmap_t *dmap; + int pos; + + if (snum < 0 || snum >= chip->npcm) + return -ENXIO; + + adev = chip->play_adev[snum]; + dmap = adev->dmap_out; + + if (adev->d->adrv_get_output_pointer != NULL) + pos = + adev->d->adrv_get_output_pointer (adev->engine_num, dmap, PCM_ENABLE_OUTPUT); + else + { + pos = dmap->fragment_counter * dmap->fragment_size; + } + pos = bytes_to_frames (substream->runtime, pos); + + return pos; +} + +static snd_pcm_uframes_t +snd_cuckoo_capture_pointer (snd_pcm_substream_t * substream) +{ + cuckoo_t *chip = snd_pcm_substream_chip (substream); + //snd_pcm_runtime_t *runtime = substream->runtime; + int snum = substream->number; + adev_t *adev; + dmap_t *dmap; + int pos; + + if (snum < 0 || snum >= chip->npcm) + return -ENXIO; + + adev = chip->capture_adev[snum]; + dmap = adev->dmap_in; + + if (adev->d->adrv_get_input_pointer != NULL) + pos = + adev->d->adrv_get_input_pointer (adev->engine_num, dmap, PCM_ENABLE_INPUT); + else + { + pos = dmap->fragment_counter * dmap->fragment_size; + } + pos = bytes_to_frames (substream->runtime, pos); + + return pos; +} + +static snd_pcm_ops_t snd_cuckoo_playback_ops = { + .open = snd_cuckoo_playback_open, + .close = snd_cuckoo_playback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_cuckoo_playback_hw_params, + .hw_free = snd_cuckoo_hw_free, + .prepare = snd_cuckoo_playback_prepare, + .trigger = snd_cuckoo_playback_trigger, + .pointer = snd_cuckoo_playback_pointer, +}; + +static snd_pcm_ops_t snd_cuckoo_capture_ops = { + .open = snd_cuckoo_capture_open, + .close = snd_cuckoo_capture_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_cuckoo_capture_hw_params, + .hw_free = snd_cuckoo_hw_free, + .prepare = snd_cuckoo_capture_prepare, + .trigger = snd_cuckoo_capture_trigger, + .pointer = snd_cuckoo_capture_pointer, +}; + +int +install_pcm_instances (cuckoo_t * chip, int cardno) +{ + int dev, err, ok = 0; + int ninputs = 0, noutputs = 0; + + for (dev = 0; dev < num_audio_devfiles; dev++) + if (audio_devfiles[dev]->card_number == cardno) + { + adev_t *adev = audio_devfiles[dev]; + adev_t *nextdev = audio_devfiles[dev + 1]; + snd_pcm_t *pcm; + + ninputs = noutputs = 0; + + ok = 0; +/* Special handling for shadow devices */ + if (dev < num_audio_devfiles - 1 && (adev->flags & ADEV_DUPLEX)) + if ((nextdev->flags & ADEV_DUPLEX) + && (nextdev->flags & ADEV_SHADOW)) + ok = 1; + +// Devices with one recording engine and multiple playback ones + if (dev < num_audio_devfiles - 1 && (adev->flags & ADEV_DUPLEX)) + if (adev->card_number == nextdev->card_number) + if ((nextdev->flags & ADEV_NOINPUT)) + ok = 1; + + if (ok) // Device needs special handling + { + if ((err = + snd_pcm_new (chip->card, "OSS/Linux", chip->npcm, 1, 1, + &pcm)) < 0) + { + printk ("cuckoo: snd_pcm_new failed - error %d\n", err); + return err; + } + + pcm->private_data = chip; + chip->pcm[chip->npcm++] = pcm; + strlcpy (pcm->name, adev->name); + + chip->capture_adev[chip->ncapture++] = nextdev; + snd_pcm_set_ops (pcm, SNDRV_PCM_STREAM_CAPTURE, + &snd_cuckoo_capture_ops); + + chip->play_adev[chip->nplay++] = adev; + snd_pcm_set_ops (pcm, SNDRV_PCM_STREAM_PLAYBACK, + &snd_cuckoo_playback_ops); + + dev++; + continue; + } + + if (!(adev->flags & ADEV_NOINPUT)) + ninputs = 1; + if (!(adev->flags & ADEV_NOOUTPUT)) + noutputs = 1; + + if ((err = + snd_pcm_new (chip->card, "OSS/Linux", chip->npcm, noutputs, + ninputs, &pcm)) < 0) + { + printk ("cuckoo: snd_pcm_new failed - error %d\n", err); + return err; + } + + pcm->private_data = chip; + chip->pcm[chip->npcm++] = pcm; + strlcpy (pcm->name, adev->name); + + if (noutputs > 0) + { + chip->play_adev[chip->nplay++] = adev; + snd_pcm_set_ops (pcm, SNDRV_PCM_STREAM_PLAYBACK, + &snd_cuckoo_playback_ops); + } + + if (ninputs > 0) + { + chip->capture_adev[chip->ncapture++] = adev; + snd_pcm_set_ops (pcm, SNDRV_PCM_STREAM_CAPTURE, + &snd_cuckoo_capture_ops); + } + } + + return 0; +} + +EXPORT_SYMBOL (install_pcm_instances); diff --git a/setup/Linux/oss/etc/S89oss b/setup/Linux/oss/etc/S89oss new file mode 100755 index 0000000..5a1cdcd --- /dev/null +++ b/setup/Linux/oss/etc/S89oss @@ -0,0 +1,80 @@ +#!/bin/bash +# +# /etc/rc.d/init.d/oss +# +# Starts the OSS sound driver +# +# chkconfig: 2345 80 20 +# description: Open Sound System for Linux (OSS/Linux) is a \ +# commercial quality sound driver distributed by 4Front Technologies \ +# (http://www.opensound.com). + +### BEGIN INIT INFO +# Provides: oss +# Required-Start: $local_fs $remote_fs +# Should-Start: +# Required-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start OSS +### END INIT INFO + +# Source function library. +if test -f /lib/lsb/init-functions +then +. /lib/lsb/init-functions +fi + +if test -f /etc/rc.d/init.d/functions +then +. /etc/rc.d/init.d/functions +fi + +# Add oss configuration. +. /etc/oss.conf + +RETVAL=0 + +# +# See how we were called. +# +case "$1" in + start) + # Check if OSS is already running + echo -n 'Starting Open Sound System: ' + if ! test -f /usr/sbin/soundon + then + exit 0 + fi + + if test -f $OSSLIBDIR/starting + then + ls -l $OSSLIBDIR/starting + echo Previous start of OSS crashed the system + echo Please resolve the situation and remove file + echo \"$OSSLIBDIR/starting\". Then start OSS by + echo running soundon + exit 0 + fi + + if ! /usr/sbin/soundon + then + echo Starting OSS failed + fi + rm -f $OSSLIBDIR/starting + ;; + stop) + echo -n 'Stopping Open Sound System: ' + + /usr/sbin/savemixer + exit 0 + ;; + restart) + $0 stop + /usr/sbin/soundoff + $0 start + ;; + *) + echo "Usage: $0 {start|stop|restart}" + exit 1 +esac diff --git a/setup/Linux/oss/scripts/90-oss_usb-create-device.fdi b/setup/Linux/oss/scripts/90-oss_usb-create-device.fdi new file mode 100644 index 0000000..28744f9 --- /dev/null +++ b/setup/Linux/oss/scripts/90-oss_usb-create-device.fdi @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<deviceinfo version="0.2"> + <device> + <match key="info.linux.driver" string="oss_usb"> + <append key="info.callouts.add" type="strlist">oss_usb-create-devices</append> + </match> + </device> +</deviceinfo> diff --git a/setup/Linux/oss/scripts/killprocs.sh b/setup/Linux/oss/scripts/killprocs.sh new file mode 100755 index 0000000..ce8d26d --- /dev/null +++ b/setup/Linux/oss/scripts/killprocs.sh @@ -0,0 +1,17 @@ +#!/bin/sh +PROCS="`fuser /dev/mixer* /dev/dsp* /dev/audio* /dev/sequencer /dev/music /dev/midi* 2>/dev/null`" + +if test "$PROCS " = " " +then + exit 0 +fi + +for pid in $PROCS +do + #ps ax|grep "^ *$pid " + echo killing $pid + kill $pid +done + +sleep 2 +exit 0 diff --git a/setup/Linux/oss/scripts/oss_usb-create-devices b/setup/Linux/oss/scripts/oss_usb-create-devices new file mode 100644 index 0000000..a6de13c --- /dev/null +++ b/setup/Linux/oss/scripts/oss_usb-create-devices @@ -0,0 +1,4 @@ +#!/bin/sh + +/usr/sbin/ossdetect -d +/usr/sbin/ossdevlinks diff --git a/setup/Linux/oss/scripts/remove_drv.sh b/setup/Linux/oss/scripts/remove_drv.sh new file mode 100644 index 0000000..55cc1b4 --- /dev/null +++ b/setup/Linux/oss/scripts/remove_drv.sh @@ -0,0 +1,164 @@ +#!/bin/sh +if test -f /etc/oss.conf +then + . /etc/oss.conf +else + OSSLIBDIR=/usr/lib/oss +fi + +# This script wipes out the previously installed sound drivers +# from the system. + +# Backup all kernel sound drivers (ALSA) and remove the kernel/sound +# directory from the system. Untar the backup package to return ALSA +# back in business. + +if test -x /sbin/chkconfig +then + /sbin/chkconfig alsasound off > /dev/null 2>&1 +elif test -x /usr/sbin/update-rc.d +then + /usr/sbin/update-rc.d -f alsa-utils remove > /dev/null 2>&1 +elif test -x /usr/sbin/alsa +then + /usr/sbin/alsa force-unload > /dev/null 2>&1 +fi + +if test -d /lib/modules/`uname -r`/kernel/sound +then + if ! test -f /lib/modules/`uname -r`/sound-preoss.tar.bz2 + then + (cd /lib/modules/`uname -r`; tar cfj /lib/modules/`uname -r`/sound-preoss.tar.bz2 kernel/sound) + fi + + rm -rf /lib/modules/`uname -r`/kernel/sound + depmod -a +fi + +# Kill all applications using ALSA or OSS/Free devices + +# We have to use ugly replacement of fuser since this command got broken +# in some Linux recent distributions. + +KILL=0 + +for n in /proc/[0-9]* +do + PID=`basename $n` + if test "`ls -l $n/fd/* 2>/dev/null|grep /dev/snd` " != " " + then + KILL=1 + fi + + if test "`ls -l $n/fd/* 2>/dev/null|grep /dev/mixer` " != " " + then + KILL=1 + fi +done + +if ! test -d $OSSLIBDIR/save +then + mkdir $OSSLIBDIR/save +fi + +if test "$KILL " = "1 " +then +echo killing + rm -f /dev/mixer.old + mv /dev/mixer /dev/mixer.old 2>/dev/null + #if test -d /dev/snd + #then + #(cd /;tar cfj $OSSLIBDIR/save/alsadevs.tar.bz2 dev/snd) + #fi + + #mv /dev/snd /dev/snd.osssave + #fuser -k -s /dev/mixer.old /dev/snd.osssave/* +fi + +# Remove all loaded ALSA modules +SOUNDDEVS= + +if test -f /dev/mixer.old +then + SOUNDDEVS="$SOUNDDEVS /dev/mixer.old" +fi + +if test -d /dev/snd.osssave +then + SOUNDDEVS="$SOUNDDEVS /dev/snd.osssave/*" +fi + +for timeout in 0 1 2 3 4 5 6 7 8 9 10 11 +do + if test "`cat /proc/modules|grep ^snd_|sed 's/ .*//'` " = " " + then + break + fi + + if test $timeout -gt 10 + then + echo Cannot unload the ALSA modules. Apparently there is some + echo application keeping them busy. + echo Please reboot your system and try to start OSS again. + ps ax + lsmod + cat /proc/devices + cat /proc/interrupts + exit 1 + fi + + if test "$SOUNDDEVS " != " " + then + fuser -s -9 $SOUNDDEVS + else + echo Cannot find any processes using the conflicting sound driver + fi + + for n in `cat /proc/modules|grep ^snd_|sed 's/ .*//'` + do + rmmod $n + #rmmod $n >/dev/null 2>&1 + done + + sleep 1 +done + +rmmod snd > /dev/null 2>&1 + +# Remove soundcore +rmmod soundcore > /dev/null 2>&1 + +rm -f /dev/mixer.old + +if cat /proc/devices|grep -q '^ *14 ' +then + + echo There still appears to be another sound driver hanging around + + lsmod + cat /proc/devices|grep '^ *14 ' + cat /proc/interrupts + + exit 1 +fi + +for n in /dev/sndstat /dev/mixer* /dev/dsp* /dev/midi* /dev/sequencer /dev/music +do + if readlink $n >/dev/null 2>&1 + then # Symbolic link + if readlink $n | grep -q asound + then # Link to ALSA devices + rm -f $n + fi + fi +done + +# Disable automatic startup of ALSA during system bootup + +if test "`ls /etc/rc.d/rc*/*alsasound*` " != " " > /dev/null 2>&1 +then + (cd /;tar cfj $OSSLIBDIR/save/alsarc/tar.bz2 etc/rc.d/rc*/*alsasound*) + rm -f /etc/rc.d/rc*/*alsasound* +fi > /dev/null 2>&1 + +exit 0 diff --git a/setup/Linux/oss/scripts/restore_drv.sh b/setup/Linux/oss/scripts/restore_drv.sh new file mode 100644 index 0000000..9046d04 --- /dev/null +++ b/setup/Linux/oss/scripts/restore_drv.sh @@ -0,0 +1,63 @@ +#!/bin/sh +if test -f /etc/oss.conf +then + . /etc/oss.conf +else + OSSLIBDIR=/usr/lib/oss +fi + +/usr/sbin/soundoff + +rm -rf /lib/modules/`uname -r`/kernel/oss + +if test -x /sbin/chkconfig +then /sbin/chkconfig oss off > /dev/null 2>&1 +else + if test -x /sbin/update-rc.d + then /usr/sbin/update-rc.d -f oss remove > /dev/null 2>&1 + fi +fi + +rm -f /etc/init.d/oss + +if ! test -d /lib/modules/`uname -r`/kernel/sound +then + if test -f /lib/modules/`uname -r`/sound-preoss.tar.bz2 + then + (cd /lib/modules/`uname -r`; tar xfj sound-preoss.tar.bz2) + /sbin/depmod -a + fi +fi + +rm -f /lib/modules/`uname -r`/sound-preoss.tar.bz2 + +if test -f $OSSLIBDIR/sysfiles.list +then + rm -f `cat $OSSLIBDIR/sysfiles.list` +fi + +if test -f $OSSLIBDIR/save/alsadevs.tar.bz2 +then + (cd /;tar xfj $OSSLIBDIR/save/alsadevs.tar.bz2) +fi + +if test -f $OSSLIBDIR/save/alsarc/tar.bz2 +then + (cd /;tar xfj $OSSLIBDIR/save/alsarc/tar.bz2) +fi + +rm -f /dev/dsp* /dev/midi* /dev/mixer* /dev/sndstat + +/sbin/ldconfig + +if test -x /sbin/chkconfig +then + /sbin/chkconfig alsasound on > /dev/null 2>&1 +else + if test -x /usr/sbin/update-rc.d + then + /usr/sbin/update-rc.d alsa-utils defaults > /dev/null 2>&1 + fi +fi + +exit 0 diff --git a/setup/Linux/oss/scripts/setup-alsa.sh b/setup/Linux/oss/scripts/setup-alsa.sh new file mode 100644 index 0000000..fdcf4ff --- /dev/null +++ b/setup/Linux/oss/scripts/setup-alsa.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +# This script will restgore selected ALSA modules that were earlier removed by +# remove_drv.sh + +if test -d /proc/asound +then +# ALSA is already loaded + exit 0 +fi + +if ! test -f /lib/modules/`uname -r`/sound-preoss.tar.bz2 +then + echo ALSA backup archive /lib/modules/`uname -r`/sound-preoss.tar.bz2 not found. Cannot continue. + exit 1 +fi + +RESTORE=kernel/sound/soundcore.ko + +for n in snd snd-pcm snd-timer snd-page-alloc +do + RESTORE="$RESTORE kernel/sound/core/$n.ko kernel/sound/acore/$n.ko" +done + +(cd /lib/modules/`uname -r` && tar xvfj sound-preoss.tar.bz2 $RESTORE) + +if test -d /dev/snd.save && ! test -d /dev/snd +then + mv /dev/snd.save /dev/snd +fi + +exit 0 diff --git a/setup/Linux/oss/scripts/showprocs.sh b/setup/Linux/oss/scripts/showprocs.sh new file mode 100755 index 0000000..827bb33 --- /dev/null +++ b/setup/Linux/oss/scripts/showprocs.sh @@ -0,0 +1,28 @@ +#!/bin/sh +PROCS="`fuser /dev/mixer* /dev/dsp* /dev/audio* /dev/sequencer /dev/music /dev/midi*|sed 's/.* //'|sort|uniq`" + +if test "$PROCS " = " " +then + exit 0 +fi + +if test "$1 " != "-q " +then +echo $PROCS +echo +echo "NOTICE!" +echo "=======" +echo +echo There are some programs still using OSS devices. You may need to stop them +echo manually: +echo +fi + +for pid in $PROCS +do + ps ax|grep "^ *$pid " +done + +echo + +exit 0 diff --git a/setup/Linux/oss/soundon.user b/setup/Linux/oss/soundon.user new file mode 100644 index 0000000..da31b6d --- /dev/null +++ b/setup/Linux/oss/soundon.user @@ -0,0 +1,7 @@ +#!/bin/sh +# +# This script can be used to run programs every time OSS is started. +# By default, this script is disabled, and contains no commands. +# To enable, add executable permissions to this file, and edit below +# commands to be run. +exit 0 diff --git a/setup/Linux/postinst b/setup/Linux/postinst new file mode 100644 index 0000000..f1ccbf3 --- /dev/null +++ b/setup/Linux/postinst @@ -0,0 +1,15 @@ +#!/bin/sh +OSSLIBDIR=/usr/lib/oss +if [ -e /tmp/OSS_UPGRADE ]; then rm /tmp/OSS_UPGRADE; fi +if [ -e /etc/oss.conf ]; then . /etc/oss.conf; else echo "OSSLIBDIR=/usr/lib/oss" > /etc/oss.conf; fi +echo "Building OSS Modules for Linux-`uname -p` `uname -r`" +cd "$OSSLIBDIR"/build +sh install.sh +if [ -x /usr/bin/update-menus ]; then /usr/bin/update-menus; fi +echo "Forcing re-detection of installed soundcards" +ossdetect +echo "Starting Open Sound System" +sync +/usr/sbin/soundoff >> /dev/null 2>&1 +sync +/usr/sbin/soundon || exit 0 diff --git a/setup/Linux/postrm b/setup/Linux/postrm new file mode 100644 index 0000000..620f8e2 --- /dev/null +++ b/setup/Linux/postrm @@ -0,0 +1,6 @@ +#!/bin/sh +OSSLIBDIR=/usr/lib/oss +if [ -e /etc/oss.conf ]; then . /etc/oss.conf; fi +if [ -e /tmp/OSS_UPGRADE ]; then echo "Upgrading OSS - will not purge $OSSLIBDIR."; else rm -rf "$OSSLIBDIR"/*; fi +rm -f /usr/lib/libflashsupport.so +if [ -x /usr/bin/update-menus ]; then /usr/bin/update-menus; fi diff --git a/setup/Linux/preinst b/setup/Linux/preinst new file mode 100644 index 0000000..ae93962 --- /dev/null +++ b/setup/Linux/preinst @@ -0,0 +1,6 @@ +#!/bin/sh +if [ -x /etc/init.d/alsa-utils ]; then /etc/init.d/alsa-utils stop || true; fi +if [ -x /usr/sbin/alsa ]; then /usr/sbin/alsa force-unload || true; fi +if [ -x /etc/init.d/alsa ]; then /etc/init.d/alsa force-unload || true; fi +touch /tmp/OSS_UPGRADE +exit 0 diff --git a/setup/Linux/prerm b/setup/Linux/prerm new file mode 100644 index 0000000..67fdf0c --- /dev/null +++ b/setup/Linux/prerm @@ -0,0 +1,4 @@ +#!/bin/sh +OSSLIBDIR=/usr/lib/oss +if [ -e /etc/oss.conf ]; then . /etc/oss.conf; fi +sh "$OSSLIBDIR"/scripts/restore_drv.sh || true diff --git a/setup/Linux/removeoss.sh b/setup/Linux/removeoss.sh new file mode 100644 index 0000000..0e9d992 --- /dev/null +++ b/setup/Linux/removeoss.sh @@ -0,0 +1,31 @@ +#!/bin/sh +if test `whoami` != "root" +then + echo "You must be super-user or logged in as root to uninstall OSS..." + exit 0 +fi + +if test -f /etc/oss.conf +then + . /etc/oss.conf +else + OSSLIBDIR=/usr/lib/oss +fi + +echo "Uninstalling OSS...." +echo "Running soundoff...." +/usr/sbin/soundoff +echo "Restoring previously install sound drivers..." +sh "$OSSLIBDIR"/scripts/restore_drv.sh +echo "Removing OSS Files in MANIFEST" +cd / +for i in `cat "$OSSLIBDIR"/MANIFEST` +do +# echo "Removing file $i" +rm -f $i +done + +echo "Removing $OSSLIBDIR directory" +rm -rf "$OSSLIBDIR" + +echo "OSS Uninstalled. However you may need to reboot the system." diff --git a/setup/Linux/sbin/soundoff b/setup/Linux/sbin/soundoff new file mode 100755 index 0000000..16ff69c --- /dev/null +++ b/setup/Linux/sbin/soundoff @@ -0,0 +1,69 @@ +#!/bin/sh +if test -f /etc/oss.conf +then + . /etc/oss.conf +else + OSSLIBDIR=/usr/lib/oss +fi + +if ! test -f /proc/opensound/devfiles +then + echo OSS not loaded. + exit 0 +fi + +if ! test -f $OSSLIBDIR/etc/installed_drivers +then + echo $OSSLIBDIR/etc/installed_drivers is missing. + exit 1 +fi + + +# Save mixer settings automatically if requested +if test -f $OSSLIBDIR/etc/userdefs && grep -q "autosave_mixer yes" $OSSLIBDIR/etc/userdefs +then + /usr/sbin/savemixer +fi + +# Save legacy devices +/usr/sbin/ossdevlinks -N + +PROGRAMS="`fuser /dev/mixer* /dev/dsp* /dev/midi* /dev/oss/*/* 2>/dev/null`" + +if test "$PROGRAMS " != " " +then + echo + echo Some applications are still using OSS - cannot unload + echo + + for n in $PROGRAMS + do + if test -f /proc/$n/cmdline + then + echo $n `cat /proc/$n/cmdline | sed 's/\x00/ /g'` + else + echo $n Unknown + fi + done + + echo + echo Please stop these applications and run soundoff again + exit 2 +fi + +for i in 1 2 3 +do + for n in `egrep "^osscore" /proc/modules 2>/dev/null | cut -d ' ' -f 4 | sed 's/,/ /g'` `cat $OSSLIBDIR/etc/installed_drivers | sed 's/#.*//'` osscore + do + /sbin/modprobe -r $n > /dev/null 2>&1 + done +done + +if ! test -f /proc/opensound/devfiles # OSS gone? +then + exit 0 +fi + +echo Cannot unload the OSS driver modules + +exit 3 diff --git a/setup/Linux/sbin/soundon b/setup/Linux/sbin/soundon new file mode 100755 index 0000000..e868fd6 --- /dev/null +++ b/setup/Linux/sbin/soundon @@ -0,0 +1,351 @@ +#!/bin/sh +if test -f /etc/oss.conf +then + . /etc/oss.conf +else + OSSLIBDIR=/usr/lib/oss +fi + +if ! test -d /proc +then + echo soundon script requires procfs to be mounted at /proc! + exit 200 +fi + +if test -f /proc/opensound/devfiles +then + echo OSS is already loaded. + exit 0 +fi + +if test -f $OSSLIBDIR/starting +then + echo Previous start of OSS crashed the system + echo Please resolve the situation and remove file + echo \"$OSSLIBDIR/starting\". Then start OSS by + echo running soundon again. + exit 1 +fi + +NOTIFY=0 + +LOG=/var/log/soundon.log +echo "Open Sound System starting" `date` > $LOG +echo "OSS version: " `cat $OSSLIBDIR/version.dat` >> $LOG 2>&1 +KERNEL_VERSION=`uname -r` +echo "Kernel version: " $KERNEL_VERSION >> $LOG +KERNEL_VERMAGIC=`/usr/sbin/ossvermagic -z -s` +echo "Kernel vermagic: " $KERNEL_VERMAGIC >> $LOG 2>&1 + +if ! test -f $OSSLIBDIR/etc/installed_drivers +then + echo No $OSSLIBDIR/etc/installed_drivers - running ossdetect >> $LOG + /usr/sbin/ossdetect -v >> $LOG +fi + +if ! test -f $OSSLIBDIR/etc/installed_drivers +then + echo Still no $OSSLIBDIR/etc/installed_drivers - cannot continue >> $LOG + echo No $OSSLIBDIR/etc/installed_drivers - cannot continue + exit 10 +fi + +UBUNTU_OVERRIDE= +POS_UBUNTU_OVERRIDE= +if test -f /lib/modules/$KERNEL_VERSION/kernel/oss/osscore.ko +then +# Verify that vermagic of OSS matches the kernel vermagic + + OSS_VERMAGIC=`/usr/sbin/ossvermagic -z -q /lib/modules/$KERNEL_VERSION/kernel/oss/osscore.ko` + + if ! test "$OSS_VERMAGIC " = "$KERNEL_VERMAGIC " + then + OSS_ORIG_VERMAGIC="$OSS_VERMAGIC" + OSS_VERMAGIC=`/usr/sbin/ossvermagic -z -u -q /lib/modules/$KERNEL_VERSION/kernel/oss/osscore.ko` + POS_UBUNTU_OVERRIDE=1 + fi + + if ! test "$OSS_VERMAGIC " = "$KERNEL_VERMAGIC " + then + echo "Old vermagic: " $OSS_VERMAGIC >> $LOG + rm -rf /lib/modules/$KERNEL_VERSION/kernel/oss + echo Previous OSS modules were for a different kernel version - removed + echo Previous OSS modules were for a different kernel version - removed >> $LOG + elif test "$POS_UBUNTU_OVERRIDE " = "1 " + then + echo "Vermagic backup check activated for Ubuntu. Backup vermagic: $OSS_VERMAGIC. OSS stored vermagic $OSS_ORIG_VERMAGIC" >> $LOG + UBUNTU_OVERRIDE="-u" + fi +fi + +if ! test -f /lib/modules/$KERNEL_VERSION/kernel/oss/osscore.ko +then + NOTIFY=1 + echo Relinking OSS kernel modules for \"$KERNEL_VERMAGIC\" + echo This may take few moments - please stand by... + echo Relinking OSS kernel modules for $KERNEL_VERMAGIC >> $LOG + + rm -f /var/log/relink.log + if ! (cd $OSSLIBDIR/build && sh install.sh > /var/log/relink.log 2>&1) + then + cat /var/log/relink.log >> $LOG 2>&1 + cat /var/log/relink.log + echo + echo Relinking the OSS kernel modules failed + rm -f /var/log/relink.log + exit 20 + fi + + cat /var/log/relink.log >> $LOG 2>&1 + echo Relinking OSS kernel modules finished + rm -f /var/log/relink.log +fi + +if ! test -f /lib/modules/$KERNEL_VERSION/kernel/oss/osscore.ko +then + echo + echo No /lib/modules/$KERNEL_VERSION/kernel/oss/osscore.ko module >> $LOG + echo No /lib/modules/$KERNEL_VERSION/kernel/oss/osscore.ko module in the system + exit 30 +fi + +OSS_VERMAGIC=`/usr/sbin/ossvermagic -z $UBUNTU_OVERRIDE -q /lib/modules/$KERNEL_VERSION/kernel/oss/osscore.ko` +echo "OSS vermagic: " $OSS_VERMAGIC >> $LOG + +if ! test "$OSS_VERMAGIC " = "$KERNEL_VERMAGIC " +then + echo OSS driver modules do not match the current kernel >> $LOG + echo + echo Error: OSS driver modules do not match the current kernel + echo + echo "Kernel vermagic: " $KERNEL_VERMAGIC + echo "OSS vermagic: " $OSS_VERMAGIC + echo + echo The most likely reason is that the kernel development package + echo installed in the system is wrong. Please refer to the documentation + echo of your Linux distribution for more info about setting up the + echo kernel/driver development environment properly. + echo + exit 40 +fi + +if test -f $OSSLIBDIR/etc/license.asc +then + /usr/sbin/ossdetect -l >> $LOG +fi + +if test -d /proc/asound || grep -q '^ *14 ' < /proc/devices +then + if ! sh $OSSLIBDIR/scripts/remove_drv.sh>> $LOG + then + echo Failed to disable conflicting sound drivers >> $LOG + echo Failed to disable conflicting sound drivers + echo Reboot and try running soundon again + echo + echo Also check that you have not compiled sound support statically + echo into the kernel. + exit 50 + fi +fi + +echo >> $LOG +echo '*** Loading OSS kernel modules ***' >> $LOG +echo >> $LOG + +touch $OSSLIBDIR/starting +sync + +OPTIONS= +if test -f $OSSLIBDIR/conf/osscore.conf +then + OPTIONS="`grep -v -h '^#' $OSSLIBDIR/conf/osscore.conf|sed 's/[ \t]//g'`" +fi + +if ! /sbin/modprobe osscore $OPTIONS +then + echo Loading the osscore module failed + echo Loading the osscore module failed >> $LOG + dmesg >> $LOG + exit 60 +fi + +echo "osscore module loaded OK" >> $LOG + +for n in `cat $OSSLIBDIR/etc/installed_drivers | sed 's/#.*//'` +do + OPTIONS= + + if test -f $OSSLIBDIR/conf/$n.conf + then + OPTIONS="`grep -v -h '^#' $OSSLIBDIR/conf/$n.conf|sed 's/[ \t]//g'`" + fi + + if ! /sbin/modprobe $n $OPTIONS + then + echo Loading module $n failed '-' ignored >> $LOG + echo Loading module $n failed '-' ignored + else + echo $n module loaded OK >> $LOG + fi +done +echo >> $LOG +echo '*** Finished loading OSS kernel modules ***' >> $LOG +echo >> $LOG + +if ! test -f /proc/opensound/devfiles +then + echo OSS Core module refused to start >> $LOG + echo OSS Core module refused to start + dmesg >> $LOG + exit 70 +fi + +/usr/sbin/ossdetect -d >> $LOG 2>&1 + +# Restore the legacy device links. This is necessary because in some +# Linux distributions they get lost when the system is booted. +if test -f $OSSLIBDIR/etc/legacy_devices +then + sh $OSSLIBDIR/etc/legacy_devices >> $LOG 2>&1 +fi + +/usr/sbin/ossdevlinks -v >> $LOG 2>&1 + +echo "+++ ossinfo -v3 +++" >> $LOG +ossinfo -v3 >> $LOG 2>&1 +echo "+++ /dev/sndstat +++" >> $LOG +cat /dev/sndstat >> $LOG 2>&1 +echo "+++ dmesg +++" >> $LOG +dmesg >> $LOG +echo "+++ lspci +++" >> $LOG +lspci -vnn >> $LOG 2>&1 +echo "+++ /proc/interrupts +++" >> $LOG +cat /proc/interrupts >> $LOG 2>&1 +echo "+++ /proc/cpuinfo +++" >> $LOG +cat /proc/cpuinfo >> $LOG 2>&1 +echo "+++ /proc/opensound/devfiles +++" >> $LOG +cat /proc/opensound/devfiles >> $LOG 2>&1 +ls -l /dev/dsp* /dev/mixer* /dev/midi* /dev/oss/*/* >> $LOG 2>&1 + +echo >> $LOG +/usr/sbin/savemixer -L -v >> $LOG 2>&1 + +# Setup ALSA emulation + +if test -f $OSSLIBDIR/.cuckoo_installed +then +# Use kernel based ALSA compatibility + + if ! test -f /lib/modules/$KERNEL_VERSION/kernel/sound/core/snd.ko + then + sh $OSSLIBDIR/scripts/setup-alsa.sh >> $LOG 2>&1 + depmod -a + fi + + echo "*** Setting up ALSA compatibility ****" >> $LOG + modprobe cuckoo >> $LOG 2>&1 + head -10 /proc/asound/version >> $LOG 2>&1 + lsmod|grep snd >> $LOG + echo "**************************************" >> $LOG +elif test -f $OSSLIBDIR/.libsalsa_installed +then +# Use library based ALSA compatibility + + if test -f $OSSLIBDIR/lib/libsalsa.so.2.0.0 + then + if test "`uname -m` " = "x86_64 " + then + ln -sf $OSSLIBDIR/lib/libsalsa.so.2.0.0 /usr/lib64/libasound.so.2 + #ln -sf $OSSLIBDIR/lib/libOSSlib.so /usr/lib64 + else + if test -s /lib/libasound.so.2 + then + ln -sf $OSSLIBDIR/lib/libsalsa.so.2.0.0 /lib/libasound.so.2 + #ln -sf $OSSLIBDIR/lib/libOSSlib.so /lib + fi + + if test -s /usr/lib/libasound.so.2 + then + ln -sf $OSSLIBDIR/lib/libsalsa.so.2.0.0 /usr/lib/libasound.so.2 + #ln -sf $OSSLIBDIR/lib/libOSSlib.so /usr/lib + fi + fi + fi +fi + +# Setup libOSSlib.so +if test -f $OSSLIBDIR/lib/libOSSlib.so +then + if test "`uname -m` " = "x86_64 " + then + ln -sf $OSSLIBDIR/lib/libOSSlib.so /usr/lib64 + ln -sf $OSSLIBDIR/lib/libossmix.so /usr/lib64 + else + if test -s /lib/libasound.so.2 + then + ln -sf $OSSLIBDIR/lib/libOSSlib.so /lib + ln -sf $OSSLIBDIR/lib/libossmix.so /lib + fi + + if test -s /usr/lib/libasound.so.2 + then + ln -sf $OSSLIBDIR/lib/libOSSlib.so /usr/lib + ln -sf $OSSLIBDIR/lib/libossmix.so /usr/lib + fi + fi +fi + +# Setup Flash 9 audio support plugin for OSS + +if test -d /usr/lib64 && test -f $OSSLIBDIR/lib/libflashsupport_64.so +then + ln -sf $OSSLIBDIR/lib/libflashsupport_64.so /usr/lib64/libflashsupport.so +fi + +if test -d /usr/lib32 && test -f $OSSLIBDIR/lib/libflashsupport_32.so +then + ln -sf $OSSLIBDIR/lib/libflashsupport_32.so /usr/lib32/libflashsupport.so +fi + +if ! test -f /usr/lib/libflashsupport.so && test -f $OSSLIBDIR/lib/libflashsupport_32.so +then + ln -sf $OSSLIBDIR/lib/libflashsupport_32.so /usr/lib/libflashsupport.so +fi + +if test -x $OSSLIBDIR/soundon.user +then + echo Running $OSSLIBDIR/soundon.user >> $LOG + $OSSLIBDIR/soundon.user >> $LOG 2>&1 +fi + +if test "`ossinfo -g|grep TRIAL` " != " " +then + echo + echo "************************************************************" + echo "* NOTE! You are using trial version of Open Sound System *" + echo "************************************************************" + echo + + sleep 1 +fi + +if test "`ossinfo -g|grep EXPIRED` " != " " +then + echo + echo "****************************************************************" + echo "* NOTE! Your Open Sound System evaluation license has expired *" + echo "****************************************************************" + echo + + sleep 15 +fi + +if test "$NOTIFY " = "1 " +then + echo + echo OSS started OK +fi + +rm -f $OSSLIBDIR/starting + +exit 0 diff --git a/setup/Linux/shlibs b/setup/Linux/shlibs new file mode 100644 index 0000000..95e6d37 --- /dev/null +++ b/setup/Linux/shlibs @@ -0,0 +1 @@ +libsalsa 2 oss-linux diff --git a/setup/Linux/spec.tmpl b/setup/Linux/spec.tmpl new file mode 100644 index 0000000..2861496 --- /dev/null +++ b/setup/Linux/spec.tmpl @@ -0,0 +1,39 @@ +Summary: Open Sound System sound drivers for Linux +License: Open Sound System +Group: System/sound +Source: oss +URL: http://www.opensound.com +Distribution: Open Sound System +Vendor: 4Front Technologies +Packager: 4Front Technologies +BuildRoot: /tmp/prototype +Requires: gcc, make +%if 0%{?suse_version} +Requires: kernel-default-devel +%else +Requires: kernel-devel +%endif + +%description +Open Sound System for Linux (OSS/Linux) is a commercial quality sound driver +distributed by 4Front Technologies (http://www.opensound.com). OSS provides +support for practically all sound cards on the market including PnP and +many PCI ones. Installation and configuration is higly automated and easy to +perform. To obtain technical support and additional features, you will need to +order a license key from http://www.opensound.com/order.html +%prep +%setup +%pre +%post +echo "Building OSS Modules for Linux-`uname -p` `uname -r`" +cd OSSLIBDIR/build +sh install.sh +echo "Starting Open Sound System" +/usr/sbin/soundoff >> /dev/null 2>&1 +/usr/sbin/soundon +exit 0 +%preun +sh OSSLIBDIR/scripts/restore_drv.sh +%postun +rm -rf OSSLIBDIR/* +rm -f /usr/lib/libflashsupport.so |