summaryrefslogtreecommitdiff
path: root/setup/Linux/oss
diff options
context:
space:
mode:
Diffstat (limited to 'setup/Linux/oss')
-rw-r--r--setup/Linux/oss/build/Makefile.osscore32
-rw-r--r--setup/Linux/oss/build/Makefile.tmpl21
-rw-r--r--setup/Linux/oss/build/install.sh347
-rw-r--r--setup/Linux/oss/build/module.inc245
-rw-r--r--setup/Linux/oss/build/osscore.c2214
-rw-r--r--setup/Linux/oss/build/ossdip.h10
-rw-r--r--setup/Linux/oss/build/pci_wrapper.inc93
-rw-r--r--setup/Linux/oss/build/usb_wrapper.inc730
-rw-r--r--setup/Linux/oss/cuckoo/Makefile23
-rw-r--r--setup/Linux/oss/cuckoo/checksum.h0
-rw-r--r--setup/Linux/oss/cuckoo/cuckoo.c251
-rw-r--r--setup/Linux/oss/cuckoo/cuckoo.h171
-rw-r--r--setup/Linux/oss/cuckoo/cuckoo_midi.c310
-rw-r--r--setup/Linux/oss/cuckoo/cuckoo_mixer.c389
-rw-r--r--setup/Linux/oss/cuckoo/cuckoo_pcm.c810
-rwxr-xr-xsetup/Linux/oss/etc/S89oss80
-rw-r--r--setup/Linux/oss/scripts/90-oss_usb-create-device.fdi8
-rwxr-xr-xsetup/Linux/oss/scripts/killprocs.sh17
-rw-r--r--setup/Linux/oss/scripts/oss_usb-create-devices4
-rw-r--r--setup/Linux/oss/scripts/remove_drv.sh164
-rw-r--r--setup/Linux/oss/scripts/restore_drv.sh63
-rw-r--r--setup/Linux/oss/scripts/setup-alsa.sh32
-rwxr-xr-xsetup/Linux/oss/scripts/showprocs.sh28
-rw-r--r--setup/Linux/oss/soundon.user7
24 files changed, 6049 insertions, 0 deletions
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